aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/matplotlib/py3/src
diff options
context:
space:
mode:
authormaxim-yurchuk <maxim-yurchuk@yandex-team.com>2025-02-11 13:26:52 +0300
committermaxim-yurchuk <maxim-yurchuk@yandex-team.com>2025-02-11 13:57:59 +0300
commitf895bba65827952ed934b2b46f9a45e30a191fd2 (patch)
tree03260c906d9ec41cdc03e2a496b15d407459cec0 /contrib/python/matplotlib/py3/src
parent5f7060466f7b9707818c2091e1a25c14f33c3474 (diff)
downloadydb-f895bba65827952ed934b2b46f9a45e30a191fd2.tar.gz
Remove deps on pandas
<https://github.com/ydb-platform/ydb/pull/14418> <https://github.com/ydb-platform/ydb/pull/14419> \-- аналогичные правки в gh Хочу залить в обход синка, чтобы посмотреть удалится ли pandas в нашей gh репе через piglet commit_hash:abca127aa37d4dbb94b07e1e18cdb8eb5b711860
Diffstat (limited to 'contrib/python/matplotlib/py3/src')
-rw-r--r--contrib/python/matplotlib/py3/src/_backend_agg.cpp176
-rw-r--r--contrib/python/matplotlib/py3/src/_backend_agg.h1280
-rw-r--r--contrib/python/matplotlib/py3/src/_backend_agg_basic_types.h123
-rw-r--r--contrib/python/matplotlib/py3/src/_backend_agg_wrapper.cpp646
-rw-r--r--contrib/python/matplotlib/py3/src/_c_internal_utils.c211
-rw-r--r--contrib/python/matplotlib/py3/src/_image_resample.h834
-rw-r--r--contrib/python/matplotlib/py3/src/_image_wrapper.cpp297
-rw-r--r--contrib/python/matplotlib/py3/src/_path.h1251
-rw-r--r--contrib/python/matplotlib/py3/src/_path_wrapper.cpp772
-rw-r--r--contrib/python/matplotlib/py3/src/_qhull_wrapper.cpp340
-rw-r--r--contrib/python/matplotlib/py3/src/_tkagg.cpp370
-rw-r--r--contrib/python/matplotlib/py3/src/_tkmini.h110
-rw-r--r--contrib/python/matplotlib/py3/src/_ttconv.cpp96
-rw-r--r--contrib/python/matplotlib/py3/src/agg_workaround.h85
-rw-r--r--contrib/python/matplotlib/py3/src/array.h80
-rw-r--r--contrib/python/matplotlib/py3/src/checkdep_freetype2.c19
-rw-r--r--contrib/python/matplotlib/py3/src/ft2font.cpp840
-rw-r--r--contrib/python/matplotlib/py3/src/ft2font.h159
-rw-r--r--contrib/python/matplotlib/py3/src/ft2font_wrapper.cpp1578
-rw-r--r--contrib/python/matplotlib/py3/src/mplutils.h99
-rw-r--r--contrib/python/matplotlib/py3/src/numpy_cpp.h578
-rw-r--r--contrib/python/matplotlib/py3/src/path_converters.h1106
-rw-r--r--contrib/python/matplotlib/py3/src/py_adaptors.h248
-rw-r--r--contrib/python/matplotlib/py3/src/py_converters.cpp558
-rw-r--r--contrib/python/matplotlib/py3/src/py_converters.h48
-rw-r--r--contrib/python/matplotlib/py3/src/py_exceptions.h72
-rw-r--r--contrib/python/matplotlib/py3/src/tri/_tri.cpp2074
-rw-r--r--contrib/python/matplotlib/py3/src/tri/_tri.h799
-rw-r--r--contrib/python/matplotlib/py3/src/tri/_tri_wrapper.cpp58
29 files changed, 0 insertions, 14907 deletions
diff --git a/contrib/python/matplotlib/py3/src/_backend_agg.cpp b/contrib/python/matplotlib/py3/src/_backend_agg.cpp
deleted file mode 100644
index 335e409719..0000000000
--- a/contrib/python/matplotlib/py3/src/_backend_agg.cpp
+++ /dev/null
@@ -1,176 +0,0 @@
-/* -*- mode: c++; c-basic-offset: 4 -*- */
-
-#define NO_IMPORT_ARRAY
-
-#include "_backend_agg.h"
-#include "mplutils.h"
-
-void BufferRegion::to_string_argb(uint8_t *buf)
-{
- unsigned char *pix;
- unsigned char tmp;
- size_t i, j;
-
- memcpy(buf, data, (size_t) height * stride);
-
- for (i = 0; i < (size_t)height; ++i) {
- pix = buf + i * stride;
- for (j = 0; j < (size_t)width; ++j) {
- // Convert rgba to argb
- tmp = pix[2];
- pix[2] = pix[0];
- pix[0] = tmp;
- pix += 4;
- }
- }
-}
-
-RendererAgg::RendererAgg(unsigned int width, unsigned int height, double dpi)
- : width(width),
- height(height),
- dpi(dpi),
- NUMBYTES((size_t)width * (size_t)height * 4),
- pixBuffer(NULL),
- renderingBuffer(),
- alphaBuffer(NULL),
- alphaMaskRenderingBuffer(),
- alphaMask(alphaMaskRenderingBuffer),
- pixfmtAlphaMask(alphaMaskRenderingBuffer),
- rendererBaseAlphaMask(),
- rendererAlphaMask(),
- scanlineAlphaMask(),
- slineP8(),
- slineBin(),
- pixFmt(),
- rendererBase(),
- rendererAA(),
- rendererBin(),
- theRasterizer(32768),
- lastclippath(NULL),
- _fill_color(agg::rgba(1, 1, 1, 0))
-{
- unsigned stride(width * 4);
-
- pixBuffer = new agg::int8u[NUMBYTES];
- renderingBuffer.attach(pixBuffer, width, height, stride);
- pixFmt.attach(renderingBuffer);
- rendererBase.attach(pixFmt);
- rendererBase.clear(_fill_color);
- rendererAA.attach(rendererBase);
- rendererBin.attach(rendererBase);
- hatch_size = int(dpi);
- hatchBuffer = new agg::int8u[hatch_size * hatch_size * 4];
- hatchRenderingBuffer.attach(hatchBuffer, hatch_size, hatch_size, hatch_size * 4);
-}
-
-RendererAgg::~RendererAgg()
-{
- delete[] hatchBuffer;
- delete[] alphaBuffer;
- delete[] pixBuffer;
-}
-
-void RendererAgg::create_alpha_buffers()
-{
- if (!alphaBuffer) {
- alphaBuffer = new agg::int8u[width * height];
- alphaMaskRenderingBuffer.attach(alphaBuffer, width, height, width);
- rendererBaseAlphaMask.attach(pixfmtAlphaMask);
- rendererAlphaMask.attach(rendererBaseAlphaMask);
- }
-}
-
-BufferRegion *RendererAgg::copy_from_bbox(agg::rect_d in_rect)
-{
- agg::rect_i rect(
- (int)in_rect.x1, height - (int)in_rect.y2, (int)in_rect.x2, height - (int)in_rect.y1);
-
- BufferRegion *reg = NULL;
- reg = new BufferRegion(rect);
-
- agg::rendering_buffer rbuf;
- rbuf.attach(reg->get_data(), reg->get_width(), reg->get_height(), reg->get_stride());
-
- pixfmt pf(rbuf);
- renderer_base rb(pf);
- rb.copy_from(renderingBuffer, &rect, -rect.x1, -rect.y1);
-
- return reg;
-}
-
-void RendererAgg::restore_region(BufferRegion &region)
-{
- if (region.get_data() == NULL) {
- throw std::runtime_error("Cannot restore_region from NULL data");
- }
-
- agg::rendering_buffer rbuf;
- rbuf.attach(region.get_data(), region.get_width(), region.get_height(), region.get_stride());
-
- rendererBase.copy_from(rbuf, 0, region.get_rect().x1, region.get_rect().y1);
-}
-
-// Restore the part of the saved region with offsets
-void
-RendererAgg::restore_region(BufferRegion &region, int xx1, int yy1, int xx2, int yy2, int x, int y )
-{
- if (region.get_data() == NULL) {
- throw std::runtime_error("Cannot restore_region from NULL data");
- }
-
- agg::rect_i &rrect = region.get_rect();
-
- agg::rect_i rect(xx1 - rrect.x1, (yy1 - rrect.y1), xx2 - rrect.x1, (yy2 - rrect.y1));
-
- agg::rendering_buffer rbuf;
- rbuf.attach(region.get_data(), region.get_width(), region.get_height(), region.get_stride());
-
- rendererBase.copy_from(rbuf, &rect, x, y);
-}
-
-bool RendererAgg::render_clippath(py::PathIterator &clippath,
- const agg::trans_affine &clippath_trans,
- e_snap_mode snap_mode)
-{
- typedef agg::conv_transform<py::PathIterator> transformed_path_t;
- typedef PathNanRemover<transformed_path_t> nan_removed_t;
- /* Unlike normal Paths, the clip path cannot be clipped to the Figure bbox,
- * because it needs to remain a complete closed path, so there is no
- * PathClipper<nan_removed_t> step. */
- typedef PathSnapper<nan_removed_t> snapped_t;
- typedef PathSimplifier<snapped_t> simplify_t;
- typedef agg::conv_curve<simplify_t> curve_t;
-
- bool has_clippath = (clippath.total_vertices() != 0);
-
- if (has_clippath &&
- (clippath.get_id() != lastclippath || clippath_trans != lastclippath_transform)) {
- create_alpha_buffers();
- agg::trans_affine trans(clippath_trans);
- trans *= agg::trans_affine_scaling(1.0, -1.0);
- trans *= agg::trans_affine_translation(0.0, (double)height);
-
- rendererBaseAlphaMask.clear(agg::gray8(0, 0));
- transformed_path_t transformed_clippath(clippath, trans);
- nan_removed_t nan_removed_clippath(transformed_clippath, true, clippath.has_codes());
- snapped_t snapped_clippath(nan_removed_clippath, snap_mode, clippath.total_vertices(), 0.0);
- simplify_t simplified_clippath(snapped_clippath,
- clippath.should_simplify() && !clippath.has_codes(),
- clippath.simplify_threshold());
- curve_t curved_clippath(simplified_clippath);
- theRasterizer.add_path(curved_clippath);
- rendererAlphaMask.color(agg::gray8(255, 255));
- agg::render_scanlines(theRasterizer, scanlineAlphaMask, rendererAlphaMask);
- lastclippath = clippath.get_id();
- lastclippath_transform = clippath_trans;
- }
-
- return has_clippath;
-}
-
-void RendererAgg::clear()
-{
- //"clear the rendered buffer";
-
- rendererBase.clear(_fill_color);
-}
diff --git a/contrib/python/matplotlib/py3/src/_backend_agg.h b/contrib/python/matplotlib/py3/src/_backend_agg.h
deleted file mode 100644
index 61c24232a8..0000000000
--- a/contrib/python/matplotlib/py3/src/_backend_agg.h
+++ /dev/null
@@ -1,1280 +0,0 @@
-/* -*- mode: c++; c-basic-offset: 4 -*- */
-
-/* _backend_agg.h
-*/
-
-#ifndef MPL_BACKEND_AGG_H
-#define MPL_BACKEND_AGG_H
-
-#include <cmath>
-#include <vector>
-#include <algorithm>
-
-#include "agg_alpha_mask_u8.h"
-#include "agg_conv_curve.h"
-#include "agg_conv_dash.h"
-#include "agg_conv_stroke.h"
-#include "agg_image_accessors.h"
-#include "agg_pixfmt_amask_adaptor.h"
-#include "agg_pixfmt_gray.h"
-#include "agg_pixfmt_rgba.h"
-#include "agg_rasterizer_scanline_aa.h"
-#include "agg_renderer_base.h"
-#include "agg_renderer_scanline.h"
-#include "agg_rendering_buffer.h"
-#include "agg_scanline_bin.h"
-#include "agg_scanline_p.h"
-#include "agg_scanline_storage_aa.h"
-#include "agg_scanline_storage_bin.h"
-#include "agg_scanline_u.h"
-#include "agg_span_allocator.h"
-#include "agg_span_converter.h"
-#include "agg_span_gouraud_rgba.h"
-#include "agg_span_image_filter_gray.h"
-#include "agg_span_image_filter_rgba.h"
-#include "agg_span_interpolator_linear.h"
-#include "agg_span_pattern_rgba.h"
-#include "util/agg_color_conv_rgb8.h"
-
-#include "_backend_agg_basic_types.h"
-#include "path_converters.h"
-#include "array.h"
-#include "agg_workaround.h"
-
-/**********************************************************************/
-
-// a helper class to pass agg::buffer objects around.
-
-class BufferRegion
-{
- public:
- BufferRegion(const agg::rect_i &r) : rect(r)
- {
- width = r.x2 - r.x1;
- height = r.y2 - r.y1;
- stride = width * 4;
- data = new agg::int8u[stride * height];
- }
-
- virtual ~BufferRegion()
- {
- delete[] data;
- };
-
- agg::int8u *get_data()
- {
- return data;
- }
-
- agg::rect_i &get_rect()
- {
- return rect;
- }
-
- int get_width()
- {
- return width;
- }
-
- int get_height()
- {
- return height;
- }
-
- int get_stride()
- {
- return stride;
- }
-
- void to_string_argb(uint8_t *buf);
-
- private:
- agg::int8u *data;
- agg::rect_i rect;
- int width;
- int height;
- int stride;
-
- private:
- // prevent copying
- BufferRegion(const BufferRegion &);
- BufferRegion &operator=(const BufferRegion &);
-};
-
-#define MARKER_CACHE_SIZE 512
-
-// the renderer
-class RendererAgg
-{
- public:
-
- typedef fixed_blender_rgba_plain<agg::rgba8, agg::order_rgba> fixed_blender_rgba32_plain;
- typedef agg::pixfmt_alpha_blend_rgba<fixed_blender_rgba32_plain, agg::rendering_buffer> pixfmt;
- typedef agg::renderer_base<pixfmt> renderer_base;
- typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_aa;
- typedef agg::renderer_scanline_bin_solid<renderer_base> renderer_bin;
- typedef agg::rasterizer_scanline_aa<agg::rasterizer_sl_clip_dbl> rasterizer;
-
- typedef agg::scanline_p8 scanline_p8;
- typedef agg::scanline_bin scanline_bin;
- typedef agg::amask_no_clip_gray8 alpha_mask_type;
- typedef agg::scanline_u8_am<alpha_mask_type> scanline_am;
-
- typedef agg::renderer_base<agg::pixfmt_gray8> renderer_base_alpha_mask_type;
- typedef agg::renderer_scanline_aa_solid<renderer_base_alpha_mask_type> renderer_alpha_mask_type;
-
- /* TODO: Remove facepair_t */
- typedef std::pair<bool, agg::rgba> facepair_t;
-
- RendererAgg(unsigned int width, unsigned int height, double dpi);
-
- virtual ~RendererAgg();
-
- unsigned int get_width()
- {
- return width;
- }
-
- unsigned int get_height()
- {
- return height;
- }
-
- template <class PathIterator>
- void draw_path(GCAgg &gc, PathIterator &path, agg::trans_affine &trans, agg::rgba &color);
-
- template <class PathIterator>
- void draw_markers(GCAgg &gc,
- PathIterator &marker_path,
- agg::trans_affine &marker_path_trans,
- PathIterator &path,
- agg::trans_affine &trans,
- agg::rgba face);
-
- template <class ImageArray>
- void draw_text_image(GCAgg &gc, ImageArray &image, int x, int y, double angle);
-
- template <class ImageArray>
- void draw_image(GCAgg &gc,
- double x,
- double y,
- ImageArray &image);
-
- template <class PathGenerator,
- class TransformArray,
- class OffsetArray,
- class ColorArray,
- class LineWidthArray,
- class AntialiasedArray>
- void draw_path_collection(GCAgg &gc,
- agg::trans_affine &master_transform,
- PathGenerator &path,
- TransformArray &transforms,
- OffsetArray &offsets,
- agg::trans_affine &offset_trans,
- ColorArray &facecolors,
- ColorArray &edgecolors,
- LineWidthArray &linewidths,
- DashesVector &linestyles,
- AntialiasedArray &antialiaseds);
-
- template <class CoordinateArray, class OffsetArray, class ColorArray>
- void draw_quad_mesh(GCAgg &gc,
- agg::trans_affine &master_transform,
- unsigned int mesh_width,
- unsigned int mesh_height,
- CoordinateArray &coordinates,
- OffsetArray &offsets,
- agg::trans_affine &offset_trans,
- ColorArray &facecolors,
- bool antialiased,
- ColorArray &edgecolors);
-
- template <class PointArray, class ColorArray>
- void draw_gouraud_triangle(GCAgg &gc,
- PointArray &points,
- ColorArray &colors,
- agg::trans_affine &trans);
-
- template <class PointArray, class ColorArray>
- void draw_gouraud_triangles(GCAgg &gc,
- PointArray &points,
- ColorArray &colors,
- agg::trans_affine &trans);
-
- agg::rect_i get_content_extents();
- void clear();
-
- BufferRegion *copy_from_bbox(agg::rect_d in_rect);
- void restore_region(BufferRegion &reg);
- void restore_region(BufferRegion &region, int xx1, int yy1, int xx2, int yy2, int x, int y);
-
- unsigned int width, height;
- double dpi;
- size_t NUMBYTES; // the number of bytes in buffer
-
- agg::int8u *pixBuffer;
- agg::rendering_buffer renderingBuffer;
-
- agg::int8u *alphaBuffer;
- agg::rendering_buffer alphaMaskRenderingBuffer;
- alpha_mask_type alphaMask;
- agg::pixfmt_gray8 pixfmtAlphaMask;
- renderer_base_alpha_mask_type rendererBaseAlphaMask;
- renderer_alpha_mask_type rendererAlphaMask;
- scanline_am scanlineAlphaMask;
-
- scanline_p8 slineP8;
- scanline_bin slineBin;
- pixfmt pixFmt;
- renderer_base rendererBase;
- renderer_aa rendererAA;
- renderer_bin rendererBin;
- rasterizer theRasterizer;
-
- void *lastclippath;
- agg::trans_affine lastclippath_transform;
-
- size_t hatch_size;
- agg::int8u *hatchBuffer;
- agg::rendering_buffer hatchRenderingBuffer;
-
- agg::rgba _fill_color;
-
- protected:
- inline double points_to_pixels(double points)
- {
- return points * dpi / 72.0;
- }
-
- template <class R>
- void set_clipbox(const agg::rect_d &cliprect, R &rasterizer);
-
- bool render_clippath(py::PathIterator &clippath, const agg::trans_affine &clippath_trans, e_snap_mode snap_mode);
-
- template <class PathIteratorType>
- void _draw_path(PathIteratorType &path, bool has_clippath, const facepair_t &face, GCAgg &gc);
-
- template <class PathIterator,
- class PathGenerator,
- class TransformArray,
- class OffsetArray,
- class ColorArray,
- class LineWidthArray,
- class AntialiasedArray>
- void _draw_path_collection_generic(GCAgg &gc,
- agg::trans_affine master_transform,
- const agg::rect_d &cliprect,
- PathIterator &clippath,
- const agg::trans_affine &clippath_trans,
- PathGenerator &path_generator,
- TransformArray &transforms,
- OffsetArray &offsets,
- const agg::trans_affine &offset_trans,
- ColorArray &facecolors,
- ColorArray &edgecolors,
- LineWidthArray &linewidths,
- DashesVector &linestyles,
- AntialiasedArray &antialiaseds,
- bool check_snap,
- bool has_codes);
-
- template <class PointArray, class ColorArray>
- void _draw_gouraud_triangle(PointArray &points,
- ColorArray &colors,
- agg::trans_affine trans,
- bool has_clippath);
-
- private:
- void create_alpha_buffers();
-
- // prevent copying
- RendererAgg(const RendererAgg &);
- RendererAgg &operator=(const RendererAgg &);
-};
-
-/***************************************************************************
- * Implementation
- */
-
-template <class path_t>
-inline void
-RendererAgg::_draw_path(path_t &path, bool has_clippath, const facepair_t &face, GCAgg &gc)
-{
- typedef agg::conv_stroke<path_t> stroke_t;
- typedef agg::conv_dash<path_t> dash_t;
- typedef agg::conv_stroke<dash_t> stroke_dash_t;
- typedef agg::pixfmt_amask_adaptor<pixfmt, alpha_mask_type> pixfmt_amask_type;
- typedef agg::renderer_base<pixfmt_amask_type> amask_ren_type;
- typedef agg::renderer_scanline_aa_solid<amask_ren_type> amask_aa_renderer_type;
- typedef agg::renderer_scanline_bin_solid<amask_ren_type> amask_bin_renderer_type;
-
- // Render face
- if (face.first) {
- theRasterizer.add_path(path);
-
- if (gc.isaa) {
- if (has_clippath) {
- pixfmt_amask_type pfa(pixFmt, alphaMask);
- amask_ren_type r(pfa);
- amask_aa_renderer_type ren(r);
- ren.color(face.second);
- agg::render_scanlines(theRasterizer, scanlineAlphaMask, ren);
- } else {
- rendererAA.color(face.second);
- agg::render_scanlines(theRasterizer, slineP8, rendererAA);
- }
- } else {
- if (has_clippath) {
- pixfmt_amask_type pfa(pixFmt, alphaMask);
- amask_ren_type r(pfa);
- amask_bin_renderer_type ren(r);
- ren.color(face.second);
- agg::render_scanlines(theRasterizer, scanlineAlphaMask, ren);
- } else {
- rendererBin.color(face.second);
- agg::render_scanlines(theRasterizer, slineP8, rendererBin);
- }
- }
- }
-
- // Render hatch
- if (gc.has_hatchpath()) {
- // Reset any clipping that may be in effect, since we'll be
- // drawing the hatch in a scratch buffer at origin (0, 0)
- theRasterizer.reset_clipping();
- rendererBase.reset_clipping(true);
-
- // Create and transform the path
- typedef agg::conv_transform<py::PathIterator> hatch_path_trans_t;
- typedef agg::conv_curve<hatch_path_trans_t> hatch_path_curve_t;
- typedef agg::conv_stroke<hatch_path_curve_t> hatch_path_stroke_t;
-
- py::PathIterator hatch_path(gc.hatchpath);
- agg::trans_affine hatch_trans;
- hatch_trans *= agg::trans_affine_scaling(1.0, -1.0);
- hatch_trans *= agg::trans_affine_translation(0.0, 1.0);
- hatch_trans *= agg::trans_affine_scaling(hatch_size, hatch_size);
- hatch_path_trans_t hatch_path_trans(hatch_path, hatch_trans);
- hatch_path_curve_t hatch_path_curve(hatch_path_trans);
- hatch_path_stroke_t hatch_path_stroke(hatch_path_curve);
- hatch_path_stroke.width(points_to_pixels(gc.hatch_linewidth));
- hatch_path_stroke.line_cap(agg::square_cap);
-
- // Render the path into the hatch buffer
- pixfmt hatch_img_pixf(hatchRenderingBuffer);
- renderer_base rb(hatch_img_pixf);
- renderer_aa rs(rb);
- rb.clear(_fill_color);
- rs.color(gc.hatch_color);
-
- theRasterizer.add_path(hatch_path_curve);
- agg::render_scanlines(theRasterizer, slineP8, rs);
- theRasterizer.add_path(hatch_path_stroke);
- agg::render_scanlines(theRasterizer, slineP8, rs);
-
- // Put clipping back on, if originally set on entry to this
- // function
- set_clipbox(gc.cliprect, theRasterizer);
- if (has_clippath) {
- render_clippath(gc.clippath.path, gc.clippath.trans, gc.snap_mode);
- }
-
- // Transfer the hatch to the main image buffer
- typedef agg::image_accessor_wrap<pixfmt,
- agg::wrap_mode_repeat_auto_pow2,
- agg::wrap_mode_repeat_auto_pow2> img_source_type;
- typedef agg::span_pattern_rgba<img_source_type> span_gen_type;
- agg::span_allocator<agg::rgba8> sa;
- img_source_type img_src(hatch_img_pixf);
- span_gen_type sg(img_src, 0, 0);
- theRasterizer.add_path(path);
-
- if (has_clippath) {
- pixfmt_amask_type pfa(pixFmt, alphaMask);
- amask_ren_type ren(pfa);
- agg::render_scanlines_aa(theRasterizer, slineP8, ren, sa, sg);
- } else {
- agg::render_scanlines_aa(theRasterizer, slineP8, rendererBase, sa, sg);
- }
- }
-
- // Render stroke
- if (gc.linewidth != 0.0) {
- double linewidth = points_to_pixels(gc.linewidth);
- if (!gc.isaa) {
- linewidth = (linewidth < 0.5) ? 0.5 : mpl_round(linewidth);
- }
- if (gc.dashes.size() == 0) {
- stroke_t stroke(path);
- stroke.width(points_to_pixels(gc.linewidth));
- stroke.line_cap(gc.cap);
- stroke.line_join(gc.join);
- stroke.miter_limit(points_to_pixels(gc.linewidth));
- theRasterizer.add_path(stroke);
- } else {
- dash_t dash(path);
- gc.dashes.dash_to_stroke(dash, dpi, gc.isaa);
- stroke_dash_t stroke(dash);
- stroke.line_cap(gc.cap);
- stroke.line_join(gc.join);
- stroke.width(linewidth);
- stroke.miter_limit(points_to_pixels(gc.linewidth));
- theRasterizer.add_path(stroke);
- }
-
- if (gc.isaa) {
- if (has_clippath) {
- pixfmt_amask_type pfa(pixFmt, alphaMask);
- amask_ren_type r(pfa);
- amask_aa_renderer_type ren(r);
- ren.color(gc.color);
- agg::render_scanlines(theRasterizer, scanlineAlphaMask, ren);
- } else {
- rendererAA.color(gc.color);
- agg::render_scanlines(theRasterizer, slineP8, rendererAA);
- }
- } else {
- if (has_clippath) {
- pixfmt_amask_type pfa(pixFmt, alphaMask);
- amask_ren_type r(pfa);
- amask_bin_renderer_type ren(r);
- ren.color(gc.color);
- agg::render_scanlines(theRasterizer, scanlineAlphaMask, ren);
- } else {
- rendererBin.color(gc.color);
- agg::render_scanlines(theRasterizer, slineBin, rendererBin);
- }
- }
- }
-}
-
-template <class PathIterator>
-inline void
-RendererAgg::draw_path(GCAgg &gc, PathIterator &path, agg::trans_affine &trans, agg::rgba &color)
-{
- typedef agg::conv_transform<py::PathIterator> transformed_path_t;
- typedef PathNanRemover<transformed_path_t> nan_removed_t;
- typedef PathClipper<nan_removed_t> clipped_t;
- typedef PathSnapper<clipped_t> snapped_t;
- typedef PathSimplifier<snapped_t> simplify_t;
- typedef agg::conv_curve<simplify_t> curve_t;
- typedef Sketch<curve_t> sketch_t;
-
- facepair_t face(color.a != 0.0, color);
-
- theRasterizer.reset_clipping();
- rendererBase.reset_clipping(true);
- set_clipbox(gc.cliprect, theRasterizer);
- bool has_clippath = render_clippath(gc.clippath.path, gc.clippath.trans, gc.snap_mode);
-
- trans *= agg::trans_affine_scaling(1.0, -1.0);
- trans *= agg::trans_affine_translation(0.0, (double)height);
- bool clip = !face.first && !gc.has_hatchpath();
- bool simplify = path.should_simplify() && clip;
- double snapping_linewidth = points_to_pixels(gc.linewidth);
- if (gc.color.a == 0.0) {
- snapping_linewidth = 0.0;
- }
-
- transformed_path_t tpath(path, trans);
- nan_removed_t nan_removed(tpath, true, path.has_codes());
- clipped_t clipped(nan_removed, clip, width, height);
- snapped_t snapped(clipped, gc.snap_mode, path.total_vertices(), snapping_linewidth);
- simplify_t simplified(snapped, simplify, path.simplify_threshold());
- curve_t curve(simplified);
- sketch_t sketch(curve, gc.sketch.scale, gc.sketch.length, gc.sketch.randomness);
-
- _draw_path(sketch, has_clippath, face, gc);
-}
-
-template <class PathIterator>
-inline void RendererAgg::draw_markers(GCAgg &gc,
- PathIterator &marker_path,
- agg::trans_affine &marker_trans,
- PathIterator &path,
- agg::trans_affine &trans,
- agg::rgba color)
-{
- typedef agg::conv_transform<py::PathIterator> transformed_path_t;
- typedef PathNanRemover<transformed_path_t> nan_removed_t;
- typedef PathSnapper<nan_removed_t> snap_t;
- typedef agg::conv_curve<snap_t> curve_t;
- typedef agg::conv_stroke<curve_t> stroke_t;
- typedef agg::pixfmt_amask_adaptor<pixfmt, alpha_mask_type> pixfmt_amask_type;
- typedef agg::renderer_base<pixfmt_amask_type> amask_ren_type;
- typedef agg::renderer_scanline_aa_solid<amask_ren_type> amask_aa_renderer_type;
-
- // Deal with the difference in y-axis direction
- marker_trans *= agg::trans_affine_scaling(1.0, -1.0);
-
- trans *= agg::trans_affine_scaling(1.0, -1.0);
- trans *= agg::trans_affine_translation(0.5, (double)height + 0.5);
-
- transformed_path_t marker_path_transformed(marker_path, marker_trans);
- nan_removed_t marker_path_nan_removed(marker_path_transformed, true, marker_path.has_codes());
- snap_t marker_path_snapped(marker_path_nan_removed,
- gc.snap_mode,
- marker_path.total_vertices(),
- points_to_pixels(gc.linewidth));
- curve_t marker_path_curve(marker_path_snapped);
-
- if (!marker_path_snapped.is_snapping()) {
- // If the path snapper isn't in effect, at least make sure the marker
- // at (0, 0) is in the center of a pixel. This, importantly, makes
- // the circle markers look centered around the point they refer to.
- marker_trans *= agg::trans_affine_translation(0.5, 0.5);
- }
-
- transformed_path_t path_transformed(path, trans);
- nan_removed_t path_nan_removed(path_transformed, false, false);
- snap_t path_snapped(path_nan_removed, SNAP_FALSE, path.total_vertices(), 0.0);
- curve_t path_curve(path_snapped);
- path_curve.rewind(0);
-
- facepair_t face(color.a != 0.0, color);
-
- // maxim's suggestions for cached scanlines
- agg::scanline_storage_aa8 scanlines;
- theRasterizer.reset();
- theRasterizer.reset_clipping();
- rendererBase.reset_clipping(true);
- agg::rect_i marker_size(0x7FFFFFFF, 0x7FFFFFFF, -0x7FFFFFFF, -0x7FFFFFFF);
-
- agg::int8u staticFillCache[MARKER_CACHE_SIZE];
- agg::int8u staticStrokeCache[MARKER_CACHE_SIZE];
- agg::int8u *fillCache = staticFillCache;
- agg::int8u *strokeCache = staticStrokeCache;
-
- try
- {
- unsigned fillSize = 0;
- if (face.first) {
- theRasterizer.add_path(marker_path_curve);
- agg::render_scanlines(theRasterizer, slineP8, scanlines);
- fillSize = scanlines.byte_size();
- if (fillSize >= MARKER_CACHE_SIZE) {
- fillCache = new agg::int8u[fillSize];
- }
- scanlines.serialize(fillCache);
- marker_size = agg::rect_i(scanlines.min_x(),
- scanlines.min_y(),
- scanlines.max_x(),
- scanlines.max_y());
- }
-
- stroke_t stroke(marker_path_curve);
- stroke.width(points_to_pixels(gc.linewidth));
- stroke.line_cap(gc.cap);
- stroke.line_join(gc.join);
- stroke.miter_limit(points_to_pixels(gc.linewidth));
- theRasterizer.reset();
- theRasterizer.add_path(stroke);
- agg::render_scanlines(theRasterizer, slineP8, scanlines);
- unsigned strokeSize = scanlines.byte_size();
- if (strokeSize >= MARKER_CACHE_SIZE) {
- strokeCache = new agg::int8u[strokeSize];
- }
- scanlines.serialize(strokeCache);
- marker_size = agg::rect_i(std::min(marker_size.x1, scanlines.min_x()),
- std::min(marker_size.y1, scanlines.min_y()),
- std::max(marker_size.x2, scanlines.max_x()),
- std::max(marker_size.y2, scanlines.max_y()));
-
- theRasterizer.reset_clipping();
- rendererBase.reset_clipping(true);
- set_clipbox(gc.cliprect, rendererBase);
- bool has_clippath = render_clippath(gc.clippath.path, gc.clippath.trans, gc.snap_mode);
-
- double x, y;
-
- agg::serialized_scanlines_adaptor_aa8 sa;
- agg::serialized_scanlines_adaptor_aa8::embedded_scanline sl;
-
- agg::rect_d clipping_rect(-1.0 - marker_size.x2,
- -1.0 - marker_size.y2,
- 1.0 + width - marker_size.x1,
- 1.0 + height - marker_size.y1);
-
- if (has_clippath) {
- while (path_curve.vertex(&x, &y) != agg::path_cmd_stop) {
- if (!(std::isfinite(x) && std::isfinite(y))) {
- continue;
- }
-
- /* These values are correctly snapped above -- so we don't want
- to round here, we really only want to truncate */
- x = floor(x);
- y = floor(y);
-
- // Cull points outside the boundary of the image.
- // Values that are too large may overflow and create
- // segfaults.
- // http://sourceforge.net/tracker/?func=detail&aid=2865490&group_id=80706&atid=560720
- if (!clipping_rect.hit_test(x, y)) {
- continue;
- }
-
- pixfmt_amask_type pfa(pixFmt, alphaMask);
- amask_ren_type r(pfa);
- amask_aa_renderer_type ren(r);
-
- if (face.first) {
- ren.color(face.second);
- sa.init(fillCache, fillSize, x, y);
- agg::render_scanlines(sa, sl, ren);
- }
- ren.color(gc.color);
- sa.init(strokeCache, strokeSize, x, y);
- agg::render_scanlines(sa, sl, ren);
- }
- } else {
- while (path_curve.vertex(&x, &y) != agg::path_cmd_stop) {
- if (!(std::isfinite(x) && std::isfinite(y))) {
- continue;
- }
-
- /* These values are correctly snapped above -- so we don't want
- to round here, we really only want to truncate */
- x = floor(x);
- y = floor(y);
-
- // Cull points outside the boundary of the image.
- // Values that are too large may overflow and create
- // segfaults.
- // http://sourceforge.net/tracker/?func=detail&aid=2865490&group_id=80706&atid=560720
- if (!clipping_rect.hit_test(x, y)) {
- continue;
- }
-
- if (face.first) {
- rendererAA.color(face.second);
- sa.init(fillCache, fillSize, x, y);
- agg::render_scanlines(sa, sl, rendererAA);
- }
-
- rendererAA.color(gc.color);
- sa.init(strokeCache, strokeSize, x, y);
- agg::render_scanlines(sa, sl, rendererAA);
- }
- }
- }
- catch (...)
- {
- if (fillCache != staticFillCache)
- delete[] fillCache;
- if (strokeCache != staticStrokeCache)
- delete[] strokeCache;
- theRasterizer.reset_clipping();
- rendererBase.reset_clipping(true);
- throw;
- }
-
- if (fillCache != staticFillCache)
- delete[] fillCache;
- if (strokeCache != staticStrokeCache)
- delete[] strokeCache;
-
- theRasterizer.reset_clipping();
- rendererBase.reset_clipping(true);
-}
-
-/**
- * This is a custom span generator that converts spans in the
- * 8-bit inverted greyscale font buffer to rgba that agg can use.
- */
-template <class ChildGenerator>
-class font_to_rgba
-{
- public:
- typedef ChildGenerator child_type;
- typedef agg::rgba8 color_type;
- typedef typename child_type::color_type child_color_type;
- typedef agg::span_allocator<child_color_type> span_alloc_type;
-
- private:
- child_type *_gen;
- color_type _color;
- span_alloc_type _allocator;
-
- public:
- font_to_rgba(child_type *gen, color_type color) : _gen(gen), _color(color)
- {
- }
-
- inline void generate(color_type *output_span, int x, int y, unsigned len)
- {
- _allocator.allocate(len);
- child_color_type *input_span = _allocator.span();
- _gen->generate(input_span, x, y, len);
-
- do {
- *output_span = _color;
- output_span->a = ((unsigned int)_color.a * (unsigned int)input_span->v) >> 8;
- ++output_span;
- ++input_span;
- } while (--len);
- }
-
- void prepare()
- {
- _gen->prepare();
- }
-};
-
-template <class ImageArray>
-inline void RendererAgg::draw_text_image(GCAgg &gc, ImageArray &image, int x, int y, double angle)
-{
- typedef agg::span_allocator<agg::rgba8> color_span_alloc_type;
- typedef agg::span_interpolator_linear<> interpolator_type;
- typedef agg::image_accessor_clip<agg::pixfmt_gray8> image_accessor_type;
- typedef agg::span_image_filter_gray<image_accessor_type, interpolator_type> image_span_gen_type;
- typedef font_to_rgba<image_span_gen_type> span_gen_type;
- typedef agg::renderer_scanline_aa<renderer_base, color_span_alloc_type, span_gen_type>
- renderer_type;
-
- theRasterizer.reset_clipping();
- rendererBase.reset_clipping(true);
- if (angle != 0.0) {
- agg::rendering_buffer srcbuf(
- image.data(), (unsigned)image.dim(1),
- (unsigned)image.dim(0), (unsigned)image.dim(1));
- agg::pixfmt_gray8 pixf_img(srcbuf);
-
- set_clipbox(gc.cliprect, theRasterizer);
-
- agg::trans_affine mtx;
- mtx *= agg::trans_affine_translation(0, -image.dim(0));
- mtx *= agg::trans_affine_rotation(-angle * (agg::pi / 180.0));
- mtx *= agg::trans_affine_translation(x, y);
-
- agg::path_storage rect;
- rect.move_to(0, 0);
- rect.line_to(image.dim(1), 0);
- rect.line_to(image.dim(1), image.dim(0));
- rect.line_to(0, image.dim(0));
- rect.line_to(0, 0);
- agg::conv_transform<agg::path_storage> rect2(rect, mtx);
-
- agg::trans_affine inv_mtx(mtx);
- inv_mtx.invert();
-
- agg::image_filter_lut filter;
- filter.calculate(agg::image_filter_spline36());
- interpolator_type interpolator(inv_mtx);
- color_span_alloc_type sa;
- image_accessor_type ia(pixf_img, agg::gray8(0));
- image_span_gen_type image_span_generator(ia, interpolator, filter);
- span_gen_type output_span_generator(&image_span_generator, gc.color);
- renderer_type ri(rendererBase, sa, output_span_generator);
-
- theRasterizer.add_path(rect2);
- agg::render_scanlines(theRasterizer, slineP8, ri);
- } else {
- agg::rect_i fig, text;
-
- int deltay = y - image.dim(0);
-
- fig.init(0, 0, width, height);
- text.init(x, deltay, x + image.dim(1), y);
- text.clip(fig);
-
- if (gc.cliprect.x1 != 0.0 || gc.cliprect.y1 != 0.0 || gc.cliprect.x2 != 0.0 || gc.cliprect.y2 != 0.0) {
- agg::rect_i clip;
-
- clip.init(mpl_round_to_int(gc.cliprect.x1),
- mpl_round_to_int(height - gc.cliprect.y2),
- mpl_round_to_int(gc.cliprect.x2),
- mpl_round_to_int(height - gc.cliprect.y1));
- text.clip(clip);
- }
-
- if (text.x2 > text.x1) {
- int deltax = text.x2 - text.x1;
- int deltax2 = text.x1 - x;
- for (int yi = text.y1; yi < text.y2; ++yi) {
- pixFmt.blend_solid_hspan(text.x1, yi, deltax, gc.color,
- &image(yi - deltay, deltax2));
- }
- }
- }
-}
-
-class span_conv_alpha
-{
- public:
- typedef agg::rgba8 color_type;
-
- double m_alpha;
-
- span_conv_alpha(double alpha) : m_alpha(alpha)
- {
- }
-
- void prepare()
- {
- }
- void generate(color_type *span, int x, int y, unsigned len) const
- {
- do {
- span->a = (agg::int8u)((double)span->a * m_alpha);
- ++span;
- } while (--len);
- }
-};
-
-template <class ImageArray>
-inline void RendererAgg::draw_image(GCAgg &gc,
- double x,
- double y,
- ImageArray &image)
-{
- double alpha = gc.alpha;
-
- theRasterizer.reset_clipping();
- rendererBase.reset_clipping(true);
- set_clipbox(gc.cliprect, theRasterizer);
- bool has_clippath = render_clippath(gc.clippath.path, gc.clippath.trans, gc.snap_mode);
-
- agg::rendering_buffer buffer;
- buffer.attach(
- image.data(), (unsigned)image.dim(1), (unsigned)image.dim(0), -(int)image.dim(1) * 4);
- pixfmt pixf(buffer);
-
- if (has_clippath) {
- agg::trans_affine mtx;
- agg::path_storage rect;
-
- mtx *= agg::trans_affine_translation((int)x, (int)(height - (y + image.dim(0))));
-
- rect.move_to(0, 0);
- rect.line_to(image.dim(1), 0);
- rect.line_to(image.dim(1), image.dim(0));
- rect.line_to(0, image.dim(0));
- rect.line_to(0, 0);
-
- agg::conv_transform<agg::path_storage> rect2(rect, mtx);
-
- agg::trans_affine inv_mtx(mtx);
- inv_mtx.invert();
-
- typedef agg::span_allocator<agg::rgba8> color_span_alloc_type;
- typedef agg::image_accessor_clip<pixfmt> image_accessor_type;
- typedef agg::span_interpolator_linear<> interpolator_type;
- typedef agg::span_image_filter_rgba_nn<image_accessor_type, interpolator_type>
- image_span_gen_type;
- typedef agg::span_converter<image_span_gen_type, span_conv_alpha> span_conv;
-
- color_span_alloc_type sa;
- image_accessor_type ia(pixf, agg::rgba8(0, 0, 0, 0));
- interpolator_type interpolator(inv_mtx);
- image_span_gen_type image_span_generator(ia, interpolator);
- span_conv_alpha conv_alpha(alpha);
- span_conv spans(image_span_generator, conv_alpha);
-
- typedef agg::pixfmt_amask_adaptor<pixfmt, alpha_mask_type> pixfmt_amask_type;
- typedef agg::renderer_base<pixfmt_amask_type> amask_ren_type;
- typedef agg::renderer_scanline_aa<amask_ren_type, color_span_alloc_type, span_conv>
- renderer_type_alpha;
-
- pixfmt_amask_type pfa(pixFmt, alphaMask);
- amask_ren_type r(pfa);
- renderer_type_alpha ri(r, sa, spans);
-
- theRasterizer.add_path(rect2);
- agg::render_scanlines(theRasterizer, scanlineAlphaMask, ri);
- } else {
- set_clipbox(gc.cliprect, rendererBase);
- rendererBase.blend_from(
- pixf, 0, (int)x, (int)(height - (y + image.dim(0))), (agg::int8u)(alpha * 255));
- }
-
- rendererBase.reset_clipping(true);
-}
-
-template <class PathIterator,
- class PathGenerator,
- class TransformArray,
- class OffsetArray,
- class ColorArray,
- class LineWidthArray,
- class AntialiasedArray>
-inline void RendererAgg::_draw_path_collection_generic(GCAgg &gc,
- agg::trans_affine master_transform,
- const agg::rect_d &cliprect,
- PathIterator &clippath,
- const agg::trans_affine &clippath_trans,
- PathGenerator &path_generator,
- TransformArray &transforms,
- OffsetArray &offsets,
- const agg::trans_affine &offset_trans,
- ColorArray &facecolors,
- ColorArray &edgecolors,
- LineWidthArray &linewidths,
- DashesVector &linestyles,
- AntialiasedArray &antialiaseds,
- bool check_snap,
- bool has_codes)
-{
- typedef agg::conv_transform<typename PathGenerator::path_iterator> transformed_path_t;
- typedef PathNanRemover<transformed_path_t> nan_removed_t;
- typedef PathClipper<nan_removed_t> clipped_t;
- typedef PathSnapper<clipped_t> snapped_t;
- typedef agg::conv_curve<snapped_t> snapped_curve_t;
- typedef agg::conv_curve<clipped_t> curve_t;
-
- size_t Npaths = path_generator.num_paths();
- size_t Noffsets = offsets.size();
- size_t N = std::max(Npaths, Noffsets);
-
- size_t Ntransforms = transforms.size();
- size_t Nfacecolors = facecolors.size();
- size_t Nedgecolors = edgecolors.size();
- size_t Nlinewidths = linewidths.size();
- size_t Nlinestyles = std::min(linestyles.size(), N);
- size_t Naa = antialiaseds.size();
-
- if ((Nfacecolors == 0 && Nedgecolors == 0) || Npaths == 0) {
- return;
- }
-
- // Handle any clipping globally
- theRasterizer.reset_clipping();
- rendererBase.reset_clipping(true);
- set_clipbox(cliprect, theRasterizer);
- bool has_clippath = render_clippath(clippath, clippath_trans, gc.snap_mode);
-
- // Set some defaults, assuming no face or edge
- gc.linewidth = 0.0;
- facepair_t face;
- face.first = Nfacecolors != 0;
- agg::trans_affine trans;
- bool do_clip = !face.first && !gc.has_hatchpath();
-
- for (int i = 0; i < (int)N; ++i) {
- typename PathGenerator::path_iterator path = path_generator(i);
-
- if (Ntransforms) {
- int it = i % Ntransforms;
- trans = agg::trans_affine(transforms(it, 0, 0),
- transforms(it, 1, 0),
- transforms(it, 0, 1),
- transforms(it, 1, 1),
- transforms(it, 0, 2),
- transforms(it, 1, 2));
- trans *= master_transform;
- } else {
- trans = master_transform;
- }
-
- if (Noffsets) {
- double xo = offsets(i % Noffsets, 0);
- double yo = offsets(i % Noffsets, 1);
- offset_trans.transform(&xo, &yo);
- trans *= agg::trans_affine_translation(xo, yo);
- }
-
- // These transformations must be done post-offsets
- trans *= agg::trans_affine_scaling(1.0, -1.0);
- trans *= agg::trans_affine_translation(0.0, (double)height);
-
- if (Nfacecolors) {
- int ic = i % Nfacecolors;
- face.second = agg::rgba(facecolors(ic, 0), facecolors(ic, 1), facecolors(ic, 2), facecolors(ic, 3));
- }
-
- if (Nedgecolors) {
- int ic = i % Nedgecolors;
- gc.color = agg::rgba(edgecolors(ic, 0), edgecolors(ic, 1), edgecolors(ic, 2), edgecolors(ic, 3));
-
- if (Nlinewidths) {
- gc.linewidth = linewidths(i % Nlinewidths);
- } else {
- gc.linewidth = 1.0;
- }
- if (Nlinestyles) {
- gc.dashes = linestyles[i % Nlinestyles];
- }
- }
-
- if (check_snap) {
- gc.isaa = antialiaseds(i % Naa);
-
- transformed_path_t tpath(path, trans);
- nan_removed_t nan_removed(tpath, true, has_codes);
- clipped_t clipped(nan_removed, do_clip, width, height);
- snapped_t snapped(
- clipped, gc.snap_mode, path.total_vertices(), points_to_pixels(gc.linewidth));
- if (has_codes) {
- snapped_curve_t curve(snapped);
- _draw_path(curve, has_clippath, face, gc);
- } else {
- _draw_path(snapped, has_clippath, face, gc);
- }
- } else {
- gc.isaa = antialiaseds(i % Naa);
-
- transformed_path_t tpath(path, trans);
- nan_removed_t nan_removed(tpath, true, has_codes);
- clipped_t clipped(nan_removed, do_clip, width, height);
- if (has_codes) {
- curve_t curve(clipped);
- _draw_path(curve, has_clippath, face, gc);
- } else {
- _draw_path(clipped, has_clippath, face, gc);
- }
- }
- }
-}
-
-template <class PathGenerator,
- class TransformArray,
- class OffsetArray,
- class ColorArray,
- class LineWidthArray,
- class AntialiasedArray>
-inline void RendererAgg::draw_path_collection(GCAgg &gc,
- agg::trans_affine &master_transform,
- PathGenerator &path,
- TransformArray &transforms,
- OffsetArray &offsets,
- agg::trans_affine &offset_trans,
- ColorArray &facecolors,
- ColorArray &edgecolors,
- LineWidthArray &linewidths,
- DashesVector &linestyles,
- AntialiasedArray &antialiaseds)
-{
- _draw_path_collection_generic(gc,
- master_transform,
- gc.cliprect,
- gc.clippath.path,
- gc.clippath.trans,
- path,
- transforms,
- offsets,
- offset_trans,
- facecolors,
- edgecolors,
- linewidths,
- linestyles,
- antialiaseds,
- true,
- true);
-}
-
-template <class CoordinateArray>
-class QuadMeshGenerator
-{
- unsigned m_meshWidth;
- unsigned m_meshHeight;
- CoordinateArray m_coordinates;
-
- class QuadMeshPathIterator
- {
- unsigned m_iterator;
- unsigned m_m, m_n;
- const CoordinateArray *m_coordinates;
-
- public:
- QuadMeshPathIterator(unsigned m, unsigned n, const CoordinateArray *coordinates)
- : m_iterator(0), m_m(m), m_n(n), m_coordinates(coordinates)
- {
- }
-
- private:
- inline unsigned vertex(unsigned idx, double *x, double *y)
- {
- size_t m = m_m + ((idx & 0x2) >> 1);
- size_t n = m_n + (((idx + 1) & 0x2) >> 1);
- *x = (*m_coordinates)(n, m, 0);
- *y = (*m_coordinates)(n, m, 1);
- return (idx) ? agg::path_cmd_line_to : agg::path_cmd_move_to;
- }
-
- public:
- inline unsigned vertex(double *x, double *y)
- {
- if (m_iterator >= total_vertices()) {
- return agg::path_cmd_stop;
- }
- return vertex(m_iterator++, x, y);
- }
-
- inline void rewind(unsigned path_id)
- {
- m_iterator = path_id;
- }
-
- inline unsigned total_vertices()
- {
- return 5;
- }
-
- inline bool should_simplify()
- {
- return false;
- }
- };
-
- public:
- typedef QuadMeshPathIterator path_iterator;
-
- inline QuadMeshGenerator(unsigned meshWidth, unsigned meshHeight, CoordinateArray &coordinates)
- : m_meshWidth(meshWidth), m_meshHeight(meshHeight), m_coordinates(coordinates)
- {
- }
-
- inline size_t num_paths() const
- {
- return (size_t) m_meshWidth * m_meshHeight;
- }
-
- inline path_iterator operator()(size_t i) const
- {
- return QuadMeshPathIterator(i % m_meshWidth, i / m_meshWidth, &m_coordinates);
- }
-};
-
-template <class CoordinateArray, class OffsetArray, class ColorArray>
-inline void RendererAgg::draw_quad_mesh(GCAgg &gc,
- agg::trans_affine &master_transform,
- unsigned int mesh_width,
- unsigned int mesh_height,
- CoordinateArray &coordinates,
- OffsetArray &offsets,
- agg::trans_affine &offset_trans,
- ColorArray &facecolors,
- bool antialiased,
- ColorArray &edgecolors)
-{
- QuadMeshGenerator<CoordinateArray> path_generator(mesh_width, mesh_height, coordinates);
-
- array::empty<double> transforms;
- array::scalar<double, 1> linewidths(gc.linewidth);
- array::scalar<uint8_t, 1> antialiaseds(antialiased);
- DashesVector linestyles;
-
- _draw_path_collection_generic(gc,
- master_transform,
- gc.cliprect,
- gc.clippath.path,
- gc.clippath.trans,
- path_generator,
- transforms,
- offsets,
- offset_trans,
- facecolors,
- edgecolors,
- linewidths,
- linestyles,
- antialiaseds,
- true, // check_snap
- false);
-}
-
-template <class PointArray, class ColorArray>
-inline void RendererAgg::_draw_gouraud_triangle(PointArray &points,
- ColorArray &colors,
- agg::trans_affine trans,
- bool has_clippath)
-{
- typedef agg::rgba8 color_t;
- typedef agg::span_gouraud_rgba<color_t> span_gen_t;
- typedef agg::span_allocator<color_t> span_alloc_t;
-
- trans *= agg::trans_affine_scaling(1.0, -1.0);
- trans *= agg::trans_affine_translation(0.0, (double)height);
-
- double tpoints[3][2];
-
- for (int i = 0; i < 3; ++i) {
- for (int j = 0; j < 2; ++j) {
- tpoints[i][j] = points(i, j);
- }
- trans.transform(&tpoints[i][0], &tpoints[i][1]);
- if(std::isnan(tpoints[i][0]) || std::isnan(tpoints[i][1])) {
- return;
- }
- }
-
- span_alloc_t span_alloc;
- span_gen_t span_gen;
-
- span_gen.colors(agg::rgba(colors(0, 0), colors(0, 1), colors(0, 2), colors(0, 3)),
- agg::rgba(colors(1, 0), colors(1, 1), colors(1, 2), colors(1, 3)),
- agg::rgba(colors(2, 0), colors(2, 1), colors(2, 2), colors(2, 3)));
- span_gen.triangle(tpoints[0][0],
- tpoints[0][1],
- tpoints[1][0],
- tpoints[1][1],
- tpoints[2][0],
- tpoints[2][1],
- 0.5);
-
- theRasterizer.add_path(span_gen);
-
- if (has_clippath) {
- typedef agg::pixfmt_amask_adaptor<pixfmt, alpha_mask_type> pixfmt_amask_type;
- typedef agg::renderer_base<pixfmt_amask_type> amask_ren_type;
- typedef agg::renderer_scanline_aa<amask_ren_type, span_alloc_t, span_gen_t>
- amask_aa_renderer_type;
-
- pixfmt_amask_type pfa(pixFmt, alphaMask);
- amask_ren_type r(pfa);
- amask_aa_renderer_type ren(r, span_alloc, span_gen);
- agg::render_scanlines(theRasterizer, scanlineAlphaMask, ren);
- } else {
- agg::render_scanlines_aa(theRasterizer, slineP8, rendererBase, span_alloc, span_gen);
- }
-}
-
-template <class PointArray, class ColorArray>
-inline void RendererAgg::draw_gouraud_triangle(GCAgg &gc,
- PointArray &points,
- ColorArray &colors,
- agg::trans_affine &trans)
-{
- theRasterizer.reset_clipping();
- rendererBase.reset_clipping(true);
- set_clipbox(gc.cliprect, theRasterizer);
- bool has_clippath = render_clippath(gc.clippath.path, gc.clippath.trans, gc.snap_mode);
-
- _draw_gouraud_triangle(points, colors, trans, has_clippath);
-}
-
-template <class PointArray, class ColorArray>
-inline void RendererAgg::draw_gouraud_triangles(GCAgg &gc,
- PointArray &points,
- ColorArray &colors,
- agg::trans_affine &trans)
-{
- theRasterizer.reset_clipping();
- rendererBase.reset_clipping(true);
- set_clipbox(gc.cliprect, theRasterizer);
- bool has_clippath = render_clippath(gc.clippath.path, gc.clippath.trans, gc.snap_mode);
-
- for (int i = 0; i < points.dim(0); ++i) {
- typename PointArray::sub_t point = points.subarray(i);
- typename ColorArray::sub_t color = colors.subarray(i);
-
- _draw_gouraud_triangle(point, color, trans, has_clippath);
- }
-}
-
-template <class R>
-void RendererAgg::set_clipbox(const agg::rect_d &cliprect, R &rasterizer)
-{
- // set the clip rectangle from the gc
-
- if (cliprect.x1 != 0.0 || cliprect.y1 != 0.0 || cliprect.x2 != 0.0 || cliprect.y2 != 0.0) {
- rasterizer.clip_box(std::max(int(floor(cliprect.x1 + 0.5)), 0),
- std::max(int(floor(height - cliprect.y1 + 0.5)), 0),
- std::min(int(floor(cliprect.x2 + 0.5)), int(width)),
- std::min(int(floor(height - cliprect.y2 + 0.5)), int(height)));
- } else {
- rasterizer.clip_box(0, 0, width, height);
- }
-}
-
-#endif
diff --git a/contrib/python/matplotlib/py3/src/_backend_agg_basic_types.h b/contrib/python/matplotlib/py3/src/_backend_agg_basic_types.h
deleted file mode 100644
index 21a84bb6a5..0000000000
--- a/contrib/python/matplotlib/py3/src/_backend_agg_basic_types.h
+++ /dev/null
@@ -1,123 +0,0 @@
-#ifndef MPL_BACKEND_AGG_BASIC_TYPES_H
-#define MPL_BACKEND_AGG_BASIC_TYPES_H
-
-/* Contains some simple types from the Agg backend that are also used
- by other modules */
-
-#include <vector>
-
-#include "agg_color_rgba.h"
-#include "agg_math_stroke.h"
-#include "path_converters.h"
-
-#include "py_adaptors.h"
-
-struct ClipPath
-{
- py::PathIterator path;
- agg::trans_affine trans;
-};
-
-struct SketchParams
-{
- double scale;
- double length;
- double randomness;
-};
-
-class Dashes
-{
- typedef std::vector<std::pair<double, double> > dash_t;
- double dash_offset;
- dash_t dashes;
-
- public:
- double get_dash_offset() const
- {
- return dash_offset;
- }
- void set_dash_offset(double x)
- {
- dash_offset = x;
- }
- void add_dash_pair(double length, double skip)
- {
- dashes.push_back(std::make_pair(length, skip));
- }
- size_t size() const
- {
- return dashes.size();
- }
-
- template <class T>
- void dash_to_stroke(T &stroke, double dpi, bool isaa)
- {
- double scaleddpi = dpi / 72.0;
- for (dash_t::const_iterator i = dashes.begin(); i != dashes.end(); ++i) {
- double val0 = i->first;
- double val1 = i->second;
- val0 = val0 * scaleddpi;
- val1 = val1 * scaleddpi;
- if (!isaa) {
- val0 = (int)val0 + 0.5;
- val1 = (int)val1 + 0.5;
- }
- stroke.add_dash(val0, val1);
- }
- stroke.dash_start(get_dash_offset() * scaleddpi);
- }
-};
-
-typedef std::vector<Dashes> DashesVector;
-
-class GCAgg
-{
- public:
- GCAgg()
- : linewidth(1.0),
- alpha(1.0),
- cap(agg::butt_cap),
- join(agg::round_join),
- snap_mode(SNAP_FALSE)
- {
- }
-
- ~GCAgg()
- {
- }
-
- double linewidth;
- double alpha;
- bool forced_alpha;
- agg::rgba color;
- bool isaa;
-
- agg::line_cap_e cap;
- agg::line_join_e join;
-
- agg::rect_d cliprect;
-
- ClipPath clippath;
-
- Dashes dashes;
-
- e_snap_mode snap_mode;
-
- py::PathIterator hatchpath;
- agg::rgba hatch_color;
- double hatch_linewidth;
-
- SketchParams sketch;
-
- bool has_hatchpath()
- {
- return hatchpath.total_vertices() != 0;
- }
-
- private:
- // prevent copying
- GCAgg(const GCAgg &);
- GCAgg &operator=(const GCAgg &);
-};
-
-#endif
diff --git a/contrib/python/matplotlib/py3/src/_backend_agg_wrapper.cpp b/contrib/python/matplotlib/py3/src/_backend_agg_wrapper.cpp
deleted file mode 100644
index ee69729be7..0000000000
--- a/contrib/python/matplotlib/py3/src/_backend_agg_wrapper.cpp
+++ /dev/null
@@ -1,646 +0,0 @@
-#include "mplutils.h"
-#include "numpy_cpp.h"
-#include "py_converters.h"
-#include "_backend_agg.h"
-
-typedef struct
-{
- PyObject_HEAD
- RendererAgg *x;
- Py_ssize_t shape[3];
- Py_ssize_t strides[3];
- Py_ssize_t suboffsets[3];
-} PyRendererAgg;
-
-static PyTypeObject PyRendererAggType;
-
-typedef struct
-{
- PyObject_HEAD
- BufferRegion *x;
- Py_ssize_t shape[3];
- Py_ssize_t strides[3];
- Py_ssize_t suboffsets[3];
-} PyBufferRegion;
-
-static PyTypeObject PyBufferRegionType;
-
-
-/**********************************************************************
- * BufferRegion
- * */
-
-static PyObject *PyBufferRegion_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
- PyBufferRegion *self;
- self = (PyBufferRegion *)type->tp_alloc(type, 0);
- self->x = NULL;
- return (PyObject *)self;
-}
-
-static void PyBufferRegion_dealloc(PyBufferRegion *self)
-{
- delete self->x;
- Py_TYPE(self)->tp_free((PyObject *)self);
-}
-
-static PyObject *PyBufferRegion_to_string(PyBufferRegion *self, PyObject *args)
-{
- char const* msg =
- "BufferRegion.to_string is deprecated since Matplotlib 3.7 and will "
- "be removed two minor releases later; use np.asarray(region) instead.";
- if (PyErr_WarnEx(PyExc_DeprecationWarning, msg, 1)) {
- return NULL;
- }
- return PyBytes_FromStringAndSize((const char *)self->x->get_data(),
- (Py_ssize_t) self->x->get_height() * self->x->get_stride());
-}
-
-/* TODO: This doesn't seem to be used internally. Remove? */
-
-static PyObject *PyBufferRegion_set_x(PyBufferRegion *self, PyObject *args)
-{
- int x;
- if (!PyArg_ParseTuple(args, "i:set_x", &x)) {
- return NULL;
- }
- self->x->get_rect().x1 = x;
-
- Py_RETURN_NONE;
-}
-
-static PyObject *PyBufferRegion_set_y(PyBufferRegion *self, PyObject *args)
-{
- int y;
- if (!PyArg_ParseTuple(args, "i:set_y", &y)) {
- return NULL;
- }
- self->x->get_rect().y1 = y;
-
- Py_RETURN_NONE;
-}
-
-static PyObject *PyBufferRegion_get_extents(PyBufferRegion *self, PyObject *args)
-{
- agg::rect_i rect = self->x->get_rect();
-
- return Py_BuildValue("IIII", rect.x1, rect.y1, rect.x2, rect.y2);
-}
-
-static PyObject *PyBufferRegion_to_string_argb(PyBufferRegion *self, PyObject *args)
-{
- char const* msg =
- "BufferRegion.to_string_argb is deprecated since Matplotlib 3.7 and "
- "will be removed two minor releases later; use "
- "np.take(region, [2, 1, 0, 3], axis=2) instead.";
- if (PyErr_WarnEx(PyExc_DeprecationWarning, msg, 1)) {
- return NULL;
- }
- PyObject *bufobj;
- uint8_t *buf;
- Py_ssize_t height, stride;
- height = self->x->get_height();
- stride = self->x->get_stride();
- bufobj = PyBytes_FromStringAndSize(NULL, height * stride);
- buf = (uint8_t *)PyBytes_AS_STRING(bufobj);
-
- CALL_CPP_CLEANUP("to_string_argb", (self->x->to_string_argb(buf)), Py_DECREF(bufobj));
-
- return bufobj;
-}
-
-int PyBufferRegion_get_buffer(PyBufferRegion *self, Py_buffer *buf, int flags)
-{
- Py_INCREF(self);
- buf->obj = (PyObject *)self;
- buf->buf = self->x->get_data();
- buf->len = (Py_ssize_t)self->x->get_width() * (Py_ssize_t)self->x->get_height() * 4;
- buf->readonly = 0;
- buf->format = (char *)"B";
- buf->ndim = 3;
- self->shape[0] = self->x->get_height();
- self->shape[1] = self->x->get_width();
- self->shape[2] = 4;
- buf->shape = self->shape;
- self->strides[0] = self->x->get_width() * 4;
- self->strides[1] = 4;
- self->strides[2] = 1;
- buf->strides = self->strides;
- buf->suboffsets = NULL;
- buf->itemsize = 1;
- buf->internal = NULL;
-
- return 1;
-}
-
-static PyTypeObject *PyBufferRegion_init_type()
-{
- static PyMethodDef methods[] = {
- { "to_string", (PyCFunction)PyBufferRegion_to_string, METH_NOARGS, NULL },
- { "to_string_argb", (PyCFunction)PyBufferRegion_to_string_argb, METH_NOARGS, NULL },
- { "set_x", (PyCFunction)PyBufferRegion_set_x, METH_VARARGS, NULL },
- { "set_y", (PyCFunction)PyBufferRegion_set_y, METH_VARARGS, NULL },
- { "get_extents", (PyCFunction)PyBufferRegion_get_extents, METH_NOARGS, NULL },
- { NULL }
- };
-
- static PyBufferProcs buffer_procs;
- buffer_procs.bf_getbuffer = (getbufferproc)PyBufferRegion_get_buffer;
-
- PyBufferRegionType.tp_name = "matplotlib.backends._backend_agg.BufferRegion";
- PyBufferRegionType.tp_basicsize = sizeof(PyBufferRegion);
- PyBufferRegionType.tp_dealloc = (destructor)PyBufferRegion_dealloc;
- PyBufferRegionType.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
- PyBufferRegionType.tp_methods = methods;
- PyBufferRegionType.tp_new = PyBufferRegion_new;
- PyBufferRegionType.tp_as_buffer = &buffer_procs;
-
- return &PyBufferRegionType;
-}
-
-/**********************************************************************
- * RendererAgg
- * */
-
-static PyObject *PyRendererAgg_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
- PyRendererAgg *self;
- self = (PyRendererAgg *)type->tp_alloc(type, 0);
- self->x = NULL;
- return (PyObject *)self;
-}
-
-static int PyRendererAgg_init(PyRendererAgg *self, PyObject *args, PyObject *kwds)
-{
- unsigned int width;
- unsigned int height;
- double dpi;
- int debug = 0;
-
- if (!PyArg_ParseTuple(args, "IId|i:RendererAgg", &width, &height, &dpi, &debug)) {
- return -1;
- }
-
- if (dpi <= 0.0) {
- PyErr_SetString(PyExc_ValueError, "dpi must be positive");
- return -1;
- }
-
- if (width >= 1 << 16 || height >= 1 << 16) {
- PyErr_Format(
- PyExc_ValueError,
- "Image size of %dx%d pixels is too large. "
- "It must be less than 2^16 in each direction.",
- width, height);
- return -1;
- }
-
- CALL_CPP_INIT("RendererAgg", self->x = new RendererAgg(width, height, dpi))
-
- return 0;
-}
-
-static void PyRendererAgg_dealloc(PyRendererAgg *self)
-{
- delete self->x;
- Py_TYPE(self)->tp_free((PyObject *)self);
-}
-
-static PyObject *PyRendererAgg_draw_path(PyRendererAgg *self, PyObject *args)
-{
- GCAgg gc;
- py::PathIterator path;
- agg::trans_affine trans;
- PyObject *faceobj = NULL;
- agg::rgba face;
-
- if (!PyArg_ParseTuple(args,
- "O&O&O&|O:draw_path",
- &convert_gcagg,
- &gc,
- &convert_path,
- &path,
- &convert_trans_affine,
- &trans,
- &faceobj)) {
- return NULL;
- }
-
- if (!convert_face(faceobj, gc, &face)) {
- return NULL;
- }
-
- CALL_CPP("draw_path", (self->x->draw_path(gc, path, trans, face)));
-
- Py_RETURN_NONE;
-}
-
-static PyObject *PyRendererAgg_draw_text_image(PyRendererAgg *self, PyObject *args)
-{
- numpy::array_view<agg::int8u, 2> image;
- double x;
- double y;
- double angle;
- GCAgg gc;
-
- if (!PyArg_ParseTuple(args,
- "O&dddO&:draw_text_image",
- &image.converter_contiguous,
- &image,
- &x,
- &y,
- &angle,
- &convert_gcagg,
- &gc)) {
- return NULL;
- }
-
- CALL_CPP("draw_text_image", (self->x->draw_text_image(gc, image, x, y, angle)));
-
- Py_RETURN_NONE;
-}
-
-PyObject *PyRendererAgg_draw_markers(PyRendererAgg *self, PyObject *args)
-{
- GCAgg gc;
- py::PathIterator marker_path;
- agg::trans_affine marker_path_trans;
- py::PathIterator path;
- agg::trans_affine trans;
- PyObject *faceobj = NULL;
- agg::rgba face;
-
- if (!PyArg_ParseTuple(args,
- "O&O&O&O&O&|O:draw_markers",
- &convert_gcagg,
- &gc,
- &convert_path,
- &marker_path,
- &convert_trans_affine,
- &marker_path_trans,
- &convert_path,
- &path,
- &convert_trans_affine,
- &trans,
- &faceobj)) {
- return NULL;
- }
-
- if (!convert_face(faceobj, gc, &face)) {
- return NULL;
- }
-
- CALL_CPP("draw_markers",
- (self->x->draw_markers(gc, marker_path, marker_path_trans, path, trans, face)));
-
- Py_RETURN_NONE;
-}
-
-static PyObject *PyRendererAgg_draw_image(PyRendererAgg *self, PyObject *args)
-{
- GCAgg gc;
- double x;
- double y;
- numpy::array_view<agg::int8u, 3> image;
-
- if (!PyArg_ParseTuple(args,
- "O&ddO&:draw_image",
- &convert_gcagg,
- &gc,
- &x,
- &y,
- &image.converter_contiguous,
- &image)) {
- return NULL;
- }
-
- x = mpl_round(x);
- y = mpl_round(y);
-
- gc.alpha = 1.0;
- CALL_CPP("draw_image", (self->x->draw_image(gc, x, y, image)));
-
- Py_RETURN_NONE;
-}
-
-static PyObject *
-PyRendererAgg_draw_path_collection(PyRendererAgg *self, PyObject *args)
-{
- GCAgg gc;
- agg::trans_affine master_transform;
- py::PathGenerator paths;
- numpy::array_view<const double, 3> transforms;
- numpy::array_view<const double, 2> offsets;
- agg::trans_affine offset_trans;
- numpy::array_view<const double, 2> facecolors;
- numpy::array_view<const double, 2> edgecolors;
- numpy::array_view<const double, 1> linewidths;
- DashesVector dashes;
- numpy::array_view<const uint8_t, 1> antialiaseds;
- PyObject *ignored;
- PyObject *offset_position; // offset position is no longer used
-
- if (!PyArg_ParseTuple(args,
- "O&O&O&O&O&O&O&O&O&O&O&OO:draw_path_collection",
- &convert_gcagg,
- &gc,
- &convert_trans_affine,
- &master_transform,
- &convert_pathgen,
- &paths,
- &convert_transforms,
- &transforms,
- &convert_points,
- &offsets,
- &convert_trans_affine,
- &offset_trans,
- &convert_colors,
- &facecolors,
- &convert_colors,
- &edgecolors,
- &linewidths.converter,
- &linewidths,
- &convert_dashes_vector,
- &dashes,
- &antialiaseds.converter,
- &antialiaseds,
- &ignored,
- &offset_position)) {
- return NULL;
- }
-
- CALL_CPP("draw_path_collection",
- (self->x->draw_path_collection(gc,
- master_transform,
- paths,
- transforms,
- offsets,
- offset_trans,
- facecolors,
- edgecolors,
- linewidths,
- dashes,
- antialiaseds)));
-
- Py_RETURN_NONE;
-}
-
-static PyObject *PyRendererAgg_draw_quad_mesh(PyRendererAgg *self, PyObject *args)
-{
- GCAgg gc;
- agg::trans_affine master_transform;
- unsigned int mesh_width;
- unsigned int mesh_height;
- numpy::array_view<const double, 3> coordinates;
- numpy::array_view<const double, 2> offsets;
- agg::trans_affine offset_trans;
- numpy::array_view<const double, 2> facecolors;
- bool antialiased;
- numpy::array_view<const double, 2> edgecolors;
-
- if (!PyArg_ParseTuple(args,
- "O&O&IIO&O&O&O&O&O&:draw_quad_mesh",
- &convert_gcagg,
- &gc,
- &convert_trans_affine,
- &master_transform,
- &mesh_width,
- &mesh_height,
- &coordinates.converter,
- &coordinates,
- &convert_points,
- &offsets,
- &convert_trans_affine,
- &offset_trans,
- &convert_colors,
- &facecolors,
- &convert_bool,
- &antialiased,
- &convert_colors,
- &edgecolors)) {
- return NULL;
- }
-
- CALL_CPP("draw_quad_mesh",
- (self->x->draw_quad_mesh(gc,
- master_transform,
- mesh_width,
- mesh_height,
- coordinates,
- offsets,
- offset_trans,
- facecolors,
- antialiased,
- edgecolors)));
-
- Py_RETURN_NONE;
-}
-
-static PyObject *
-PyRendererAgg_draw_gouraud_triangle(PyRendererAgg *self, PyObject *args)
-{
- GCAgg gc;
- numpy::array_view<const double, 2> points;
- numpy::array_view<const double, 2> colors;
- agg::trans_affine trans;
-
- if (!PyArg_ParseTuple(args,
- "O&O&O&O&|O:draw_gouraud_triangle",
- &convert_gcagg,
- &gc,
- &points.converter,
- &points,
- &colors.converter,
- &colors,
- &convert_trans_affine,
- &trans)) {
- return NULL;
- }
-
- if (points.dim(0) != 3 || points.dim(1) != 2) {
- PyErr_Format(PyExc_ValueError,
- "points must have shape (3, 2), "
- "got (%" NPY_INTP_FMT ", %" NPY_INTP_FMT ")",
- points.dim(0), points.dim(1));
- return NULL;
- }
-
- if (colors.dim(0) != 3 || colors.dim(1) != 4) {
- PyErr_Format(PyExc_ValueError,
- "colors must have shape (3, 4), "
- "got (%" NPY_INTP_FMT ", %" NPY_INTP_FMT ")",
- colors.dim(0), colors.dim(1));
- return NULL;
- }
-
-
- CALL_CPP("draw_gouraud_triangle", (self->x->draw_gouraud_triangle(gc, points, colors, trans)));
-
- Py_RETURN_NONE;
-}
-
-static PyObject *
-PyRendererAgg_draw_gouraud_triangles(PyRendererAgg *self, PyObject *args)
-{
- GCAgg gc;
- numpy::array_view<const double, 3> points;
- numpy::array_view<const double, 3> colors;
- agg::trans_affine trans;
-
- if (!PyArg_ParseTuple(args,
- "O&O&O&O&|O:draw_gouraud_triangles",
- &convert_gcagg,
- &gc,
- &points.converter,
- &points,
- &colors.converter,
- &colors,
- &convert_trans_affine,
- &trans)) {
- return NULL;
- }
- if (points.size() && !check_trailing_shape(points, "points", 3, 2)) {
- return NULL;
- }
- if (colors.size() && !check_trailing_shape(colors, "colors", 3, 4)) {
- return NULL;
- }
- if (points.size() != colors.size()) {
- PyErr_Format(PyExc_ValueError,
- "points and colors arrays must be the same length, got "
- "%" NPY_INTP_FMT " points and %" NPY_INTP_FMT "colors",
- points.dim(0), colors.dim(0));
- return NULL;
- }
-
- CALL_CPP("draw_gouraud_triangles", self->x->draw_gouraud_triangles(gc, points, colors, trans));
-
- Py_RETURN_NONE;
-}
-
-int PyRendererAgg_get_buffer(PyRendererAgg *self, Py_buffer *buf, int flags)
-{
- Py_INCREF(self);
- buf->obj = (PyObject *)self;
- buf->buf = self->x->pixBuffer;
- buf->len = (Py_ssize_t)self->x->get_width() * (Py_ssize_t)self->x->get_height() * 4;
- buf->readonly = 0;
- buf->format = (char *)"B";
- buf->ndim = 3;
- self->shape[0] = self->x->get_height();
- self->shape[1] = self->x->get_width();
- self->shape[2] = 4;
- buf->shape = self->shape;
- self->strides[0] = self->x->get_width() * 4;
- self->strides[1] = 4;
- self->strides[2] = 1;
- buf->strides = self->strides;
- buf->suboffsets = NULL;
- buf->itemsize = 1;
- buf->internal = NULL;
-
- return 1;
-}
-
-static PyObject *PyRendererAgg_clear(PyRendererAgg *self, PyObject *args)
-{
- CALL_CPP("clear", self->x->clear());
-
- Py_RETURN_NONE;
-}
-
-static PyObject *PyRendererAgg_copy_from_bbox(PyRendererAgg *self, PyObject *args)
-{
- agg::rect_d bbox;
- BufferRegion *reg;
- PyObject *regobj;
-
- if (!PyArg_ParseTuple(args, "O&:copy_from_bbox", &convert_rect, &bbox)) {
- return 0;
- }
-
- CALL_CPP("copy_from_bbox", (reg = self->x->copy_from_bbox(bbox)));
-
- regobj = PyBufferRegion_new(&PyBufferRegionType, NULL, NULL);
- ((PyBufferRegion *)regobj)->x = reg;
-
- return regobj;
-}
-
-static PyObject *PyRendererAgg_restore_region(PyRendererAgg *self, PyObject *args)
-{
- PyBufferRegion *regobj;
- int xx1 = 0, yy1 = 0, xx2 = 0, yy2 = 0, x = 0, y = 0;
-
- if (!PyArg_ParseTuple(args,
- "O!|iiiiii:restore_region",
- &PyBufferRegionType,
- &regobj,
- &xx1,
- &yy1,
- &xx2,
- &yy2,
- &x,
- &y)) {
- return 0;
- }
-
- if (PySequence_Size(args) == 1) {
- CALL_CPP("restore_region", self->x->restore_region(*(regobj->x)));
- } else {
- CALL_CPP("restore_region", self->x->restore_region(*(regobj->x), xx1, yy1, xx2, yy2, x, y));
- }
-
- Py_RETURN_NONE;
-}
-
-static PyTypeObject *PyRendererAgg_init_type()
-{
- static PyMethodDef methods[] = {
- {"draw_path", (PyCFunction)PyRendererAgg_draw_path, METH_VARARGS, NULL},
- {"draw_markers", (PyCFunction)PyRendererAgg_draw_markers, METH_VARARGS, NULL},
- {"draw_text_image", (PyCFunction)PyRendererAgg_draw_text_image, METH_VARARGS, NULL},
- {"draw_image", (PyCFunction)PyRendererAgg_draw_image, METH_VARARGS, NULL},
- {"draw_path_collection", (PyCFunction)PyRendererAgg_draw_path_collection, METH_VARARGS, NULL},
- {"draw_quad_mesh", (PyCFunction)PyRendererAgg_draw_quad_mesh, METH_VARARGS, NULL},
- {"draw_gouraud_triangle", (PyCFunction)PyRendererAgg_draw_gouraud_triangle, METH_VARARGS, NULL},
- {"draw_gouraud_triangles", (PyCFunction)PyRendererAgg_draw_gouraud_triangles, METH_VARARGS, NULL},
-
- {"clear", (PyCFunction)PyRendererAgg_clear, METH_NOARGS, NULL},
-
- {"copy_from_bbox", (PyCFunction)PyRendererAgg_copy_from_bbox, METH_VARARGS, NULL},
- {"restore_region", (PyCFunction)PyRendererAgg_restore_region, METH_VARARGS, NULL},
- {NULL}
- };
-
- static PyBufferProcs buffer_procs;
- buffer_procs.bf_getbuffer = (getbufferproc)PyRendererAgg_get_buffer;
-
- PyRendererAggType.tp_name = "matplotlib.backends._backend_agg.RendererAgg";
- PyRendererAggType.tp_basicsize = sizeof(PyRendererAgg);
- PyRendererAggType.tp_dealloc = (destructor)PyRendererAgg_dealloc;
- PyRendererAggType.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
- PyRendererAggType.tp_methods = methods;
- PyRendererAggType.tp_init = (initproc)PyRendererAgg_init;
- PyRendererAggType.tp_new = PyRendererAgg_new;
- PyRendererAggType.tp_as_buffer = &buffer_procs;
-
- return &PyRendererAggType;
-}
-
-static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "_backend_agg" };
-
-PyMODINIT_FUNC PyInit__backend_agg(void)
-{
- import_array();
- PyObject *m;
- if (!(m = PyModule_Create(&moduledef))
- || prepare_and_add_type(PyRendererAgg_init_type(), m)
- // BufferRegion is not constructible from Python, thus not added to the module.
- || PyType_Ready(PyBufferRegion_init_type())
- ) {
- Py_XDECREF(m);
- return NULL;
- }
- return m;
-}
diff --git a/contrib/python/matplotlib/py3/src/_c_internal_utils.c b/contrib/python/matplotlib/py3/src/_c_internal_utils.c
deleted file mode 100644
index f1bd22a42c..0000000000
--- a/contrib/python/matplotlib/py3/src/_c_internal_utils.c
+++ /dev/null
@@ -1,211 +0,0 @@
-#define PY_SSIZE_T_CLEAN
-#include <Python.h>
-#ifdef __linux__
-#include <dlfcn.h>
-#endif
-#ifdef _WIN32
-#include <Objbase.h>
-#include <Shobjidl.h>
-#include <Windows.h>
-#endif
-
-static PyObject*
-mpl_display_is_valid(PyObject* module)
-{
-#ifdef __linux__
- void* libX11;
- // The getenv check is redundant but helps performance as it is much faster
- // than dlopen().
- if (getenv("DISPLAY")
- && (libX11 = dlopen("libX11.so.6", RTLD_LAZY))) {
- struct Display* display = NULL;
- struct Display* (* XOpenDisplay)(char const*) =
- dlsym(libX11, "XOpenDisplay");
- int (* XCloseDisplay)(struct Display*) =
- dlsym(libX11, "XCloseDisplay");
- if (XOpenDisplay && XCloseDisplay
- && (display = XOpenDisplay(NULL))) {
- XCloseDisplay(display);
- }
- if (dlclose(libX11)) {
- PyErr_SetString(PyExc_RuntimeError, dlerror());
- return NULL;
- }
- if (display) {
- Py_RETURN_TRUE;
- }
- }
- void* libwayland_client;
- if (getenv("WAYLAND_DISPLAY")
- && (libwayland_client = dlopen("libwayland-client.so.0", RTLD_LAZY))) {
- struct wl_display* display = NULL;
- struct wl_display* (* wl_display_connect)(char const*) =
- dlsym(libwayland_client, "wl_display_connect");
- void (* wl_display_disconnect)(struct wl_display*) =
- dlsym(libwayland_client, "wl_display_disconnect");
- if (wl_display_connect && wl_display_disconnect
- && (display = wl_display_connect(NULL))) {
- wl_display_disconnect(display);
- }
- if (dlclose(libwayland_client)) {
- PyErr_SetString(PyExc_RuntimeError, dlerror());
- return NULL;
- }
- if (display) {
- Py_RETURN_TRUE;
- }
- }
- Py_RETURN_FALSE;
-#else
- Py_RETURN_TRUE;
-#endif
-}
-
-static PyObject*
-mpl_GetCurrentProcessExplicitAppUserModelID(PyObject* module)
-{
-#ifdef _WIN32
- wchar_t* appid = NULL;
- HRESULT hr = GetCurrentProcessExplicitAppUserModelID(&appid);
- if (FAILED(hr)) {
- return PyErr_SetFromWindowsErr(hr);
- }
- PyObject* py_appid = PyUnicode_FromWideChar(appid, -1);
- CoTaskMemFree(appid);
- return py_appid;
-#else
- Py_RETURN_NONE;
-#endif
-}
-
-static PyObject*
-mpl_SetCurrentProcessExplicitAppUserModelID(PyObject* module, PyObject* arg)
-{
-#ifdef _WIN32
- wchar_t* appid = PyUnicode_AsWideCharString(arg, NULL);
- if (!appid) {
- return NULL;
- }
- HRESULT hr = SetCurrentProcessExplicitAppUserModelID(appid);
- PyMem_Free(appid);
- if (FAILED(hr)) {
- return PyErr_SetFromWindowsErr(hr);
- }
- Py_RETURN_NONE;
-#else
- Py_RETURN_NONE;
-#endif
-}
-
-static PyObject*
-mpl_GetForegroundWindow(PyObject* module)
-{
-#ifdef _WIN32
- return PyLong_FromVoidPtr(GetForegroundWindow());
-#else
- Py_RETURN_NONE;
-#endif
-}
-
-static PyObject*
-mpl_SetForegroundWindow(PyObject* module, PyObject *arg)
-{
-#ifdef _WIN32
- HWND handle = PyLong_AsVoidPtr(arg);
- if (PyErr_Occurred()) {
- return NULL;
- }
- if (!SetForegroundWindow(handle)) {
- return PyErr_Format(PyExc_RuntimeError, "Error setting window");
- }
- Py_RETURN_NONE;
-#else
- Py_RETURN_NONE;
-#endif
-}
-
-static PyObject*
-mpl_SetProcessDpiAwareness_max(PyObject* module)
-{
-#ifdef _WIN32
-#ifdef _DPI_AWARENESS_CONTEXTS_
- // These functions and options were added in later Windows 10 updates, so
- // must be loaded dynamically.
- typedef BOOL (WINAPI *IsValidDpiAwarenessContext_t)(DPI_AWARENESS_CONTEXT);
- typedef BOOL (WINAPI *SetProcessDpiAwarenessContext_t)(DPI_AWARENESS_CONTEXT);
-
- HMODULE user32 = LoadLibrary("user32.dll");
- IsValidDpiAwarenessContext_t IsValidDpiAwarenessContextPtr =
- (IsValidDpiAwarenessContext_t)GetProcAddress(
- user32, "IsValidDpiAwarenessContext");
- SetProcessDpiAwarenessContext_t SetProcessDpiAwarenessContextPtr =
- (SetProcessDpiAwarenessContext_t)GetProcAddress(
- user32, "SetProcessDpiAwarenessContext");
- DPI_AWARENESS_CONTEXT ctxs[3] = {
- DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2, // Win10 Creators Update
- DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE, // Win10
- DPI_AWARENESS_CONTEXT_SYSTEM_AWARE}; // Win10
- if (IsValidDpiAwarenessContextPtr != NULL
- && SetProcessDpiAwarenessContextPtr != NULL) {
- for (int i = 0; i < sizeof(ctxs) / sizeof(DPI_AWARENESS_CONTEXT); ++i) {
- if (IsValidDpiAwarenessContextPtr(ctxs[i])) {
- SetProcessDpiAwarenessContextPtr(ctxs[i]);
- break;
- }
- }
- } else {
- // Added in Windows Vista.
- SetProcessDPIAware();
- }
- FreeLibrary(user32);
-#else
- // Added in Windows Vista.
- SetProcessDPIAware();
-#endif
-#endif
- Py_RETURN_NONE;
-}
-
-static PyMethodDef functions[] = {
- {"display_is_valid", (PyCFunction)mpl_display_is_valid, METH_NOARGS,
- "display_is_valid()\n--\n\n"
- "Check whether the current X11 or Wayland display is valid.\n\n"
- "On Linux, returns True if either $DISPLAY is set and XOpenDisplay(NULL)\n"
- "succeeds, or $WAYLAND_DISPLAY is set and wl_display_connect(NULL)\n"
- "succeeds.\n\n"
- "On other platforms, always returns True."},
- {"Win32_GetCurrentProcessExplicitAppUserModelID",
- (PyCFunction)mpl_GetCurrentProcessExplicitAppUserModelID, METH_NOARGS,
- "Win32_GetCurrentProcessExplicitAppUserModelID()\n--\n\n"
- "Wrapper for Windows's GetCurrentProcessExplicitAppUserModelID.\n\n"
- "On non-Windows platforms, always returns None."},
- {"Win32_SetCurrentProcessExplicitAppUserModelID",
- (PyCFunction)mpl_SetCurrentProcessExplicitAppUserModelID, METH_O,
- "Win32_SetCurrentProcessExplicitAppUserModelID(appid, /)\n--\n\n"
- "Wrapper for Windows's SetCurrentProcessExplicitAppUserModelID.\n\n"
- "On non-Windows platforms, does nothing."},
- {"Win32_GetForegroundWindow",
- (PyCFunction)mpl_GetForegroundWindow, METH_NOARGS,
- "Win32_GetForegroundWindow()\n--\n\n"
- "Wrapper for Windows' GetForegroundWindow.\n\n"
- "On non-Windows platforms, always returns None."},
- {"Win32_SetForegroundWindow",
- (PyCFunction)mpl_SetForegroundWindow, METH_O,
- "Win32_SetForegroundWindow(hwnd, /)\n--\n\n"
- "Wrapper for Windows' SetForegroundWindow.\n\n"
- "On non-Windows platforms, does nothing."},
- {"Win32_SetProcessDpiAwareness_max",
- (PyCFunction)mpl_SetProcessDpiAwareness_max, METH_NOARGS,
- "Win32_SetProcessDpiAwareness_max()\n--\n\n"
- "Set Windows' process DPI awareness to best option available.\n\n"
- "On non-Windows platforms, does nothing."},
- {NULL, NULL}}; // sentinel.
-static PyModuleDef util_module = {
- PyModuleDef_HEAD_INIT, "_c_internal_utils", NULL, 0, functions
-};
-
-#pragma GCC visibility push(default)
-PyMODINIT_FUNC PyInit__c_internal_utils(void)
-{
- return PyModule_Create(&util_module);
-}
diff --git a/contrib/python/matplotlib/py3/src/_image_resample.h b/contrib/python/matplotlib/py3/src/_image_resample.h
deleted file mode 100644
index 2c91da4087..0000000000
--- a/contrib/python/matplotlib/py3/src/_image_resample.h
+++ /dev/null
@@ -1,834 +0,0 @@
-/* -*- mode: c++; c-basic-offset: 4 -*- */
-
-#ifndef MPL_RESAMPLE_H
-#define MPL_RESAMPLE_H
-
-#include "agg_image_accessors.h"
-#include "agg_path_storage.h"
-#include "agg_pixfmt_gray.h"
-#include "agg_pixfmt_rgb.h"
-#include "agg_pixfmt_rgba.h"
-#include "agg_renderer_base.h"
-#include "agg_renderer_scanline.h"
-#include "agg_rasterizer_scanline_aa.h"
-#include "agg_scanline_u.h"
-#include "agg_span_allocator.h"
-#include "agg_span_converter.h"
-#include "agg_span_image_filter_gray.h"
-#include "agg_span_image_filter_rgba.h"
-#include "agg_span_interpolator_adaptor.h"
-#include "agg_span_interpolator_linear.h"
-
-#include "agg_workaround.h"
-
-#include <type_traits>
-
-// Based on:
-
-//----------------------------------------------------------------------------
-// Anti-Grain Geometry - Version 2.4
-// Copyright (C) 2002-2005 Maxim Shemanarev (http://antigrain.com/)
-//
-// Permission to copy, use, modify, sell and distribute this software
-// is granted provided this copyright notice appears in all copies.
-// This software is provided "as is" without express or implied
-// warranty, and with no claim as to its suitability for any purpose.
-//
-//----------------------------------------------------------------------------
-// Contact: mcseem@antigrain.com
-// mcseemagg@yahoo.com
-// http://antigrain.com/
-//----------------------------------------------------------------------------
-//
-// Adaptation for high precision colors has been sponsored by
-// Liberty Technology Systems, Inc., visit http://lib-sys.com
-//
-// Liberty Technology Systems, Inc. is the provider of
-// PostScript and PDF technology for software developers.
-//
-
-//===================================================================gray64
-namespace agg
-{
- struct gray64
- {
- typedef double value_type;
- typedef double calc_type;
- typedef double long_type;
- typedef gray64 self_type;
-
- value_type v;
- value_type a;
-
- //--------------------------------------------------------------------
- gray64() {}
-
- //--------------------------------------------------------------------
- explicit gray64(value_type v_, value_type a_ = 1) :
- v(v_), a(a_) {}
-
- //--------------------------------------------------------------------
- gray64(const self_type& c, value_type a_) :
- v(c.v), a(a_) {}
-
- //--------------------------------------------------------------------
- gray64(const gray64& c) :
- v(c.v),
- a(c.a) {}
-
- //--------------------------------------------------------------------
- static AGG_INLINE double to_double(value_type a)
- {
- return a;
- }
-
- //--------------------------------------------------------------------
- static AGG_INLINE value_type from_double(double a)
- {
- return value_type(a);
- }
-
- //--------------------------------------------------------------------
- static AGG_INLINE value_type empty_value()
- {
- return 0;
- }
-
- //--------------------------------------------------------------------
- static AGG_INLINE value_type full_value()
- {
- return 1;
- }
-
- //--------------------------------------------------------------------
- AGG_INLINE bool is_transparent() const
- {
- return a <= 0;
- }
-
- //--------------------------------------------------------------------
- AGG_INLINE bool is_opaque() const
- {
- return a >= 1;
- }
-
- //--------------------------------------------------------------------
- static AGG_INLINE value_type invert(value_type x)
- {
- return 1 - x;
- }
-
- //--------------------------------------------------------------------
- static AGG_INLINE value_type multiply(value_type a, value_type b)
- {
- return value_type(a * b);
- }
-
- //--------------------------------------------------------------------
- static AGG_INLINE value_type demultiply(value_type a, value_type b)
- {
- return (b == 0) ? 0 : value_type(a / b);
- }
-
- //--------------------------------------------------------------------
- template<typename T>
- static AGG_INLINE T downscale(T a)
- {
- return a;
- }
-
- //--------------------------------------------------------------------
- template<typename T>
- static AGG_INLINE T downshift(T a, unsigned n)
- {
- return n > 0 ? a / (1 << n) : a;
- }
-
- //--------------------------------------------------------------------
- static AGG_INLINE value_type mult_cover(value_type a, cover_type b)
- {
- return value_type(a * b / cover_mask);
- }
-
- //--------------------------------------------------------------------
- static AGG_INLINE cover_type scale_cover(cover_type a, value_type b)
- {
- return cover_type(uround(a * b));
- }
-
- //--------------------------------------------------------------------
- // Interpolate p to q by a, assuming q is premultiplied by a.
- static AGG_INLINE value_type prelerp(value_type p, value_type q, value_type a)
- {
- return (1 - a) * p + q; // more accurate than "p + q - p * a"
- }
-
- //--------------------------------------------------------------------
- // Interpolate p to q by a.
- static AGG_INLINE value_type lerp(value_type p, value_type q, value_type a)
- {
- // The form "p + a * (q - p)" avoids a multiplication, but may produce an
- // inaccurate result. For example, "p + (q - p)" may not be exactly equal
- // to q. Therefore, stick to the basic expression, which at least produces
- // the correct result at either extreme.
- return (1 - a) * p + a * q;
- }
-
- //--------------------------------------------------------------------
- self_type& clear()
- {
- v = a = 0;
- return *this;
- }
-
- //--------------------------------------------------------------------
- self_type& transparent()
- {
- a = 0;
- return *this;
- }
-
- //--------------------------------------------------------------------
- self_type& opacity(double a_)
- {
- if (a_ < 0) a = 0;
- else if (a_ > 1) a = 1;
- else a = value_type(a_);
- return *this;
- }
-
- //--------------------------------------------------------------------
- double opacity() const
- {
- return a;
- }
-
-
- //--------------------------------------------------------------------
- self_type& premultiply()
- {
- if (a < 0) v = 0;
- else if(a < 1) v *= a;
- return *this;
- }
-
- //--------------------------------------------------------------------
- self_type& demultiply()
- {
- if (a < 0) v = 0;
- else if (a < 1) v /= a;
- return *this;
- }
-
- //--------------------------------------------------------------------
- self_type gradient(self_type c, double k) const
- {
- return self_type(
- value_type(v + (c.v - v) * k),
- value_type(a + (c.a - a) * k));
- }
-
- //--------------------------------------------------------------------
- static self_type no_color() { return self_type(0,0); }
- };
-
-
- //====================================================================rgba32
- struct rgba64
- {
- typedef double value_type;
- typedef double calc_type;
- typedef double long_type;
- typedef rgba64 self_type;
-
- value_type r;
- value_type g;
- value_type b;
- value_type a;
-
- //--------------------------------------------------------------------
- rgba64() {}
-
- //--------------------------------------------------------------------
- rgba64(value_type r_, value_type g_, value_type b_, value_type a_= 1) :
- r(r_), g(g_), b(b_), a(a_) {}
-
- //--------------------------------------------------------------------
- rgba64(const self_type& c, float a_) :
- r(c.r), g(c.g), b(c.b), a(a_) {}
-
- //--------------------------------------------------------------------
- rgba64(const rgba& c) :
- r(value_type(c.r)), g(value_type(c.g)), b(value_type(c.b)), a(value_type(c.a)) {}
-
- //--------------------------------------------------------------------
- operator rgba() const
- {
- return rgba(r, g, b, a);
- }
-
- //--------------------------------------------------------------------
- static AGG_INLINE double to_double(value_type a)
- {
- return a;
- }
-
- //--------------------------------------------------------------------
- static AGG_INLINE value_type from_double(double a)
- {
- return value_type(a);
- }
-
- //--------------------------------------------------------------------
- static AGG_INLINE value_type empty_value()
- {
- return 0;
- }
-
- //--------------------------------------------------------------------
- static AGG_INLINE value_type full_value()
- {
- return 1;
- }
-
- //--------------------------------------------------------------------
- AGG_INLINE bool is_transparent() const
- {
- return a <= 0;
- }
-
- //--------------------------------------------------------------------
- AGG_INLINE bool is_opaque() const
- {
- return a >= 1;
- }
-
- //--------------------------------------------------------------------
- static AGG_INLINE value_type invert(value_type x)
- {
- return 1 - x;
- }
-
- //--------------------------------------------------------------------
- static AGG_INLINE value_type multiply(value_type a, value_type b)
- {
- return value_type(a * b);
- }
-
- //--------------------------------------------------------------------
- static AGG_INLINE value_type demultiply(value_type a, value_type b)
- {
- return (b == 0) ? 0 : value_type(a / b);
- }
-
- //--------------------------------------------------------------------
- template<typename T>
- static AGG_INLINE T downscale(T a)
- {
- return a;
- }
-
- //--------------------------------------------------------------------
- template<typename T>
- static AGG_INLINE T downshift(T a, unsigned n)
- {
- return n > 0 ? a / (1 << n) : a;
- }
-
- //--------------------------------------------------------------------
- static AGG_INLINE value_type mult_cover(value_type a, cover_type b)
- {
- return value_type(a * b / cover_mask);
- }
-
- //--------------------------------------------------------------------
- static AGG_INLINE cover_type scale_cover(cover_type a, value_type b)
- {
- return cover_type(uround(a * b));
- }
-
- //--------------------------------------------------------------------
- // Interpolate p to q by a, assuming q is premultiplied by a.
- static AGG_INLINE value_type prelerp(value_type p, value_type q, value_type a)
- {
- return (1 - a) * p + q; // more accurate than "p + q - p * a"
- }
-
- //--------------------------------------------------------------------
- // Interpolate p to q by a.
- static AGG_INLINE value_type lerp(value_type p, value_type q, value_type a)
- {
- // The form "p + a * (q - p)" avoids a multiplication, but may produce an
- // inaccurate result. For example, "p + (q - p)" may not be exactly equal
- // to q. Therefore, stick to the basic expression, which at least produces
- // the correct result at either extreme.
- return (1 - a) * p + a * q;
- }
-
- //--------------------------------------------------------------------
- self_type& clear()
- {
- r = g = b = a = 0;
- return *this;
- }
-
- //--------------------------------------------------------------------
- self_type& transparent()
- {
- a = 0;
- return *this;
- }
-
- //--------------------------------------------------------------------
- AGG_INLINE self_type& opacity(double a_)
- {
- if (a_ < 0) a = 0;
- else if (a_ > 1) a = 1;
- else a = value_type(a_);
- return *this;
- }
-
- //--------------------------------------------------------------------
- double opacity() const
- {
- return a;
- }
-
- //--------------------------------------------------------------------
- AGG_INLINE self_type& premultiply()
- {
- if (a < 1)
- {
- if (a <= 0)
- {
- r = g = b = 0;
- }
- else
- {
- r *= a;
- g *= a;
- b *= a;
- }
- }
- return *this;
- }
-
- //--------------------------------------------------------------------
- AGG_INLINE self_type& demultiply()
- {
- if (a < 1)
- {
- if (a <= 0)
- {
- r = g = b = 0;
- }
- else
- {
- r /= a;
- g /= a;
- b /= a;
- }
- }
- return *this;
- }
-
- //--------------------------------------------------------------------
- AGG_INLINE self_type gradient(const self_type& c, double k) const
- {
- self_type ret;
- ret.r = value_type(r + (c.r - r) * k);
- ret.g = value_type(g + (c.g - g) * k);
- ret.b = value_type(b + (c.b - b) * k);
- ret.a = value_type(a + (c.a - a) * k);
- return ret;
- }
-
- //--------------------------------------------------------------------
- AGG_INLINE void add(const self_type& c, unsigned cover)
- {
- if (cover == cover_mask)
- {
- if (c.is_opaque())
- {
- *this = c;
- return;
- }
- else
- {
- r += c.r;
- g += c.g;
- b += c.b;
- a += c.a;
- }
- }
- else
- {
- r += mult_cover(c.r, cover);
- g += mult_cover(c.g, cover);
- b += mult_cover(c.b, cover);
- a += mult_cover(c.a, cover);
- }
- if (a > 1) a = 1;
- if (r > a) r = a;
- if (g > a) g = a;
- if (b > a) b = a;
- }
-
- //--------------------------------------------------------------------
- static self_type no_color() { return self_type(0,0,0,0); }
- };
-}
-
-
-typedef enum {
- NEAREST,
- BILINEAR,
- BICUBIC,
- SPLINE16,
- SPLINE36,
- HANNING,
- HAMMING,
- HERMITE,
- KAISER,
- QUADRIC,
- CATROM,
- GAUSSIAN,
- BESSEL,
- MITCHELL,
- SINC,
- LANCZOS,
- BLACKMAN,
- _n_interpolation
-} interpolation_e;
-
-
-// T is rgba if and only if it has an T::r field.
-template<typename T, typename = void> struct is_grayscale : std::true_type {};
-template<typename T> struct is_grayscale<T, decltype(T::r, void())> : std::false_type {};
-
-
-template<typename color_type>
-struct type_mapping
-{
- using blender_type = typename std::conditional<
- is_grayscale<color_type>::value,
- agg::blender_gray<color_type>,
- typename std::conditional<
- std::is_same<color_type, agg::rgba8>::value,
- fixed_blender_rgba_plain<color_type, agg::order_rgba>,
- agg::blender_rgba_plain<color_type, agg::order_rgba>
- >::type
- >::type;
- using pixfmt_type = typename std::conditional<
- is_grayscale<color_type>::value,
- agg::pixfmt_alpha_blend_gray<blender_type, agg::rendering_buffer>,
- agg::pixfmt_alpha_blend_rgba<blender_type, agg::rendering_buffer>
- >::type;
- using pixfmt_pre_type = typename std::conditional<
- is_grayscale<color_type>::value,
- pixfmt_type,
- agg::pixfmt_alpha_blend_rgba<
- typename std::conditional<
- std::is_same<color_type, agg::rgba8>::value,
- fixed_blender_rgba_pre<color_type, agg::order_rgba>,
- agg::blender_rgba_pre<color_type, agg::order_rgba>
- >::type,
- agg::rendering_buffer>
- >::type;
- template<typename A> using span_gen_affine_type = typename std::conditional<
- is_grayscale<color_type>::value,
- agg::span_image_resample_gray_affine<A>,
- agg::span_image_resample_rgba_affine<A>
- >::type;
- template<typename A, typename B> using span_gen_filter_type = typename std::conditional<
- is_grayscale<color_type>::value,
- agg::span_image_filter_gray<A, B>,
- agg::span_image_filter_rgba<A, B>
- >::type;
- template<typename A, typename B> using span_gen_nn_type = typename std::conditional<
- is_grayscale<color_type>::value,
- agg::span_image_filter_gray_nn<A, B>,
- agg::span_image_filter_rgba_nn<A, B>
- >::type;
-};
-
-
-template<typename color_type>
-class span_conv_alpha
-{
-public:
- span_conv_alpha(const double alpha) :
- m_alpha(alpha)
- {
- }
-
- void prepare() {}
-
- void generate(color_type* span, int x, int y, unsigned len) const
- {
- if (m_alpha != 1.0) {
- do {
- span->a *= m_alpha;
- ++span;
- } while (--len);
- }
- }
-private:
-
- const double m_alpha;
-};
-
-
-/* A class to use a lookup table for a transformation */
-class lookup_distortion
-{
-public:
- lookup_distortion(const double *mesh, int in_width, int in_height,
- int out_width, int out_height) :
- m_mesh(mesh),
- m_in_width(in_width),
- m_in_height(in_height),
- m_out_width(out_width),
- m_out_height(out_height)
- {}
-
- void calculate(int* x, int* y) {
- if (m_mesh) {
- double dx = double(*x) / agg::image_subpixel_scale;
- double dy = double(*y) / agg::image_subpixel_scale;
- if (dx >= 0 && dx < m_out_width &&
- dy >= 0 && dy < m_out_height) {
- const double *coord = m_mesh + (int(dy) * m_out_width + int(dx)) * 2;
- *x = int(coord[0] * agg::image_subpixel_scale);
- *y = int(coord[1] * agg::image_subpixel_scale);
- }
- }
- }
-
-protected:
- const double *m_mesh;
- int m_in_width;
- int m_in_height;
- int m_out_width;
- int m_out_height;
-};
-
-
-struct resample_params_t {
- interpolation_e interpolation;
- bool is_affine;
- agg::trans_affine affine;
- const double *transform_mesh;
- bool resample;
- bool norm;
- double radius;
- double alpha;
-};
-
-
-static void get_filter(const resample_params_t &params,
- agg::image_filter_lut &filter)
-{
- switch (params.interpolation) {
- case NEAREST:
- case _n_interpolation:
- // Never should get here. Here to silence compiler warnings.
- break;
-
- case HANNING:
- filter.calculate(agg::image_filter_hanning(), params.norm);
- break;
-
- case HAMMING:
- filter.calculate(agg::image_filter_hamming(), params.norm);
- break;
-
- case HERMITE:
- filter.calculate(agg::image_filter_hermite(), params.norm);
- break;
-
- case BILINEAR:
- filter.calculate(agg::image_filter_bilinear(), params.norm);
- break;
-
- case BICUBIC:
- filter.calculate(agg::image_filter_bicubic(), params.norm);
- break;
-
- case SPLINE16:
- filter.calculate(agg::image_filter_spline16(), params.norm);
- break;
-
- case SPLINE36:
- filter.calculate(agg::image_filter_spline36(), params.norm);
- break;
-
- case KAISER:
- filter.calculate(agg::image_filter_kaiser(), params.norm);
- break;
-
- case QUADRIC:
- filter.calculate(agg::image_filter_quadric(), params.norm);
- break;
-
- case CATROM:
- filter.calculate(agg::image_filter_catrom(), params.norm);
- break;
-
- case GAUSSIAN:
- filter.calculate(agg::image_filter_gaussian(), params.norm);
- break;
-
- case BESSEL:
- filter.calculate(agg::image_filter_bessel(), params.norm);
- break;
-
- case MITCHELL:
- filter.calculate(agg::image_filter_mitchell(), params.norm);
- break;
-
- case SINC:
- filter.calculate(agg::image_filter_sinc(params.radius), params.norm);
- break;
-
- case LANCZOS:
- filter.calculate(agg::image_filter_lanczos(params.radius), params.norm);
- break;
-
- case BLACKMAN:
- filter.calculate(agg::image_filter_blackman(params.radius), params.norm);
- break;
- }
-}
-
-
-template<typename color_type>
-void resample(
- const void *input, int in_width, int in_height,
- void *output, int out_width, int out_height,
- resample_params_t &params)
-{
- using type_mapping_t = type_mapping<color_type>;
-
- using input_pixfmt_t = typename type_mapping_t::pixfmt_type;
- using output_pixfmt_t = typename type_mapping_t::pixfmt_type;
-
- using renderer_t = agg::renderer_base<output_pixfmt_t>;
- using rasterizer_t = agg::rasterizer_scanline_aa<agg::rasterizer_sl_clip_dbl>;
-
- using reflect_t = agg::wrap_mode_reflect;
- using image_accessor_t = agg::image_accessor_wrap<input_pixfmt_t, reflect_t, reflect_t>;
-
- using span_alloc_t = agg::span_allocator<color_type>;
- using span_conv_alpha_t = span_conv_alpha<color_type>;
-
- using affine_interpolator_t = agg::span_interpolator_linear<>;
- using arbitrary_interpolator_t =
- agg::span_interpolator_adaptor<agg::span_interpolator_linear<>, lookup_distortion>;
-
- size_t itemsize = sizeof(color_type);
- if (is_grayscale<color_type>::value) {
- itemsize /= 2; // agg::grayXX includes an alpha channel which we don't have.
- }
-
- if (params.interpolation != NEAREST &&
- params.is_affine &&
- fabs(params.affine.sx) == 1.0 &&
- fabs(params.affine.sy) == 1.0 &&
- params.affine.shx == 0.0 &&
- params.affine.shy == 0.0) {
- params.interpolation = NEAREST;
- }
-
- span_alloc_t span_alloc;
- rasterizer_t rasterizer;
- agg::scanline_u8 scanline;
-
- span_conv_alpha_t conv_alpha(params.alpha);
-
- agg::rendering_buffer input_buffer;
- input_buffer.attach(
- (unsigned char *)input, in_width, in_height, in_width * itemsize);
- input_pixfmt_t input_pixfmt(input_buffer);
- image_accessor_t input_accessor(input_pixfmt);
-
- agg::rendering_buffer output_buffer;
- output_buffer.attach(
- (unsigned char *)output, out_width, out_height, out_width * itemsize);
- output_pixfmt_t output_pixfmt(output_buffer);
- renderer_t renderer(output_pixfmt);
-
- agg::trans_affine inverted = params.affine;
- inverted.invert();
-
- rasterizer.clip_box(0, 0, out_width, out_height);
-
- agg::path_storage path;
- if (params.is_affine) {
- path.move_to(0, 0);
- path.line_to(in_width, 0);
- path.line_to(in_width, in_height);
- path.line_to(0, in_height);
- path.close_polygon();
- agg::conv_transform<agg::path_storage> rectangle(path, params.affine);
- rasterizer.add_path(rectangle);
- } else {
- path.move_to(0, 0);
- path.line_to(out_width, 0);
- path.line_to(out_width, out_height);
- path.line_to(0, out_height);
- path.close_polygon();
- rasterizer.add_path(path);
- }
-
- if (params.interpolation == NEAREST) {
- if (params.is_affine) {
- using span_gen_t = typename type_mapping_t::template span_gen_nn_type<image_accessor_t, affine_interpolator_t>;
- using span_conv_t = agg::span_converter<span_gen_t, span_conv_alpha_t>;
- using nn_renderer_t = agg::renderer_scanline_aa<renderer_t, span_alloc_t, span_conv_t>;
- affine_interpolator_t interpolator(inverted);
- span_gen_t span_gen(input_accessor, interpolator);
- span_conv_t span_conv(span_gen, conv_alpha);
- nn_renderer_t nn_renderer(renderer, span_alloc, span_conv);
- agg::render_scanlines(rasterizer, scanline, nn_renderer);
- } else {
- using span_gen_t = typename type_mapping_t::template span_gen_nn_type<image_accessor_t, arbitrary_interpolator_t>;
- using span_conv_t = agg::span_converter<span_gen_t, span_conv_alpha_t>;
- using nn_renderer_t = agg::renderer_scanline_aa<renderer_t, span_alloc_t, span_conv_t>;
- lookup_distortion dist(
- params.transform_mesh, in_width, in_height, out_width, out_height);
- arbitrary_interpolator_t interpolator(inverted, dist);
- span_gen_t span_gen(input_accessor, interpolator);
- span_conv_t span_conv(span_gen, conv_alpha);
- nn_renderer_t nn_renderer(renderer, span_alloc, span_conv);
- agg::render_scanlines(rasterizer, scanline, nn_renderer);
- }
- } else {
- agg::image_filter_lut filter;
- get_filter(params, filter);
-
- if (params.is_affine && params.resample) {
- using span_gen_t = typename type_mapping_t::template span_gen_affine_type<image_accessor_t>;
- using span_conv_t = agg::span_converter<span_gen_t, span_conv_alpha_t>;
- using int_renderer_t = agg::renderer_scanline_aa<renderer_t, span_alloc_t, span_conv_t>;
- affine_interpolator_t interpolator(inverted);
- span_gen_t span_gen(input_accessor, interpolator, filter);
- span_conv_t span_conv(span_gen, conv_alpha);
- int_renderer_t int_renderer(renderer, span_alloc, span_conv);
- agg::render_scanlines(rasterizer, scanline, int_renderer);
- } else {
- using span_gen_t = typename type_mapping_t::template span_gen_filter_type<image_accessor_t, arbitrary_interpolator_t>;
- using span_conv_t = agg::span_converter<span_gen_t, span_conv_alpha_t>;
- using int_renderer_t = agg::renderer_scanline_aa<renderer_t, span_alloc_t, span_conv_t>;
- lookup_distortion dist(
- params.transform_mesh, in_width, in_height, out_width, out_height);
- arbitrary_interpolator_t interpolator(inverted, dist);
- span_gen_t span_gen(input_accessor, interpolator, filter);
- span_conv_t span_conv(span_gen, conv_alpha);
- int_renderer_t int_renderer(renderer, span_alloc, span_conv);
- agg::render_scanlines(rasterizer, scanline, int_renderer);
- }
- }
-}
-
-#endif /* MPL_RESAMPLE_H */
diff --git a/contrib/python/matplotlib/py3/src/_image_wrapper.cpp b/contrib/python/matplotlib/py3/src/_image_wrapper.cpp
deleted file mode 100644
index ca6ae8b222..0000000000
--- a/contrib/python/matplotlib/py3/src/_image_wrapper.cpp
+++ /dev/null
@@ -1,297 +0,0 @@
-#include "mplutils.h"
-#include "_image_resample.h"
-#include "numpy_cpp.h"
-#include "py_converters.h"
-
-
-/**********************************************************************
- * Free functions
- * */
-
-const char* image_resample__doc__ =
-"resample(input_array, output_array, transform, interpolation=NEAREST, resample=False, alpha=1.0, norm=False, radius=1.0)\n"
-"--\n\n"
-
-"Resample input_array, blending it in-place into output_array, using an\n"
-"affine transformation.\n\n"
-
-"Parameters\n"
-"----------\n"
-"input_array : 2-d or 3-d NumPy array of float, double or `numpy.uint8`\n"
-" If 2-d, the image is grayscale. If 3-d, the image must be of size\n"
-" 4 in the last dimension and represents RGBA data.\n\n"
-
-"output_array : 2-d or 3-d NumPy array of float, double or `numpy.uint8`\n"
-" The dtype and number of dimensions must match `input_array`.\n\n"
-
-"transform : matplotlib.transforms.Transform instance\n"
-" The transformation from the input array to the output array.\n\n"
-
-"interpolation : int, default: NEAREST\n"
-" The interpolation method. Must be one of the following constants\n"
-" defined in this module:\n\n"
-
-" NEAREST, BILINEAR, BICUBIC, SPLINE16, SPLINE36,\n"
-" HANNING, HAMMING, HERMITE, KAISER, QUADRIC, CATROM, GAUSSIAN,\n"
-" BESSEL, MITCHELL, SINC, LANCZOS, BLACKMAN\n\n"
-
-"resample : bool, optional\n"
-" When `True`, use a full resampling method. When `False`, only\n"
-" resample when the output image is larger than the input image.\n\n"
-
-"alpha : float, default: 1\n"
-" The transparency level, from 0 (transparent) to 1 (opaque).\n\n"
-
-"norm : bool, default: False\n"
-" Whether to norm the interpolation function.\n\n"
-
-"radius: float, default: 1\n"
-" The radius of the kernel, if method is SINC, LANCZOS or BLACKMAN.\n";
-
-
-static PyArrayObject *
-_get_transform_mesh(PyObject *py_affine, npy_intp *dims)
-{
- /* TODO: Could we get away with float, rather than double, arrays here? */
-
- /* Given a non-affine transform object, create a mesh that maps
- every pixel in the output image to the input image. This is used
- as a lookup table during the actual resampling. */
-
- PyObject *py_inverse = NULL;
- npy_intp out_dims[3];
-
- out_dims[0] = dims[0] * dims[1];
- out_dims[1] = 2;
-
- py_inverse = PyObject_CallMethod(py_affine, "inverted", NULL);
- if (py_inverse == NULL) {
- return NULL;
- }
-
- numpy::array_view<double, 2> input_mesh(out_dims);
- double *p = (double *)input_mesh.data();
-
- for (npy_intp y = 0; y < dims[0]; ++y) {
- for (npy_intp x = 0; x < dims[1]; ++x) {
- *p++ = (double)x;
- *p++ = (double)y;
- }
- }
-
- PyObject *output_mesh = PyObject_CallMethod(
- py_inverse, "transform", "O", input_mesh.pyobj_steal());
-
- Py_DECREF(py_inverse);
-
- if (output_mesh == NULL) {
- return NULL;
- }
-
- PyArrayObject *output_mesh_array =
- (PyArrayObject *)PyArray_ContiguousFromAny(
- output_mesh, NPY_DOUBLE, 2, 2);
-
- Py_DECREF(output_mesh);
-
- if (output_mesh_array == NULL) {
- return NULL;
- }
-
- return output_mesh_array;
-}
-
-
-static PyObject *
-image_resample(PyObject *self, PyObject* args, PyObject *kwargs)
-{
- PyObject *py_input = NULL;
- PyObject *py_output = NULL;
- PyObject *py_transform = NULL;
- resample_params_t params;
-
- PyArrayObject *input = NULL;
- PyArrayObject *output = NULL;
- PyArrayObject *transform_mesh = NULL;
- int ndim;
- int type;
-
- params.interpolation = NEAREST;
- params.transform_mesh = NULL;
- params.resample = false;
- params.norm = false;
- params.radius = 1.0;
- params.alpha = 1.0;
-
- const char *kwlist[] = {
- "input_array", "output_array", "transform", "interpolation",
- "resample", "alpha", "norm", "radius", NULL };
-
- if (!PyArg_ParseTupleAndKeywords(
- args, kwargs, "OOO|iO&dO&d:resample", (char **)kwlist,
- &py_input, &py_output, &py_transform,
- &params.interpolation, &convert_bool, &params.resample,
- &params.alpha, &convert_bool, &params.norm, &params.radius)) {
- return NULL;
- }
-
- if (params.interpolation < 0 || params.interpolation >= _n_interpolation) {
- PyErr_Format(PyExc_ValueError, "Invalid interpolation value %d",
- params.interpolation);
- goto error;
- }
-
- input = (PyArrayObject *)PyArray_FromAny(
- py_input, NULL, 2, 3, NPY_ARRAY_C_CONTIGUOUS, NULL);
- if (!input) {
- goto error;
- }
- ndim = PyArray_NDIM(input);
- type = PyArray_TYPE(input);
-
- if (!PyArray_Check(py_output)) {
- PyErr_SetString(PyExc_ValueError, "Output array must be a NumPy array");
- goto error;
- }
- output = (PyArrayObject *)py_output;
- if (PyArray_NDIM(output) != ndim) {
- PyErr_Format(
- PyExc_ValueError,
- "Input (%dD) and output (%dD) have different dimensionalities.",
- ndim, PyArray_NDIM(output));
- goto error;
- }
- // PyArray_FromAny above checks that input is 2D or 3D.
- if (ndim == 3 && (PyArray_DIM(input, 2) != 4 || PyArray_DIM(output, 2) != 4)) {
- PyErr_Format(
- PyExc_ValueError,
- "If 3D, input and output arrays must be RGBA with shape (M, N, 4); "
- "got trailing dimensions of %" NPY_INTP_FMT " and %" NPY_INTP_FMT
- " respectively", PyArray_DIM(input, 2), PyArray_DIM(output, 2));
- goto error;
- }
- if (PyArray_TYPE(output) != type) {
- PyErr_SetString(PyExc_ValueError, "Mismatched types");
- goto error;
- }
- if (!PyArray_IS_C_CONTIGUOUS(output)) {
- PyErr_SetString(PyExc_ValueError, "Output array must be C-contiguous");
- goto error;
- }
-
- if (py_transform == NULL || py_transform == Py_None) {
- params.is_affine = true;
- } else {
- PyObject *py_is_affine;
- int py_is_affine2;
- py_is_affine = PyObject_GetAttrString(py_transform, "is_affine");
- if (!py_is_affine) {
- goto error;
- }
-
- py_is_affine2 = PyObject_IsTrue(py_is_affine);
- Py_DECREF(py_is_affine);
-
- if (py_is_affine2 == -1) {
- goto error;
- } else if (py_is_affine2) {
- if (!convert_trans_affine(py_transform, &params.affine)) {
- goto error;
- }
- params.is_affine = true;
- } else {
- transform_mesh = _get_transform_mesh(
- py_transform, PyArray_DIMS(output));
- if (!transform_mesh) {
- goto error;
- }
- params.transform_mesh = (double *)PyArray_DATA(transform_mesh);
- params.is_affine = false;
- }
- }
-
- if (auto resampler =
- (ndim == 2) ? (
- (type == NPY_UINT8) ? resample<agg::gray8> :
- (type == NPY_INT8) ? resample<agg::gray8> :
- (type == NPY_UINT16) ? resample<agg::gray16> :
- (type == NPY_INT16) ? resample<agg::gray16> :
- (type == NPY_FLOAT32) ? resample<agg::gray32> :
- (type == NPY_FLOAT64) ? resample<agg::gray64> :
- nullptr) : (
- // ndim == 3
- (type == NPY_UINT8) ? resample<agg::rgba8> :
- (type == NPY_INT8) ? resample<agg::rgba8> :
- (type == NPY_UINT16) ? resample<agg::rgba16> :
- (type == NPY_INT16) ? resample<agg::rgba16> :
- (type == NPY_FLOAT32) ? resample<agg::rgba32> :
- (type == NPY_FLOAT64) ? resample<agg::rgba64> :
- nullptr)) {
- Py_BEGIN_ALLOW_THREADS
- resampler(
- PyArray_DATA(input), PyArray_DIM(input, 1), PyArray_DIM(input, 0),
- PyArray_DATA(output), PyArray_DIM(output, 1), PyArray_DIM(output, 0),
- params);
- Py_END_ALLOW_THREADS
- } else {
- PyErr_SetString(
- PyExc_ValueError,
- "arrays must be of dtype byte, short, float32 or float64");
- goto error;
- }
-
- Py_DECREF(input);
- Py_XDECREF(transform_mesh);
- Py_RETURN_NONE;
-
- error:
- Py_XDECREF(input);
- Py_XDECREF(transform_mesh);
- return NULL;
-}
-
-static PyMethodDef module_functions[] = {
- {"resample", (PyCFunction)image_resample, METH_VARARGS|METH_KEYWORDS, image_resample__doc__},
- {NULL}
-};
-
-static struct PyModuleDef moduledef = {
- PyModuleDef_HEAD_INIT, "_image", NULL, 0, module_functions,
-};
-
-PyMODINIT_FUNC PyInit__image(void)
-{
- PyObject *m;
-
- import_array();
-
- m = PyModule_Create(&moduledef);
-
- if (m == NULL) {
- return NULL;
- }
-
- if (PyModule_AddIntConstant(m, "NEAREST", NEAREST) ||
- PyModule_AddIntConstant(m, "BILINEAR", BILINEAR) ||
- PyModule_AddIntConstant(m, "BICUBIC", BICUBIC) ||
- PyModule_AddIntConstant(m, "SPLINE16", SPLINE16) ||
- PyModule_AddIntConstant(m, "SPLINE36", SPLINE36) ||
- PyModule_AddIntConstant(m, "HANNING", HANNING) ||
- PyModule_AddIntConstant(m, "HAMMING", HAMMING) ||
- PyModule_AddIntConstant(m, "HERMITE", HERMITE) ||
- PyModule_AddIntConstant(m, "KAISER", KAISER) ||
- PyModule_AddIntConstant(m, "QUADRIC", QUADRIC) ||
- PyModule_AddIntConstant(m, "CATROM", CATROM) ||
- PyModule_AddIntConstant(m, "GAUSSIAN", GAUSSIAN) ||
- PyModule_AddIntConstant(m, "BESSEL", BESSEL) ||
- PyModule_AddIntConstant(m, "MITCHELL", MITCHELL) ||
- PyModule_AddIntConstant(m, "SINC", SINC) ||
- PyModule_AddIntConstant(m, "LANCZOS", LANCZOS) ||
- PyModule_AddIntConstant(m, "BLACKMAN", BLACKMAN) ||
- PyModule_AddIntConstant(m, "_n_interpolation", _n_interpolation)) {
- Py_DECREF(m);
- return NULL;
- }
-
- return m;
-}
diff --git a/contrib/python/matplotlib/py3/src/_path.h b/contrib/python/matplotlib/py3/src/_path.h
deleted file mode 100644
index 61c4ed07d0..0000000000
--- a/contrib/python/matplotlib/py3/src/_path.h
+++ /dev/null
@@ -1,1251 +0,0 @@
-/* -*- mode: c++; c-basic-offset: 4 -*- */
-
-#ifndef MPL_PATH_H
-#define MPL_PATH_H
-
-#include <limits>
-#include <math.h>
-#include <vector>
-#include <cmath>
-#include <algorithm>
-#include <string>
-
-#include "agg_conv_contour.h"
-#include "agg_conv_curve.h"
-#include "agg_conv_stroke.h"
-#include "agg_conv_transform.h"
-#include "agg_path_storage.h"
-#include "agg_trans_affine.h"
-
-#include "path_converters.h"
-#include "_backend_agg_basic_types.h"
-#include "numpy_cpp.h"
-
-struct XY
-{
- double x;
- double y;
-
- XY(double x_, double y_) : x(x_), y(y_)
- {
- }
-
- bool operator==(const XY& o)
- {
- return (x == o.x && y == o.y);
- }
-
- bool operator!=(const XY& o)
- {
- return (x != o.x || y != o.y);
- }
-};
-
-typedef std::vector<XY> Polygon;
-
-void _finalize_polygon(std::vector<Polygon> &result, int closed_only)
-{
- if (result.size() == 0) {
- return;
- }
-
- Polygon &polygon = result.back();
-
- /* Clean up the last polygon in the result. */
- if (polygon.size() == 0) {
- result.pop_back();
- } else if (closed_only) {
- if (polygon.size() < 3) {
- result.pop_back();
- } else if (polygon.front() != polygon.back()) {
- polygon.push_back(polygon.front());
- }
- }
-}
-
-//
-// The following function was found in the Agg 2.3 examples (interactive_polygon.cpp).
-// It has been generalized to work on (possibly curved) polylines, rather than
-// just polygons. The original comments have been kept intact.
-// -- Michael Droettboom 2007-10-02
-//
-//======= Crossings Multiply algorithm of InsideTest ========================
-//
-// By Eric Haines, 3D/Eye Inc, erich@eye.com
-//
-// This version is usually somewhat faster than the original published in
-// Graphics Gems IV; by turning the division for testing the X axis crossing
-// into a tricky multiplication test this part of the test became faster,
-// which had the additional effect of making the test for "both to left or
-// both to right" a bit slower for triangles than simply computing the
-// intersection each time. The main increase is in triangle testing speed,
-// which was about 15% faster; all other polygon complexities were pretty much
-// the same as before. On machines where division is very expensive (not the
-// case on the HP 9000 series on which I tested) this test should be much
-// faster overall than the old code. Your mileage may (in fact, will) vary,
-// depending on the machine and the test data, but in general I believe this
-// code is both shorter and faster. This test was inspired by unpublished
-// Graphics Gems submitted by Joseph Samosky and Mark Haigh-Hutchinson.
-// Related work by Samosky is in:
-//
-// Samosky, Joseph, "SectionView: A system for interactively specifying and
-// visualizing sections through three-dimensional medical image data",
-// M.S. Thesis, Department of Electrical Engineering and Computer Science,
-// Massachusetts Institute of Technology, 1993.
-//
-// Shoot a test ray along +X axis. The strategy is to compare vertex Y values
-// to the testing point's Y and quickly discard edges which are entirely to one
-// side of the test ray. Note that CONVEX and WINDING code can be added as
-// for the CrossingsTest() code; it is left out here for clarity.
-//
-// Input 2D polygon _pgon_ with _numverts_ number of vertices and test point
-// _point_, returns 1 if inside, 0 if outside.
-template <class PathIterator, class PointArray, class ResultArray>
-void point_in_path_impl(PointArray &points, PathIterator &path, ResultArray &inside_flag)
-{
- uint8_t yflag1;
- double vtx0, vty0, vtx1, vty1;
- double tx, ty;
- double sx, sy;
- double x, y;
- size_t i;
- bool all_done;
-
- size_t n = points.size();
-
- std::vector<uint8_t> yflag0(n);
- std::vector<uint8_t> subpath_flag(n);
-
- path.rewind(0);
-
- for (i = 0; i < n; ++i) {
- inside_flag[i] = 0;
- }
-
- unsigned code = 0;
- do {
- if (code != agg::path_cmd_move_to) {
- code = path.vertex(&x, &y);
- if (code == agg::path_cmd_stop ||
- (code & agg::path_cmd_end_poly) == agg::path_cmd_end_poly) {
- continue;
- }
- }
-
- sx = vtx0 = vtx1 = x;
- sy = vty0 = vty1 = y;
-
- for (i = 0; i < n; ++i) {
- ty = points(i, 1);
-
- if (std::isfinite(ty)) {
- // get test bit for above/below X axis
- yflag0[i] = (vty0 >= ty);
-
- subpath_flag[i] = 0;
- }
- }
-
- do {
- code = path.vertex(&x, &y);
-
- // The following cases denote the beginning on a new subpath
- if (code == agg::path_cmd_stop ||
- (code & agg::path_cmd_end_poly) == agg::path_cmd_end_poly) {
- x = sx;
- y = sy;
- } else if (code == agg::path_cmd_move_to) {
- break;
- }
-
- for (i = 0; i < n; ++i) {
- tx = points(i, 0);
- ty = points(i, 1);
-
- if (!(std::isfinite(tx) && std::isfinite(ty))) {
- continue;
- }
-
- yflag1 = (vty1 >= ty);
- // Check if endpoints straddle (are on opposite sides) of
- // X axis (i.e. the Y's differ); if so, +X ray could
- // intersect this edge. The old test also checked whether
- // the endpoints are both to the right or to the left of
- // the test point. However, given the faster intersection
- // point computation used below, this test was found to be
- // a break-even proposition for most polygons and a loser
- // for triangles (where 50% or more of the edges which
- // survive this test will cross quadrants and so have to
- // have the X intersection computed anyway). I credit
- // Joseph Samosky with inspiring me to try dropping the
- // "both left or both right" part of my code.
- if (yflag0[i] != yflag1) {
- // Check intersection of pgon segment with +X ray.
- // Note if >= point's X; if so, the ray hits it. The
- // division operation is avoided for the ">=" test by
- // checking the sign of the first vertex wrto the test
- // point; idea inspired by Joseph Samosky's and Mark
- // Haigh-Hutchinson's different polygon inclusion
- // tests.
- if (((vty1 - ty) * (vtx0 - vtx1) >= (vtx1 - tx) * (vty0 - vty1)) == yflag1) {
- subpath_flag[i] ^= 1;
- }
- }
-
- // Move to the next pair of vertices, retaining info as
- // possible.
- yflag0[i] = yflag1;
- }
-
- vtx0 = vtx1;
- vty0 = vty1;
-
- vtx1 = x;
- vty1 = y;
- } while (code != agg::path_cmd_stop &&
- (code & agg::path_cmd_end_poly) != agg::path_cmd_end_poly);
-
- all_done = true;
- for (i = 0; i < n; ++i) {
- tx = points(i, 0);
- ty = points(i, 1);
-
- if (!(std::isfinite(tx) && std::isfinite(ty))) {
- continue;
- }
-
- yflag1 = (vty1 >= ty);
- if (yflag0[i] != yflag1) {
- if (((vty1 - ty) * (vtx0 - vtx1) >= (vtx1 - tx) * (vty0 - vty1)) == yflag1) {
- subpath_flag[i] = subpath_flag[i] ^ true;
- }
- }
- inside_flag[i] |= subpath_flag[i];
- if (inside_flag[i] == 0) {
- all_done = false;
- }
- }
-
- if (all_done) {
- break;
- }
- } while (code != agg::path_cmd_stop);
-}
-
-template <class PathIterator, class PointArray, class ResultArray>
-inline void points_in_path(PointArray &points,
- const double r,
- PathIterator &path,
- agg::trans_affine &trans,
- ResultArray &result)
-{
- typedef agg::conv_transform<PathIterator> transformed_path_t;
- typedef PathNanRemover<transformed_path_t> no_nans_t;
- typedef agg::conv_curve<no_nans_t> curve_t;
- typedef agg::conv_contour<curve_t> contour_t;
-
- size_t i;
- for (i = 0; i < points.size(); ++i) {
- result[i] = false;
- }
-
- if (path.total_vertices() < 3) {
- return;
- }
-
- transformed_path_t trans_path(path, trans);
- no_nans_t no_nans_path(trans_path, true, path.has_codes());
- curve_t curved_path(no_nans_path);
- if (r != 0.0) {
- contour_t contoured_path(curved_path);
- contoured_path.width(r);
- point_in_path_impl(points, contoured_path, result);
- } else {
- point_in_path_impl(points, curved_path, result);
- }
-}
-
-template <class PathIterator>
-inline bool point_in_path(
- double x, double y, const double r, PathIterator &path, agg::trans_affine &trans)
-{
- npy_intp shape[] = {1, 2};
- numpy::array_view<double, 2> points(shape);
- points(0, 0) = x;
- points(0, 1) = y;
-
- int result[1];
- result[0] = 0;
-
- points_in_path(points, r, path, trans, result);
-
- return result[0] != 0;
-}
-
-template <class PathIterator>
-inline bool point_on_path(
- double x, double y, const double r, PathIterator &path, agg::trans_affine &trans)
-{
- typedef agg::conv_transform<PathIterator> transformed_path_t;
- typedef PathNanRemover<transformed_path_t> no_nans_t;
- typedef agg::conv_curve<no_nans_t> curve_t;
- typedef agg::conv_stroke<curve_t> stroke_t;
-
- npy_intp shape[] = {1, 2};
- numpy::array_view<double, 2> points(shape);
- points(0, 0) = x;
- points(0, 1) = y;
-
- int result[1];
- result[0] = 0;
-
- transformed_path_t trans_path(path, trans);
- no_nans_t nan_removed_path(trans_path, true, path.has_codes());
- curve_t curved_path(nan_removed_path);
- stroke_t stroked_path(curved_path);
- stroked_path.width(r * 2.0);
- point_in_path_impl(points, stroked_path, result);
- return result[0] != 0;
-}
-
-struct extent_limits
-{
- double x0;
- double y0;
- double x1;
- double y1;
- double xm;
- double ym;
-};
-
-void reset_limits(extent_limits &e)
-{
- e.x0 = std::numeric_limits<double>::infinity();
- e.y0 = std::numeric_limits<double>::infinity();
- e.x1 = -std::numeric_limits<double>::infinity();
- e.y1 = -std::numeric_limits<double>::infinity();
- /* xm and ym are the minimum positive values in the data, used
- by log scaling */
- e.xm = std::numeric_limits<double>::infinity();
- e.ym = std::numeric_limits<double>::infinity();
-}
-
-inline void update_limits(double x, double y, extent_limits &e)
-{
- if (x < e.x0)
- e.x0 = x;
- if (y < e.y0)
- e.y0 = y;
- if (x > e.x1)
- e.x1 = x;
- if (y > e.y1)
- e.y1 = y;
- /* xm and ym are the minimum positive values in the data, used
- by log scaling */
- if (x > 0.0 && x < e.xm)
- e.xm = x;
- if (y > 0.0 && y < e.ym)
- e.ym = y;
-}
-
-template <class PathIterator>
-void update_path_extents(PathIterator &path, agg::trans_affine &trans, extent_limits &extents)
-{
- typedef agg::conv_transform<PathIterator> transformed_path_t;
- typedef PathNanRemover<transformed_path_t> nan_removed_t;
- double x, y;
- unsigned code;
-
- transformed_path_t tpath(path, trans);
- nan_removed_t nan_removed(tpath, true, path.has_codes());
-
- nan_removed.rewind(0);
-
- while ((code = nan_removed.vertex(&x, &y)) != agg::path_cmd_stop) {
- if ((code & agg::path_cmd_end_poly) == agg::path_cmd_end_poly) {
- continue;
- }
- update_limits(x, y, extents);
- }
-}
-
-template <class PathGenerator, class TransformArray, class OffsetArray>
-void get_path_collection_extents(agg::trans_affine &master_transform,
- PathGenerator &paths,
- TransformArray &transforms,
- OffsetArray &offsets,
- agg::trans_affine &offset_trans,
- extent_limits &extent)
-{
- if (offsets.size() != 0 && offsets.dim(1) != 2) {
- throw std::runtime_error("Offsets array must have shape (N, 2)");
- }
-
- size_t Npaths = paths.size();
- size_t Noffsets = offsets.size();
- size_t N = std::max(Npaths, Noffsets);
- size_t Ntransforms = std::min(transforms.size(), N);
- size_t i;
-
- agg::trans_affine trans;
-
- reset_limits(extent);
-
- for (i = 0; i < N; ++i) {
- typename PathGenerator::path_iterator path(paths(i % Npaths));
- if (Ntransforms) {
- size_t ti = i % Ntransforms;
- trans = agg::trans_affine(transforms(ti, 0, 0),
- transforms(ti, 1, 0),
- transforms(ti, 0, 1),
- transforms(ti, 1, 1),
- transforms(ti, 0, 2),
- transforms(ti, 1, 2));
- } else {
- trans = master_transform;
- }
-
- if (Noffsets) {
- double xo = offsets(i % Noffsets, 0);
- double yo = offsets(i % Noffsets, 1);
- offset_trans.transform(&xo, &yo);
- trans *= agg::trans_affine_translation(xo, yo);
- }
-
- update_path_extents(path, trans, extent);
- }
-}
-
-template <class PathGenerator, class TransformArray, class OffsetArray>
-void point_in_path_collection(double x,
- double y,
- double radius,
- agg::trans_affine &master_transform,
- PathGenerator &paths,
- TransformArray &transforms,
- OffsetArray &offsets,
- agg::trans_affine &offset_trans,
- bool filled,
- std::vector<int> &result)
-{
- size_t Npaths = paths.size();
-
- if (Npaths == 0) {
- return;
- }
-
- size_t Noffsets = offsets.size();
- size_t N = std::max(Npaths, Noffsets);
- size_t Ntransforms = std::min(transforms.size(), N);
- size_t i;
-
- agg::trans_affine trans;
-
- for (i = 0; i < N; ++i) {
- typename PathGenerator::path_iterator path = paths(i % Npaths);
-
- if (Ntransforms) {
- size_t ti = i % Ntransforms;
- trans = agg::trans_affine(transforms(ti, 0, 0),
- transforms(ti, 1, 0),
- transforms(ti, 0, 1),
- transforms(ti, 1, 1),
- transforms(ti, 0, 2),
- transforms(ti, 1, 2));
- trans *= master_transform;
- } else {
- trans = master_transform;
- }
-
- if (Noffsets) {
- double xo = offsets(i % Noffsets, 0);
- double yo = offsets(i % Noffsets, 1);
- offset_trans.transform(&xo, &yo);
- trans *= agg::trans_affine_translation(xo, yo);
- }
-
- if (filled) {
- if (point_in_path(x, y, radius, path, trans)) {
- result.push_back(i);
- }
- } else {
- if (point_on_path(x, y, radius, path, trans)) {
- result.push_back(i);
- }
- }
- }
-}
-
-template <class PathIterator1, class PathIterator2>
-bool path_in_path(PathIterator1 &a,
- agg::trans_affine &atrans,
- PathIterator2 &b,
- agg::trans_affine &btrans)
-{
- typedef agg::conv_transform<PathIterator2> transformed_path_t;
- typedef PathNanRemover<transformed_path_t> no_nans_t;
- typedef agg::conv_curve<no_nans_t> curve_t;
-
- if (a.total_vertices() < 3) {
- return false;
- }
-
- transformed_path_t b_path_trans(b, btrans);
- no_nans_t b_no_nans(b_path_trans, true, b.has_codes());
- curve_t b_curved(b_no_nans);
-
- double x, y;
- b_curved.rewind(0);
- while (b_curved.vertex(&x, &y) != agg::path_cmd_stop) {
- if (!point_in_path(x, y, 0.0, a, atrans)) {
- return false;
- }
- }
-
- return true;
-}
-
-/** The clip_path_to_rect code here is a clean-room implementation of
- the Sutherland-Hodgman clipping algorithm described here:
-
- https://en.wikipedia.org/wiki/Sutherland-Hodgman_clipping_algorithm
-*/
-
-namespace clip_to_rect_filters
-{
-/* There are four different passes needed to create/remove
- vertices (one for each side of the rectangle). The differences
- between those passes are encapsulated in these functor classes.
-*/
-struct bisectx
-{
- double m_x;
-
- bisectx(double x) : m_x(x)
- {
- }
-
- inline void bisect(double sx, double sy, double px, double py, double *bx, double *by) const
- {
- *bx = m_x;
- double dx = px - sx;
- double dy = py - sy;
- *by = sy + dy * ((m_x - sx) / dx);
- }
-};
-
-struct xlt : public bisectx
-{
- xlt(double x) : bisectx(x)
- {
- }
-
- inline bool is_inside(double x, double y) const
- {
- return x <= m_x;
- }
-};
-
-struct xgt : public bisectx
-{
- xgt(double x) : bisectx(x)
- {
- }
-
- inline bool is_inside(double x, double y) const
- {
- return x >= m_x;
- }
-};
-
-struct bisecty
-{
- double m_y;
-
- bisecty(double y) : m_y(y)
- {
- }
-
- inline void bisect(double sx, double sy, double px, double py, double *bx, double *by) const
- {
- *by = m_y;
- double dx = px - sx;
- double dy = py - sy;
- *bx = sx + dx * ((m_y - sy) / dy);
- }
-};
-
-struct ylt : public bisecty
-{
- ylt(double y) : bisecty(y)
- {
- }
-
- inline bool is_inside(double x, double y) const
- {
- return y <= m_y;
- }
-};
-
-struct ygt : public bisecty
-{
- ygt(double y) : bisecty(y)
- {
- }
-
- inline bool is_inside(double x, double y) const
- {
- return y >= m_y;
- }
-};
-}
-
-template <class Filter>
-inline void clip_to_rect_one_step(const Polygon &polygon, Polygon &result, const Filter &filter)
-{
- double sx, sy, px, py, bx, by;
- bool sinside, pinside;
- result.clear();
-
- if (polygon.size() == 0) {
- return;
- }
-
- sx = polygon.back().x;
- sy = polygon.back().y;
- for (Polygon::const_iterator i = polygon.begin(); i != polygon.end(); ++i) {
- px = i->x;
- py = i->y;
-
- sinside = filter.is_inside(sx, sy);
- pinside = filter.is_inside(px, py);
-
- if (sinside ^ pinside) {
- filter.bisect(sx, sy, px, py, &bx, &by);
- result.push_back(XY(bx, by));
- }
-
- if (pinside) {
- result.push_back(XY(px, py));
- }
-
- sx = px;
- sy = py;
- }
-}
-
-template <class PathIterator>
-void
-clip_path_to_rect(PathIterator &path, agg::rect_d &rect, bool inside, std::vector<Polygon> &results)
-{
- double xmin, ymin, xmax, ymax;
- if (rect.x1 < rect.x2) {
- xmin = rect.x1;
- xmax = rect.x2;
- } else {
- xmin = rect.x2;
- xmax = rect.x1;
- }
-
- if (rect.y1 < rect.y2) {
- ymin = rect.y1;
- ymax = rect.y2;
- } else {
- ymin = rect.y2;
- ymax = rect.y1;
- }
-
- if (!inside) {
- std::swap(xmin, xmax);
- std::swap(ymin, ymax);
- }
-
- typedef agg::conv_curve<PathIterator> curve_t;
- curve_t curve(path);
-
- Polygon polygon1, polygon2;
- double x = 0, y = 0;
- unsigned code = 0;
- curve.rewind(0);
-
- do {
- // Grab the next subpath and store it in polygon1
- polygon1.clear();
- do {
- if (code == agg::path_cmd_move_to) {
- polygon1.push_back(XY(x, y));
- }
-
- code = curve.vertex(&x, &y);
-
- if (code == agg::path_cmd_stop) {
- break;
- }
-
- if (code != agg::path_cmd_move_to) {
- polygon1.push_back(XY(x, y));
- }
- } while ((code & agg::path_cmd_end_poly) != agg::path_cmd_end_poly);
-
- // The result of each step is fed into the next (note the
- // swapping of polygon1 and polygon2 at each step).
- clip_to_rect_one_step(polygon1, polygon2, clip_to_rect_filters::xlt(xmax));
- clip_to_rect_one_step(polygon2, polygon1, clip_to_rect_filters::xgt(xmin));
- clip_to_rect_one_step(polygon1, polygon2, clip_to_rect_filters::ylt(ymax));
- clip_to_rect_one_step(polygon2, polygon1, clip_to_rect_filters::ygt(ymin));
-
- // Empty polygons aren't very useful, so skip them
- if (polygon1.size()) {
- _finalize_polygon(results, 1);
- results.push_back(polygon1);
- }
- } while (code != agg::path_cmd_stop);
-
- _finalize_polygon(results, 1);
-}
-
-template <class VerticesArray, class ResultArray>
-void affine_transform_2d(VerticesArray &vertices, agg::trans_affine &trans, ResultArray &result)
-{
- if (vertices.size() != 0 && vertices.dim(1) != 2) {
- throw std::runtime_error("Invalid vertices array.");
- }
-
- size_t n = vertices.size();
- double x;
- double y;
- double t0;
- double t1;
- double t;
-
- for (size_t i = 0; i < n; ++i) {
- x = vertices(i, 0);
- y = vertices(i, 1);
-
- t0 = trans.sx * x;
- t1 = trans.shx * y;
- t = t0 + t1 + trans.tx;
- result(i, 0) = t;
-
- t0 = trans.shy * x;
- t1 = trans.sy * y;
- t = t0 + t1 + trans.ty;
- result(i, 1) = t;
- }
-}
-
-template <class VerticesArray, class ResultArray>
-void affine_transform_1d(VerticesArray &vertices, agg::trans_affine &trans, ResultArray &result)
-{
- if (vertices.dim(0) != 2) {
- throw std::runtime_error("Invalid vertices array.");
- }
-
- double x;
- double y;
- double t0;
- double t1;
- double t;
-
- x = vertices(0);
- y = vertices(1);
-
- t0 = trans.sx * x;
- t1 = trans.shx * y;
- t = t0 + t1 + trans.tx;
- result(0) = t;
-
- t0 = trans.shy * x;
- t1 = trans.sy * y;
- t = t0 + t1 + trans.ty;
- result(1) = t;
-}
-
-template <class BBoxArray>
-int count_bboxes_overlapping_bbox(agg::rect_d &a, BBoxArray &bboxes)
-{
- agg::rect_d b;
- int count = 0;
-
- if (a.x2 < a.x1) {
- std::swap(a.x1, a.x2);
- }
- if (a.y2 < a.y1) {
- std::swap(a.y1, a.y2);
- }
-
- size_t num_bboxes = bboxes.size();
- for (size_t i = 0; i < num_bboxes; ++i) {
- b = agg::rect_d(bboxes(i, 0, 0), bboxes(i, 0, 1), bboxes(i, 1, 0), bboxes(i, 1, 1));
-
- if (b.x2 < b.x1) {
- std::swap(b.x1, b.x2);
- }
- if (b.y2 < b.y1) {
- std::swap(b.y1, b.y2);
- }
- if (!((b.x2 <= a.x1) || (b.y2 <= a.y1) || (b.x1 >= a.x2) || (b.y1 >= a.y2))) {
- ++count;
- }
- }
-
- return count;
-}
-
-
-inline bool isclose(double a, double b)
-{
- // relative and absolute tolerance values are chosen empirically
- // it looks the atol value matters here because of round-off errors
- const double rtol = 1e-10;
- const double atol = 1e-13;
-
- // as per python's math.isclose
- return fabs(a-b) <= fmax(rtol * fmax(fabs(a), fabs(b)), atol);
-}
-
-
-inline bool segments_intersect(const double &x1,
- const double &y1,
- const double &x2,
- const double &y2,
- const double &x3,
- const double &y3,
- const double &x4,
- const double &y4)
-{
- // determinant
- double den = ((y4 - y3) * (x2 - x1)) - ((x4 - x3) * (y2 - y1));
-
- // If den == 0 we have two possibilities:
- if (isclose(den, 0.0)) {
- double t_area = (x2*y3 - x3*y2) - x1*(y3 - y2) + y1*(x3 - x2);
- // 1 - If the area of the triangle made by the 3 first points (2 from the first segment
- // plus one from the second) is zero, they are collinear
- if (isclose(t_area, 0.0)) {
- if (x1 == x2 && x2 == x3) { // segments have infinite slope (vertical lines)
- // and lie on the same line
- return (fmin(y1, y2) <= fmin(y3, y4) && fmin(y3, y4) <= fmax(y1, y2)) ||
- (fmin(y3, y4) <= fmin(y1, y2) && fmin(y1, y2) <= fmax(y3, y4));
- }
- else {
- return (fmin(x1, x2) <= fmin(x3, x4) && fmin(x3, x4) <= fmax(x1, x2)) ||
- (fmin(x3, x4) <= fmin(x1, x2) && fmin(x1, x2) <= fmax(x3, x4));
- }
- }
- // 2 - If t_area is not zero, the segments are parallel, but not collinear
- else {
- return false;
- }
- }
-
- const double n1 = ((x4 - x3) * (y1 - y3)) - ((y4 - y3) * (x1 - x3));
- const double n2 = ((x2 - x1) * (y1 - y3)) - ((y2 - y1) * (x1 - x3));
-
- const double u1 = n1 / den;
- const double u2 = n2 / den;
-
- return ((u1 > 0.0 || isclose(u1, 0.0)) &&
- (u1 < 1.0 || isclose(u1, 1.0)) &&
- (u2 > 0.0 || isclose(u2, 0.0)) &&
- (u2 < 1.0 || isclose(u2, 1.0)));
-}
-
-template <class PathIterator1, class PathIterator2>
-bool path_intersects_path(PathIterator1 &p1, PathIterator2 &p2)
-{
- typedef PathNanRemover<py::PathIterator> no_nans_t;
- typedef agg::conv_curve<no_nans_t> curve_t;
-
- if (p1.total_vertices() < 2 || p2.total_vertices() < 2) {
- return false;
- }
-
- no_nans_t n1(p1, true, p1.has_codes());
- no_nans_t n2(p2, true, p2.has_codes());
-
- curve_t c1(n1);
- curve_t c2(n2);
-
- double x11, y11, x12, y12;
- double x21, y21, x22, y22;
-
- c1.vertex(&x11, &y11);
- while (c1.vertex(&x12, &y12) != agg::path_cmd_stop) {
- // if the segment in path 1 is (almost) 0 length, skip to next vertex
- if ((isclose((x11 - x12) * (x11 - x12) + (y11 - y12) * (y11 - y12), 0))){
- continue;
- }
- c2.rewind(0);
- c2.vertex(&x21, &y21);
-
- while (c2.vertex(&x22, &y22) != agg::path_cmd_stop) {
- // if the segment in path 2 is (almost) 0 length, skip to next vertex
- if ((isclose((x21 - x22) * (x21 - x22) + (y21 - y22) * (y21 - y22), 0))){
- continue;
- }
-
- if (segments_intersect(x11, y11, x12, y12, x21, y21, x22, y22)) {
- return true;
- }
- x21 = x22;
- y21 = y22;
- }
- x11 = x12;
- y11 = y12;
- }
-
- return false;
-}
-
-// returns whether the segment from (x1,y1) to (x2,y2)
-// intersects the rectangle centered at (cx,cy) with size (w,h)
-// see doc/segment_intersects_rectangle.svg for a more detailed explanation
-inline bool segment_intersects_rectangle(double x1, double y1,
- double x2, double y2,
- double cx, double cy,
- double w, double h)
-{
- return fabs(x1 + x2 - 2.0 * cx) < fabs(x1 - x2) + w &&
- fabs(y1 + y2 - 2.0 * cy) < fabs(y1 - y2) + h &&
- 2.0 * fabs((x1 - cx) * (y1 - y2) - (y1 - cy) * (x1 - x2)) <
- w * fabs(y1 - y2) + h * fabs(x1 - x2);
-}
-
-template <class PathIterator>
-bool path_intersects_rectangle(PathIterator &path,
- double rect_x1, double rect_y1,
- double rect_x2, double rect_y2,
- bool filled)
-{
- typedef PathNanRemover<py::PathIterator> no_nans_t;
- typedef agg::conv_curve<no_nans_t> curve_t;
-
- if (path.total_vertices() == 0) {
- return false;
- }
-
- no_nans_t no_nans(path, true, path.has_codes());
- curve_t curve(no_nans);
-
- double cx = (rect_x1 + rect_x2) * 0.5, cy = (rect_y1 + rect_y2) * 0.5;
- double w = fabs(rect_x1 - rect_x2), h = fabs(rect_y1 - rect_y2);
-
- double x1, y1, x2, y2;
-
- curve.vertex(&x1, &y1);
- if (2.0 * fabs(x1 - cx) <= w && 2.0 * fabs(y1 - cy) <= h) {
- return true;
- }
-
- while (curve.vertex(&x2, &y2) != agg::path_cmd_stop) {
- if (segment_intersects_rectangle(x1, y1, x2, y2, cx, cy, w, h)) {
- return true;
- }
- x1 = x2;
- y1 = y2;
- }
-
- if (filled) {
- agg::trans_affine trans;
- if (point_in_path(cx, cy, 0.0, path, trans)) {
- return true;
- }
- }
-
- return false;
-}
-
-template <class PathIterator>
-void convert_path_to_polygons(PathIterator &path,
- agg::trans_affine &trans,
- double width,
- double height,
- int closed_only,
- std::vector<Polygon> &result)
-{
- typedef agg::conv_transform<py::PathIterator> transformed_path_t;
- typedef PathNanRemover<transformed_path_t> nan_removal_t;
- typedef PathClipper<nan_removal_t> clipped_t;
- typedef PathSimplifier<clipped_t> simplify_t;
- typedef agg::conv_curve<simplify_t> curve_t;
-
- bool do_clip = width != 0.0 && height != 0.0;
- bool simplify = path.should_simplify();
-
- transformed_path_t tpath(path, trans);
- nan_removal_t nan_removed(tpath, true, path.has_codes());
- clipped_t clipped(nan_removed, do_clip, width, height);
- simplify_t simplified(clipped, simplify, path.simplify_threshold());
- curve_t curve(simplified);
-
- result.push_back(Polygon());
- Polygon *polygon = &result.back();
- double x, y;
- unsigned code;
-
- while ((code = curve.vertex(&x, &y)) != agg::path_cmd_stop) {
- if ((code & agg::path_cmd_end_poly) == agg::path_cmd_end_poly) {
- _finalize_polygon(result, 1);
- result.push_back(Polygon());
- polygon = &result.back();
- } else {
- if (code == agg::path_cmd_move_to) {
- _finalize_polygon(result, closed_only);
- result.push_back(Polygon());
- polygon = &result.back();
- }
- polygon->push_back(XY(x, y));
- }
- }
-
- _finalize_polygon(result, closed_only);
-}
-
-template <class VertexSource>
-void
-__cleanup_path(VertexSource &source, std::vector<double> &vertices, std::vector<npy_uint8> &codes)
-{
- unsigned code;
- double x, y;
- do {
- code = source.vertex(&x, &y);
- vertices.push_back(x);
- vertices.push_back(y);
- codes.push_back((npy_uint8)code);
- } while (code != agg::path_cmd_stop);
-}
-
-template <class PathIterator>
-void cleanup_path(PathIterator &path,
- agg::trans_affine &trans,
- bool remove_nans,
- bool do_clip,
- const agg::rect_base<double> &rect,
- e_snap_mode snap_mode,
- double stroke_width,
- bool do_simplify,
- bool return_curves,
- SketchParams sketch_params,
- std::vector<double> &vertices,
- std::vector<unsigned char> &codes)
-{
- typedef agg::conv_transform<py::PathIterator> transformed_path_t;
- typedef PathNanRemover<transformed_path_t> nan_removal_t;
- typedef PathClipper<nan_removal_t> clipped_t;
- typedef PathSnapper<clipped_t> snapped_t;
- typedef PathSimplifier<snapped_t> simplify_t;
- typedef agg::conv_curve<simplify_t> curve_t;
- typedef Sketch<curve_t> sketch_t;
-
- transformed_path_t tpath(path, trans);
- nan_removal_t nan_removed(tpath, remove_nans, path.has_codes());
- clipped_t clipped(nan_removed, do_clip, rect);
- snapped_t snapped(clipped, snap_mode, path.total_vertices(), stroke_width);
- simplify_t simplified(snapped, do_simplify, path.simplify_threshold());
-
- vertices.reserve(path.total_vertices() * 2);
- codes.reserve(path.total_vertices());
-
- if (return_curves && sketch_params.scale == 0.0) {
- __cleanup_path(simplified, vertices, codes);
- } else {
- curve_t curve(simplified);
- sketch_t sketch(curve, sketch_params.scale, sketch_params.length, sketch_params.randomness);
- __cleanup_path(sketch, vertices, codes);
- }
-}
-
-void quad2cubic(double x0, double y0,
- double x1, double y1,
- double x2, double y2,
- double *outx, double *outy)
-{
-
- outx[0] = x0 + 2./3. * (x1 - x0);
- outy[0] = y0 + 2./3. * (y1 - y0);
- outx[1] = outx[0] + 1./3. * (x2 - x0);
- outy[1] = outy[0] + 1./3. * (y2 - y0);
- outx[2] = x2;
- outy[2] = y2;
-}
-
-
-void __add_number(double val, char format_code, int precision,
- std::string& buffer)
-{
- if (precision == -1) {
- // Special-case for compat with old ttconv code, which *truncated*
- // values with a cast to int instead of rounding them as printf
- // would do. The only point where non-integer values arise is from
- // quad2cubic conversion (as we already perform a first truncation
- // on Python's side), which can introduce additional floating point
- // error (by adding 2/3 delta-x and then 1/3 delta-x), so compensate by
- // first rounding to the closest 1/3 and then truncating.
- char str[255];
- PyOS_snprintf(str, 255, "%d", (int)(round(val * 3)) / 3);
- buffer += str;
- } else {
- char *str = PyOS_double_to_string(
- val, format_code, precision, Py_DTSF_ADD_DOT_0, NULL);
- // Delete trailing zeros and decimal point
- char *c = str + strlen(str) - 1; // Start at last character.
- // Rewind through all the zeros and, if present, the trailing decimal
- // point. Py_DTSF_ADD_DOT_0 ensures we won't go past the start of str.
- while (*c == '0') {
- --c;
- }
- if (*c == '.') {
- --c;
- }
- try {
- buffer.append(str, c + 1);
- } catch (std::bad_alloc& e) {
- PyMem_Free(str);
- throw e;
- }
- PyMem_Free(str);
- }
-}
-
-
-template <class PathIterator>
-bool __convert_to_string(PathIterator &path,
- int precision,
- char **codes,
- bool postfix,
- std::string& buffer)
-{
- const char format_code = 'f';
-
- double x[3];
- double y[3];
- double last_x = 0.0;
- double last_y = 0.0;
-
- unsigned code;
-
- while ((code = path.vertex(&x[0], &y[0])) != agg::path_cmd_stop) {
- if (code == CLOSEPOLY) {
- buffer += codes[4];
- } else if (code < 5) {
- size_t size = NUM_VERTICES[code];
-
- for (size_t i = 1; i < size; ++i) {
- unsigned subcode = path.vertex(&x[i], &y[i]);
- if (subcode != code) {
- return false;
- }
- }
-
- /* For formats that don't support quad curves, convert to
- cubic curves */
- if (code == CURVE3 && codes[code - 1][0] == '\0') {
- quad2cubic(last_x, last_y, x[0], y[0], x[1], y[1], x, y);
- code++;
- size = 3;
- }
-
- if (!postfix) {
- buffer += codes[code - 1];
- buffer += ' ';
- }
-
- for (size_t i = 0; i < size; ++i) {
- __add_number(x[i], format_code, precision, buffer);
- buffer += ' ';
- __add_number(y[i], format_code, precision, buffer);
- buffer += ' ';
- }
-
- if (postfix) {
- buffer += codes[code - 1];
- }
-
- last_x = x[size - 1];
- last_y = y[size - 1];
- } else {
- // Unknown code value
- return false;
- }
-
- buffer += '\n';
- }
-
- return true;
-}
-
-template <class PathIterator>
-bool convert_to_string(PathIterator &path,
- agg::trans_affine &trans,
- agg::rect_d &clip_rect,
- bool simplify,
- SketchParams sketch_params,
- int precision,
- char **codes,
- bool postfix,
- std::string& buffer)
-{
- size_t buffersize;
- typedef agg::conv_transform<py::PathIterator> transformed_path_t;
- typedef PathNanRemover<transformed_path_t> nan_removal_t;
- typedef PathClipper<nan_removal_t> clipped_t;
- typedef PathSimplifier<clipped_t> simplify_t;
- typedef agg::conv_curve<simplify_t> curve_t;
- typedef Sketch<curve_t> sketch_t;
-
- bool do_clip = (clip_rect.x1 < clip_rect.x2 && clip_rect.y1 < clip_rect.y2);
-
- transformed_path_t tpath(path, trans);
- nan_removal_t nan_removed(tpath, true, path.has_codes());
- clipped_t clipped(nan_removed, do_clip, clip_rect);
- simplify_t simplified(clipped, simplify, path.simplify_threshold());
-
- buffersize = (size_t) path.total_vertices() * (precision + 5) * 4;
- if (buffersize == 0) {
- return true;
- }
-
- if (sketch_params.scale != 0.0) {
- buffersize *= 10;
- }
-
- buffer.reserve(buffersize);
-
- if (sketch_params.scale == 0.0) {
- return __convert_to_string(simplified, precision, codes, postfix, buffer);
- } else {
- curve_t curve(simplified);
- sketch_t sketch(curve, sketch_params.scale, sketch_params.length, sketch_params.randomness);
- return __convert_to_string(sketch, precision, codes, postfix, buffer);
- }
-
-}
-
-template<class T>
-bool is_sorted_and_has_non_nan(PyArrayObject *array)
-{
- char* ptr = PyArray_BYTES(array);
- npy_intp size = PyArray_DIM(array, 0),
- stride = PyArray_STRIDE(array, 0);
- using limits = std::numeric_limits<T>;
- T last = limits::has_infinity ? -limits::infinity() : limits::min();
- bool found_non_nan = false;
-
- for (npy_intp i = 0; i < size; ++i, ptr += stride) {
- T current = *(T*)ptr;
- // The following tests !isnan(current), but also works for integral
- // types. (The isnan(IntegralType) overload is absent on MSVC.)
- if (current == current) {
- found_non_nan = true;
- if (current < last) {
- return false;
- }
- last = current;
- }
- }
- return found_non_nan;
-};
-
-
-#endif
diff --git a/contrib/python/matplotlib/py3/src/_path_wrapper.cpp b/contrib/python/matplotlib/py3/src/_path_wrapper.cpp
deleted file mode 100644
index 369d9e0308..0000000000
--- a/contrib/python/matplotlib/py3/src/_path_wrapper.cpp
+++ /dev/null
@@ -1,772 +0,0 @@
-#include "numpy_cpp.h"
-
-#include "_path.h"
-
-#include "py_converters.h"
-#include "py_adaptors.h"
-
-PyObject *convert_polygon_vector(std::vector<Polygon> &polygons)
-{
- PyObject *pyresult = PyList_New(polygons.size());
-
- for (size_t i = 0; i < polygons.size(); ++i) {
- Polygon poly = polygons[i];
- npy_intp dims[2];
- dims[1] = 2;
-
- dims[0] = (npy_intp)poly.size();
-
- numpy::array_view<double, 2> subresult(dims);
- memcpy(subresult.data(), &poly[0], sizeof(double) * poly.size() * 2);
-
- if (PyList_SetItem(pyresult, i, subresult.pyobj())) {
- Py_DECREF(pyresult);
- return NULL;
- }
- }
-
- return pyresult;
-}
-
-const char *Py_point_in_path__doc__ =
- "point_in_path(x, y, radius, path, trans)\n"
- "--\n\n";
-
-static PyObject *Py_point_in_path(PyObject *self, PyObject *args)
-{
- double x, y, r;
- py::PathIterator path;
- agg::trans_affine trans;
- bool result;
-
- if (!PyArg_ParseTuple(args,
- "dddO&O&:point_in_path",
- &x,
- &y,
- &r,
- &convert_path,
- &path,
- &convert_trans_affine,
- &trans)) {
- return NULL;
- }
-
- CALL_CPP("point_in_path", (result = point_in_path(x, y, r, path, trans)));
-
- if (result) {
- Py_RETURN_TRUE;
- } else {
- Py_RETURN_FALSE;
- }
-}
-
-const char *Py_points_in_path__doc__ =
- "points_in_path(points, radius, path, trans)\n"
- "--\n\n";
-
-static PyObject *Py_points_in_path(PyObject *self, PyObject *args)
-{
- numpy::array_view<const double, 2> points;
- double r;
- py::PathIterator path;
- agg::trans_affine trans;
-
- if (!PyArg_ParseTuple(args,
- "O&dO&O&:points_in_path",
- &convert_points,
- &points,
- &r,
- &convert_path,
- &path,
- &convert_trans_affine,
- &trans)) {
- return NULL;
- }
-
- npy_intp dims[] = { (npy_intp)points.size() };
- numpy::array_view<uint8_t, 1> results(dims);
-
- CALL_CPP("points_in_path", (points_in_path(points, r, path, trans, results)));
-
- return results.pyobj();
-}
-
-const char *Py_update_path_extents__doc__ =
- "update_path_extents(path, trans, rect, minpos, ignore)\n"
- "--\n\n";
-
-static PyObject *Py_update_path_extents(PyObject *self, PyObject *args)
-{
- py::PathIterator path;
- agg::trans_affine trans;
- agg::rect_d rect;
- numpy::array_view<double, 1> minpos;
- int ignore;
- int changed;
-
- if (!PyArg_ParseTuple(args,
- "O&O&O&O&i:update_path_extents",
- &convert_path,
- &path,
- &convert_trans_affine,
- &trans,
- &convert_rect,
- &rect,
- &minpos.converter,
- &minpos,
- &ignore)) {
- return NULL;
- }
-
- if (minpos.dim(0) != 2) {
- PyErr_Format(PyExc_ValueError,
- "minpos must be of length 2, got %" NPY_INTP_FMT,
- minpos.dim(0));
- return NULL;
- }
-
- extent_limits e;
-
- if (ignore) {
- CALL_CPP("update_path_extents", reset_limits(e));
- } else {
- if (rect.x1 > rect.x2) {
- e.x0 = std::numeric_limits<double>::infinity();
- e.x1 = -std::numeric_limits<double>::infinity();
- } else {
- e.x0 = rect.x1;
- e.x1 = rect.x2;
- }
- if (rect.y1 > rect.y2) {
- e.y0 = std::numeric_limits<double>::infinity();
- e.y1 = -std::numeric_limits<double>::infinity();
- } else {
- e.y0 = rect.y1;
- e.y1 = rect.y2;
- }
- e.xm = minpos(0);
- e.ym = minpos(1);
- }
-
- CALL_CPP("update_path_extents", (update_path_extents(path, trans, e)));
-
- changed = (e.x0 != rect.x1 || e.y0 != rect.y1 || e.x1 != rect.x2 || e.y1 != rect.y2 ||
- e.xm != minpos(0) || e.ym != minpos(1));
-
- npy_intp extentsdims[] = { 2, 2 };
- numpy::array_view<double, 2> outextents(extentsdims);
- outextents(0, 0) = e.x0;
- outextents(0, 1) = e.y0;
- outextents(1, 0) = e.x1;
- outextents(1, 1) = e.y1;
-
- npy_intp minposdims[] = { 2 };
- numpy::array_view<double, 1> outminpos(minposdims);
- outminpos(0) = e.xm;
- outminpos(1) = e.ym;
-
- return Py_BuildValue(
- "NNi", outextents.pyobj(), outminpos.pyobj(), changed);
-}
-
-const char *Py_get_path_collection_extents__doc__ =
- "get_path_collection_extents("
- "master_transform, paths, transforms, offsets, offset_transform)\n"
- "--\n\n";
-
-static PyObject *Py_get_path_collection_extents(PyObject *self, PyObject *args)
-{
- agg::trans_affine master_transform;
- py::PathGenerator paths;
- numpy::array_view<const double, 3> transforms;
- numpy::array_view<const double, 2> offsets;
- agg::trans_affine offset_trans;
- extent_limits e;
-
- if (!PyArg_ParseTuple(args,
- "O&O&O&O&O&:get_path_collection_extents",
- &convert_trans_affine,
- &master_transform,
- &convert_pathgen,
- &paths,
- &convert_transforms,
- &transforms,
- &convert_points,
- &offsets,
- &convert_trans_affine,
- &offset_trans)) {
- return NULL;
- }
-
- CALL_CPP("get_path_collection_extents",
- (get_path_collection_extents(
- master_transform, paths, transforms, offsets, offset_trans, e)));
-
- npy_intp dims[] = { 2, 2 };
- numpy::array_view<double, 2> extents(dims);
- extents(0, 0) = e.x0;
- extents(0, 1) = e.y0;
- extents(1, 0) = e.x1;
- extents(1, 1) = e.y1;
-
- npy_intp minposdims[] = { 2 };
- numpy::array_view<double, 1> minpos(minposdims);
- minpos(0) = e.xm;
- minpos(1) = e.ym;
-
- return Py_BuildValue("NN", extents.pyobj(), minpos.pyobj());
-}
-
-const char *Py_point_in_path_collection__doc__ =
- "point_in_path_collection("
- "x, y, radius, master_transform, paths, transforms, offsets, "
- "offset_trans, filled)\n"
- "--\n\n";
-
-static PyObject *Py_point_in_path_collection(PyObject *self, PyObject *args)
-{
- double x, y, radius;
- agg::trans_affine master_transform;
- py::PathGenerator paths;
- numpy::array_view<const double, 3> transforms;
- numpy::array_view<const double, 2> offsets;
- agg::trans_affine offset_trans;
- bool filled;
- std::vector<int> result;
-
- if (!PyArg_ParseTuple(args,
- "dddO&O&O&O&O&O&:point_in_path_collection",
- &x,
- &y,
- &radius,
- &convert_trans_affine,
- &master_transform,
- &convert_pathgen,
- &paths,
- &convert_transforms,
- &transforms,
- &convert_points,
- &offsets,
- &convert_trans_affine,
- &offset_trans,
- &convert_bool,
- &filled)) {
- return NULL;
- }
-
- CALL_CPP("point_in_path_collection",
- (point_in_path_collection(x,
- y,
- radius,
- master_transform,
- paths,
- transforms,
- offsets,
- offset_trans,
- filled,
- result)));
-
- npy_intp dims[] = {(npy_intp)result.size() };
- numpy::array_view<int, 1> pyresult(dims);
- if (result.size() > 0) {
- memcpy(pyresult.data(), &result[0], result.size() * sizeof(int));
- }
- return pyresult.pyobj();
-}
-
-const char *Py_path_in_path__doc__ =
- "path_in_path(path_a, trans_a, path_b, trans_b)\n"
- "--\n\n";
-
-static PyObject *Py_path_in_path(PyObject *self, PyObject *args)
-{
- py::PathIterator a;
- agg::trans_affine atrans;
- py::PathIterator b;
- agg::trans_affine btrans;
- bool result;
-
- if (!PyArg_ParseTuple(args,
- "O&O&O&O&:path_in_path",
- &convert_path,
- &a,
- &convert_trans_affine,
- &atrans,
- &convert_path,
- &b,
- &convert_trans_affine,
- &btrans)) {
- return NULL;
- }
-
- CALL_CPP("path_in_path", (result = path_in_path(a, atrans, b, btrans)));
-
- if (result) {
- Py_RETURN_TRUE;
- } else {
- Py_RETURN_FALSE;
- }
-}
-
-const char *Py_clip_path_to_rect__doc__ =
- "clip_path_to_rect(path, rect, inside)\n"
- "--\n\n";
-
-static PyObject *Py_clip_path_to_rect(PyObject *self, PyObject *args)
-{
- py::PathIterator path;
- agg::rect_d rect;
- bool inside;
- std::vector<Polygon> result;
-
- if (!PyArg_ParseTuple(args,
- "O&O&O&:clip_path_to_rect",
- &convert_path,
- &path,
- &convert_rect,
- &rect,
- &convert_bool,
- &inside)) {
- return NULL;
- }
-
- CALL_CPP("clip_path_to_rect", (clip_path_to_rect(path, rect, inside, result)));
-
- return convert_polygon_vector(result);
-}
-
-const char *Py_affine_transform__doc__ =
- "affine_transform(points, trans)\n"
- "--\n\n";
-
-static PyObject *Py_affine_transform(PyObject *self, PyObject *args)
-{
- PyObject *vertices_obj;
- agg::trans_affine trans;
-
- if (!PyArg_ParseTuple(args,
- "OO&:affine_transform",
- &vertices_obj,
- &convert_trans_affine,
- &trans)) {
- return NULL;
- }
-
- PyArrayObject* vertices_arr = (PyArrayObject *)PyArray_ContiguousFromAny(vertices_obj, NPY_DOUBLE, 1, 2);
- if (vertices_arr == NULL) {
- return NULL;
- }
-
- if (PyArray_NDIM(vertices_arr) == 2) {
- numpy::array_view<double, 2> vertices(vertices_arr);
- Py_DECREF(vertices_arr);
-
- npy_intp dims[] = { (npy_intp)vertices.size(), 2 };
- numpy::array_view<double, 2> result(dims);
- CALL_CPP("affine_transform", (affine_transform_2d(vertices, trans, result)));
- return result.pyobj();
- } else { // PyArray_NDIM(vertices_arr) == 1
- numpy::array_view<double, 1> vertices(vertices_arr);
- Py_DECREF(vertices_arr);
-
- npy_intp dims[] = { (npy_intp)vertices.size() };
- numpy::array_view<double, 1> result(dims);
- CALL_CPP("affine_transform", (affine_transform_1d(vertices, trans, result)));
- return result.pyobj();
- }
-}
-
-const char *Py_count_bboxes_overlapping_bbox__doc__ =
- "count_bboxes_overlapping_bbox(bbox, bboxes)\n"
- "--\n\n";
-
-static PyObject *Py_count_bboxes_overlapping_bbox(PyObject *self, PyObject *args)
-{
- agg::rect_d bbox;
- numpy::array_view<const double, 3> bboxes;
- int result;
-
- if (!PyArg_ParseTuple(args,
- "O&O&:count_bboxes_overlapping_bbox",
- &convert_rect,
- &bbox,
- &convert_bboxes,
- &bboxes)) {
- return NULL;
- }
-
- CALL_CPP("count_bboxes_overlapping_bbox",
- (result = count_bboxes_overlapping_bbox(bbox, bboxes)));
-
- return PyLong_FromLong(result);
-}
-
-const char *Py_path_intersects_path__doc__ =
- "path_intersects_path(path1, path2, filled=False)\n"
- "--\n\n";
-
-static PyObject *Py_path_intersects_path(PyObject *self, PyObject *args, PyObject *kwds)
-{
- py::PathIterator p1;
- py::PathIterator p2;
- agg::trans_affine t1;
- agg::trans_affine t2;
- int filled = 0;
- const char *names[] = { "p1", "p2", "filled", NULL };
- bool result;
-
- if (!PyArg_ParseTupleAndKeywords(args,
- kwds,
- "O&O&i:path_intersects_path",
- (char **)names,
- &convert_path,
- &p1,
- &convert_path,
- &p2,
- &filled)) {
- return NULL;
- }
-
- CALL_CPP("path_intersects_path", (result = path_intersects_path(p1, p2)));
- if (filled) {
- if (!result) {
- CALL_CPP("path_intersects_path",
- (result = path_in_path(p1, t1, p2, t2)));
- }
- if (!result) {
- CALL_CPP("path_intersects_path",
- (result = path_in_path(p2, t1, p1, t2)));
- }
- }
-
- if (result) {
- Py_RETURN_TRUE;
- } else {
- Py_RETURN_FALSE;
- }
-}
-
-const char *Py_path_intersects_rectangle__doc__ =
- "path_intersects_rectangle("
- "path, rect_x1, rect_y1, rect_x2, rect_y2, filled=False)\n"
- "--\n\n";
-
-static PyObject *Py_path_intersects_rectangle(PyObject *self, PyObject *args, PyObject *kwds)
-{
- py::PathIterator path;
- double rect_x1, rect_y1, rect_x2, rect_y2;
- bool filled = false;
- const char *names[] = { "path", "rect_x1", "rect_y1", "rect_x2", "rect_y2", "filled", NULL };
- bool result;
-
- if (!PyArg_ParseTupleAndKeywords(args,
- kwds,
- "O&dddd|O&:path_intersects_rectangle",
- (char **)names,
- &convert_path,
- &path,
- &rect_x1,
- &rect_y1,
- &rect_x2,
- &rect_y2,
- &convert_bool,
- &filled)) {
- return NULL;
- }
-
- CALL_CPP("path_intersects_rectangle", (result = path_intersects_rectangle(path, rect_x1, rect_y1, rect_x2, rect_y2, filled)));
-
- if (result) {
- Py_RETURN_TRUE;
- } else {
- Py_RETURN_FALSE;
- }
-}
-
-const char *Py_convert_path_to_polygons__doc__ =
- "convert_path_to_polygons(path, trans, width=0, height=0)\n"
- "--\n\n";
-
-static PyObject *Py_convert_path_to_polygons(PyObject *self, PyObject *args, PyObject *kwds)
-{
- py::PathIterator path;
- agg::trans_affine trans;
- double width = 0.0, height = 0.0;
- int closed_only = 1;
- std::vector<Polygon> result;
- const char *names[] = { "path", "transform", "width", "height", "closed_only", NULL };
-
- if (!PyArg_ParseTupleAndKeywords(args,
- kwds,
- "O&O&|ddi:convert_path_to_polygons",
- (char **)names,
- &convert_path,
- &path,
- &convert_trans_affine,
- &trans,
- &width,
- &height,
- &closed_only)) {
- return NULL;
- }
-
- CALL_CPP("convert_path_to_polygons",
- (convert_path_to_polygons(path, trans, width, height, closed_only, result)));
-
- return convert_polygon_vector(result);
-}
-
-const char *Py_cleanup_path__doc__ =
- "cleanup_path("
- "path, trans, remove_nans, clip_rect, snap_mode, stroke_width, simplify, "
- "return_curves, sketch)\n"
- "--\n\n";
-
-static PyObject *Py_cleanup_path(PyObject *self, PyObject *args)
-{
- py::PathIterator path;
- agg::trans_affine trans;
- bool remove_nans;
- agg::rect_d clip_rect;
- e_snap_mode snap_mode;
- double stroke_width;
- PyObject *simplifyobj;
- bool simplify = false;
- bool return_curves;
- SketchParams sketch;
-
- if (!PyArg_ParseTuple(args,
- "O&O&O&O&O&dOO&O&:cleanup_path",
- &convert_path,
- &path,
- &convert_trans_affine,
- &trans,
- &convert_bool,
- &remove_nans,
- &convert_rect,
- &clip_rect,
- &convert_snap,
- &snap_mode,
- &stroke_width,
- &simplifyobj,
- &convert_bool,
- &return_curves,
- &convert_sketch_params,
- &sketch)) {
- return NULL;
- }
-
- if (simplifyobj == Py_None) {
- simplify = path.should_simplify();
- } else {
- switch (PyObject_IsTrue(simplifyobj)) {
- case 0: simplify = false; break;
- case 1: simplify = true; break;
- default: return NULL; // errored.
- }
- }
-
- bool do_clip = (clip_rect.x1 < clip_rect.x2 && clip_rect.y1 < clip_rect.y2);
-
- std::vector<double> vertices;
- std::vector<npy_uint8> codes;
-
- CALL_CPP("cleanup_path",
- (cleanup_path(path,
- trans,
- remove_nans,
- do_clip,
- clip_rect,
- snap_mode,
- stroke_width,
- simplify,
- return_curves,
- sketch,
- vertices,
- codes)));
-
- size_t length = codes.size();
-
- npy_intp vertices_dims[] = {(npy_intp)length, 2 };
- numpy::array_view<double, 2> pyvertices(vertices_dims);
-
- npy_intp codes_dims[] = {(npy_intp)length };
- numpy::array_view<unsigned char, 1> pycodes(codes_dims);
-
- memcpy(pyvertices.data(), &vertices[0], sizeof(double) * 2 * length);
- memcpy(pycodes.data(), &codes[0], sizeof(unsigned char) * length);
-
- return Py_BuildValue("NN", pyvertices.pyobj(), pycodes.pyobj());
-}
-
-const char *Py_convert_to_string__doc__ =
- "convert_to_string("
- "path, trans, clip_rect, simplify, sketch, precision, codes, postfix)\n"
- "--\n\n"
- "Convert *path* to a bytestring.\n"
- "\n"
- "The first five parameters (up to *sketch*) are interpreted as in\n"
- "`.cleanup_path`. The following ones are detailed below.\n"
- "\n"
- "Parameters\n"
- "----------\n"
- "path : Path\n"
- "trans : Transform or None\n"
- "clip_rect : sequence of 4 floats, or None\n"
- "simplify : bool\n"
- "sketch : tuple of 3 floats, or None\n"
- "precision : int\n"
- " The precision used to \"%.*f\"-format the values. Trailing zeros\n"
- " and decimal points are always removed. (precision=-1 is a special\n"
- " case used to implement ttconv-back-compatible conversion.)\n"
- "codes : sequence of 5 bytestrings\n"
- " The bytes representation of each opcode (MOVETO, LINETO, CURVE3,\n"
- " CURVE4, CLOSEPOLY), in that order. If the bytes for CURVE3 is\n"
- " empty, quad segments are automatically converted to cubic ones\n"
- " (this is used by backends such as pdf and ps, which do not support\n"
- " quads).\n"
- "postfix : bool\n"
- " Whether the opcode comes after the values (True) or before (False).\n"
- ;
-
-static PyObject *Py_convert_to_string(PyObject *self, PyObject *args)
-{
- py::PathIterator path;
- agg::trans_affine trans;
- agg::rect_d cliprect;
- PyObject *simplifyobj;
- bool simplify = false;
- SketchParams sketch;
- int precision;
- char *codes[5];
- bool postfix;
- std::string buffer;
- bool status;
-
- if (!PyArg_ParseTuple(args,
- "O&O&O&OO&i(yyyyy)O&:convert_to_string",
- &convert_path,
- &path,
- &convert_trans_affine,
- &trans,
- &convert_rect,
- &cliprect,
- &simplifyobj,
- &convert_sketch_params,
- &sketch,
- &precision,
- &codes[0],
- &codes[1],
- &codes[2],
- &codes[3],
- &codes[4],
- &convert_bool,
- &postfix)) {
- return NULL;
- }
-
- if (simplifyobj == Py_None) {
- simplify = path.should_simplify();
- } else {
- switch (PyObject_IsTrue(simplifyobj)) {
- case 0: simplify = false; break;
- case 1: simplify = true; break;
- default: return NULL; // errored.
- }
- }
-
- CALL_CPP("convert_to_string",
- (status = convert_to_string(
- path, trans, cliprect, simplify, sketch,
- precision, codes, postfix, buffer)));
-
- if (!status) {
- PyErr_SetString(PyExc_ValueError, "Malformed path codes");
- return NULL;
- }
-
- return PyBytes_FromStringAndSize(buffer.c_str(), buffer.size());
-}
-
-
-const char *Py_is_sorted_and_has_non_nan__doc__ =
- "is_sorted_and_has_non_nan(array, /)\n"
- "--\n\n"
- "Return whether the 1D *array* is monotonically increasing, ignoring NaNs,\n"
- "and has at least one non-nan value.";
-
-static PyObject *Py_is_sorted_and_has_non_nan(PyObject *self, PyObject *obj)
-{
- bool result;
-
- PyArrayObject *array = (PyArrayObject *)PyArray_FromAny(
- obj, NULL, 1, 1, 0, NULL);
-
- if (array == NULL) {
- return NULL;
- }
-
- /* Handle just the most common types here, otherwise coerce to double */
- switch (PyArray_TYPE(array)) {
- case NPY_INT:
- result = is_sorted_and_has_non_nan<npy_int>(array);
- break;
- case NPY_LONG:
- result = is_sorted_and_has_non_nan<npy_long>(array);
- break;
- case NPY_LONGLONG:
- result = is_sorted_and_has_non_nan<npy_longlong>(array);
- break;
- case NPY_FLOAT:
- result = is_sorted_and_has_non_nan<npy_float>(array);
- break;
- case NPY_DOUBLE:
- result = is_sorted_and_has_non_nan<npy_double>(array);
- break;
- default:
- Py_DECREF(array);
- array = (PyArrayObject *)PyArray_FromObject(obj, NPY_DOUBLE, 1, 1);
- if (array == NULL) {
- return NULL;
- }
- result = is_sorted_and_has_non_nan<npy_double>(array);
- }
-
- Py_DECREF(array);
-
- if (result) {
- Py_RETURN_TRUE;
- } else {
- Py_RETURN_FALSE;
- }
-}
-
-
-static PyMethodDef module_functions[] = {
- {"point_in_path", (PyCFunction)Py_point_in_path, METH_VARARGS, Py_point_in_path__doc__},
- {"points_in_path", (PyCFunction)Py_points_in_path, METH_VARARGS, Py_points_in_path__doc__},
- {"update_path_extents", (PyCFunction)Py_update_path_extents, METH_VARARGS, Py_update_path_extents__doc__},
- {"get_path_collection_extents", (PyCFunction)Py_get_path_collection_extents, METH_VARARGS, Py_get_path_collection_extents__doc__},
- {"point_in_path_collection", (PyCFunction)Py_point_in_path_collection, METH_VARARGS, Py_point_in_path_collection__doc__},
- {"path_in_path", (PyCFunction)Py_path_in_path, METH_VARARGS, Py_path_in_path__doc__},
- {"clip_path_to_rect", (PyCFunction)Py_clip_path_to_rect, METH_VARARGS, Py_clip_path_to_rect__doc__},
- {"affine_transform", (PyCFunction)Py_affine_transform, METH_VARARGS, Py_affine_transform__doc__},
- {"count_bboxes_overlapping_bbox", (PyCFunction)Py_count_bboxes_overlapping_bbox, METH_VARARGS, Py_count_bboxes_overlapping_bbox__doc__},
- {"path_intersects_path", (PyCFunction)Py_path_intersects_path, METH_VARARGS|METH_KEYWORDS, Py_path_intersects_path__doc__},
- {"path_intersects_rectangle", (PyCFunction)Py_path_intersects_rectangle, METH_VARARGS|METH_KEYWORDS, Py_path_intersects_rectangle__doc__},
- {"convert_path_to_polygons", (PyCFunction)Py_convert_path_to_polygons, METH_VARARGS|METH_KEYWORDS, Py_convert_path_to_polygons__doc__},
- {"cleanup_path", (PyCFunction)Py_cleanup_path, METH_VARARGS, Py_cleanup_path__doc__},
- {"convert_to_string", (PyCFunction)Py_convert_to_string, METH_VARARGS, Py_convert_to_string__doc__},
- {"is_sorted_and_has_non_nan", (PyCFunction)Py_is_sorted_and_has_non_nan, METH_O, Py_is_sorted_and_has_non_nan__doc__},
- {NULL}
-};
-
-static struct PyModuleDef moduledef = {
- PyModuleDef_HEAD_INIT, "_path", NULL, 0, module_functions
-};
-
-PyMODINIT_FUNC PyInit__path(void)
-{
- import_array();
- return PyModule_Create(&moduledef);
-}
diff --git a/contrib/python/matplotlib/py3/src/_qhull_wrapper.cpp b/contrib/python/matplotlib/py3/src/_qhull_wrapper.cpp
deleted file mode 100644
index 7e4f306305..0000000000
--- a/contrib/python/matplotlib/py3/src/_qhull_wrapper.cpp
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- * Wrapper module for libqhull, providing Delaunay triangulation.
- *
- * This module's methods should not be accessed directly. To obtain a Delaunay
- * triangulation, construct an instance of the matplotlib.tri.Triangulation
- * class without specifying a triangles array.
- */
-#define PY_SSIZE_T_CLEAN
-#include "Python.h"
-#include "numpy_cpp.h"
-#ifdef _MSC_VER
-/* The Qhull header does not declare this as extern "C", but only MSVC seems to
- * do name mangling on global variables. We thus need to declare this before
- * the header so that it treats it correctly, and doesn't mangle the name. */
-extern "C" {
-extern const char qh_version[];
-}
-#endif
-#include "libqhull_r/qhull_ra.h"
-#include <cstdio>
-#include <vector>
-
-
-#ifndef MPL_DEVNULL
-#error "MPL_DEVNULL must be defined as the OS-equivalent of /dev/null"
-#endif
-
-#define STRINGIFY(x) STR(x)
-#define STR(x) #x
-
-
-static const char* qhull_error_msg[6] = {
- "", /* 0 = qh_ERRnone */
- "input inconsistency", /* 1 = qh_ERRinput */
- "singular input data", /* 2 = qh_ERRsingular */
- "precision error", /* 3 = qh_ERRprec */
- "insufficient memory", /* 4 = qh_ERRmem */
- "internal error"}; /* 5 = qh_ERRqhull */
-
-
-/* Return the indices of the 3 vertices that comprise the specified facet (i.e.
- * triangle). */
-static void
-get_facet_vertices(qhT* qh, const facetT* facet, int indices[3])
-{
- vertexT *vertex, **vertexp;
- FOREACHvertex_(facet->vertices) {
- *indices++ = qh_pointid(qh, vertex->point);
- }
-}
-
-/* Return the indices of the 3 triangles that are neighbors of the specified
- * facet (triangle). */
-static void
-get_facet_neighbours(const facetT* facet, std::vector<int>& tri_indices,
- int indices[3])
-{
- facetT *neighbor, **neighborp;
- FOREACHneighbor_(facet) {
- *indices++ = (neighbor->upperdelaunay ? -1 : tri_indices[neighbor->id]);
- }
-}
-
-/* Return true if the specified points arrays contain at least 3 unique points,
- * or false otherwise. */
-static bool
-at_least_3_unique_points(npy_intp npoints, const double* x, const double* y)
-{
- int i;
- const int unique1 = 0; /* First unique point has index 0. */
- int unique2 = 0; /* Second unique point index is 0 until set. */
-
- if (npoints < 3) {
- return false;
- }
-
- for (i = 1; i < npoints; ++i) {
- if (unique2 == 0) {
- /* Looking for second unique point. */
- if (x[i] != x[unique1] || y[i] != y[unique1]) {
- unique2 = i;
- }
- }
- else {
- /* Looking for third unique point. */
- if ( (x[i] != x[unique1] || y[i] != y[unique1]) &&
- (x[i] != x[unique2] || y[i] != y[unique2]) ) {
- /* 3 unique points found, with indices 0, unique2 and i. */
- return true;
- }
- }
- }
-
- /* Run out of points before 3 unique points found. */
- return false;
-}
-
-/* Holds on to info from Qhull so that it can be destructed automatically. */
-class QhullInfo {
-public:
- QhullInfo(FILE *error_file, qhT* qh) {
- this->error_file = error_file;
- this->qh = qh;
- }
-
- ~QhullInfo() {
- qh_freeqhull(this->qh, !qh_ALL);
- int curlong, totlong; /* Memory remaining. */
- qh_memfreeshort(this->qh, &curlong, &totlong);
- if (curlong || totlong) {
- PyErr_WarnEx(PyExc_RuntimeWarning,
- "Qhull could not free all allocated memory", 1);
- }
-
- if (this->error_file != stderr) {
- fclose(error_file);
- }
- }
-
-private:
- FILE* error_file;
- qhT* qh;
-};
-
-/* Delaunay implementation method.
- * If hide_qhull_errors is true then qhull error messages are discarded;
- * if it is false then they are written to stderr. */
-static PyObject*
-delaunay_impl(npy_intp npoints, const double* x, const double* y,
- bool hide_qhull_errors)
-{
- qhT qh_qh; /* qh variable type and name must be like */
- qhT* qh = &qh_qh; /* this for Qhull macros to work correctly. */
- facetT* facet;
- int i, ntri, max_facet_id;
- int exitcode; /* Value returned from qh_new_qhull(). */
- const int ndim = 2;
- double x_mean = 0.0;
- double y_mean = 0.0;
-
- QHULL_LIB_CHECK
-
- /* Allocate points. */
- std::vector<coordT> points(npoints * ndim);
-
- /* Determine mean x, y coordinates. */
- for (i = 0; i < npoints; ++i) {
- x_mean += x[i];
- y_mean += y[i];
- }
- x_mean /= npoints;
- y_mean /= npoints;
-
- /* Prepare points array to pass to qhull. */
- for (i = 0; i < npoints; ++i) {
- points[2*i ] = x[i] - x_mean;
- points[2*i+1] = y[i] - y_mean;
- }
-
- /* qhull expects a FILE* to write errors to. */
- FILE* error_file = NULL;
- if (hide_qhull_errors) {
- /* qhull errors are ignored by writing to OS-equivalent of /dev/null.
- * Rather than have OS-specific code here, instead it is determined by
- * setupext.py and passed in via the macro MPL_DEVNULL. */
- error_file = fopen(STRINGIFY(MPL_DEVNULL), "w");
- if (error_file == NULL) {
- throw std::runtime_error("Could not open devnull");
- }
- }
- else {
- /* qhull errors written to stderr. */
- error_file = stderr;
- }
-
- /* Perform Delaunay triangulation. */
- QhullInfo info(error_file, qh);
- qh_zero(qh, error_file);
- exitcode = qh_new_qhull(qh, ndim, (int)npoints, points.data(), False,
- (char*)"qhull d Qt Qbb Qc Qz", NULL, error_file);
- if (exitcode != qh_ERRnone) {
- PyErr_Format(PyExc_RuntimeError,
- "Error in qhull Delaunay triangulation calculation: %s (exitcode=%d)%s",
- qhull_error_msg[exitcode], exitcode,
- hide_qhull_errors ? "; use python verbose option (-v) to see original qhull error." : "");
- return NULL;
- }
-
- /* Split facets so that they only have 3 points each. */
- qh_triangulate(qh);
-
- /* Determine ntri and max_facet_id.
- Note that libqhull uses macros to iterate through collections. */
- ntri = 0;
- FORALLfacets {
- if (!facet->upperdelaunay) {
- ++ntri;
- }
- }
-
- max_facet_id = qh->facet_id - 1;
-
- /* Create array to map facet id to triangle index. */
- std::vector<int> tri_indices(max_facet_id+1);
-
- /* Allocate Python arrays to return. */
- npy_intp dims[2] = {ntri, 3};
- numpy::array_view<int, ndim> triangles(dims);
- int* triangles_ptr = triangles.data();
-
- numpy::array_view<int, ndim> neighbors(dims);
- int* neighbors_ptr = neighbors.data();
-
- /* Determine triangles array and set tri_indices array. */
- i = 0;
- FORALLfacets {
- if (!facet->upperdelaunay) {
- int indices[3];
- tri_indices[facet->id] = i++;
- get_facet_vertices(qh, facet, indices);
- *triangles_ptr++ = (facet->toporient ? indices[0] : indices[2]);
- *triangles_ptr++ = indices[1];
- *triangles_ptr++ = (facet->toporient ? indices[2] : indices[0]);
- }
- else {
- tri_indices[facet->id] = -1;
- }
- }
-
- /* Determine neighbors array. */
- FORALLfacets {
- if (!facet->upperdelaunay) {
- int indices[3];
- get_facet_neighbours(facet, tri_indices, indices);
- *neighbors_ptr++ = (facet->toporient ? indices[2] : indices[0]);
- *neighbors_ptr++ = (facet->toporient ? indices[0] : indices[2]);
- *neighbors_ptr++ = indices[1];
- }
- }
-
- PyObject* tuple = PyTuple_New(2);
- if (tuple == 0) {
- throw std::runtime_error("Failed to create Python tuple");
- }
-
- PyTuple_SET_ITEM(tuple, 0, triangles.pyobj());
- PyTuple_SET_ITEM(tuple, 1, neighbors.pyobj());
- return tuple;
-}
-
-/* Process Python arguments and call Delaunay implementation method. */
-static PyObject*
-delaunay(PyObject *self, PyObject *args)
-{
- numpy::array_view<double, 1> xarray;
- numpy::array_view<double, 1> yarray;
- PyObject* ret;
- npy_intp npoints;
- const double* x;
- const double* y;
- int verbose = 0;
-
- if (!PyArg_ParseTuple(args, "O&O&i:delaunay",
- &xarray.converter_contiguous, &xarray,
- &yarray.converter_contiguous, &yarray,
- &verbose)) {
- return NULL;
- }
-
- npoints = xarray.dim(0);
- if (npoints != yarray.dim(0)) {
- PyErr_SetString(PyExc_ValueError,
- "x and y must be 1D arrays of the same length");
- return NULL;
- }
-
- if (npoints < 3) {
- PyErr_SetString(PyExc_ValueError,
- "x and y arrays must have a length of at least 3");
- return NULL;
- }
-
- x = xarray.data();
- y = yarray.data();
-
- if (!at_least_3_unique_points(npoints, x, y)) {
- PyErr_SetString(PyExc_ValueError,
- "x and y arrays must consist of at least 3 unique points");
- return NULL;
- }
-
- CALL_CPP("qhull.delaunay",
- (ret = delaunay_impl(npoints, x, y, verbose == 0)));
-
- return ret;
-}
-
-/* Return qhull version string for assistance in debugging. */
-static PyObject*
-version(PyObject *self, PyObject *arg)
-{
- return PyBytes_FromString(qh_version);
-}
-
-static PyMethodDef qhull_methods[] = {
- {"delaunay", delaunay, METH_VARARGS,
- "delaunay(x, y, verbose, /)\n"
- "--\n\n"
- "Compute a Delaunay triangulation.\n"
- "\n"
- "Parameters\n"
- "----------\n"
- "x, y : 1d arrays\n"
- " The coordinates of the point set, which must consist of at least\n"
- " three unique points.\n"
- "verbose : int\n"
- " Python's verbosity level.\n"
- "\n"
- "Returns\n"
- "-------\n"
- "triangles, neighbors : int arrays, shape (ntri, 3)\n"
- " Indices of triangle vertices and indices of triangle neighbors.\n"
- },
- {"version", version, METH_NOARGS,
- "version()\n--\n\n"
- "Return the qhull version string."},
- {NULL, NULL, 0, NULL}
-};
-
-static struct PyModuleDef qhull_module = {
- PyModuleDef_HEAD_INIT,
- "qhull", "Computing Delaunay triangulations.\n", -1, qhull_methods
-};
-
-PyMODINIT_FUNC
-PyInit__qhull(void)
-{
- import_array();
- return PyModule_Create(&qhull_module);
-}
diff --git a/contrib/python/matplotlib/py3/src/_tkagg.cpp b/contrib/python/matplotlib/py3/src/_tkagg.cpp
deleted file mode 100644
index 5c36b3f07f..0000000000
--- a/contrib/python/matplotlib/py3/src/_tkagg.cpp
+++ /dev/null
@@ -1,370 +0,0 @@
-/* -*- mode: c++; c-basic-offset: 4 -*- */
-
-// Where is PIL?
-//
-// Many years ago, Matplotlib used to include code from PIL (the Python Imaging
-// Library). Since then, the code has changed a lot - the organizing principle
-// and methods of operation are now quite different. Because our review of
-// the codebase showed that all the code that came from PIL was removed or
-// rewritten, we have removed the PIL licensing information. If you want PIL,
-// you can get it at https://python-pillow.org/
-
-#define PY_SSIZE_T_CLEAN
-#include <Python.h>
-
-#ifdef _WIN32
-#define WIN32_DLL
-#endif
-#ifdef __CYGWIN__
-/*
- * Unfortunately cygwin's libdl inherits restrictions from the underlying
- * Windows OS, at least currently. Therefore, a symbol may be loaded from a
- * module by dlsym() only if it is really located in the given module,
- * dependencies are not included. So we have to use native WinAPI on Cygwin
- * also.
- */
-#define WIN32_DLL
-static inline PyObject *PyErr_SetFromWindowsErr(int ierr) {
- PyErr_SetString(PyExc_OSError, "Call to EnumProcessModules failed");
- return NULL;
-}
-#endif
-
-#ifdef WIN32_DLL
-#include <string>
-#include <windows.h>
-#include <commctrl.h>
-#define PSAPI_VERSION 1
-#include <psapi.h> // Must be linked with 'psapi' library
-#define dlsym GetProcAddress
-#else
-#include <dlfcn.h>
-#endif
-
-// Include our own excerpts from the Tcl / Tk headers
-#include "_tkmini.h"
-
-static int convert_voidptr(PyObject *obj, void *p)
-{
- void **val = (void **)p;
- *val = PyLong_AsVoidPtr(obj);
- return *val != NULL ? 1 : !PyErr_Occurred();
-}
-
-// Global vars for Tk functions. We load these symbols from the tkinter
-// extension module or loaded Tk libraries at run-time.
-static Tk_FindPhoto_t TK_FIND_PHOTO;
-static Tk_PhotoPutBlock_t TK_PHOTO_PUT_BLOCK;
-// Global vars for Tcl functions. We load these symbols from the tkinter
-// extension module or loaded Tcl libraries at run-time.
-static Tcl_SetVar_t TCL_SETVAR;
-
-static PyObject *mpl_tk_blit(PyObject *self, PyObject *args)
-{
- Tcl_Interp *interp;
- char const *photo_name;
- int height, width;
- unsigned char *data_ptr;
- int comp_rule;
- int put_retval;
- int o0, o1, o2, o3;
- int x1, x2, y1, y2;
- Tk_PhotoHandle photo;
- Tk_PhotoImageBlock block;
- if (!PyArg_ParseTuple(args, "O&s(iiO&)i(iiii)(iiii):blit",
- convert_voidptr, &interp, &photo_name,
- &height, &width, convert_voidptr, &data_ptr,
- &comp_rule,
- &o0, &o1, &o2, &o3,
- &x1, &x2, &y1, &y2)) {
- goto exit;
- }
- if (!(photo = TK_FIND_PHOTO(interp, photo_name))) {
- PyErr_SetString(PyExc_ValueError, "Failed to extract Tk_PhotoHandle");
- goto exit;
- }
- if (0 > y1 || y1 > y2 || y2 > height || 0 > x1 || x1 > x2 || x2 > width) {
- PyErr_SetString(PyExc_ValueError, "Attempting to draw out of bounds");
- goto exit;
- }
- if (comp_rule != TK_PHOTO_COMPOSITE_OVERLAY && comp_rule != TK_PHOTO_COMPOSITE_SET) {
- PyErr_SetString(PyExc_ValueError, "Invalid comp_rule argument");
- goto exit;
- }
-
- Py_BEGIN_ALLOW_THREADS
- block.pixelPtr = data_ptr + 4 * ((height - y2) * width + x1);
- block.width = x2 - x1;
- block.height = y2 - y1;
- block.pitch = 4 * width;
- block.pixelSize = 4;
- block.offset[0] = o0;
- block.offset[1] = o1;
- block.offset[2] = o2;
- block.offset[3] = o3;
- put_retval = TK_PHOTO_PUT_BLOCK(
- interp, photo, &block, x1, height - y2, x2 - x1, y2 - y1, comp_rule);
- Py_END_ALLOW_THREADS
- if (put_retval == TCL_ERROR) {
- return PyErr_NoMemory();
- }
-
-exit:
- if (PyErr_Occurred()) {
- return NULL;
- } else {
- Py_RETURN_NONE;
- }
-}
-
-#ifdef WIN32_DLL
-LRESULT CALLBACK
-DpiSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
- UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
-{
- switch (uMsg) {
- case WM_DPICHANGED:
- // This function is a subclassed window procedure, and so is run during
- // the Tcl/Tk event loop. Unfortunately, Tkinter has a *second* lock on
- // Tcl threading that is not exposed publicly, but is currently taken
- // while we're in the window procedure. So while we can take the GIL to
- // call Python code, we must not also call *any* Tk code from Python.
- // So stay with Tcl calls in C only.
- {
- // This variable naming must match the name used in
- // lib/matplotlib/backends/_backend_tk.py:FigureManagerTk.
- std::string var_name("window_dpi");
- var_name += std::to_string((unsigned long long)hwnd);
-
- // X is high word, Y is low word, but they are always equal.
- std::string dpi = std::to_string(LOWORD(wParam));
-
- Tcl_Interp* interp = (Tcl_Interp*)dwRefData;
- TCL_SETVAR(interp, var_name.c_str(), dpi.c_str(), 0);
- }
- return 0;
- case WM_NCDESTROY:
- RemoveWindowSubclass(hwnd, DpiSubclassProc, uIdSubclass);
- break;
- }
-
- return DefSubclassProc(hwnd, uMsg, wParam, lParam);
-}
-#endif
-
-static PyObject*
-mpl_tk_enable_dpi_awareness(PyObject* self, PyObject*const* args,
- Py_ssize_t nargs)
-{
- if (nargs != 2) {
- return PyErr_Format(PyExc_TypeError,
- "enable_dpi_awareness() takes 2 positional "
- "arguments but %zd were given",
- nargs);
- }
-
-#ifdef WIN32_DLL
- HWND frame_handle = NULL;
- Tcl_Interp *interp = NULL;
-
- if (!convert_voidptr(args[0], &frame_handle)) {
- return NULL;
- }
- if (!convert_voidptr(args[1], &interp)) {
- return NULL;
- }
-
-#ifdef _DPI_AWARENESS_CONTEXTS_
- HMODULE user32 = LoadLibrary("user32.dll");
-
- typedef DPI_AWARENESS_CONTEXT (WINAPI *GetWindowDpiAwarenessContext_t)(HWND);
- GetWindowDpiAwarenessContext_t GetWindowDpiAwarenessContextPtr =
- (GetWindowDpiAwarenessContext_t)GetProcAddress(
- user32, "GetWindowDpiAwarenessContext");
- if (GetWindowDpiAwarenessContextPtr == NULL) {
- FreeLibrary(user32);
- Py_RETURN_FALSE;
- }
-
- typedef BOOL (WINAPI *AreDpiAwarenessContextsEqual_t)(DPI_AWARENESS_CONTEXT,
- DPI_AWARENESS_CONTEXT);
- AreDpiAwarenessContextsEqual_t AreDpiAwarenessContextsEqualPtr =
- (AreDpiAwarenessContextsEqual_t)GetProcAddress(
- user32, "AreDpiAwarenessContextsEqual");
- if (AreDpiAwarenessContextsEqualPtr == NULL) {
- FreeLibrary(user32);
- Py_RETURN_FALSE;
- }
-
- DPI_AWARENESS_CONTEXT ctx = GetWindowDpiAwarenessContextPtr(frame_handle);
- bool per_monitor = (
- AreDpiAwarenessContextsEqualPtr(
- ctx, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) ||
- AreDpiAwarenessContextsEqualPtr(
- ctx, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE));
-
- if (per_monitor) {
- // Per monitor aware means we need to handle WM_DPICHANGED by wrapping
- // the Window Procedure, and the Python side needs to trace the Tk
- // window_dpi variable stored on interp.
- SetWindowSubclass(frame_handle, DpiSubclassProc, 0, (DWORD_PTR)interp);
- }
- FreeLibrary(user32);
- return PyBool_FromLong(per_monitor);
-#endif
-#endif
-
- Py_RETURN_NONE;
-}
-
-static PyMethodDef functions[] = {
- { "blit", (PyCFunction)mpl_tk_blit, METH_VARARGS },
- { "enable_dpi_awareness", (PyCFunction)mpl_tk_enable_dpi_awareness,
- METH_FASTCALL },
- { NULL, NULL } /* sentinel */
-};
-
-// Functions to fill global Tcl/Tk function pointers by dynamic loading.
-
-template <class T>
-bool load_tcl_tk(T lib)
-{
- // Try to fill Tcl/Tk global vars with function pointers. Return whether
- // all of them have been filled.
- if (auto ptr = dlsym(lib, "Tcl_SetVar")) {
- TCL_SETVAR = (Tcl_SetVar_t)ptr;
- }
- if (auto ptr = dlsym(lib, "Tk_FindPhoto")) {
- TK_FIND_PHOTO = (Tk_FindPhoto_t)ptr;
- }
- if (auto ptr = dlsym(lib, "Tk_PhotoPutBlock")) {
- TK_PHOTO_PUT_BLOCK = (Tk_PhotoPutBlock_t)ptr;
- }
- return TCL_SETVAR && TK_FIND_PHOTO && TK_PHOTO_PUT_BLOCK;
-}
-
-#ifdef WIN32_DLL
-
-/* On Windows, we can't load the tkinter module to get the Tcl/Tk symbols,
- * because Windows does not load symbols into the library name-space of
- * importing modules. So, knowing that tkinter has already been imported by
- * Python, we scan all modules in the running process for the Tcl/Tk function
- * names.
- */
-
-void load_tkinter_funcs(void)
-{
- HANDLE process = GetCurrentProcess(); // Pseudo-handle, doesn't need closing.
- HMODULE* modules = NULL;
- DWORD size;
- if (!EnumProcessModules(process, NULL, 0, &size)) {
- PyErr_SetFromWindowsErr(0);
- goto exit;
- }
- if (!(modules = static_cast<HMODULE*>(malloc(size)))) {
- PyErr_NoMemory();
- goto exit;
- }
- if (!EnumProcessModules(process, modules, size, &size)) {
- PyErr_SetFromWindowsErr(0);
- goto exit;
- }
- for (unsigned i = 0; i < size / sizeof(HMODULE); ++i) {
- if (load_tcl_tk(modules[i])) {
- return;
- }
- }
-exit:
- free(modules);
-}
-
-#else // not Windows
-
-/*
- * On Unix, we can get the Tk symbols from the tkinter module, because tkinter
- * uses these symbols, and the symbols are therefore visible in the tkinter
- * dynamic library (module).
- */
-
-void load_tkinter_funcs(void)
-{
- // Load tkinter global funcs from tkinter compiled module.
- void *main_program = NULL, *tkinter_lib = NULL;
- PyObject *module = NULL, *py_path = NULL, *py_path_b = NULL;
- char *path;
-
- // Try loading from the main program namespace first.
- main_program = dlopen(NULL, RTLD_LAZY);
- if (load_tcl_tk(main_program)) {
- goto exit;
- }
- // Clear exception triggered when we didn't find symbols above.
- PyErr_Clear();
-
- // Handle PyPy first, as that import will correctly fail on CPython.
- module = PyImport_ImportModule("_tkinter.tklib_cffi"); // PyPy
- if (!module) {
- PyErr_Clear();
- module = PyImport_ImportModule("_tkinter"); // CPython
- }
- if (!(module &&
- (py_path = PyObject_GetAttrString(module, "__file__")) &&
- (py_path_b = PyUnicode_EncodeFSDefault(py_path)) &&
- (path = PyBytes_AsString(py_path_b)))) {
- goto exit;
- }
- tkinter_lib = dlopen(path, RTLD_LAZY);
- if (!tkinter_lib) {
- PyErr_SetString(PyExc_RuntimeError, dlerror());
- goto exit;
- }
- if (load_tcl_tk(tkinter_lib)) {
- goto exit;
- }
-
-exit:
- // We don't need to keep a reference open as the main program & tkinter
- // have been imported. Try to close each library separately (otherwise the
- // second dlclose could clear a dlerror from the first dlclose).
- bool raised_dlerror = false;
- if (main_program && dlclose(main_program) && !raised_dlerror) {
- PyErr_SetString(PyExc_RuntimeError, dlerror());
- raised_dlerror = true;
- }
- if (tkinter_lib && dlclose(tkinter_lib) && !raised_dlerror) {
- PyErr_SetString(PyExc_RuntimeError, dlerror());
- raised_dlerror = true;
- }
- Py_XDECREF(module);
- Py_XDECREF(py_path);
- Py_XDECREF(py_path_b);
-}
-#endif // end not Windows
-
-static PyModuleDef _tkagg_module = {
- PyModuleDef_HEAD_INIT, "_tkagg", NULL, -1, functions
-};
-
-PyMODINIT_FUNC PyInit__tkagg(void)
-{
- load_tkinter_funcs();
- PyObject *type, *value, *traceback;
- PyErr_Fetch(&type, &value, &traceback);
- // Always raise ImportError (normalizing a previously set exception if
- // needed) to interact properly with backend auto-fallback.
- if (value) {
- PyErr_NormalizeException(&type, &value, &traceback);
- PyErr_SetObject(PyExc_ImportError, value);
- return NULL;
- } else if (!TCL_SETVAR) {
- PyErr_SetString(PyExc_ImportError, "Failed to load Tcl_SetVar");
- return NULL;
- } else if (!TK_FIND_PHOTO) {
- PyErr_SetString(PyExc_ImportError, "Failed to load Tk_FindPhoto");
- return NULL;
- } else if (!TK_PHOTO_PUT_BLOCK) {
- PyErr_SetString(PyExc_ImportError, "Failed to load Tk_PhotoPutBlock");
- return NULL;
- }
- return PyModule_Create(&_tkagg_module);
-}
diff --git a/contrib/python/matplotlib/py3/src/_tkmini.h b/contrib/python/matplotlib/py3/src/_tkmini.h
deleted file mode 100644
index 85f245815e..0000000000
--- a/contrib/python/matplotlib/py3/src/_tkmini.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/* Small excerpts from the Tcl / Tk 8.6 headers
- *
- * License terms copied from:
- * http://www.tcl.tk/software/tcltk/license.html
- * as of 20 May 2016.
- *
- * Copyright (c) 1987-1994 The Regents of the University of California.
- * Copyright (c) 1993-1996 Lucent Technologies.
- * Copyright (c) 1994-1998 Sun Microsystems, Inc.
- * Copyright (c) 1998-2000 by Scriptics Corporation.
- * Copyright (c) 2002 by Kevin B. Kenny. All rights reserved.
- *
- * This software is copyrighted by the Regents of the University
- * of California, Sun Microsystems, Inc., Scriptics Corporation,
- * and other parties. The following terms apply to all files
- * associated with the software unless explicitly disclaimed in
- * individual files.
- *
- * The authors hereby grant permission to use, copy, modify,
- * distribute, and license this software and its documentation
- * for any purpose, provided that existing copyright notices are
- * retained in all copies and that this notice is included
- * verbatim in any distributions. No written agreement, license,
- * or royalty fee is required for any of the authorized uses.
- * Modifications to this software may be copyrighted by their
- * authors and need not follow the licensing terms described
- * here, provided that the new terms are clearly indicated on
- * the first page of each file where they apply.
- *
- * IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO
- * ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR
- * CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS
- * SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF, EVEN
- * IF THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- * PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON
- * AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO
- * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
- * ENHANCEMENTS, OR MODIFICATIONS.
- *
- * GOVERNMENT USE: If you are acquiring this software on behalf
- * of the U.S. government, the Government shall have only
- * "Restricted Rights" in the software and related documentation
- * as defined in the Federal Acquisition Regulations (FARs) in
- * Clause 52.227.19 (c) (2). If you are acquiring the software
- * on behalf of the Department of Defense, the software shall be
- * classified as "Commercial Computer Software" and the
- * Government shall have only "Restricted Rights" as defined in
- * Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the
- * foregoing, the authors grant the U.S. Government and others
- * acting in its behalf permission to use and distribute the
- * software in accordance with the terms specified in this
- * license
- */
-
-/*
- * Unless otherwise noted, these definitions are stable from Tcl / Tk 8.5
- * through Tck / Tk master as of 21 May 2016
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Users of versions of Tcl >= 8.6 encouraged to treat Tcl_Interp as an opaque
- * pointer. The following definition results when TCL_NO_DEPRECATED defined.
- */
-typedef struct Tcl_Interp Tcl_Interp;
-
-/* Tk header excerpts */
-
-typedef void *Tk_PhotoHandle;
-
-typedef struct Tk_PhotoImageBlock
-{
- unsigned char *pixelPtr;
- int width;
- int height;
- int pitch;
- int pixelSize;
- int offset[4];
-} Tk_PhotoImageBlock;
-
-#define TK_PHOTO_COMPOSITE_OVERLAY 0 // apply transparency rules pixel-wise
-#define TK_PHOTO_COMPOSITE_SET 1 // set image buffer directly
-#define TCL_OK 0
-#define TCL_ERROR 1
-
-/* Typedefs derived from function signatures in Tk header */
-/* Tk_FindPhoto typedef */
-typedef Tk_PhotoHandle (*Tk_FindPhoto_t) (Tcl_Interp *interp, const char
- *imageName);
-/* Tk_PhotoPutBLock typedef */
-typedef int (*Tk_PhotoPutBlock_t) (Tcl_Interp *interp, Tk_PhotoHandle handle,
- Tk_PhotoImageBlock *blockPtr, int x, int y,
- int width, int height, int compRule);
-
-/* Typedefs derived from function signatures in Tcl header */
-/* Tcl_SetVar typedef */
-typedef const char *(*Tcl_SetVar_t)(Tcl_Interp *interp, const char *varName,
- const char *newValue, int flags);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/contrib/python/matplotlib/py3/src/_ttconv.cpp b/contrib/python/matplotlib/py3/src/_ttconv.cpp
deleted file mode 100644
index 72fdfba696..0000000000
--- a/contrib/python/matplotlib/py3/src/_ttconv.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/* -*- mode: c++; c-basic-offset: 4 -*- */
-
-/*
- _ttconv.c
-
- Python wrapper for TrueType conversion library in ../ttconv.
- */
-#include "mplutils.h"
-
-#include <pybind11/pybind11.h>
-#include "ttconv/pprdrv.h"
-#include <vector>
-
-namespace py = pybind11;
-
-/**
- * An implementation of TTStreamWriter that writes to a Python
- * file-like object.
- */
-class PythonFileWriter : public TTStreamWriter
-{
- py::function _write_method;
-
- public:
- PythonFileWriter(py::object& file_object)
- : _write_method(file_object.attr("write")) {}
-
- virtual void write(const char *a)
- {
- PyObject* decoded = PyUnicode_DecodeLatin1(a, strlen(a), "");
- if (decoded == NULL) {
- throw py::error_already_set();
- }
- _write_method(py::handle(decoded));
- Py_DECREF(decoded);
- }
-};
-
-static void convert_ttf_to_ps(
- const char *filename,
- py::object &output,
- int fonttype,
- py::iterable* glyph_ids)
-{
- PythonFileWriter output_(output);
-
- std::vector<int> glyph_ids_;
- if (glyph_ids) {
- for (py::handle glyph_id: *glyph_ids) {
- glyph_ids_.push_back(glyph_id.cast<int>());
- }
- }
-
- if (fonttype != 3 && fonttype != 42) {
- throw py::value_error(
- "fonttype must be either 3 (raw Postscript) or 42 (embedded Truetype)");
- }
-
- try
- {
- insert_ttfont(filename, output_, static_cast<font_type_enum>(fonttype), glyph_ids_);
- }
- catch (TTException &e)
- {
- throw std::runtime_error(e.getMessage());
- }
- catch (...)
- {
- throw std::runtime_error("Unknown C++ exception");
- }
-}
-
-PYBIND11_MODULE(_ttconv, m) {
- m.doc() = "Module to handle converting and subsetting TrueType "
- "fonts to Postscript Type 3, Postscript Type 42 and "
- "Pdf Type 3 fonts.";
- m.def("convert_ttf_to_ps", &convert_ttf_to_ps,
- py::arg("filename"),
- py::arg("output"),
- py::arg("fonttype"),
- py::arg("glyph_ids") = py::none(),
- "Converts the Truetype font into a Type 3 or Type 42 Postscript font, "
- "optionally subsetting the font to only the desired set of characters.\n"
- "\n"
- "filename is the path to a TTF font file.\n"
- "output is a Python file-like object with a write method that the Postscript "
- "font data will be written to.\n"
- "fonttype may be either 3 or 42. Type 3 is a \"raw Postscript\" font. "
- "Type 42 is an embedded Truetype font. Glyph subsetting is not supported "
- "for Type 42 fonts within this module (needs to be done externally).\n"
- "glyph_ids (optional) is a list of glyph ids (integers) to keep when "
- "subsetting to a Type 3 font. If glyph_ids is not provided or is None, "
- "then all glyphs will be included. If any of the glyphs specified are "
- "composite glyphs, then the component glyphs will also be included."
- );
-}
diff --git a/contrib/python/matplotlib/py3/src/agg_workaround.h b/contrib/python/matplotlib/py3/src/agg_workaround.h
deleted file mode 100644
index 4762195192..0000000000
--- a/contrib/python/matplotlib/py3/src/agg_workaround.h
+++ /dev/null
@@ -1,85 +0,0 @@
-#ifndef MPL_AGG_WORKAROUND_H
-#define MPL_AGG_WORKAROUND_H
-
-#include "agg_pixfmt_rgba.h"
-
-/**********************************************************************
- WORKAROUND: This class is to workaround a bug in Agg SVN where the
- blending of RGBA32 pixels does not preserve enough precision
-*/
-
-template<class ColorT, class Order>
-struct fixed_blender_rgba_pre : agg::conv_rgba_pre<ColorT, Order>
-{
- typedef ColorT color_type;
- typedef Order order_type;
- typedef typename color_type::value_type value_type;
- typedef typename color_type::calc_type calc_type;
- typedef typename color_type::long_type long_type;
- enum base_scale_e
- {
- base_shift = color_type::base_shift,
- base_mask = color_type::base_mask
- };
-
- //--------------------------------------------------------------------
- static AGG_INLINE void blend_pix(value_type* p,
- value_type cr, value_type cg, value_type cb,
- value_type alpha, agg::cover_type cover)
- {
- blend_pix(p,
- color_type::mult_cover(cr, cover),
- color_type::mult_cover(cg, cover),
- color_type::mult_cover(cb, cover),
- color_type::mult_cover(alpha, cover));
- }
-
- //--------------------------------------------------------------------
- static AGG_INLINE void blend_pix(value_type* p,
- value_type cr, value_type cg, value_type cb,
- value_type alpha)
- {
- alpha = base_mask - alpha;
- p[Order::R] = (value_type)(((p[Order::R] * alpha) >> base_shift) + cr);
- p[Order::G] = (value_type)(((p[Order::G] * alpha) >> base_shift) + cg);
- p[Order::B] = (value_type)(((p[Order::B] * alpha) >> base_shift) + cb);
- p[Order::A] = (value_type)(base_mask - ((alpha * (base_mask - p[Order::A])) >> base_shift));
- }
-};
-
-
-template<class ColorT, class Order>
-struct fixed_blender_rgba_plain : agg::conv_rgba_plain<ColorT, Order>
-{
- typedef ColorT color_type;
- typedef Order order_type;
- typedef typename color_type::value_type value_type;
- typedef typename color_type::calc_type calc_type;
- typedef typename color_type::long_type long_type;
- enum base_scale_e { base_shift = color_type::base_shift };
-
- //--------------------------------------------------------------------
- static AGG_INLINE void blend_pix(value_type* p,
- value_type cr, value_type cg, value_type cb, value_type alpha, agg::cover_type cover)
- {
- blend_pix(p, cr, cg, cb, color_type::mult_cover(alpha, cover));
- }
-
- //--------------------------------------------------------------------
- static AGG_INLINE void blend_pix(value_type* p,
- value_type cr, value_type cg, value_type cb, value_type alpha)
- {
- if(alpha == 0) return;
- calc_type a = p[Order::A];
- calc_type r = p[Order::R] * a;
- calc_type g = p[Order::G] * a;
- calc_type b = p[Order::B] * a;
- a = ((alpha + a) << base_shift) - alpha * a;
- p[Order::A] = (value_type)(a >> base_shift);
- p[Order::R] = (value_type)((((cr << base_shift) - r) * alpha + (r << base_shift)) / a);
- p[Order::G] = (value_type)((((cg << base_shift) - g) * alpha + (g << base_shift)) / a);
- p[Order::B] = (value_type)((((cb << base_shift) - b) * alpha + (b << base_shift)) / a);
- }
-};
-
-#endif
diff --git a/contrib/python/matplotlib/py3/src/array.h b/contrib/python/matplotlib/py3/src/array.h
deleted file mode 100644
index 47d8299554..0000000000
--- a/contrib/python/matplotlib/py3/src/array.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/* -*- mode: c++; c-basic-offset: 4 -*- */
-
-/* Utilities to create scalars and empty arrays that behave like the
- Numpy array wrappers in numpy_cpp.h */
-
-#ifndef MPL_SCALAR_H
-#define MPL_SCALAR_H
-
-namespace array
-{
-
-template <typename T, int ND>
-class scalar
-{
- public:
- T m_value;
-
- scalar(const T value) : m_value(value)
- {
- }
-
- T &operator()(int i, int j = 0, int k = 0)
- {
- return m_value;
- }
-
- const T &operator()(int i, int j = 0, int k = 0) const
- {
- return m_value;
- }
-
- int dim(size_t i)
- {
- return 1;
- }
-
- size_t size()
- {
- return 1;
- }
-};
-
-template <typename T>
-class empty
-{
- public:
- typedef empty<T> sub_t;
-
- empty()
- {
- }
-
- T &operator()(int i, int j = 0, int k = 0)
- {
- throw std::runtime_error("Accessed empty array");
- }
-
- const T &operator()(int i, int j = 0, int k = 0) const
- {
- throw std::runtime_error("Accessed empty array");
- }
-
- sub_t operator[](int i) const
- {
- return empty<T>();
- }
-
- int dim(size_t i) const
- {
- return 0;
- }
-
- size_t size() const
- {
- return 0;
- }
-};
-}
-
-#endif
diff --git a/contrib/python/matplotlib/py3/src/checkdep_freetype2.c b/contrib/python/matplotlib/py3/src/checkdep_freetype2.c
deleted file mode 100644
index 8d9d8ca24a..0000000000
--- a/contrib/python/matplotlib/py3/src/checkdep_freetype2.c
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifdef __has_include
- #if !__has_include(<ft2build.h>)
- #error "FreeType version 2.3 or higher is required. \
-You may unset the system_freetype entry in mplsetup.cfg to let Matplotlib download it."
- #endif
-#endif
-
-#include <ft2build.h>
-#include FT_FREETYPE_H
-
-#define XSTR(x) STR(x)
-#define STR(x) #x
-
-#pragma message("Compiling with FreeType version " \
- XSTR(FREETYPE_MAJOR) "." XSTR(FREETYPE_MINOR) "." XSTR(FREETYPE_PATCH) ".")
-#if FREETYPE_MAJOR << 16 + FREETYPE_MINOR << 8 + FREETYPE_PATCH < 0x020300
- #error "FreeType version 2.3 or higher is required. \
-You may unset the system_freetype entry in mplsetup.cfg to let Matplotlib download it."
-#endif
diff --git a/contrib/python/matplotlib/py3/src/ft2font.cpp b/contrib/python/matplotlib/py3/src/ft2font.cpp
deleted file mode 100644
index 9750413741..0000000000
--- a/contrib/python/matplotlib/py3/src/ft2font.cpp
+++ /dev/null
@@ -1,840 +0,0 @@
-/* -*- mode: c++; c-basic-offset: 4 -*- */
-
-#define NO_IMPORT_ARRAY
-
-#include <algorithm>
-#include <iterator>
-#include <sstream>
-#include <stdexcept>
-#include <string>
-
-#include "ft2font.h"
-#include "mplutils.h"
-#include "numpy_cpp.h"
-#include "py_exceptions.h"
-
-#ifndef M_PI
-#define M_PI 3.14159265358979323846264338328
-#endif
-
-/**
- To improve the hinting of the fonts, this code uses a hack
- presented here:
-
- http://agg.sourceforge.net/antigrain.com/research/font_rasterization/index.html
-
- The idea is to limit the effect of hinting in the x-direction, while
- preserving hinting in the y-direction. Since freetype does not
- support this directly, the dpi in the x-direction is set higher than
- in the y-direction, which affects the hinting grid. Then, a global
- transform is placed on the font to shrink it back to the desired
- size. While it is a bit surprising that the dpi setting affects
- hinting, whereas the global transform does not, this is documented
- behavior of FreeType, and therefore hopefully unlikely to change.
- The FreeType 2 tutorial says:
-
- NOTE: The transformation is applied to every glyph that is
- loaded through FT_Load_Glyph and is completely independent of
- any hinting process. This means that you won't get the same
- results if you load a glyph at the size of 24 pixels, or a glyph
- at the size at 12 pixels scaled by 2 through a transform,
- because the hints will have been computed differently (except
- you have disabled hints).
- */
-
-FT_Library _ft2Library;
-
-// FreeType error codes; loaded as per fterror.h.
-static char const* ft_error_string(FT_Error error) {
-#undef __FTERRORS_H__
-#define FT_ERROR_START_LIST switch (error) {
-#define FT_ERRORDEF( e, v, s ) case v: return s;
-#define FT_ERROR_END_LIST default: return NULL; }
-#include FT_ERRORS_H
-}
-
-void throw_ft_error(std::string message, FT_Error error) {
- char const* s = ft_error_string(error);
- std::ostringstream os("");
- if (s) {
- os << message << " (" << s << "; error code 0x" << std::hex << error << ")";
- } else { // Should not occur, but don't add another error from failed lookup.
- os << message << " (error code 0x" << std::hex << error << ")";
- }
- throw std::runtime_error(os.str());
-}
-
-FT2Image::FT2Image() : m_dirty(true), m_buffer(NULL), m_width(0), m_height(0)
-{
-}
-
-FT2Image::FT2Image(unsigned long width, unsigned long height)
- : m_dirty(true), m_buffer(NULL), m_width(0), m_height(0)
-{
- resize(width, height);
-}
-
-FT2Image::~FT2Image()
-{
- delete[] m_buffer;
-}
-
-void FT2Image::resize(long width, long height)
-{
- if (width <= 0) {
- width = 1;
- }
- if (height <= 0) {
- height = 1;
- }
- size_t numBytes = width * height;
-
- if ((unsigned long)width != m_width || (unsigned long)height != m_height) {
- if (numBytes > m_width * m_height) {
- delete[] m_buffer;
- m_buffer = NULL;
- m_buffer = new unsigned char[numBytes];
- }
-
- m_width = (unsigned long)width;
- m_height = (unsigned long)height;
- }
-
- if (numBytes && m_buffer) {
- memset(m_buffer, 0, numBytes);
- }
-
- m_dirty = true;
-}
-
-void FT2Image::draw_bitmap(FT_Bitmap *bitmap, FT_Int x, FT_Int y)
-{
- FT_Int image_width = (FT_Int)m_width;
- FT_Int image_height = (FT_Int)m_height;
- FT_Int char_width = bitmap->width;
- FT_Int char_height = bitmap->rows;
-
- FT_Int x1 = std::min(std::max(x, 0), image_width);
- FT_Int y1 = std::min(std::max(y, 0), image_height);
- FT_Int x2 = std::min(std::max(x + char_width, 0), image_width);
- FT_Int y2 = std::min(std::max(y + char_height, 0), image_height);
-
- FT_Int x_start = std::max(0, -x);
- FT_Int y_offset = y1 - std::max(0, -y);
-
- if (bitmap->pixel_mode == FT_PIXEL_MODE_GRAY) {
- for (FT_Int i = y1; i < y2; ++i) {
- unsigned char *dst = m_buffer + (i * image_width + x1);
- unsigned char *src = bitmap->buffer + (((i - y_offset) * bitmap->pitch) + x_start);
- for (FT_Int j = x1; j < x2; ++j, ++dst, ++src)
- *dst |= *src;
- }
- } else if (bitmap->pixel_mode == FT_PIXEL_MODE_MONO) {
- for (FT_Int i = y1; i < y2; ++i) {
- unsigned char *dst = m_buffer + (i * image_width + x1);
- unsigned char *src = bitmap->buffer + ((i - y_offset) * bitmap->pitch);
- for (FT_Int j = x1; j < x2; ++j, ++dst) {
- int x = (j - x1 + x_start);
- int val = *(src + (x >> 3)) & (1 << (7 - (x & 0x7)));
- *dst = val ? 255 : *dst;
- }
- }
- } else {
- throw std::runtime_error("Unknown pixel mode");
- }
-
- m_dirty = true;
-}
-
-void FT2Image::draw_rect(unsigned long x0, unsigned long y0, unsigned long x1, unsigned long y1)
-{
- if (x0 > m_width || x1 > m_width || y0 > m_height || y1 > m_height) {
- throw std::runtime_error("Rect coords outside image bounds");
- }
-
- size_t top = y0 * m_width;
- size_t bottom = y1 * m_width;
- for (size_t i = x0; i < x1 + 1; ++i) {
- m_buffer[i + top] = 255;
- m_buffer[i + bottom] = 255;
- }
-
- for (size_t j = y0 + 1; j < y1; ++j) {
- m_buffer[x0 + j * m_width] = 255;
- m_buffer[x1 + j * m_width] = 255;
- }
-
- m_dirty = true;
-}
-
-void
-FT2Image::draw_rect_filled(unsigned long x0, unsigned long y0, unsigned long x1, unsigned long y1)
-{
- x0 = std::min(x0, m_width);
- y0 = std::min(y0, m_height);
- x1 = std::min(x1 + 1, m_width);
- y1 = std::min(y1 + 1, m_height);
-
- for (size_t j = y0; j < y1; j++) {
- for (size_t i = x0; i < x1; i++) {
- m_buffer[i + j * m_width] = 255;
- }
- }
-
- m_dirty = true;
-}
-
-static void ft_glyph_warn(FT_ULong charcode)
-{
- PyObject *text_helpers = NULL, *tmp = NULL;
- if (!(text_helpers = PyImport_ImportModule("matplotlib._text_helpers")) ||
- !(tmp = PyObject_CallMethod(text_helpers, "warn_on_missing_glyph", "k", charcode))) {
- goto exit;
- }
-exit:
- Py_XDECREF(text_helpers);
- Py_XDECREF(tmp);
- if (PyErr_Occurred()) {
- throw py::exception();
- }
-}
-
-static FT_UInt
-ft_get_char_index_or_warn(FT_Face face, FT_ULong charcode, bool warn = true)
-{
- FT_UInt glyph_index = FT_Get_Char_Index(face, charcode);
- if (glyph_index) {
- return glyph_index;
- }
- if (warn) {
- ft_glyph_warn(charcode);
- }
- return 0;
-}
-
-// ft_outline_decomposer should be passed to FT_Outline_Decompose. On the
-// first pass, vertices and codes are set to NULL, and index is simply
-// incremented for each vertex that should be inserted, so that it is set, at
-// the end, to the total number of vertices. On a second pass, vertices and
-// codes should point to correctly sized arrays, and index set again to zero,
-// to get fill vertices and codes with the outline decomposition.
-struct ft_outline_decomposer
-{
- int index;
- double* vertices;
- unsigned char* codes;
-};
-
-static int
-ft_outline_move_to(FT_Vector const* to, void* user)
-{
- ft_outline_decomposer* d = reinterpret_cast<ft_outline_decomposer*>(user);
- if (d->codes) {
- if (d->index) {
- // Appending CLOSEPOLY is important to make patheffects work.
- *(d->vertices++) = 0;
- *(d->vertices++) = 0;
- *(d->codes++) = CLOSEPOLY;
- }
- *(d->vertices++) = to->x * (1. / 64.);
- *(d->vertices++) = to->y * (1. / 64.);
- *(d->codes++) = MOVETO;
- }
- d->index += d->index ? 2 : 1;
- return 0;
-}
-
-static int
-ft_outline_line_to(FT_Vector const* to, void* user)
-{
- ft_outline_decomposer* d = reinterpret_cast<ft_outline_decomposer*>(user);
- if (d->codes) {
- *(d->vertices++) = to->x * (1. / 64.);
- *(d->vertices++) = to->y * (1. / 64.);
- *(d->codes++) = LINETO;
- }
- d->index++;
- return 0;
-}
-
-static int
-ft_outline_conic_to(FT_Vector const* control, FT_Vector const* to, void* user)
-{
- ft_outline_decomposer* d = reinterpret_cast<ft_outline_decomposer*>(user);
- if (d->codes) {
- *(d->vertices++) = control->x * (1. / 64.);
- *(d->vertices++) = control->y * (1. / 64.);
- *(d->vertices++) = to->x * (1. / 64.);
- *(d->vertices++) = to->y * (1. / 64.);
- *(d->codes++) = CURVE3;
- *(d->codes++) = CURVE3;
- }
- d->index += 2;
- return 0;
-}
-
-static int
-ft_outline_cubic_to(
- FT_Vector const* c1, FT_Vector const* c2, FT_Vector const* to, void* user)
-{
- ft_outline_decomposer* d = reinterpret_cast<ft_outline_decomposer*>(user);
- if (d->codes) {
- *(d->vertices++) = c1->x * (1. / 64.);
- *(d->vertices++) = c1->y * (1. / 64.);
- *(d->vertices++) = c2->x * (1. / 64.);
- *(d->vertices++) = c2->y * (1. / 64.);
- *(d->vertices++) = to->x * (1. / 64.);
- *(d->vertices++) = to->y * (1. / 64.);
- *(d->codes++) = CURVE4;
- *(d->codes++) = CURVE4;
- *(d->codes++) = CURVE4;
- }
- d->index += 3;
- return 0;
-}
-
-static FT_Outline_Funcs ft_outline_funcs = {
- ft_outline_move_to,
- ft_outline_line_to,
- ft_outline_conic_to,
- ft_outline_cubic_to};
-
-PyObject*
-FT2Font::get_path()
-{
- if (!face->glyph) {
- PyErr_SetString(PyExc_RuntimeError, "No glyph loaded");
- return NULL;
- }
- ft_outline_decomposer decomposer = {};
- if (FT_Error error =
- FT_Outline_Decompose(
- &face->glyph->outline, &ft_outline_funcs, &decomposer)) {
- PyErr_Format(PyExc_RuntimeError,
- "FT_Outline_Decompose failed with error 0x%x", error);
- return NULL;
- }
- if (!decomposer.index) { // Don't append CLOSEPOLY to null glyphs.
- npy_intp vertices_dims[2] = { 0, 2 };
- numpy::array_view<double, 2> vertices(vertices_dims);
- npy_intp codes_dims[1] = { 0 };
- numpy::array_view<unsigned char, 1> codes(codes_dims);
- return Py_BuildValue("NN", vertices.pyobj(), codes.pyobj());
- }
- npy_intp vertices_dims[2] = { decomposer.index + 1, 2 };
- numpy::array_view<double, 2> vertices(vertices_dims);
- npy_intp codes_dims[1] = { decomposer.index + 1 };
- numpy::array_view<unsigned char, 1> codes(codes_dims);
- decomposer.index = 0;
- decomposer.vertices = vertices.data();
- decomposer.codes = codes.data();
- if (FT_Error error =
- FT_Outline_Decompose(
- &face->glyph->outline, &ft_outline_funcs, &decomposer)) {
- PyErr_Format(PyExc_RuntimeError,
- "FT_Outline_Decompose failed with error 0x%x", error);
- return NULL;
- }
- *(decomposer.vertices++) = 0;
- *(decomposer.vertices++) = 0;
- *(decomposer.codes++) = CLOSEPOLY;
- return Py_BuildValue("NN", vertices.pyobj(), codes.pyobj());
-}
-
-FT2Font::FT2Font(FT_Open_Args &open_args,
- long hinting_factor_,
- std::vector<FT2Font *> &fallback_list)
- : image(), face(NULL)
-{
- clear();
-
- FT_Error error = FT_Open_Face(_ft2Library, &open_args, 0, &face);
- if (error) {
- throw_ft_error("Can not load face", error);
- }
-
- // set default kerning factor to 0, i.e., no kerning manipulation
- kerning_factor = 0;
-
- // set a default fontsize 12 pt at 72dpi
- hinting_factor = hinting_factor_;
-
- error = FT_Set_Char_Size(face, 12 * 64, 0, 72 * (unsigned int)hinting_factor, 72);
- if (error) {
- FT_Done_Face(face);
- throw_ft_error("Could not set the fontsize", error);
- }
-
- if (open_args.stream != NULL) {
- face->face_flags |= FT_FACE_FLAG_EXTERNAL_STREAM;
- }
-
- FT_Matrix transform = { 65536 / hinting_factor, 0, 0, 65536 };
- FT_Set_Transform(face, &transform, 0);
-
- // Set fallbacks
- std::copy(fallback_list.begin(), fallback_list.end(), std::back_inserter(fallbacks));
-}
-
-FT2Font::~FT2Font()
-{
- for (size_t i = 0; i < glyphs.size(); i++) {
- FT_Done_Glyph(glyphs[i]);
- }
-
- if (face) {
- FT_Done_Face(face);
- }
-}
-
-void FT2Font::clear()
-{
- pen.x = 0;
- pen.y = 0;
-
- for (size_t i = 0; i < glyphs.size(); i++) {
- FT_Done_Glyph(glyphs[i]);
- }
-
- glyphs.clear();
- glyph_to_font.clear();
- char_to_font.clear();
-
- for (size_t i = 0; i < fallbacks.size(); i++) {
- fallbacks[i]->clear();
- }
-}
-
-void FT2Font::set_size(double ptsize, double dpi)
-{
- FT_Error error = FT_Set_Char_Size(
- face, (FT_F26Dot6)(ptsize * 64), 0, (FT_UInt)(dpi * hinting_factor), (FT_UInt)dpi);
- if (error) {
- throw_ft_error("Could not set the fontsize", error);
- }
- FT_Matrix transform = { 65536 / hinting_factor, 0, 0, 65536 };
- FT_Set_Transform(face, &transform, 0);
-
- for (size_t i = 0; i < fallbacks.size(); i++) {
- fallbacks[i]->set_size(ptsize, dpi);
- }
-}
-
-void FT2Font::set_charmap(int i)
-{
- if (i >= face->num_charmaps) {
- throw std::runtime_error("i exceeds the available number of char maps");
- }
- FT_CharMap charmap = face->charmaps[i];
- if (FT_Error error = FT_Set_Charmap(face, charmap)) {
- throw_ft_error("Could not set the charmap", error);
- }
-}
-
-void FT2Font::select_charmap(unsigned long i)
-{
- if (FT_Error error = FT_Select_Charmap(face, (FT_Encoding)i)) {
- throw_ft_error("Could not set the charmap", error);
- }
-}
-
-int FT2Font::get_kerning(FT_UInt left, FT_UInt right, FT_UInt mode, bool fallback = false)
-{
- if (fallback && glyph_to_font.find(left) != glyph_to_font.end() &&
- glyph_to_font.find(right) != glyph_to_font.end()) {
- FT2Font *left_ft_object = glyph_to_font[left];
- FT2Font *right_ft_object = glyph_to_font[right];
- if (left_ft_object != right_ft_object) {
- // we do not know how to do kerning between different fonts
- return 0;
- }
- // if left_ft_object is the same as right_ft_object,
- // do the exact same thing which set_text does.
- return right_ft_object->get_kerning(left, right, mode, false);
- }
- else
- {
- FT_Vector delta;
- return get_kerning(left, right, mode, delta);
- }
-}
-
-int FT2Font::get_kerning(FT_UInt left, FT_UInt right, FT_UInt mode, FT_Vector &delta)
-{
- if (!FT_HAS_KERNING(face)) {
- return 0;
- }
-
- if (!FT_Get_Kerning(face, left, right, mode, &delta)) {
- return (int)(delta.x) / (hinting_factor << kerning_factor);
- } else {
- return 0;
- }
-}
-
-void FT2Font::set_kerning_factor(int factor)
-{
- kerning_factor = factor;
- for (size_t i = 0; i < fallbacks.size(); i++) {
- fallbacks[i]->set_kerning_factor(factor);
- }
-}
-
-void FT2Font::set_text(
- size_t N, uint32_t *codepoints, double angle, FT_Int32 flags, std::vector<double> &xys)
-{
- FT_Matrix matrix; /* transformation matrix */
-
- angle = angle * (2 * M_PI / 360.0);
-
- // this computes width and height in subpixels so we have to multiply by 64
- double cosangle = cos(angle) * 0x10000L;
- double sinangle = sin(angle) * 0x10000L;
-
- matrix.xx = (FT_Fixed)cosangle;
- matrix.xy = (FT_Fixed)-sinangle;
- matrix.yx = (FT_Fixed)sinangle;
- matrix.yy = (FT_Fixed)cosangle;
-
- clear();
-
- bbox.xMin = bbox.yMin = 32000;
- bbox.xMax = bbox.yMax = -32000;
-
- FT_UInt previous = 0;
- FT2Font *previous_ft_object = NULL;
-
- for (size_t n = 0; n < N; n++) {
- FT_UInt glyph_index = 0;
- FT_BBox glyph_bbox;
- FT_Pos last_advance;
-
- FT_Error charcode_error, glyph_error;
- FT2Font *ft_object_with_glyph = this;
- bool was_found = load_char_with_fallback(ft_object_with_glyph, glyph_index, glyphs,
- char_to_font, glyph_to_font, codepoints[n], flags,
- charcode_error, glyph_error, false);
- if (!was_found) {
- ft_glyph_warn((FT_ULong)codepoints[n]);
-
- // render missing glyph tofu
- // come back to top-most font
- ft_object_with_glyph = this;
- char_to_font[codepoints[n]] = ft_object_with_glyph;
- glyph_to_font[glyph_index] = ft_object_with_glyph;
- ft_object_with_glyph->load_glyph(glyph_index, flags, ft_object_with_glyph, false);
- }
-
- // retrieve kerning distance and move pen position
- if ((ft_object_with_glyph == previous_ft_object) && // if both fonts are the same
- ft_object_with_glyph->has_kerning() && // if the font knows how to kern
- previous && glyph_index // and we really have 2 glyphs
- ) {
- FT_Vector delta;
- pen.x += ft_object_with_glyph->get_kerning(previous, glyph_index, FT_KERNING_DEFAULT, delta);
- }
-
- // extract glyph image and store it in our table
- FT_Glyph &thisGlyph = glyphs[glyphs.size() - 1];
-
- last_advance = ft_object_with_glyph->get_face()->glyph->advance.x;
- FT_Glyph_Transform(thisGlyph, 0, &pen);
- FT_Glyph_Transform(thisGlyph, &matrix, 0);
- xys.push_back(pen.x);
- xys.push_back(pen.y);
-
- FT_Glyph_Get_CBox(thisGlyph, FT_GLYPH_BBOX_SUBPIXELS, &glyph_bbox);
-
- bbox.xMin = std::min(bbox.xMin, glyph_bbox.xMin);
- bbox.xMax = std::max(bbox.xMax, glyph_bbox.xMax);
- bbox.yMin = std::min(bbox.yMin, glyph_bbox.yMin);
- bbox.yMax = std::max(bbox.yMax, glyph_bbox.yMax);
-
- pen.x += last_advance;
-
- previous = glyph_index;
- previous_ft_object = ft_object_with_glyph;
-
- }
-
- FT_Vector_Transform(&pen, &matrix);
- advance = pen.x;
-
- if (bbox.xMin > bbox.xMax) {
- bbox.xMin = bbox.yMin = bbox.xMax = bbox.yMax = 0;
- }
-}
-
-void FT2Font::load_char(long charcode, FT_Int32 flags, FT2Font *&ft_object, bool fallback = false)
-{
- // if this is parent FT2Font, cache will be filled in 2 ways:
- // 1. set_text was previously called
- // 2. set_text was not called and fallback was enabled
- if (fallback && char_to_font.find(charcode) != char_to_font.end()) {
- ft_object = char_to_font[charcode];
- // since it will be assigned to ft_object anyway
- FT2Font *throwaway = NULL;
- ft_object->load_char(charcode, flags, throwaway, false);
- } else if (fallback) {
- FT_UInt final_glyph_index;
- FT_Error charcode_error, glyph_error;
- FT2Font *ft_object_with_glyph = this;
- bool was_found = load_char_with_fallback(ft_object_with_glyph, final_glyph_index, glyphs, char_to_font,
- glyph_to_font, charcode, flags, charcode_error, glyph_error, true);
- if (!was_found) {
- ft_glyph_warn(charcode);
- if (charcode_error) {
- throw_ft_error("Could not load charcode", charcode_error);
- }
- else if (glyph_error) {
- throw_ft_error("Could not load charcode", glyph_error);
- }
- }
- ft_object = ft_object_with_glyph;
- } else {
- ft_object = this;
- FT_UInt glyph_index = ft_get_char_index_or_warn(face, (FT_ULong)charcode);
-
- if (FT_Error error = FT_Load_Glyph(face, glyph_index, flags)) {
- throw_ft_error("Could not load charcode", error);
- }
- FT_Glyph thisGlyph;
- if (FT_Error error = FT_Get_Glyph(face->glyph, &thisGlyph)) {
- throw_ft_error("Could not get glyph", error);
- }
- glyphs.push_back(thisGlyph);
- }
-}
-
-
-bool FT2Font::get_char_fallback_index(FT_ULong charcode, int& index) const
-{
- FT_UInt glyph_index = FT_Get_Char_Index(face, charcode);
- if (glyph_index) {
- // -1 means the host has the char and we do not need to fallback
- index = -1;
- return true;
- } else {
- int inner_index = 0;
- bool was_found;
-
- for (size_t i = 0; i < fallbacks.size(); ++i) {
- // TODO handle recursion somehow!
- was_found = fallbacks[i]->get_char_fallback_index(charcode, inner_index);
- if (was_found) {
- index = i;
- return true;
- }
- }
- }
- return false;
-}
-
-
-bool FT2Font::load_char_with_fallback(FT2Font *&ft_object_with_glyph,
- FT_UInt &final_glyph_index,
- std::vector<FT_Glyph> &parent_glyphs,
- std::unordered_map<long, FT2Font *> &parent_char_to_font,
- std::unordered_map<FT_UInt, FT2Font *> &parent_glyph_to_font,
- long charcode,
- FT_Int32 flags,
- FT_Error &charcode_error,
- FT_Error &glyph_error,
- bool override = false)
-{
- FT_UInt glyph_index = FT_Get_Char_Index(face, charcode);
-
- if (glyph_index || override) {
- charcode_error = FT_Load_Glyph(face, glyph_index, flags);
- if (charcode_error) {
- return false;
- }
-
- FT_Glyph thisGlyph;
- glyph_error = FT_Get_Glyph(face->glyph, &thisGlyph);
- if (glyph_error) {
- return false;
- }
-
- final_glyph_index = glyph_index;
-
- // cache the result for future
- // need to store this for anytime a character is loaded from a parent
- // FT2Font object or to generate a mapping of individual characters to fonts
- ft_object_with_glyph = this;
- parent_glyph_to_font[final_glyph_index] = this;
- parent_char_to_font[charcode] = this;
- parent_glyphs.push_back(thisGlyph);
- return true;
- }
-
- else {
- for (size_t i = 0; i < fallbacks.size(); ++i) {
- bool was_found = fallbacks[i]->load_char_with_fallback(
- ft_object_with_glyph, final_glyph_index, parent_glyphs, parent_char_to_font,
- parent_glyph_to_font, charcode, flags, charcode_error, glyph_error, override);
- if (was_found) {
- return true;
- }
- }
- return false;
- }
-}
-
-void FT2Font::load_glyph(FT_UInt glyph_index,
- FT_Int32 flags,
- FT2Font *&ft_object,
- bool fallback = false)
-{
- // cache is only for parent FT2Font
- if (fallback && glyph_to_font.find(glyph_index) != glyph_to_font.end()) {
- ft_object = glyph_to_font[glyph_index];
- } else {
- ft_object = this;
- }
-
- ft_object->load_glyph(glyph_index, flags);
-}
-
-void FT2Font::load_glyph(FT_UInt glyph_index, FT_Int32 flags)
-{
- if (FT_Error error = FT_Load_Glyph(face, glyph_index, flags)) {
- throw_ft_error("Could not load glyph", error);
- }
- FT_Glyph thisGlyph;
- if (FT_Error error = FT_Get_Glyph(face->glyph, &thisGlyph)) {
- throw_ft_error("Could not get glyph", error);
- }
- glyphs.push_back(thisGlyph);
-}
-
-FT_UInt FT2Font::get_char_index(FT_ULong charcode, bool fallback = false)
-{
- FT2Font *ft_object = NULL;
- if (fallback && char_to_font.find(charcode) != char_to_font.end()) {
- // fallback denotes whether we want to search fallback list.
- // should call set_text/load_char_with_fallback to parent FT2Font before
- // wanting to use fallback list here. (since that populates the cache)
- ft_object = char_to_font[charcode];
- } else {
- // set as self
- ft_object = this;
- }
-
- // historically, get_char_index never raises a warning
- return ft_get_char_index_or_warn(ft_object->get_face(), charcode, false);
-}
-
-void FT2Font::get_width_height(long *width, long *height)
-{
- *width = advance;
- *height = bbox.yMax - bbox.yMin;
-}
-
-long FT2Font::get_descent()
-{
- return -bbox.yMin;
-}
-
-void FT2Font::get_bitmap_offset(long *x, long *y)
-{
- *x = bbox.xMin;
- *y = 0;
-}
-
-void FT2Font::draw_glyphs_to_bitmap(bool antialiased)
-{
- long width = (bbox.xMax - bbox.xMin) / 64 + 2;
- long height = (bbox.yMax - bbox.yMin) / 64 + 2;
-
- image.resize(width, height);
-
- for (size_t n = 0; n < glyphs.size(); n++) {
- FT_Error error = FT_Glyph_To_Bitmap(
- &glyphs[n], antialiased ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO, 0, 1);
- if (error) {
- throw_ft_error("Could not convert glyph to bitmap", error);
- }
-
- FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyphs[n];
- // now, draw to our target surface (convert position)
-
- // bitmap left and top in pixel, string bbox in subpixel
- FT_Int x = (FT_Int)(bitmap->left - (bbox.xMin * (1. / 64.)));
- FT_Int y = (FT_Int)((bbox.yMax * (1. / 64.)) - bitmap->top + 1);
-
- image.draw_bitmap(&bitmap->bitmap, x, y);
- }
-}
-
-void FT2Font::get_xys(bool antialiased, std::vector<double> &xys)
-{
- for (size_t n = 0; n < glyphs.size(); n++) {
-
- FT_Error error = FT_Glyph_To_Bitmap(
- &glyphs[n], antialiased ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO, 0, 1);
- if (error) {
- throw_ft_error("Could not convert glyph to bitmap", error);
- }
-
- FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyphs[n];
-
- // bitmap left and top in pixel, string bbox in subpixel
- FT_Int x = (FT_Int)(bitmap->left - bbox.xMin * (1. / 64.));
- FT_Int y = (FT_Int)(bbox.yMax * (1. / 64.) - bitmap->top + 1);
- // make sure the index is non-neg
- x = x < 0 ? 0 : x;
- y = y < 0 ? 0 : y;
- xys.push_back(x);
- xys.push_back(y);
- }
-}
-
-void FT2Font::draw_glyph_to_bitmap(FT2Image &im, int x, int y, size_t glyphInd, bool antialiased)
-{
- FT_Vector sub_offset;
- sub_offset.x = 0; // int((xd - (double)x) * 64.0);
- sub_offset.y = 0; // int((yd - (double)y) * 64.0);
-
- if (glyphInd >= glyphs.size()) {
- throw std::runtime_error("glyph num is out of range");
- }
-
- FT_Error error = FT_Glyph_To_Bitmap(
- &glyphs[glyphInd],
- antialiased ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO,
- &sub_offset, // additional translation
- 1 // destroy image
- );
- if (error) {
- throw_ft_error("Could not convert glyph to bitmap", error);
- }
-
- FT_BitmapGlyph bitmap = (FT_BitmapGlyph)glyphs[glyphInd];
-
- im.draw_bitmap(&bitmap->bitmap, x + bitmap->left, y);
-}
-
-void FT2Font::get_glyph_name(unsigned int glyph_number, char *buffer, bool fallback = false)
-{
- if (fallback && glyph_to_font.find(glyph_number) != glyph_to_font.end()) {
- // cache is only for parent FT2Font
- FT2Font *ft_object = glyph_to_font[glyph_number];
- ft_object->get_glyph_name(glyph_number, buffer, false);
- return;
- }
- if (!FT_HAS_GLYPH_NAMES(face)) {
- /* Note that this generated name must match the name that
- is generated by ttconv in ttfont_CharStrings_getname. */
- PyOS_snprintf(buffer, 128, "uni%08x", glyph_number);
- } else {
- if (FT_Error error = FT_Get_Glyph_Name(face, glyph_number, buffer, 128)) {
- throw_ft_error("Could not get glyph names", error);
- }
- }
-}
-
-long FT2Font::get_name_index(char *name)
-{
- return FT_Get_Name_Index(face, (FT_String *)name);
-}
diff --git a/contrib/python/matplotlib/py3/src/ft2font.h b/contrib/python/matplotlib/py3/src/ft2font.h
deleted file mode 100644
index d566c3f9bd..0000000000
--- a/contrib/python/matplotlib/py3/src/ft2font.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/* -*- mode: c++; c-basic-offset: 4 -*- */
-
-/* A python interface to FreeType */
-#pragma once
-#ifndef MPL_FT2FONT_H
-#define MPL_FT2FONT_H
-#include <vector>
-#include <stdint.h>
-#include <unordered_map>
-
-extern "C" {
-#include <ft2build.h>
-#include FT_FREETYPE_H
-#include FT_GLYPH_H
-#include FT_OUTLINE_H
-#include FT_SFNT_NAMES_H
-#include FT_TYPE1_TABLES_H
-#include FT_TRUETYPE_TABLES_H
-}
-
-#define PY_SSIZE_T_CLEAN
-#include <Python.h>
-
-/*
- By definition, FT_FIXED as 2 16bit values stored in a single long.
- */
-#define FIXED_MAJOR(val) (signed short)((val & 0xffff0000) >> 16)
-#define FIXED_MINOR(val) (unsigned short)(val & 0xffff)
-
-// the FreeType string rendered into a width, height buffer
-class FT2Image
-{
- public:
- FT2Image();
- FT2Image(unsigned long width, unsigned long height);
- virtual ~FT2Image();
-
- void resize(long width, long height);
- void draw_bitmap(FT_Bitmap *bitmap, FT_Int x, FT_Int y);
- void draw_rect(unsigned long x0, unsigned long y0, unsigned long x1, unsigned long y1);
- void draw_rect_filled(unsigned long x0, unsigned long y0, unsigned long x1, unsigned long y1);
-
- unsigned char *get_buffer()
- {
- return m_buffer;
- }
- unsigned long get_width()
- {
- return m_width;
- }
- unsigned long get_height()
- {
- return m_height;
- }
-
- private:
- bool m_dirty;
- unsigned char *m_buffer;
- unsigned long m_width;
- unsigned long m_height;
-
- // prevent copying
- FT2Image(const FT2Image &);
- FT2Image &operator=(const FT2Image &);
-};
-
-extern FT_Library _ft2Library;
-
-class FT2Font
-{
-
- public:
- FT2Font(FT_Open_Args &open_args, long hinting_factor, std::vector<FT2Font *> &fallback_list);
- virtual ~FT2Font();
- void clear();
- void set_size(double ptsize, double dpi);
- void set_charmap(int i);
- void select_charmap(unsigned long i);
- void set_text(
- size_t N, uint32_t *codepoints, double angle, FT_Int32 flags, std::vector<double> &xys);
- int get_kerning(FT_UInt left, FT_UInt right, FT_UInt mode, bool fallback);
- int get_kerning(FT_UInt left, FT_UInt right, FT_UInt mode, FT_Vector &delta);
- void set_kerning_factor(int factor);
- void load_char(long charcode, FT_Int32 flags, FT2Font *&ft_object, bool fallback);
- bool load_char_with_fallback(FT2Font *&ft_object_with_glyph,
- FT_UInt &final_glyph_index,
- std::vector<FT_Glyph> &parent_glyphs,
- std::unordered_map<long, FT2Font *> &parent_char_to_font,
- std::unordered_map<FT_UInt, FT2Font *> &parent_glyph_to_font,
- long charcode,
- FT_Int32 flags,
- FT_Error &charcode_error,
- FT_Error &glyph_error,
- bool override);
- void load_glyph(FT_UInt glyph_index, FT_Int32 flags, FT2Font *&ft_object, bool fallback);
- void load_glyph(FT_UInt glyph_index, FT_Int32 flags);
- void get_width_height(long *width, long *height);
- void get_bitmap_offset(long *x, long *y);
- long get_descent();
- // TODO: Since we know the size of the array upfront, we probably don't
- // need to dynamically allocate like this
- void get_xys(bool antialiased, std::vector<double> &xys);
- void draw_glyphs_to_bitmap(bool antialiased);
- void draw_glyph_to_bitmap(FT2Image &im, int x, int y, size_t glyphInd, bool antialiased);
- void get_glyph_name(unsigned int glyph_number, char *buffer, bool fallback);
- long get_name_index(char *name);
- FT_UInt get_char_index(FT_ULong charcode, bool fallback);
- PyObject* get_path();
- bool get_char_fallback_index(FT_ULong charcode, int& index) const;
-
- FT_Face const &get_face() const
- {
- return face;
- }
-
- FT2Image &get_image()
- {
- return image;
- }
- FT_Glyph const &get_last_glyph() const
- {
- return glyphs.back();
- }
- size_t get_last_glyph_index() const
- {
- return glyphs.size() - 1;
- }
- size_t get_num_glyphs() const
- {
- return glyphs.size();
- }
- long get_hinting_factor() const
- {
- return hinting_factor;
- }
- FT_Bool has_kerning() const
- {
- return FT_HAS_KERNING(face);
- }
-
- private:
- FT2Image image;
- FT_Face face;
- FT_Vector pen; /* untransformed origin */
- std::vector<FT_Glyph> glyphs;
- std::vector<FT2Font *> fallbacks;
- std::unordered_map<FT_UInt, FT2Font *> glyph_to_font;
- std::unordered_map<long, FT2Font *> char_to_font;
- FT_BBox bbox;
- FT_Pos advance;
- long hinting_factor;
- int kerning_factor;
-
- // prevent copying
- FT2Font(const FT2Font &);
- FT2Font &operator=(const FT2Font &);
-};
-
-#endif
diff --git a/contrib/python/matplotlib/py3/src/ft2font_wrapper.cpp b/contrib/python/matplotlib/py3/src/ft2font_wrapper.cpp
deleted file mode 100644
index 7888a9c212..0000000000
--- a/contrib/python/matplotlib/py3/src/ft2font_wrapper.cpp
+++ /dev/null
@@ -1,1578 +0,0 @@
-#include "mplutils.h"
-#include "ft2font.h"
-#include "py_converters.h"
-#include "py_exceptions.h"
-#include "numpy_cpp.h"
-
-// From Python
-#include <structmember.h>
-
-#include <set>
-#include <algorithm>
-
-#define STRINGIFY(s) XSTRINGIFY(s)
-#define XSTRINGIFY(s) #s
-
-static PyObject *convert_xys_to_array(std::vector<double> &xys)
-{
- npy_intp dims[] = {(npy_intp)xys.size() / 2, 2 };
- if (dims[0] > 0) {
- return PyArray_SimpleNewFromData(2, dims, NPY_DOUBLE, &xys[0]);
- } else {
- return PyArray_SimpleNew(2, dims, NPY_DOUBLE);
- }
-}
-
-/**********************************************************************
- * FT2Image
- * */
-
-typedef struct
-{
- PyObject_HEAD
- FT2Image *x;
- Py_ssize_t shape[2];
- Py_ssize_t strides[2];
- Py_ssize_t suboffsets[2];
-} PyFT2Image;
-
-static PyTypeObject PyFT2ImageType;
-
-static PyObject *PyFT2Image_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
- PyFT2Image *self;
- self = (PyFT2Image *)type->tp_alloc(type, 0);
- self->x = NULL;
- return (PyObject *)self;
-}
-
-static int PyFT2Image_init(PyFT2Image *self, PyObject *args, PyObject *kwds)
-{
- double width;
- double height;
-
- if (!PyArg_ParseTuple(args, "dd:FT2Image", &width, &height)) {
- return -1;
- }
-
- CALL_CPP_INIT("FT2Image", (self->x = new FT2Image(width, height)));
-
- return 0;
-}
-
-static void PyFT2Image_dealloc(PyFT2Image *self)
-{
- delete self->x;
- Py_TYPE(self)->tp_free((PyObject *)self);
-}
-
-const char *PyFT2Image_draw_rect__doc__ =
- "draw_rect(self, x0, y0, x1, y1)\n"
- "--\n\n"
- "Draw an empty rectangle to the image.\n"
- "\n"
- ".. deprecated:: 3.8\n";
-;
-
-static PyObject *PyFT2Image_draw_rect(PyFT2Image *self, PyObject *args)
-{
- char const* msg =
- "FT2Image.draw_rect is deprecated since Matplotlib 3.8 and will be removed "
- "two minor releases later as it is not used in the library. If you rely on "
- "it, please let us know.";
- if (PyErr_WarnEx(PyExc_DeprecationWarning, msg, 1)) {
- return NULL;
- }
-
- double x0, y0, x1, y1;
-
- if (!PyArg_ParseTuple(args, "dddd:draw_rect", &x0, &y0, &x1, &y1)) {
- return NULL;
- }
-
- CALL_CPP("draw_rect", (self->x->draw_rect(x0, y0, x1, y1)));
-
- Py_RETURN_NONE;
-}
-
-const char *PyFT2Image_draw_rect_filled__doc__ =
- "draw_rect_filled(self, x0, y0, x1, y1)\n"
- "--\n\n"
- "Draw a filled rectangle to the image.\n";
-
-static PyObject *PyFT2Image_draw_rect_filled(PyFT2Image *self, PyObject *args)
-{
- double x0, y0, x1, y1;
-
- if (!PyArg_ParseTuple(args, "dddd:draw_rect_filled", &x0, &y0, &x1, &y1)) {
- return NULL;
- }
-
- CALL_CPP("draw_rect_filled", (self->x->draw_rect_filled(x0, y0, x1, y1)));
-
- Py_RETURN_NONE;
-}
-
-static int PyFT2Image_get_buffer(PyFT2Image *self, Py_buffer *buf, int flags)
-{
- FT2Image *im = self->x;
-
- Py_INCREF(self);
- buf->obj = (PyObject *)self;
- buf->buf = im->get_buffer();
- buf->len = im->get_width() * im->get_height();
- buf->readonly = 0;
- buf->format = (char *)"B";
- buf->ndim = 2;
- self->shape[0] = im->get_height();
- self->shape[1] = im->get_width();
- buf->shape = self->shape;
- self->strides[0] = im->get_width();
- self->strides[1] = 1;
- buf->strides = self->strides;
- buf->suboffsets = NULL;
- buf->itemsize = 1;
- buf->internal = NULL;
-
- return 1;
-}
-
-static PyTypeObject* PyFT2Image_init_type()
-{
- static PyMethodDef methods[] = {
- {"draw_rect", (PyCFunction)PyFT2Image_draw_rect, METH_VARARGS, PyFT2Image_draw_rect__doc__},
- {"draw_rect_filled", (PyCFunction)PyFT2Image_draw_rect_filled, METH_VARARGS, PyFT2Image_draw_rect_filled__doc__},
- {NULL}
- };
-
- static PyBufferProcs buffer_procs;
- buffer_procs.bf_getbuffer = (getbufferproc)PyFT2Image_get_buffer;
-
- PyFT2ImageType.tp_name = "matplotlib.ft2font.FT2Image";
- PyFT2ImageType.tp_basicsize = sizeof(PyFT2Image);
- PyFT2ImageType.tp_dealloc = (destructor)PyFT2Image_dealloc;
- PyFT2ImageType.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
- PyFT2ImageType.tp_methods = methods;
- PyFT2ImageType.tp_new = PyFT2Image_new;
- PyFT2ImageType.tp_init = (initproc)PyFT2Image_init;
- PyFT2ImageType.tp_as_buffer = &buffer_procs;
-
- return &PyFT2ImageType;
-}
-
-/**********************************************************************
- * Glyph
- * */
-
-typedef struct
-{
- PyObject_HEAD
- size_t glyphInd;
- long width;
- long height;
- long horiBearingX;
- long horiBearingY;
- long horiAdvance;
- long linearHoriAdvance;
- long vertBearingX;
- long vertBearingY;
- long vertAdvance;
- FT_BBox bbox;
-} PyGlyph;
-
-static PyTypeObject PyGlyphType;
-
-static PyObject *PyGlyph_from_FT2Font(const FT2Font *font)
-{
- const FT_Face &face = font->get_face();
- const long hinting_factor = font->get_hinting_factor();
- const FT_Glyph &glyph = font->get_last_glyph();
-
- PyGlyph *self;
- self = (PyGlyph *)PyGlyphType.tp_alloc(&PyGlyphType, 0);
-
- self->glyphInd = font->get_last_glyph_index();
- FT_Glyph_Get_CBox(glyph, ft_glyph_bbox_subpixels, &self->bbox);
-
- self->width = face->glyph->metrics.width / hinting_factor;
- self->height = face->glyph->metrics.height;
- self->horiBearingX = face->glyph->metrics.horiBearingX / hinting_factor;
- self->horiBearingY = face->glyph->metrics.horiBearingY;
- self->horiAdvance = face->glyph->metrics.horiAdvance;
- self->linearHoriAdvance = face->glyph->linearHoriAdvance / hinting_factor;
- self->vertBearingX = face->glyph->metrics.vertBearingX;
- self->vertBearingY = face->glyph->metrics.vertBearingY;
- self->vertAdvance = face->glyph->metrics.vertAdvance;
-
- return (PyObject *)self;
-}
-
-static void PyGlyph_dealloc(PyGlyph *self)
-{
- Py_TYPE(self)->tp_free((PyObject *)self);
-}
-
-static PyObject *PyGlyph_get_bbox(PyGlyph *self, void *closure)
-{
- return Py_BuildValue(
- "llll", self->bbox.xMin, self->bbox.yMin, self->bbox.xMax, self->bbox.yMax);
-}
-
-static PyTypeObject *PyGlyph_init_type()
-{
- static PyMemberDef members[] = {
- {(char *)"width", T_LONG, offsetof(PyGlyph, width), READONLY, (char *)""},
- {(char *)"height", T_LONG, offsetof(PyGlyph, height), READONLY, (char *)""},
- {(char *)"horiBearingX", T_LONG, offsetof(PyGlyph, horiBearingX), READONLY, (char *)""},
- {(char *)"horiBearingY", T_LONG, offsetof(PyGlyph, horiBearingY), READONLY, (char *)""},
- {(char *)"horiAdvance", T_LONG, offsetof(PyGlyph, horiAdvance), READONLY, (char *)""},
- {(char *)"linearHoriAdvance", T_LONG, offsetof(PyGlyph, linearHoriAdvance), READONLY, (char *)""},
- {(char *)"vertBearingX", T_LONG, offsetof(PyGlyph, vertBearingX), READONLY, (char *)""},
- {(char *)"vertBearingY", T_LONG, offsetof(PyGlyph, vertBearingY), READONLY, (char *)""},
- {(char *)"vertAdvance", T_LONG, offsetof(PyGlyph, vertAdvance), READONLY, (char *)""},
- {NULL}
- };
-
- static PyGetSetDef getset[] = {
- {(char *)"bbox", (getter)PyGlyph_get_bbox, NULL, NULL, NULL},
- {NULL}
- };
-
- PyGlyphType.tp_name = "matplotlib.ft2font.Glyph";
- PyGlyphType.tp_basicsize = sizeof(PyGlyph);
- PyGlyphType.tp_dealloc = (destructor)PyGlyph_dealloc;
- PyGlyphType.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
- PyGlyphType.tp_members = members;
- PyGlyphType.tp_getset = getset;
-
- return &PyGlyphType;
-}
-
-/**********************************************************************
- * FT2Font
- * */
-
-struct PyFT2Font
-{
- PyObject_HEAD
- FT2Font *x;
- PyObject *py_file;
- FT_StreamRec stream;
- Py_ssize_t shape[2];
- Py_ssize_t strides[2];
- Py_ssize_t suboffsets[2];
- std::vector<PyObject *> fallbacks;
-};
-
-static PyTypeObject PyFT2FontType;
-
-static unsigned long read_from_file_callback(FT_Stream stream,
- unsigned long offset,
- unsigned char *buffer,
- unsigned long count)
-{
- PyObject *py_file = ((PyFT2Font *)stream->descriptor.pointer)->py_file;
- PyObject *seek_result = NULL, *read_result = NULL;
- Py_ssize_t n_read = 0;
- if (!(seek_result = PyObject_CallMethod(py_file, "seek", "k", offset))
- || !(read_result = PyObject_CallMethod(py_file, "read", "k", count))) {
- goto exit;
- }
- char *tmpbuf;
- if (PyBytes_AsStringAndSize(read_result, &tmpbuf, &n_read) == -1) {
- goto exit;
- }
- memcpy(buffer, tmpbuf, n_read);
-exit:
- Py_XDECREF(seek_result);
- Py_XDECREF(read_result);
- if (PyErr_Occurred()) {
- PyErr_WriteUnraisable(py_file);
- if (!count) {
- return 1; // Non-zero signals error, when count == 0.
- }
- }
- return (unsigned long)n_read;
-}
-
-static void close_file_callback(FT_Stream stream)
-{
- PyObject *type, *value, *traceback;
- PyErr_Fetch(&type, &value, &traceback);
- PyFT2Font *self = (PyFT2Font *)stream->descriptor.pointer;
- PyObject *close_result = NULL;
- if (!(close_result = PyObject_CallMethod(self->py_file, "close", ""))) {
- goto exit;
- }
-exit:
- Py_XDECREF(close_result);
- Py_CLEAR(self->py_file);
- if (PyErr_Occurred()) {
- PyErr_WriteUnraisable((PyObject*)self);
- }
- PyErr_Restore(type, value, traceback);
-}
-
-static PyObject *PyFT2Font_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
- PyFT2Font *self;
- self = (PyFT2Font *)type->tp_alloc(type, 0);
- self->x = NULL;
- self->py_file = NULL;
- memset(&self->stream, 0, sizeof(FT_StreamRec));
- return (PyObject *)self;
-}
-
-const char *PyFT2Font_init__doc__ =
- "FT2Font(filename, hinting_factor=8, *, _fallback_list=None, _kerning_factor=0)\n"
- "--\n\n"
- "Create a new FT2Font object.\n"
- "\n"
- "Parameters\n"
- "----------\n"
- "filename : str or file-like\n"
- " The source of the font data in a format (ttf or ttc) that FreeType can read\n"
- "\n"
- "hinting_factor : int, optional\n"
- " Must be positive. Used to scale the hinting in the x-direction\n"
- "_fallback_list : list of FT2Font, optional\n"
- " A list of FT2Font objects used to find missing glyphs.\n"
- "\n"
- " .. warning::\n"
- " This API is both private and provisional: do not use it directly\n"
- "\n"
- "_kerning_factor : int, optional\n"
- " Used to adjust the degree of kerning.\n"
- "\n"
- " .. warning::\n"
- " This API is private: do not use it directly\n"
- "\n"
- "Attributes\n"
- "----------\n"
- "num_faces : int\n"
- " Number of faces in file.\n"
- "face_flags, style_flags : int\n"
- " Face and style flags; see the ft2font constants.\n"
- "num_glyphs : int\n"
- " Number of glyphs in the face.\n"
- "family_name, style_name : str\n"
- " Face family and style name.\n"
- "num_fixed_sizes : int\n"
- " Number of bitmap in the face.\n"
- "scalable : bool\n"
- " Whether face is scalable; attributes after this one are only\n"
- " defined for scalable faces.\n"
- "bbox : tuple[int, int, int, int]\n"
- " Face global bounding box (xmin, ymin, xmax, ymax).\n"
- "units_per_EM : int\n"
- " Number of font units covered by the EM.\n"
- "ascender, descender : int\n"
- " Ascender and descender in 26.6 units.\n"
- "height : int\n"
- " Height in 26.6 units; used to compute a default line spacing\n"
- " (baseline-to-baseline distance).\n"
- "max_advance_width, max_advance_height : int\n"
- " Maximum horizontal and vertical cursor advance for all glyphs.\n"
- "underline_position, underline_thickness : int\n"
- " Vertical position and thickness of the underline bar.\n"
- "postscript_name : str\n"
- " PostScript name of the font.\n";
-
-static int PyFT2Font_init(PyFT2Font *self, PyObject *args, PyObject *kwds)
-{
- PyObject *filename = NULL, *open = NULL, *data = NULL, *fallback_list = NULL;
- FT_Open_Args open_args;
- long hinting_factor = 8;
- int kerning_factor = 0;
- const char *names[] = {
- "filename", "hinting_factor", "_fallback_list", "_kerning_factor", NULL
- };
- std::vector<FT2Font *> fallback_fonts;
- if (!PyArg_ParseTupleAndKeywords(
- args, kwds, "O|l$Oi:FT2Font", (char **)names, &filename,
- &hinting_factor, &fallback_list, &kerning_factor)) {
- return -1;
- }
- if (hinting_factor <= 0) {
- PyErr_SetString(PyExc_ValueError,
- "hinting_factor must be greater than 0");
- goto exit;
- }
-
- self->stream.base = NULL;
- self->stream.size = 0x7fffffff; // Unknown size.
- self->stream.pos = 0;
- self->stream.descriptor.pointer = self;
- self->stream.read = &read_from_file_callback;
- memset((void *)&open_args, 0, sizeof(FT_Open_Args));
- open_args.flags = FT_OPEN_STREAM;
- open_args.stream = &self->stream;
-
- if (fallback_list) {
- if (!PyList_Check(fallback_list)) {
- PyErr_SetString(PyExc_TypeError, "Fallback list must be a list");
- goto exit;
- }
- Py_ssize_t size = PyList_Size(fallback_list);
-
- // go through fallbacks once to make sure the types are right
- for (Py_ssize_t i = 0; i < size; ++i) {
- // this returns a borrowed reference
- PyObject* item = PyList_GetItem(fallback_list, i);
- if (!PyObject_IsInstance(item, PyObject_Type(reinterpret_cast<PyObject *>(self)))) {
- PyErr_SetString(PyExc_TypeError, "Fallback fonts must be FT2Font objects.");
- goto exit;
- }
- }
- // go through a second time to add them to our lists
- for (Py_ssize_t i = 0; i < size; ++i) {
- // this returns a borrowed reference
- PyObject* item = PyList_GetItem(fallback_list, i);
- // Increase the ref count, we will undo this in dealloc this makes
- // sure things do not get gc'd under us!
- Py_INCREF(item);
- self->fallbacks.push_back(item);
- // Also (locally) cache the underlying FT2Font objects. As long as
- // the Python objects are kept alive, these pointer are good.
- FT2Font *fback = reinterpret_cast<PyFT2Font *>(item)->x;
- fallback_fonts.push_back(fback);
- }
- }
-
- if (PyBytes_Check(filename) || PyUnicode_Check(filename)) {
- if (!(open = PyDict_GetItemString(PyEval_GetBuiltins(), "open")) // Borrowed reference.
- || !(self->py_file = PyObject_CallFunction(open, "Os", filename, "rb"))) {
- goto exit;
- }
- self->stream.close = &close_file_callback;
- } else if (!PyObject_HasAttrString(filename, "read")
- || !(data = PyObject_CallMethod(filename, "read", "i", 0))
- || !PyBytes_Check(data)) {
- PyErr_SetString(PyExc_TypeError,
- "First argument must be a path to a font file or a binary-mode file object");
- Py_CLEAR(data);
- goto exit;
- } else {
- self->py_file = filename;
- self->stream.close = NULL;
- Py_INCREF(filename);
- }
- Py_CLEAR(data);
-
- CALL_CPP_FULL(
- "FT2Font", (self->x = new FT2Font(open_args, hinting_factor, fallback_fonts)),
- Py_CLEAR(self->py_file), -1);
-
- CALL_CPP_INIT("FT2Font->set_kerning_factor", (self->x->set_kerning_factor(kerning_factor)));
-
-exit:
- return PyErr_Occurred() ? -1 : 0;
-}
-
-static void PyFT2Font_dealloc(PyFT2Font *self)
-{
- delete self->x;
- for (size_t i = 0; i < self->fallbacks.size(); i++) {
- Py_DECREF(self->fallbacks[i]);
- }
-
- Py_XDECREF(self->py_file);
- Py_TYPE(self)->tp_free((PyObject *)self);
-}
-
-const char *PyFT2Font_clear__doc__ =
- "clear(self)\n"
- "--\n\n"
- "Clear all the glyphs, reset for a new call to `.set_text`.\n";
-
-static PyObject *PyFT2Font_clear(PyFT2Font *self, PyObject *args)
-{
- CALL_CPP("clear", (self->x->clear()));
-
- Py_RETURN_NONE;
-}
-
-const char *PyFT2Font_set_size__doc__ =
- "set_size(self, ptsize, dpi)\n"
- "--\n\n"
- "Set the point size and dpi of the text.\n";
-
-static PyObject *PyFT2Font_set_size(PyFT2Font *self, PyObject *args)
-{
- double ptsize;
- double dpi;
-
- if (!PyArg_ParseTuple(args, "dd:set_size", &ptsize, &dpi)) {
- return NULL;
- }
-
- CALL_CPP("set_size", (self->x->set_size(ptsize, dpi)));
-
- Py_RETURN_NONE;
-}
-
-const char *PyFT2Font_set_charmap__doc__ =
- "set_charmap(self, i)\n"
- "--\n\n"
- "Make the i-th charmap current.\n";
-
-static PyObject *PyFT2Font_set_charmap(PyFT2Font *self, PyObject *args)
-{
- int i;
-
- if (!PyArg_ParseTuple(args, "i:set_charmap", &i)) {
- return NULL;
- }
-
- CALL_CPP("set_charmap", (self->x->set_charmap(i)));
-
- Py_RETURN_NONE;
-}
-
-const char *PyFT2Font_select_charmap__doc__ =
- "select_charmap(self, i)\n"
- "--\n\n"
- "Select a charmap by its FT_Encoding number.\n";
-
-static PyObject *PyFT2Font_select_charmap(PyFT2Font *self, PyObject *args)
-{
- unsigned long i;
-
- if (!PyArg_ParseTuple(args, "k:select_charmap", &i)) {
- return NULL;
- }
-
- CALL_CPP("select_charmap", self->x->select_charmap(i));
-
- Py_RETURN_NONE;
-}
-
-const char *PyFT2Font_get_kerning__doc__ =
- "get_kerning(self, left, right, mode)\n"
- "--\n\n"
- "Get the kerning between *left* and *right* glyph indices.\n"
- "*mode* is a kerning mode constant:\n\n"
- "- KERNING_DEFAULT - Return scaled and grid-fitted kerning distances\n"
- "- KERNING_UNFITTED - Return scaled but un-grid-fitted kerning distances\n"
- "- KERNING_UNSCALED - Return the kerning vector in original font units\n";
-
-static PyObject *PyFT2Font_get_kerning(PyFT2Font *self, PyObject *args)
-{
- FT_UInt left, right, mode;
- int result;
- int fallback = 1;
-
- if (!PyArg_ParseTuple(args, "III:get_kerning", &left, &right, &mode)) {
- return NULL;
- }
-
- CALL_CPP("get_kerning", (result = self->x->get_kerning(left, right, mode, (bool)fallback)));
-
- return PyLong_FromLong(result);
-}
-
-const char *PyFT2Font_get_fontmap__doc__ =
- "_get_fontmap(self, string)\n"
- "--\n\n"
- "Get a mapping between characters and the font that includes them.\n"
- "A dictionary mapping unicode characters to PyFT2Font objects.";
-static PyObject *PyFT2Font_get_fontmap(PyFT2Font *self, PyObject *args, PyObject *kwds)
-{
- PyObject *textobj;
- const char *names[] = { "string", NULL };
-
- if (!PyArg_ParseTupleAndKeywords(
- args, kwds, "O:_get_fontmap", (char **)names, &textobj)) {
- return NULL;
- }
-
- std::set<FT_ULong> codepoints;
- size_t size;
-
- if (PyUnicode_Check(textobj)) {
- size = PyUnicode_GET_LENGTH(textobj);
- for (size_t i = 0; i < size; ++i) {
- codepoints.insert(PyUnicode_ReadChar(textobj, i));
- }
- } else {
- PyErr_SetString(PyExc_TypeError, "string must be str");
- return NULL;
- }
- PyObject *char_to_font;
- if (!(char_to_font = PyDict_New())) {
- return NULL;
- }
- for (auto it = codepoints.begin(); it != codepoints.end(); ++it) {
- auto x = *it;
- PyObject* target_font;
- int index;
- if (self->x->get_char_fallback_index(x, index)) {
- if (index >= 0) {
- target_font = self->fallbacks[index];
- } else {
- target_font = (PyObject *)self;
- }
- } else {
- // TODO Handle recursion!
- target_font = (PyObject *)self;
- }
-
- PyObject *key = NULL;
- bool error = (!(key = PyUnicode_FromFormat("%c", x))
- || (PyDict_SetItem(char_to_font, key, target_font) == -1));
- Py_XDECREF(key);
- if (error) {
- Py_DECREF(char_to_font);
- PyErr_SetString(PyExc_ValueError, "Something went very wrong");
- return NULL;
- }
- }
- return char_to_font;
-}
-
-
-const char *PyFT2Font_set_text__doc__ =
- "set_text(self, string, angle=0.0, flags=32)\n"
- "--\n\n"
- "Set the text *string* and *angle*.\n"
- "*flags* can be a bitwise-or of the LOAD_XXX constants;\n"
- "the default value is LOAD_FORCE_AUTOHINT.\n"
- "You must call this before `.draw_glyphs_to_bitmap`.\n"
- "A sequence of x,y positions is returned.\n";
-
-static PyObject *PyFT2Font_set_text(PyFT2Font *self, PyObject *args, PyObject *kwds)
-{
- PyObject *textobj;
- double angle = 0.0;
- FT_Int32 flags = FT_LOAD_FORCE_AUTOHINT;
- std::vector<double> xys;
- const char *names[] = { "string", "angle", "flags", NULL };
-
- /* This makes a technically incorrect assumption that FT_Int32 is
- int. In theory it can also be long, if the size of int is less
- than 32 bits. This is very unlikely on modern platforms. */
- if (!PyArg_ParseTupleAndKeywords(
- args, kwds, "O|di:set_text", (char **)names, &textobj, &angle, &flags)) {
- return NULL;
- }
-
- std::vector<uint32_t> codepoints;
- size_t size;
-
- if (PyUnicode_Check(textobj)) {
- size = PyUnicode_GET_LENGTH(textobj);
- codepoints.resize(size);
- for (size_t i = 0; i < size; ++i) {
- codepoints[i] = PyUnicode_ReadChar(textobj, i);
- }
- } else {
- PyErr_SetString(PyExc_TypeError, "set_text requires str-input.");
- return NULL;
- }
-
- uint32_t* codepoints_array = NULL;
- if (size > 0) {
- codepoints_array = &codepoints[0];
- }
- CALL_CPP("set_text", self->x->set_text(size, codepoints_array, angle, flags, xys));
-
- return convert_xys_to_array(xys);
-}
-
-const char *PyFT2Font_get_num_glyphs__doc__ =
- "get_num_glyphs(self)\n"
- "--\n\n"
- "Return the number of loaded glyphs.\n";
-
-static PyObject *PyFT2Font_get_num_glyphs(PyFT2Font *self, PyObject *args)
-{
- return PyLong_FromSize_t(self->x->get_num_glyphs());
-}
-
-const char *PyFT2Font_load_char__doc__ =
- "load_char(self, charcode, flags=32)\n"
- "--\n\n"
- "Load character with *charcode* in current fontfile and set glyph.\n"
- "*flags* can be a bitwise-or of the LOAD_XXX constants;\n"
- "the default value is LOAD_FORCE_AUTOHINT.\n"
- "Return value is a Glyph object, with attributes\n\n"
- "- width: glyph width\n"
- "- height: glyph height\n"
- "- bbox: the glyph bbox (xmin, ymin, xmax, ymax)\n"
- "- horiBearingX: left side bearing in horizontal layouts\n"
- "- horiBearingY: top side bearing in horizontal layouts\n"
- "- horiAdvance: advance width for horizontal layout\n"
- "- vertBearingX: left side bearing in vertical layouts\n"
- "- vertBearingY: top side bearing in vertical layouts\n"
- "- vertAdvance: advance height for vertical layout\n";
-
-static PyObject *PyFT2Font_load_char(PyFT2Font *self, PyObject *args, PyObject *kwds)
-{
- long charcode;
- int fallback = 1;
- FT_Int32 flags = FT_LOAD_FORCE_AUTOHINT;
- const char *names[] = { "charcode", "flags", NULL };
-
- /* This makes a technically incorrect assumption that FT_Int32 is
- int. In theory it can also be long, if the size of int is less
- than 32 bits. This is very unlikely on modern platforms. */
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "l|i:load_char", (char **)names, &charcode,
- &flags)) {
- return NULL;
- }
-
- FT2Font *ft_object = NULL;
- CALL_CPP("load_char", (self->x->load_char(charcode, flags, ft_object, (bool)fallback)));
-
- return PyGlyph_from_FT2Font(ft_object);
-}
-
-const char *PyFT2Font_load_glyph__doc__ =
- "load_glyph(self, glyphindex, flags=32)\n"
- "--\n\n"
- "Load character with *glyphindex* in current fontfile and set glyph.\n"
- "*flags* can be a bitwise-or of the LOAD_XXX constants;\n"
- "the default value is LOAD_FORCE_AUTOHINT.\n"
- "Return value is a Glyph object, with attributes\n\n"
- "- width: glyph width\n"
- "- height: glyph height\n"
- "- bbox: the glyph bbox (xmin, ymin, xmax, ymax)\n"
- "- horiBearingX: left side bearing in horizontal layouts\n"
- "- horiBearingY: top side bearing in horizontal layouts\n"
- "- horiAdvance: advance width for horizontal layout\n"
- "- vertBearingX: left side bearing in vertical layouts\n"
- "- vertBearingY: top side bearing in vertical layouts\n"
- "- vertAdvance: advance height for vertical layout\n";
-
-static PyObject *PyFT2Font_load_glyph(PyFT2Font *self, PyObject *args, PyObject *kwds)
-{
- FT_UInt glyph_index;
- FT_Int32 flags = FT_LOAD_FORCE_AUTOHINT;
- int fallback = 1;
- const char *names[] = { "glyph_index", "flags", NULL };
-
- /* This makes a technically incorrect assumption that FT_Int32 is
- int. In theory it can also be long, if the size of int is less
- than 32 bits. This is very unlikely on modern platforms. */
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "I|i:load_glyph", (char **)names, &glyph_index,
- &flags)) {
- return NULL;
- }
-
- FT2Font *ft_object = NULL;
- CALL_CPP("load_glyph", (self->x->load_glyph(glyph_index, flags, ft_object, (bool)fallback)));
-
- return PyGlyph_from_FT2Font(ft_object);
-}
-
-const char *PyFT2Font_get_width_height__doc__ =
- "get_width_height(self)\n"
- "--\n\n"
- "Get the width and height in 26.6 subpixels of the current string set by `.set_text`.\n"
- "The rotation of the string is accounted for. To get width and height\n"
- "in pixels, divide these values by 64.\n";
-
-static PyObject *PyFT2Font_get_width_height(PyFT2Font *self, PyObject *args)
-{
- long width, height;
-
- CALL_CPP("get_width_height", (self->x->get_width_height(&width, &height)));
-
- return Py_BuildValue("ll", width, height);
-}
-
-const char *PyFT2Font_get_bitmap_offset__doc__ =
- "get_bitmap_offset(self)\n"
- "--\n\n"
- "Get the (x, y) offset in 26.6 subpixels for the bitmap if ink hangs left or below (0, 0).\n"
- "Since Matplotlib only supports left-to-right text, y is always 0.\n";
-
-static PyObject *PyFT2Font_get_bitmap_offset(PyFT2Font *self, PyObject *args)
-{
- long x, y;
-
- CALL_CPP("get_bitmap_offset", (self->x->get_bitmap_offset(&x, &y)));
-
- return Py_BuildValue("ll", x, y);
-}
-
-const char *PyFT2Font_get_descent__doc__ =
- "get_descent(self)\n"
- "--\n\n"
- "Get the descent in 26.6 subpixels of the current string set by `.set_text`.\n"
- "The rotation of the string is accounted for. To get the descent\n"
- "in pixels, divide this value by 64.\n";
-
-static PyObject *PyFT2Font_get_descent(PyFT2Font *self, PyObject *args)
-{
- long descent;
-
- CALL_CPP("get_descent", (descent = self->x->get_descent()));
-
- return PyLong_FromLong(descent);
-}
-
-const char *PyFT2Font_draw_glyphs_to_bitmap__doc__ =
- "draw_glyphs_to_bitmap(self, antialiased=True)\n"
- "--\n\n"
- "Draw the glyphs that were loaded by `.set_text` to the bitmap.\n"
- "The bitmap size will be automatically set to include the glyphs.\n";
-
-static PyObject *PyFT2Font_draw_glyphs_to_bitmap(PyFT2Font *self, PyObject *args, PyObject *kwds)
-{
- bool antialiased = true;
- const char *names[] = { "antialiased", NULL };
-
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&:draw_glyphs_to_bitmap",
- (char **)names, &convert_bool, &antialiased)) {
- return NULL;
- }
-
- CALL_CPP("draw_glyphs_to_bitmap", (self->x->draw_glyphs_to_bitmap(antialiased)));
-
- Py_RETURN_NONE;
-}
-
-const char *PyFT2Font_get_xys__doc__ =
- "get_xys(self, antialiased=True)\n"
- "--\n\n"
- "Get the xy locations of the current glyphs.\n"
- "\n"
- ".. deprecated:: 3.8\n";
-
-static PyObject *PyFT2Font_get_xys(PyFT2Font *self, PyObject *args, PyObject *kwds)
-{
- char const* msg =
- "FT2Font.get_xys is deprecated since Matplotlib 3.8 and will be removed two "
- "minor releases later as it is not used in the library. If you rely on it, "
- "please let us know.";
- if (PyErr_WarnEx(PyExc_DeprecationWarning, msg, 1)) {
- return NULL;
- }
-
- bool antialiased = true;
- std::vector<double> xys;
- const char *names[] = { "antialiased", NULL };
-
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&:get_xys",
- (char **)names, &convert_bool, &antialiased)) {
- return NULL;
- }
-
- CALL_CPP("get_xys", (self->x->get_xys(antialiased, xys)));
-
- return convert_xys_to_array(xys);
-}
-
-const char *PyFT2Font_draw_glyph_to_bitmap__doc__ =
- "draw_glyph_to_bitmap(self, image, x, y, glyph, antialiased=True)\n"
- "--\n\n"
- "Draw a single glyph to the bitmap at pixel locations x, y\n"
- "Note it is your responsibility to set up the bitmap manually\n"
- "with ``set_bitmap_size(w, h)`` before this call is made.\n"
- "\n"
- "If you want automatic layout, use `.set_text` in combinations with\n"
- "`.draw_glyphs_to_bitmap`. This function is instead intended for people\n"
- "who want to render individual glyphs (e.g., returned by `.load_char`)\n"
- "at precise locations.\n";
-
-static PyObject *PyFT2Font_draw_glyph_to_bitmap(PyFT2Font *self, PyObject *args, PyObject *kwds)
-{
- PyFT2Image *image;
- double xd, yd;
- PyGlyph *glyph;
- bool antialiased = true;
- const char *names[] = { "image", "x", "y", "glyph", "antialiased", NULL };
-
- if (!PyArg_ParseTupleAndKeywords(args,
- kwds,
- "O!ddO!|O&:draw_glyph_to_bitmap",
- (char **)names,
- &PyFT2ImageType,
- &image,
- &xd,
- &yd,
- &PyGlyphType,
- &glyph,
- &convert_bool,
- &antialiased)) {
- return NULL;
- }
-
- CALL_CPP("draw_glyph_to_bitmap",
- self->x->draw_glyph_to_bitmap(*(image->x), xd, yd, glyph->glyphInd, antialiased));
-
- Py_RETURN_NONE;
-}
-
-const char *PyFT2Font_get_glyph_name__doc__ =
- "get_glyph_name(self, index)\n"
- "--\n\n"
- "Retrieve the ASCII name of a given glyph *index* in a face.\n"
- "\n"
- "Due to Matplotlib's internal design, for fonts that do not contain glyph\n"
- "names (per FT_FACE_FLAG_GLYPH_NAMES), this returns a made-up name which\n"
- "does *not* roundtrip through `.get_name_index`.\n";
-
-static PyObject *PyFT2Font_get_glyph_name(PyFT2Font *self, PyObject *args)
-{
- unsigned int glyph_number;
- char buffer[128];
- int fallback = 1;
-
- if (!PyArg_ParseTuple(args, "I:get_glyph_name", &glyph_number)) {
- return NULL;
- }
- CALL_CPP("get_glyph_name", (self->x->get_glyph_name(glyph_number, buffer, (bool)fallback)));
- return PyUnicode_FromString(buffer);
-}
-
-const char *PyFT2Font_get_charmap__doc__ =
- "get_charmap(self)\n"
- "--\n\n"
- "Return a dict that maps the character codes of the selected charmap\n"
- "(Unicode by default) to their corresponding glyph indices.\n";
-
-static PyObject *PyFT2Font_get_charmap(PyFT2Font *self, PyObject *args)
-{
- PyObject *charmap;
- if (!(charmap = PyDict_New())) {
- return NULL;
- }
- FT_UInt index;
- FT_ULong code = FT_Get_First_Char(self->x->get_face(), &index);
- while (index != 0) {
- PyObject *key = NULL, *val = NULL;
- bool error = (!(key = PyLong_FromLong(code))
- || !(val = PyLong_FromLong(index))
- || (PyDict_SetItem(charmap, key, val) == -1));
- Py_XDECREF(key);
- Py_XDECREF(val);
- if (error) {
- Py_DECREF(charmap);
- return NULL;
- }
- code = FT_Get_Next_Char(self->x->get_face(), code, &index);
- }
- return charmap;
-}
-
-
-const char *PyFT2Font_get_char_index__doc__ =
- "get_char_index(self, codepoint)\n"
- "--\n\n"
- "Return the glyph index corresponding to a character *codepoint*.\n";
-
-static PyObject *PyFT2Font_get_char_index(PyFT2Font *self, PyObject *args)
-{
- FT_UInt index;
- FT_ULong ccode;
- int fallback = 1;
-
- if (!PyArg_ParseTuple(args, "k:get_char_index", &ccode)) {
- return NULL;
- }
-
- CALL_CPP("get_char_index", index = self->x->get_char_index(ccode, (bool)fallback));
-
- return PyLong_FromLong(index);
-}
-
-
-const char *PyFT2Font_get_sfnt__doc__ =
- "get_sfnt(self)\n"
- "--\n\n"
- "Load the entire SFNT names table, as a dict whose keys are\n"
- "(platform-ID, ISO-encoding-scheme, language-code, and description)\n"
- "tuples.\n";
-
-static PyObject *PyFT2Font_get_sfnt(PyFT2Font *self, PyObject *args)
-{
- PyObject *names;
-
- if (!(self->x->get_face()->face_flags & FT_FACE_FLAG_SFNT)) {
- PyErr_SetString(PyExc_ValueError, "No SFNT name table");
- return NULL;
- }
-
- size_t count = FT_Get_Sfnt_Name_Count(self->x->get_face());
-
- names = PyDict_New();
- if (names == NULL) {
- return NULL;
- }
-
- for (FT_UInt j = 0; j < count; ++j) {
- FT_SfntName sfnt;
- FT_Error error = FT_Get_Sfnt_Name(self->x->get_face(), j, &sfnt);
-
- if (error) {
- Py_DECREF(names);
- PyErr_SetString(PyExc_ValueError, "Could not get SFNT name");
- return NULL;
- }
-
- PyObject *key = Py_BuildValue(
- "HHHH", sfnt.platform_id, sfnt.encoding_id, sfnt.language_id, sfnt.name_id);
- if (key == NULL) {
- Py_DECREF(names);
- return NULL;
- }
-
- PyObject *val = PyBytes_FromStringAndSize((const char *)sfnt.string, sfnt.string_len);
- if (val == NULL) {
- Py_DECREF(key);
- Py_DECREF(names);
- return NULL;
- }
-
- if (PyDict_SetItem(names, key, val)) {
- Py_DECREF(key);
- Py_DECREF(val);
- Py_DECREF(names);
- return NULL;
- }
-
- Py_DECREF(key);
- Py_DECREF(val);
- }
-
- return names;
-}
-
-const char *PyFT2Font_get_name_index__doc__ =
- "get_name_index(self, name)\n"
- "--\n\n"
- "Return the glyph index of a given glyph *name*.\n"
- "The glyph index 0 means 'undefined character code'.\n";
-
-static PyObject *PyFT2Font_get_name_index(PyFT2Font *self, PyObject *args)
-{
- char *glyphname;
- long name_index;
- if (!PyArg_ParseTuple(args, "s:get_name_index", &glyphname)) {
- return NULL;
- }
- CALL_CPP("get_name_index", name_index = self->x->get_name_index(glyphname));
- return PyLong_FromLong(name_index);
-}
-
-const char *PyFT2Font_get_ps_font_info__doc__ =
- "get_ps_font_info(self)\n"
- "--\n\n"
- "Return the information in the PS Font Info structure.\n";
-
-static PyObject *PyFT2Font_get_ps_font_info(PyFT2Font *self, PyObject *args)
-{
- PS_FontInfoRec fontinfo;
-
- FT_Error error = FT_Get_PS_Font_Info(self->x->get_face(), &fontinfo);
- if (error) {
- PyErr_SetString(PyExc_ValueError, "Could not get PS font info");
- return NULL;
- }
-
- return Py_BuildValue("ssssslbhH",
- fontinfo.version ? fontinfo.version : "",
- fontinfo.notice ? fontinfo.notice : "",
- fontinfo.full_name ? fontinfo.full_name : "",
- fontinfo.family_name ? fontinfo.family_name : "",
- fontinfo.weight ? fontinfo.weight : "",
- fontinfo.italic_angle,
- fontinfo.is_fixed_pitch,
- fontinfo.underline_position,
- fontinfo.underline_thickness);
-}
-
-const char *PyFT2Font_get_sfnt_table__doc__ =
- "get_sfnt_table(self, name)\n"
- "--\n\n"
- "Return one of the following SFNT tables: head, maxp, OS/2, hhea, "
- "vhea, post, or pclt.\n";
-
-static PyObject *PyFT2Font_get_sfnt_table(PyFT2Font *self, PyObject *args)
-{
- char *tagname;
- if (!PyArg_ParseTuple(args, "s:get_sfnt_table", &tagname)) {
- return NULL;
- }
-
- int tag;
- const char *tags[] = { "head", "maxp", "OS/2", "hhea", "vhea", "post", "pclt", NULL };
-
- for (tag = 0; tags[tag] != NULL; tag++) {
- if (strncmp(tagname, tags[tag], 5) == 0) {
- break;
- }
- }
-
- void *table = FT_Get_Sfnt_Table(self->x->get_face(), (FT_Sfnt_Tag)tag);
- if (!table) {
- Py_RETURN_NONE;
- }
-
- switch (tag) {
- case 0: {
- char head_dict[] =
- "{s:(h,H), s:(h,H), s:l, s:l, s:H, s:H,"
- "s:(l,l), s:(l,l), s:h, s:h, s:h, s:h, s:H, s:H, s:h, s:h, s:h}";
- TT_Header *t = (TT_Header *)table;
- return Py_BuildValue(head_dict,
- "version", FIXED_MAJOR(t->Table_Version), FIXED_MINOR(t->Table_Version),
- "fontRevision", FIXED_MAJOR(t->Font_Revision), FIXED_MINOR(t->Font_Revision),
- "checkSumAdjustment", t->CheckSum_Adjust,
- "magicNumber", t->Magic_Number,
- "flags", t->Flags,
- "unitsPerEm", t->Units_Per_EM,
- "created", t->Created[0], t->Created[1],
- "modified", t->Modified[0], t->Modified[1],
- "xMin", t->xMin,
- "yMin", t->yMin,
- "xMax", t->xMax,
- "yMax", t->yMax,
- "macStyle", t->Mac_Style,
- "lowestRecPPEM", t->Lowest_Rec_PPEM,
- "fontDirectionHint", t->Font_Direction,
- "indexToLocFormat", t->Index_To_Loc_Format,
- "glyphDataFormat", t->Glyph_Data_Format);
- }
- case 1: {
- char maxp_dict[] =
- "{s:(h,H), s:H, s:H, s:H, s:H, s:H, s:H,"
- "s:H, s:H, s:H, s:H, s:H, s:H, s:H, s:H}";
- TT_MaxProfile *t = (TT_MaxProfile *)table;
- return Py_BuildValue(maxp_dict,
- "version", FIXED_MAJOR(t->version), FIXED_MINOR(t->version),
- "numGlyphs", t->numGlyphs,
- "maxPoints", t->maxPoints,
- "maxContours", t->maxContours,
- "maxComponentPoints", t->maxCompositePoints,
- "maxComponentContours", t->maxCompositeContours,
- "maxZones", t->maxZones,
- "maxTwilightPoints", t->maxTwilightPoints,
- "maxStorage", t->maxStorage,
- "maxFunctionDefs", t->maxFunctionDefs,
- "maxInstructionDefs", t->maxInstructionDefs,
- "maxStackElements", t->maxStackElements,
- "maxSizeOfInstructions", t->maxSizeOfInstructions,
- "maxComponentElements", t->maxComponentElements,
- "maxComponentDepth", t->maxComponentDepth);
- }
- case 2: {
- char os_2_dict[] =
- "{s:H, s:h, s:H, s:H, s:H, s:h, s:h, s:h,"
- "s:h, s:h, s:h, s:h, s:h, s:h, s:h, s:h, s:y#, s:(kkkk),"
- "s:y#, s:H, s:H, s:H}";
- TT_OS2 *t = (TT_OS2 *)table;
- return Py_BuildValue(os_2_dict,
- "version", t->version,
- "xAvgCharWidth", t->xAvgCharWidth,
- "usWeightClass", t->usWeightClass,
- "usWidthClass", t->usWidthClass,
- "fsType", t->fsType,
- "ySubscriptXSize", t->ySubscriptXSize,
- "ySubscriptYSize", t->ySubscriptYSize,
- "ySubscriptXOffset", t->ySubscriptXOffset,
- "ySubscriptYOffset", t->ySubscriptYOffset,
- "ySuperscriptXSize", t->ySuperscriptXSize,
- "ySuperscriptYSize", t->ySuperscriptYSize,
- "ySuperscriptXOffset", t->ySuperscriptXOffset,
- "ySuperscriptYOffset", t->ySuperscriptYOffset,
- "yStrikeoutSize", t->yStrikeoutSize,
- "yStrikeoutPosition", t->yStrikeoutPosition,
- "sFamilyClass", t->sFamilyClass,
- "panose", t->panose, Py_ssize_t(10),
- "ulCharRange", t->ulUnicodeRange1, t->ulUnicodeRange2, t->ulUnicodeRange3, t->ulUnicodeRange4,
- "achVendID", t->achVendID, Py_ssize_t(4),
- "fsSelection", t->fsSelection,
- "fsFirstCharIndex", t->usFirstCharIndex,
- "fsLastCharIndex", t->usLastCharIndex);
- }
- case 3: {
- char hhea_dict[] =
- "{s:(h,H), s:h, s:h, s:h, s:H, s:h, s:h, s:h,"
- "s:h, s:h, s:h, s:h, s:H}";
- TT_HoriHeader *t = (TT_HoriHeader *)table;
- return Py_BuildValue(hhea_dict,
- "version", FIXED_MAJOR(t->Version), FIXED_MINOR(t->Version),
- "ascent", t->Ascender,
- "descent", t->Descender,
- "lineGap", t->Line_Gap,
- "advanceWidthMax", t->advance_Width_Max,
- "minLeftBearing", t->min_Left_Side_Bearing,
- "minRightBearing", t->min_Right_Side_Bearing,
- "xMaxExtent", t->xMax_Extent,
- "caretSlopeRise", t->caret_Slope_Rise,
- "caretSlopeRun", t->caret_Slope_Run,
- "caretOffset", t->caret_Offset,
- "metricDataFormat", t->metric_Data_Format,
- "numOfLongHorMetrics", t->number_Of_HMetrics);
- }
- case 4: {
- char vhea_dict[] =
- "{s:(h,H), s:h, s:h, s:h, s:H, s:h, s:h, s:h,"
- "s:h, s:h, s:h, s:h, s:H}";
- TT_VertHeader *t = (TT_VertHeader *)table;
- return Py_BuildValue(vhea_dict,
- "version", FIXED_MAJOR(t->Version), FIXED_MINOR(t->Version),
- "vertTypoAscender", t->Ascender,
- "vertTypoDescender", t->Descender,
- "vertTypoLineGap", t->Line_Gap,
- "advanceHeightMax", t->advance_Height_Max,
- "minTopSideBearing", t->min_Top_Side_Bearing,
- "minBottomSizeBearing", t->min_Bottom_Side_Bearing,
- "yMaxExtent", t->yMax_Extent,
- "caretSlopeRise", t->caret_Slope_Rise,
- "caretSlopeRun", t->caret_Slope_Run,
- "caretOffset", t->caret_Offset,
- "metricDataFormat", t->metric_Data_Format,
- "numOfLongVerMetrics", t->number_Of_VMetrics);
- }
- case 5: {
- char post_dict[] = "{s:(h,H), s:(h,H), s:h, s:h, s:k, s:k, s:k, s:k, s:k}";
- TT_Postscript *t = (TT_Postscript *)table;
- return Py_BuildValue(post_dict,
- "format", FIXED_MAJOR(t->FormatType), FIXED_MINOR(t->FormatType),
- "italicAngle", FIXED_MAJOR(t->italicAngle), FIXED_MINOR(t->italicAngle),
- "underlinePosition", t->underlinePosition,
- "underlineThickness", t->underlineThickness,
- "isFixedPitch", t->isFixedPitch,
- "minMemType42", t->minMemType42,
- "maxMemType42", t->maxMemType42,
- "minMemType1", t->minMemType1,
- "maxMemType1", t->maxMemType1);
- }
- case 6: {
- char pclt_dict[] =
- "{s:(h,H), s:k, s:H, s:H, s:H, s:H, s:H, s:H, s:y#, s:y#, s:b, "
- "s:b, s:b}";
- TT_PCLT *t = (TT_PCLT *)table;
- return Py_BuildValue(pclt_dict,
- "version", FIXED_MAJOR(t->Version), FIXED_MINOR(t->Version),
- "fontNumber", t->FontNumber,
- "pitch", t->Pitch,
- "xHeight", t->xHeight,
- "style", t->Style,
- "typeFamily", t->TypeFamily,
- "capHeight", t->CapHeight,
- "symbolSet", t->SymbolSet,
- "typeFace", t->TypeFace, Py_ssize_t(16),
- "characterComplement", t->CharacterComplement, Py_ssize_t(8),
- "strokeWeight", t->StrokeWeight,
- "widthType", t->WidthType,
- "serifStyle", t->SerifStyle);
- }
- default:
- Py_RETURN_NONE;
- }
-}
-
-const char *PyFT2Font_get_path__doc__ =
- "get_path(self)\n"
- "--\n\n"
- "Get the path data from the currently loaded glyph as a tuple of vertices, "
- "codes.\n";
-
-static PyObject *PyFT2Font_get_path(PyFT2Font *self, PyObject *args)
-{
- CALL_CPP("get_path", return self->x->get_path());
-}
-
-const char *PyFT2Font_get_image__doc__ =
- "get_image(self)\n"
- "--\n\n"
- "Return the underlying image buffer for this font object.\n";
-
-static PyObject *PyFT2Font_get_image(PyFT2Font *self, PyObject *args)
-{
- FT2Image &im = self->x->get_image();
- npy_intp dims[] = {(npy_intp)im.get_height(), (npy_intp)im.get_width() };
- return PyArray_SimpleNewFromData(2, dims, NPY_UBYTE, im.get_buffer());
-}
-
-static PyObject *PyFT2Font_postscript_name(PyFT2Font *self, void *closure)
-{
- const char *ps_name = FT_Get_Postscript_Name(self->x->get_face());
- if (ps_name == NULL) {
- ps_name = "UNAVAILABLE";
- }
-
- return PyUnicode_FromString(ps_name);
-}
-
-static PyObject *PyFT2Font_num_faces(PyFT2Font *self, void *closure)
-{
- return PyLong_FromLong(self->x->get_face()->num_faces);
-}
-
-static PyObject *PyFT2Font_family_name(PyFT2Font *self, void *closure)
-{
- const char *name = self->x->get_face()->family_name;
- if (name == NULL) {
- name = "UNAVAILABLE";
- }
- return PyUnicode_FromString(name);
-}
-
-static PyObject *PyFT2Font_style_name(PyFT2Font *self, void *closure)
-{
- const char *name = self->x->get_face()->style_name;
- if (name == NULL) {
- name = "UNAVAILABLE";
- }
- return PyUnicode_FromString(name);
-}
-
-static PyObject *PyFT2Font_face_flags(PyFT2Font *self, void *closure)
-{
- return PyLong_FromLong(self->x->get_face()->face_flags);
-}
-
-static PyObject *PyFT2Font_style_flags(PyFT2Font *self, void *closure)
-{
- return PyLong_FromLong(self->x->get_face()->style_flags);
-}
-
-static PyObject *PyFT2Font_num_glyphs(PyFT2Font *self, void *closure)
-{
- return PyLong_FromLong(self->x->get_face()->num_glyphs);
-}
-
-static PyObject *PyFT2Font_num_fixed_sizes(PyFT2Font *self, void *closure)
-{
- return PyLong_FromLong(self->x->get_face()->num_fixed_sizes);
-}
-
-static PyObject *PyFT2Font_num_charmaps(PyFT2Font *self, void *closure)
-{
- return PyLong_FromLong(self->x->get_face()->num_charmaps);
-}
-
-static PyObject *PyFT2Font_scalable(PyFT2Font *self, void *closure)
-{
- if (FT_IS_SCALABLE(self->x->get_face())) {
- Py_RETURN_TRUE;
- }
- Py_RETURN_FALSE;
-}
-
-static PyObject *PyFT2Font_units_per_EM(PyFT2Font *self, void *closure)
-{
- return PyLong_FromLong(self->x->get_face()->units_per_EM);
-}
-
-static PyObject *PyFT2Font_get_bbox(PyFT2Font *self, void *closure)
-{
- FT_BBox *bbox = &(self->x->get_face()->bbox);
-
- return Py_BuildValue("llll",
- bbox->xMin, bbox->yMin, bbox->xMax, bbox->yMax);
-}
-
-static PyObject *PyFT2Font_ascender(PyFT2Font *self, void *closure)
-{
- return PyLong_FromLong(self->x->get_face()->ascender);
-}
-
-static PyObject *PyFT2Font_descender(PyFT2Font *self, void *closure)
-{
- return PyLong_FromLong(self->x->get_face()->descender);
-}
-
-static PyObject *PyFT2Font_height(PyFT2Font *self, void *closure)
-{
- return PyLong_FromLong(self->x->get_face()->height);
-}
-
-static PyObject *PyFT2Font_max_advance_width(PyFT2Font *self, void *closure)
-{
- return PyLong_FromLong(self->x->get_face()->max_advance_width);
-}
-
-static PyObject *PyFT2Font_max_advance_height(PyFT2Font *self, void *closure)
-{
- return PyLong_FromLong(self->x->get_face()->max_advance_height);
-}
-
-static PyObject *PyFT2Font_underline_position(PyFT2Font *self, void *closure)
-{
- return PyLong_FromLong(self->x->get_face()->underline_position);
-}
-
-static PyObject *PyFT2Font_underline_thickness(PyFT2Font *self, void *closure)
-{
- return PyLong_FromLong(self->x->get_face()->underline_thickness);
-}
-
-static PyObject *PyFT2Font_fname(PyFT2Font *self, void *closure)
-{
- if (self->stream.close) { // Called passed a filename to the constructor.
- return PyObject_GetAttrString(self->py_file, "name");
- } else {
- Py_INCREF(self->py_file);
- return self->py_file;
- }
-}
-
-static int PyFT2Font_get_buffer(PyFT2Font *self, Py_buffer *buf, int flags)
-{
- FT2Image &im = self->x->get_image();
-
- Py_INCREF(self);
- buf->obj = (PyObject *)self;
- buf->buf = im.get_buffer();
- buf->len = im.get_width() * im.get_height();
- buf->readonly = 0;
- buf->format = (char *)"B";
- buf->ndim = 2;
- self->shape[0] = im.get_height();
- self->shape[1] = im.get_width();
- buf->shape = self->shape;
- self->strides[0] = im.get_width();
- self->strides[1] = 1;
- buf->strides = self->strides;
- buf->suboffsets = NULL;
- buf->itemsize = 1;
- buf->internal = NULL;
-
- return 1;
-}
-
-static PyTypeObject *PyFT2Font_init_type()
-{
- static PyGetSetDef getset[] = {
- {(char *)"postscript_name", (getter)PyFT2Font_postscript_name, NULL, NULL, NULL},
- {(char *)"num_faces", (getter)PyFT2Font_num_faces, NULL, NULL, NULL},
- {(char *)"family_name", (getter)PyFT2Font_family_name, NULL, NULL, NULL},
- {(char *)"style_name", (getter)PyFT2Font_style_name, NULL, NULL, NULL},
- {(char *)"face_flags", (getter)PyFT2Font_face_flags, NULL, NULL, NULL},
- {(char *)"style_flags", (getter)PyFT2Font_style_flags, NULL, NULL, NULL},
- {(char *)"num_glyphs", (getter)PyFT2Font_num_glyphs, NULL, NULL, NULL},
- {(char *)"num_fixed_sizes", (getter)PyFT2Font_num_fixed_sizes, NULL, NULL, NULL},
- {(char *)"num_charmaps", (getter)PyFT2Font_num_charmaps, NULL, NULL, NULL},
- {(char *)"scalable", (getter)PyFT2Font_scalable, NULL, NULL, NULL},
- {(char *)"units_per_EM", (getter)PyFT2Font_units_per_EM, NULL, NULL, NULL},
- {(char *)"bbox", (getter)PyFT2Font_get_bbox, NULL, NULL, NULL},
- {(char *)"ascender", (getter)PyFT2Font_ascender, NULL, NULL, NULL},
- {(char *)"descender", (getter)PyFT2Font_descender, NULL, NULL, NULL},
- {(char *)"height", (getter)PyFT2Font_height, NULL, NULL, NULL},
- {(char *)"max_advance_width", (getter)PyFT2Font_max_advance_width, NULL, NULL, NULL},
- {(char *)"max_advance_height", (getter)PyFT2Font_max_advance_height, NULL, NULL, NULL},
- {(char *)"underline_position", (getter)PyFT2Font_underline_position, NULL, NULL, NULL},
- {(char *)"underline_thickness", (getter)PyFT2Font_underline_thickness, NULL, NULL, NULL},
- {(char *)"fname", (getter)PyFT2Font_fname, NULL, NULL, NULL},
- {NULL}
- };
-
- static PyMethodDef methods[] = {
- {"clear", (PyCFunction)PyFT2Font_clear, METH_NOARGS, PyFT2Font_clear__doc__},
- {"set_size", (PyCFunction)PyFT2Font_set_size, METH_VARARGS, PyFT2Font_set_size__doc__},
- {"set_charmap", (PyCFunction)PyFT2Font_set_charmap, METH_VARARGS, PyFT2Font_set_charmap__doc__},
- {"select_charmap", (PyCFunction)PyFT2Font_select_charmap, METH_VARARGS, PyFT2Font_select_charmap__doc__},
- {"get_kerning", (PyCFunction)PyFT2Font_get_kerning, METH_VARARGS, PyFT2Font_get_kerning__doc__},
- {"set_text", (PyCFunction)PyFT2Font_set_text, METH_VARARGS|METH_KEYWORDS, PyFT2Font_set_text__doc__},
- {"_get_fontmap", (PyCFunction)PyFT2Font_get_fontmap, METH_VARARGS|METH_KEYWORDS, PyFT2Font_get_fontmap__doc__},
- {"get_num_glyphs", (PyCFunction)PyFT2Font_get_num_glyphs, METH_NOARGS, PyFT2Font_get_num_glyphs__doc__},
- {"load_char", (PyCFunction)PyFT2Font_load_char, METH_VARARGS|METH_KEYWORDS, PyFT2Font_load_char__doc__},
- {"load_glyph", (PyCFunction)PyFT2Font_load_glyph, METH_VARARGS|METH_KEYWORDS, PyFT2Font_load_glyph__doc__},
- {"get_width_height", (PyCFunction)PyFT2Font_get_width_height, METH_NOARGS, PyFT2Font_get_width_height__doc__},
- {"get_bitmap_offset", (PyCFunction)PyFT2Font_get_bitmap_offset, METH_NOARGS, PyFT2Font_get_bitmap_offset__doc__},
- {"get_descent", (PyCFunction)PyFT2Font_get_descent, METH_NOARGS, PyFT2Font_get_descent__doc__},
- {"draw_glyphs_to_bitmap", (PyCFunction)PyFT2Font_draw_glyphs_to_bitmap, METH_VARARGS|METH_KEYWORDS, PyFT2Font_draw_glyphs_to_bitmap__doc__},
- {"get_xys", (PyCFunction)PyFT2Font_get_xys, METH_VARARGS|METH_KEYWORDS, PyFT2Font_get_xys__doc__},
- {"draw_glyph_to_bitmap", (PyCFunction)PyFT2Font_draw_glyph_to_bitmap, METH_VARARGS|METH_KEYWORDS, PyFT2Font_draw_glyph_to_bitmap__doc__},
- {"get_glyph_name", (PyCFunction)PyFT2Font_get_glyph_name, METH_VARARGS, PyFT2Font_get_glyph_name__doc__},
- {"get_charmap", (PyCFunction)PyFT2Font_get_charmap, METH_NOARGS, PyFT2Font_get_charmap__doc__},
- {"get_char_index", (PyCFunction)PyFT2Font_get_char_index, METH_VARARGS, PyFT2Font_get_char_index__doc__},
- {"get_sfnt", (PyCFunction)PyFT2Font_get_sfnt, METH_NOARGS, PyFT2Font_get_sfnt__doc__},
- {"get_name_index", (PyCFunction)PyFT2Font_get_name_index, METH_VARARGS, PyFT2Font_get_name_index__doc__},
- {"get_ps_font_info", (PyCFunction)PyFT2Font_get_ps_font_info, METH_NOARGS, PyFT2Font_get_ps_font_info__doc__},
- {"get_sfnt_table", (PyCFunction)PyFT2Font_get_sfnt_table, METH_VARARGS, PyFT2Font_get_sfnt_table__doc__},
- {"get_path", (PyCFunction)PyFT2Font_get_path, METH_NOARGS, PyFT2Font_get_path__doc__},
- {"get_image", (PyCFunction)PyFT2Font_get_image, METH_NOARGS, PyFT2Font_get_image__doc__},
- {NULL}
- };
-
- static PyBufferProcs buffer_procs;
- buffer_procs.bf_getbuffer = (getbufferproc)PyFT2Font_get_buffer;
-
- PyFT2FontType.tp_name = "matplotlib.ft2font.FT2Font";
- PyFT2FontType.tp_doc = PyFT2Font_init__doc__;
- PyFT2FontType.tp_basicsize = sizeof(PyFT2Font);
- PyFT2FontType.tp_dealloc = (destructor)PyFT2Font_dealloc;
- PyFT2FontType.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
- PyFT2FontType.tp_methods = methods;
- PyFT2FontType.tp_getset = getset;
- PyFT2FontType.tp_new = PyFT2Font_new;
- PyFT2FontType.tp_init = (initproc)PyFT2Font_init;
- PyFT2FontType.tp_as_buffer = &buffer_procs;
-
- return &PyFT2FontType;
-}
-
-static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "ft2font" };
-
-PyMODINIT_FUNC PyInit_ft2font(void)
-{
- import_array();
-
- if (FT_Init_FreeType(&_ft2Library)) { // initialize library
- return PyErr_Format(
- PyExc_RuntimeError, "Could not initialize the freetype2 library");
- }
- FT_Int major, minor, patch;
- char version_string[64];
- FT_Library_Version(_ft2Library, &major, &minor, &patch);
- snprintf(version_string, sizeof(version_string), "%d.%d.%d", major, minor, patch);
-
- PyObject *m;
- if (!(m = PyModule_Create(&moduledef)) ||
- prepare_and_add_type(PyFT2Image_init_type(), m) ||
- prepare_and_add_type(PyFT2Font_init_type(), m) ||
- // Glyph is not constructible from Python, thus not added to the module.
- PyType_Ready(PyGlyph_init_type()) ||
- PyModule_AddStringConstant(m, "__freetype_version__", version_string) ||
- PyModule_AddStringConstant(m, "__freetype_build_type__", STRINGIFY(FREETYPE_BUILD_TYPE)) ||
- PyModule_AddIntConstant(m, "SCALABLE", FT_FACE_FLAG_SCALABLE) ||
- PyModule_AddIntConstant(m, "FIXED_SIZES", FT_FACE_FLAG_FIXED_SIZES) ||
- PyModule_AddIntConstant(m, "FIXED_WIDTH", FT_FACE_FLAG_FIXED_WIDTH) ||
- PyModule_AddIntConstant(m, "SFNT", FT_FACE_FLAG_SFNT) ||
- PyModule_AddIntConstant(m, "HORIZONTAL", FT_FACE_FLAG_HORIZONTAL) ||
- PyModule_AddIntConstant(m, "VERTICAL", FT_FACE_FLAG_VERTICAL) ||
- PyModule_AddIntConstant(m, "KERNING", FT_FACE_FLAG_KERNING) ||
- PyModule_AddIntConstant(m, "FAST_GLYPHS", FT_FACE_FLAG_FAST_GLYPHS) ||
- PyModule_AddIntConstant(m, "MULTIPLE_MASTERS", FT_FACE_FLAG_MULTIPLE_MASTERS) ||
- PyModule_AddIntConstant(m, "GLYPH_NAMES", FT_FACE_FLAG_GLYPH_NAMES) ||
- PyModule_AddIntConstant(m, "EXTERNAL_STREAM", FT_FACE_FLAG_EXTERNAL_STREAM) ||
- PyModule_AddIntConstant(m, "ITALIC", FT_STYLE_FLAG_ITALIC) ||
- PyModule_AddIntConstant(m, "BOLD", FT_STYLE_FLAG_BOLD) ||
- PyModule_AddIntConstant(m, "KERNING_DEFAULT", FT_KERNING_DEFAULT) ||
- PyModule_AddIntConstant(m, "KERNING_UNFITTED", FT_KERNING_UNFITTED) ||
- PyModule_AddIntConstant(m, "KERNING_UNSCALED", FT_KERNING_UNSCALED) ||
- PyModule_AddIntConstant(m, "LOAD_DEFAULT", FT_LOAD_DEFAULT) ||
- PyModule_AddIntConstant(m, "LOAD_NO_SCALE", FT_LOAD_NO_SCALE) ||
- PyModule_AddIntConstant(m, "LOAD_NO_HINTING", FT_LOAD_NO_HINTING) ||
- PyModule_AddIntConstant(m, "LOAD_RENDER", FT_LOAD_RENDER) ||
- PyModule_AddIntConstant(m, "LOAD_NO_BITMAP", FT_LOAD_NO_BITMAP) ||
- PyModule_AddIntConstant(m, "LOAD_VERTICAL_LAYOUT", FT_LOAD_VERTICAL_LAYOUT) ||
- PyModule_AddIntConstant(m, "LOAD_FORCE_AUTOHINT", FT_LOAD_FORCE_AUTOHINT) ||
- PyModule_AddIntConstant(m, "LOAD_CROP_BITMAP", FT_LOAD_CROP_BITMAP) ||
- PyModule_AddIntConstant(m, "LOAD_PEDANTIC", FT_LOAD_PEDANTIC) ||
- PyModule_AddIntConstant(m, "LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH", FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH) ||
- PyModule_AddIntConstant(m, "LOAD_NO_RECURSE", FT_LOAD_NO_RECURSE) ||
- PyModule_AddIntConstant(m, "LOAD_IGNORE_TRANSFORM", FT_LOAD_IGNORE_TRANSFORM) ||
- PyModule_AddIntConstant(m, "LOAD_MONOCHROME", FT_LOAD_MONOCHROME) ||
- PyModule_AddIntConstant(m, "LOAD_LINEAR_DESIGN", FT_LOAD_LINEAR_DESIGN) ||
- PyModule_AddIntConstant(m, "LOAD_NO_AUTOHINT", (unsigned long)FT_LOAD_NO_AUTOHINT) ||
- PyModule_AddIntConstant(m, "LOAD_TARGET_NORMAL", (unsigned long)FT_LOAD_TARGET_NORMAL) ||
- PyModule_AddIntConstant(m, "LOAD_TARGET_LIGHT", (unsigned long)FT_LOAD_TARGET_LIGHT) ||
- PyModule_AddIntConstant(m, "LOAD_TARGET_MONO", (unsigned long)FT_LOAD_TARGET_MONO) ||
- PyModule_AddIntConstant(m, "LOAD_TARGET_LCD", (unsigned long)FT_LOAD_TARGET_LCD) ||
- PyModule_AddIntConstant(m, "LOAD_TARGET_LCD_V", (unsigned long)FT_LOAD_TARGET_LCD_V)) {
- FT_Done_FreeType(_ft2Library);
- Py_XDECREF(m);
- return NULL;
- }
-
- return m;
-}
diff --git a/contrib/python/matplotlib/py3/src/mplutils.h b/contrib/python/matplotlib/py3/src/mplutils.h
deleted file mode 100644
index 6eb89899ca..0000000000
--- a/contrib/python/matplotlib/py3/src/mplutils.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/* -*- mode: c++; c-basic-offset: 4 -*- */
-
-/* Small utilities that are shared by most extension modules. */
-
-#ifndef MPLUTILS_H
-#define MPLUTILS_H
-#define PY_SSIZE_T_CLEAN
-
-#include <Python.h>
-#include <stdint.h>
-
-#ifdef _POSIX_C_SOURCE
-# undef _POSIX_C_SOURCE
-#endif
-#ifndef _AIX
-#ifdef _XOPEN_SOURCE
-# undef _XOPEN_SOURCE
-#endif
-#endif
-
-// Prevent multiple conflicting definitions of swab from stdlib.h and unistd.h
-#if defined(__sun) || defined(sun)
-#if defined(_XPG4)
-#undef _XPG4
-#endif
-#if defined(_XPG3)
-#undef _XPG3
-#endif
-#endif
-
-
-inline int mpl_round_to_int(double v)
-{
- return (int)(v + ((v >= 0.0) ? 0.5 : -0.5));
-}
-
-inline double mpl_round(double v)
-{
- return (double)mpl_round_to_int(v);
-}
-
-// 'kind' codes for paths.
-enum {
- STOP = 0,
- MOVETO = 1,
- LINETO = 2,
- CURVE3 = 3,
- CURVE4 = 4,
- CLOSEPOLY = 0x4f
-};
-
-const size_t NUM_VERTICES[] = { 1, 1, 1, 2, 3, 1 };
-
-inline int prepare_and_add_type(PyTypeObject *type, PyObject *module)
-{
- if (PyType_Ready(type)) {
- return -1;
- }
- char const* ptr = strrchr(type->tp_name, '.');
- if (!ptr) {
- PyErr_SetString(PyExc_ValueError, "tp_name should be a qualified name");
- return -1;
- }
- if (PyModule_AddObject(module, ptr + 1, (PyObject *)type)) {
- return -1;
- }
- return 0;
-}
-
-#ifdef __cplusplus // not for macosx.m
-// Check that array has shape (N, d1) or (N, d1, d2). We cast d1, d2 to longs
-// so that we don't need to access the NPY_INTP_FMT macro here.
-
-template<typename T>
-inline bool check_trailing_shape(T array, char const* name, long d1)
-{
- if (array.dim(1) != d1) {
- PyErr_Format(PyExc_ValueError,
- "%s must have shape (N, %ld), got (%ld, %ld)",
- name, d1, array.dim(0), array.dim(1));
- return false;
- }
- return true;
-}
-
-template<typename T>
-inline bool check_trailing_shape(T array, char const* name, long d1, long d2)
-{
- if (array.dim(1) != d1 || array.dim(2) != d2) {
- PyErr_Format(PyExc_ValueError,
- "%s must have shape (N, %ld, %ld), got (%ld, %ld, %ld)",
- name, d1, d2, array.dim(0), array.dim(1), array.dim(2));
- return false;
- }
- return true;
-}
-#endif
-
-#endif
diff --git a/contrib/python/matplotlib/py3/src/numpy_cpp.h b/contrib/python/matplotlib/py3/src/numpy_cpp.h
deleted file mode 100644
index 36c763d158..0000000000
--- a/contrib/python/matplotlib/py3/src/numpy_cpp.h
+++ /dev/null
@@ -1,578 +0,0 @@
-/* -*- mode: c++; c-basic-offset: 4 -*- */
-
-#ifndef MPL_NUMPY_CPP_H
-#define MPL_NUMPY_CPP_H
-#define PY_SSIZE_T_CLEAN
-/***************************************************************************
- * This file is based on original work by Mark Wiebe, available at:
- *
- * http://github.com/mwiebe/numpy-cpp
- *
- * However, the needs of matplotlib wrappers, such as treating an
- * empty array as having the correct dimensions, have made this rather
- * matplotlib-specific, so it's no longer compatible with the
- * original.
- */
-
-#include "py_exceptions.h"
-
-#include <complex>
-
-#ifdef _POSIX_C_SOURCE
-# undef _POSIX_C_SOURCE
-#endif
-#ifndef _AIX
-#ifdef _XOPEN_SOURCE
-# undef _XOPEN_SOURCE
-#endif
-#endif
-
-// Prevent multiple conflicting definitions of swab from stdlib.h and unistd.h
-#if defined(__sun) || defined(sun)
-#if defined(_XPG4)
-#undef _XPG4
-#endif
-#if defined(_XPG3)
-#undef _XPG3
-#endif
-#endif
-
-#include <Python.h>
-#include <numpy/ndarrayobject.h>
-
-namespace numpy
-{
-
-// Type traits for the NumPy types
-template <typename T>
-struct type_num_of;
-
-/* Be careful with bool arrays as python has sizeof(npy_bool) == 1, but it is
- * not always the case that sizeof(bool) == 1. Using the array_view_accessors
- * is always fine regardless of sizeof(bool), so do this rather than using
- * array.data() and pointer arithmetic which will not work correctly if
- * sizeof(bool) != 1. */
-template <> struct type_num_of<bool>
-{
- enum {
- value = NPY_BOOL
- };
-};
-template <>
-struct type_num_of<npy_byte>
-{
- enum {
- value = NPY_BYTE
- };
-};
-template <>
-struct type_num_of<npy_ubyte>
-{
- enum {
- value = NPY_UBYTE
- };
-};
-template <>
-struct type_num_of<npy_short>
-{
- enum {
- value = NPY_SHORT
- };
-};
-template <>
-struct type_num_of<npy_ushort>
-{
- enum {
- value = NPY_USHORT
- };
-};
-template <>
-struct type_num_of<npy_int>
-{
- enum {
- value = NPY_INT
- };
-};
-template <>
-struct type_num_of<npy_uint>
-{
- enum {
- value = NPY_UINT
- };
-};
-template <>
-struct type_num_of<npy_long>
-{
- enum {
- value = NPY_LONG
- };
-};
-template <>
-struct type_num_of<npy_ulong>
-{
- enum {
- value = NPY_ULONG
- };
-};
-template <>
-struct type_num_of<npy_longlong>
-{
- enum {
- value = NPY_LONGLONG
- };
-};
-template <>
-struct type_num_of<npy_ulonglong>
-{
- enum {
- value = NPY_ULONGLONG
- };
-};
-template <>
-struct type_num_of<npy_float>
-{
- enum {
- value = NPY_FLOAT
- };
-};
-template <>
-struct type_num_of<npy_double>
-{
- enum {
- value = NPY_DOUBLE
- };
-};
-#if NPY_LONGDOUBLE != NPY_DOUBLE
-template <>
-struct type_num_of<npy_longdouble>
-{
- enum {
- value = NPY_LONGDOUBLE
- };
-};
-#endif
-template <>
-struct type_num_of<npy_cfloat>
-{
- enum {
- value = NPY_CFLOAT
- };
-};
-template <>
-struct type_num_of<std::complex<npy_float> >
-{
- enum {
- value = NPY_CFLOAT
- };
-};
-template <>
-struct type_num_of<npy_cdouble>
-{
- enum {
- value = NPY_CDOUBLE
- };
-};
-template <>
-struct type_num_of<std::complex<npy_double> >
-{
- enum {
- value = NPY_CDOUBLE
- };
-};
-#if NPY_CLONGDOUBLE != NPY_CDOUBLE
-template <>
-struct type_num_of<npy_clongdouble>
-{
- enum {
- value = NPY_CLONGDOUBLE
- };
-};
-template <>
-struct type_num_of<std::complex<npy_longdouble> >
-{
- enum {
- value = NPY_CLONGDOUBLE
- };
-};
-#endif
-template <>
-struct type_num_of<PyObject *>
-{
- enum {
- value = NPY_OBJECT
- };
-};
-template <typename T>
-struct type_num_of<T &>
-{
- enum {
- value = type_num_of<T>::value
- };
-};
-template <typename T>
-struct type_num_of<const T>
-{
- enum {
- value = type_num_of<T>::value
- };
-};
-
-template <typename T>
-struct is_const
-{
- enum {
- value = false
- };
-};
-template <typename T>
-struct is_const<const T>
-{
- enum {
- value = true
- };
-};
-
-namespace detail
-{
-template <template <typename, int> class AV, typename T, int ND>
-class array_view_accessors;
-
-template <template <typename, int> class AV, typename T>
-class array_view_accessors<AV, T, 1>
-{
- public:
- typedef AV<T, 1> AVC;
- typedef T sub_t;
-
- T &operator()(npy_intp i)
- {
- AVC *self = static_cast<AVC *>(this);
-
- return *reinterpret_cast<T *>(self->m_data + self->m_strides[0] * i);
- }
-
- const T &operator()(npy_intp i) const
- {
- const AVC *self = static_cast<const AVC *>(this);
-
- return *reinterpret_cast<const T *>(self->m_data + self->m_strides[0] * i);
- }
-
- T &operator[](npy_intp i)
- {
- AVC *self = static_cast<AVC *>(this);
-
- return *reinterpret_cast<T *>(self->m_data + self->m_strides[0] * i);
- }
-
- const T &operator[](npy_intp i) const
- {
- const AVC *self = static_cast<const AVC *>(this);
-
- return *reinterpret_cast<const T *>(self->m_data + self->m_strides[0] * i);
- }
-};
-
-template <template <typename, int> class AV, typename T>
-class array_view_accessors<AV, T, 2>
-{
- public:
- typedef AV<T, 2> AVC;
- typedef AV<T, 1> sub_t;
-
- T &operator()(npy_intp i, npy_intp j)
- {
- AVC *self = static_cast<AVC *>(this);
-
- return *reinterpret_cast<T *>(self->m_data + self->m_strides[0] * i +
- self->m_strides[1] * j);
- }
-
- const T &operator()(npy_intp i, npy_intp j) const
- {
- const AVC *self = static_cast<const AVC *>(this);
-
- return *reinterpret_cast<const T *>(self->m_data + self->m_strides[0] * i +
- self->m_strides[1] * j);
- }
-
- sub_t subarray(npy_intp i) const
- {
- const AVC *self = static_cast<const AVC *>(this);
-
- return sub_t(self->m_arr,
- self->m_data + self->m_strides[0] * i,
- self->m_shape + 1,
- self->m_strides + 1);
- }
-};
-
-template <template <typename, int> class AV, typename T>
-class array_view_accessors<AV, T, 3>
-{
- public:
- typedef AV<T, 3> AVC;
- typedef AV<T, 2> sub_t;
-
- T &operator()(npy_intp i, npy_intp j, npy_intp k)
- {
- AVC *self = static_cast<AVC *>(this);
-
- return *reinterpret_cast<T *>(self->m_data + self->m_strides[0] * i +
- self->m_strides[1] * j + self->m_strides[2] * k);
- }
-
- const T &operator()(npy_intp i, npy_intp j, npy_intp k) const
- {
- const AVC *self = static_cast<const AVC *>(this);
-
- return *reinterpret_cast<const T *>(self->m_data + self->m_strides[0] * i +
- self->m_strides[1] * j + self->m_strides[2] * k);
- }
-
- sub_t subarray(npy_intp i) const
- {
- const AVC *self = static_cast<const AVC *>(this);
-
- return sub_t(self->m_arr,
- self->m_data + self->m_strides[0] * i,
- self->m_shape + 1,
- self->m_strides + 1);
- }
-
-
-};
-
-// When adding instantiations of array_view_accessors, remember to add entries
-// to zeros[] below.
-
-}
-
-static npy_intp zeros[] = { 0, 0, 0 };
-
-template <typename T, int ND>
-class array_view : public detail::array_view_accessors<array_view, T, ND>
-{
- friend class detail::array_view_accessors<numpy::array_view, T, ND>;
-
- private:
- // Copies of the array data
- PyArrayObject *m_arr;
- npy_intp *m_shape;
- npy_intp *m_strides;
- char *m_data;
-
- public:
- typedef T value_type;
-
- enum {
- ndim = ND
- };
-
- array_view() : m_arr(NULL), m_data(NULL)
- {
- m_shape = zeros;
- m_strides = zeros;
- }
-
- array_view(PyObject *arr, bool contiguous = false) : m_arr(NULL), m_data(NULL)
- {
- if (!set(arr, contiguous)) {
- throw py::exception();
- }
- }
-
- array_view(const array_view &other) : m_arr(NULL), m_data(NULL)
- {
- m_arr = other.m_arr;
- Py_XINCREF(m_arr);
- m_data = other.m_data;
- m_shape = other.m_shape;
- m_strides = other.m_strides;
- }
-
- array_view(PyArrayObject *arr, char *data, npy_intp *shape, npy_intp *strides)
- {
- m_arr = arr;
- Py_XINCREF(arr);
- m_data = data;
- m_shape = shape;
- m_strides = strides;
- }
-
- array_view(PyArrayObject *arr)
- {
- m_arr = arr;
- Py_XINCREF(arr);
- m_shape = PyArray_DIMS(m_arr);
- m_strides = PyArray_STRIDES(m_arr);
- m_data = PyArray_BYTES(m_arr);
- }
-
- array_view(npy_intp shape[ND]) : m_arr(NULL), m_shape(NULL), m_strides(NULL), m_data(NULL)
- {
- PyObject *arr = PyArray_SimpleNew(ND, shape, type_num_of<T>::value);
- if (arr == NULL) {
- throw py::exception();
- }
- if (!set(arr, true)) {
- Py_DECREF(arr);
- throw py::exception();
- }
- Py_DECREF(arr);
- }
-
- ~array_view()
- {
- Py_XDECREF(m_arr);
- }
-
- array_view& operator=(const array_view &other)
- {
- if (this != &other)
- {
- Py_XDECREF(m_arr);
- m_arr = other.m_arr;
- Py_XINCREF(m_arr);
- m_data = other.m_data;
- m_shape = other.m_shape;
- m_strides = other.m_strides;
- }
- return *this;
- }
-
- bool set(PyObject *arr, bool contiguous = false)
- {
- PyArrayObject *tmp;
-
- if (arr == NULL || arr == Py_None) {
- Py_XDECREF(m_arr);
- m_arr = NULL;
- m_data = NULL;
- m_shape = zeros;
- m_strides = zeros;
- } else {
- if (contiguous) {
- tmp = (PyArrayObject *)PyArray_ContiguousFromAny(arr, type_num_of<T>::value, 0, ND);
- } else {
- tmp = (PyArrayObject *)PyArray_FromObject(arr, type_num_of<T>::value, 0, ND);
- }
- if (tmp == NULL) {
- return false;
- }
-
- if (PyArray_NDIM(tmp) == 0 || PyArray_DIM(tmp, 0) == 0) {
- Py_XDECREF(m_arr);
- m_arr = NULL;
- m_data = NULL;
- m_shape = zeros;
- m_strides = zeros;
- if (PyArray_NDIM(tmp) == 0 && ND == 0) {
- m_arr = tmp;
- return true;
- }
- }
- if (PyArray_NDIM(tmp) != ND) {
- PyErr_Format(PyExc_ValueError,
- "Expected %d-dimensional array, got %d",
- ND,
- PyArray_NDIM(tmp));
- Py_DECREF(tmp);
- return false;
- }
-
- /* Copy some of the data to the view object for faster access */
- Py_XDECREF(m_arr);
- m_arr = tmp;
- m_shape = PyArray_DIMS(m_arr);
- m_strides = PyArray_STRIDES(m_arr);
- m_data = PyArray_BYTES(tmp);
- }
-
- return true;
- }
-
- npy_intp dim(size_t i) const
- {
- if (i >= ND) {
- return 0;
- }
- return m_shape[i];
- }
-
- /*
- In most cases, code should use size() instead of dim(0), since
- size() == 0 when any dimension is 0.
- */
- size_t size() const
- {
- bool empty = (ND == 0);
- for (size_t i = 0; i < ND; i++) {
- if (m_shape[i] == 0) {
- empty = true;
- }
- }
- if (empty) {
- return 0;
- } else {
- return (size_t)dim(0);
- }
- }
-
- bool empty() const
- {
- return size() == 0;
- }
-
- // Do not use this for array_view<bool, ND>. See comment near top of file.
- const T *data() const
- {
- return (const T *)m_data;
- }
-
- // Do not use this for array_view<bool, ND>. See comment near top of file.
- T *data()
- {
- return (T *)m_data;
- }
-
- // Return a new reference.
- PyObject *pyobj()
- {
- Py_XINCREF(m_arr);
- return (PyObject *)m_arr;
- }
-
- // Steal a reference.
- PyObject *pyobj_steal()
- {
- return (PyObject *)m_arr;
- }
-
- static int converter(PyObject *obj, void *arrp)
- {
- array_view<T, ND> *arr = (array_view<T, ND> *)arrp;
-
- if (!arr->set(obj)) {
- return 0;
- }
-
- return 1;
- }
-
- static int converter_contiguous(PyObject *obj, void *arrp)
- {
- array_view<T, ND> *arr = (array_view<T, ND> *)arrp;
-
- if (!arr->set(obj, true)) {
- return 0;
- }
-
- return 1;
- }
-};
-
-} // namespace numpy
-
-
-#endif
diff --git a/contrib/python/matplotlib/py3/src/path_converters.h b/contrib/python/matplotlib/py3/src/path_converters.h
deleted file mode 100644
index 8583d84855..0000000000
--- a/contrib/python/matplotlib/py3/src/path_converters.h
+++ /dev/null
@@ -1,1106 +0,0 @@
-/* -*- mode: c++; c-basic-offset: 4 -*- */
-
-#ifndef MPL_PATH_CONVERTERS_H
-#define MPL_PATH_CONVERTERS_H
-
-#include <cmath>
-#include <stdint.h>
-#include "agg_path_storage.h"
-#include "agg_clip_liang_barsky.h"
-#include "mplutils.h"
-#include "agg_conv_segmentator.h"
-
-/*
- This file contains a number of vertex converters that modify
- paths. They all work as iterators, where the output is generated
- on-the-fly, and don't require a copy of the full data.
-
- Each class represents a discrete step in a "path-cleansing" pipeline.
- They are currently applied in the following order in the Agg backend:
-
- 1. Affine transformation (implemented in Agg, not here)
-
- 2. PathNanRemover: skips over segments containing non-finite numbers
- by inserting MOVETO commands
-
- 3. PathClipper: Clips line segments to a given rectangle. This is
- helpful for data reduction, and also to avoid a limitation in
- Agg where coordinates cannot be larger than 24-bit signed
- integers.
-
- 4. PathSnapper: Rounds the path to the nearest center-pixels.
- This makes rectilinear curves look much better.
-
- 5. PathSimplifier: Removes line segments from highly dense paths
- that would not have an impact on their appearance. Speeds up
- rendering and reduces file sizes.
-
- 6. curve-to-line-segment conversion (implemented in Agg, not here)
-
- 7. stroking (implemented in Agg, not here)
- */
-
-/************************************************************
- This is a base class for vertex converters that need to queue their
- output. It is designed to be as fast as possible vs. the STL's queue
- which is more flexible.
- */
-template <int QueueSize>
-class EmbeddedQueue
-{
- protected:
- EmbeddedQueue() : m_queue_read(0), m_queue_write(0)
- {
- // empty
- }
-
- struct item
- {
- item()
- {
- }
-
- inline void set(const unsigned cmd_, const double x_, const double y_)
- {
- cmd = cmd_;
- x = x_;
- y = y_;
- }
- unsigned cmd;
- double x;
- double y;
- };
- int m_queue_read;
- int m_queue_write;
- item m_queue[QueueSize];
-
- inline void queue_push(const unsigned cmd, const double x, const double y)
- {
- m_queue[m_queue_write++].set(cmd, x, y);
- }
-
- inline bool queue_nonempty()
- {
- return m_queue_read < m_queue_write;
- }
-
- inline bool queue_pop(unsigned *cmd, double *x, double *y)
- {
- if (queue_nonempty()) {
- const item &front = m_queue[m_queue_read++];
- *cmd = front.cmd;
- *x = front.x;
- *y = front.y;
-
- return true;
- }
-
- m_queue_read = 0;
- m_queue_write = 0;
-
- return false;
- }
-
- inline void queue_clear()
- {
- m_queue_read = 0;
- m_queue_write = 0;
- }
-};
-
-/* Defines when path segment types have more than one vertex */
-static const size_t num_extra_points_map[] =
- {0, 0, 0, 1,
- 2, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0
- };
-
-/* An implementation of a simple linear congruential random number
- generator. This is a "classic" and fast RNG which works fine for
- our purposes of sketching lines, but should not be used for things
- that matter, like crypto. We are implementing this ourselves
- rather than using the C stdlib so that the seed state is not shared
- with other third-party code. There are recent C++ options, but we
- still require nothing later than C++98 for compatibility
- reasons. */
-class RandomNumberGenerator
-{
-private:
- /* These are the same constants from MS Visual C++, which
- has the nice property that the modulus is 2^32, thus
- saving an explicit modulo operation
- */
- static const uint32_t a = 214013;
- static const uint32_t c = 2531011;
- uint32_t m_seed;
-
-public:
- RandomNumberGenerator() : m_seed(0) {}
- RandomNumberGenerator(int seed) : m_seed(seed) {}
-
- void seed(int seed)
- {
- m_seed = seed;
- }
-
- double get_double()
- {
- m_seed = (a * m_seed + c);
- return (double)m_seed / (double)(1LL << 32);
- }
-};
-
-/*
- PathNanRemover is a vertex converter that removes non-finite values
- from the vertices list, and inserts MOVETO commands as necessary to
- skip over them. If a curve segment contains at least one non-finite
- value, the entire curve segment will be skipped.
- */
-template <class VertexSource>
-class PathNanRemover : protected EmbeddedQueue<4>
-{
- VertexSource *m_source;
- bool m_remove_nans;
- bool m_has_codes;
- bool valid_segment_exists;
- bool m_last_segment_valid;
- bool m_was_broken;
- double m_initX;
- double m_initY;
-
- public:
- /* has_codes should be true if the path contains bezier curve segments, or
- * closed loops, as this requires a slower algorithm to remove the NaNs.
- * When in doubt, set to true.
- */
- PathNanRemover(VertexSource &source, bool remove_nans, bool has_codes)
- : m_source(&source), m_remove_nans(remove_nans), m_has_codes(has_codes),
- m_last_segment_valid(false), m_was_broken(false),
- m_initX(nan("")), m_initY(nan(""))
- {
- // ignore all close/end_poly commands until after the first valid
- // (nan-free) command is encountered
- valid_segment_exists = false;
- }
-
- inline void rewind(unsigned path_id)
- {
- queue_clear();
- m_source->rewind(path_id);
- }
-
- inline unsigned vertex(double *x, double *y)
- {
- unsigned code;
-
- if (!m_remove_nans) {
- return m_source->vertex(x, y);
- }
-
- if (m_has_codes) {
- /* This is the slow method for when there might be curves or closed
- * loops. */
- if (queue_pop(&code, x, y)) {
- return code;
- }
-
- bool needs_move_to = false;
- while (true) {
- /* The approach here is to push each full curve
- segment into the queue. If any non-finite values
- are found along the way, the queue is emptied, and
- the next curve segment is handled. */
- code = m_source->vertex(x, y);
- /* The vertices attached to STOP and CLOSEPOLY are never used,
- * so we leave them as-is even if NaN. */
- if (code == agg::path_cmd_stop) {
- return code;
- } else if (code == (agg::path_cmd_end_poly |
- agg::path_flags_close) &&
- valid_segment_exists) {
- /* However, CLOSEPOLY only makes sense if a valid MOVETO
- * command has already been emitted. But if a NaN was
- * removed in the path, then we cannot close it as it is no
- * longer a loop. We must emulate that by inserting a
- * LINETO instead. */
- if (m_was_broken) {
- if (m_last_segment_valid && (
- std::isfinite(m_initX) &&
- std::isfinite(m_initY))) {
- /* Join to start if both ends are valid. */
- queue_push(agg::path_cmd_line_to, m_initX, m_initY);
- break;
- } else {
- /* Skip the close, in case there are additional
- * subpaths. */
- continue;
- }
- m_was_broken = false;
- break;
- } else {
- return code;
- }
- } else if (code == agg::path_cmd_move_to) {
- /* Save the initial point in order to produce the last
- * segment closing a loop, *if* we broke the loop. */
- m_initX = *x;
- m_initY = *y;
- m_was_broken = false;
- }
-
- if (needs_move_to) {
- queue_push(agg::path_cmd_move_to, *x, *y);
- }
-
- size_t num_extra_points = num_extra_points_map[code & 0xF];
- m_last_segment_valid = (std::isfinite(*x) && std::isfinite(*y));
- queue_push(code, *x, *y);
-
- /* Note: this test cannot be short-circuited, since we need to
- advance through the entire curve no matter what */
- for (size_t i = 0; i < num_extra_points; ++i) {
- m_source->vertex(x, y);
- m_last_segment_valid = m_last_segment_valid &&
- (std::isfinite(*x) && std::isfinite(*y));
- queue_push(code, *x, *y);
- }
-
- if (m_last_segment_valid) {
- valid_segment_exists = true;
- break;
- }
-
- m_was_broken = true;
- queue_clear();
-
- /* If the last point is finite, we use that for the
- moveto, otherwise, we'll use the first vertex of
- the next curve. */
- if (std::isfinite(*x) && std::isfinite(*y)) {
- queue_push(agg::path_cmd_move_to, *x, *y);
- needs_move_to = false;
- } else {
- needs_move_to = true;
- }
- }
-
- if (queue_pop(&code, x, y)) {
- return code;
- } else {
- return agg::path_cmd_stop;
- }
- } else // !m_has_codes
- {
- /* This is the fast path for when we know we have no codes. */
- code = m_source->vertex(x, y);
-
- if (code == agg::path_cmd_stop ||
- (code == (agg::path_cmd_end_poly | agg::path_flags_close) &&
- valid_segment_exists)) {
- return code;
- }
-
- if (!(std::isfinite(*x) && std::isfinite(*y))) {
- do {
- code = m_source->vertex(x, y);
- if (code == agg::path_cmd_stop ||
- (code == (agg::path_cmd_end_poly | agg::path_flags_close) &&
- valid_segment_exists)) {
- return code;
- }
- } while (!(std::isfinite(*x) && std::isfinite(*y)));
- return agg::path_cmd_move_to;
- }
- valid_segment_exists = true;
- return code;
- }
- }
-};
-
-/************************************************************
- PathClipper uses the Liang-Barsky line clipping algorithm (as
- implemented in Agg) to clip the path to a given rectangle. Lines
- will never extend outside of the rectangle. Curve segments are not
- clipped, but are always included in their entirety.
- */
-template <class VertexSource>
-class PathClipper : public EmbeddedQueue<3>
-{
- VertexSource *m_source;
- bool m_do_clipping;
- agg::rect_base<double> m_cliprect;
- double m_lastX;
- double m_lastY;
- bool m_moveto;
- double m_initX;
- double m_initY;
- bool m_has_init;
- bool m_was_clipped;
-
- public:
- PathClipper(VertexSource &source, bool do_clipping, double width, double height)
- : m_source(&source),
- m_do_clipping(do_clipping),
- m_cliprect(-1.0, -1.0, width + 1.0, height + 1.0),
- m_lastX(nan("")),
- m_lastY(nan("")),
- m_moveto(true),
- m_initX(nan("")),
- m_initY(nan("")),
- m_has_init(false),
- m_was_clipped(false)
- {
- // empty
- }
-
- PathClipper(VertexSource &source, bool do_clipping, const agg::rect_base<double> &rect)
- : m_source(&source),
- m_do_clipping(do_clipping),
- m_cliprect(rect),
- m_lastX(nan("")),
- m_lastY(nan("")),
- m_moveto(true),
- m_initX(nan("")),
- m_initY(nan("")),
- m_has_init(false),
- m_was_clipped(false)
- {
- m_cliprect.x1 -= 1.0;
- m_cliprect.y1 -= 1.0;
- m_cliprect.x2 += 1.0;
- m_cliprect.y2 += 1.0;
- }
-
- inline void rewind(unsigned path_id)
- {
- m_has_init = false;
- m_was_clipped = false;
- m_moveto = true;
- m_source->rewind(path_id);
- }
-
- int draw_clipped_line(double x0, double y0, double x1, double y1,
- bool closed=false)
- {
- unsigned moved = agg::clip_line_segment(&x0, &y0, &x1, &y1, m_cliprect);
- // moved >= 4 - Fully clipped
- // moved & 1 != 0 - First point has been moved
- // moved & 2 != 0 - Second point has been moved
- m_was_clipped = m_was_clipped || (moved != 0);
- if (moved < 4) {
- if (moved & 1 || m_moveto) {
- queue_push(agg::path_cmd_move_to, x0, y0);
- }
- queue_push(agg::path_cmd_line_to, x1, y1);
- if (closed && !m_was_clipped) {
- // Close the path only if the end point hasn't moved.
- queue_push(agg::path_cmd_end_poly | agg::path_flags_close,
- x1, y1);
- }
-
- m_moveto = false;
- return 1;
- }
-
- return 0;
- }
-
- unsigned vertex(double *x, double *y)
- {
- unsigned code;
- bool emit_moveto = false;
-
- if (!m_do_clipping) {
- // If not doing any clipping, just pass along the vertices verbatim
- return m_source->vertex(x, y);
- }
-
- /* This is the slow path where we actually do clipping */
-
- if (queue_pop(&code, x, y)) {
- return code;
- }
-
- while ((code = m_source->vertex(x, y)) != agg::path_cmd_stop) {
- emit_moveto = false;
-
- switch (code) {
- case (agg::path_cmd_end_poly | agg::path_flags_close):
- if (m_has_init) {
- // Queue the line from last point to the initial point, and
- // if never clipped, add a close code.
- draw_clipped_line(m_lastX, m_lastY, m_initX, m_initY,
- true);
- } else {
- // An empty path that is immediately closed.
- queue_push(
- agg::path_cmd_end_poly | agg::path_flags_close,
- m_lastX, m_lastY);
- }
- // If paths were not clipped, then the above code queued
- // something, and we should exit the loop. Otherwise, continue
- // to the next point, as there may be a new subpath.
- if (queue_nonempty()) {
- goto exit_loop;
- }
- break;
-
- case agg::path_cmd_move_to:
-
- // was the last command a moveto (and we have
- // seen at least one command ?
- // if so, shove it in the queue if in clip box
- if (m_moveto && m_has_init &&
- m_lastX >= m_cliprect.x1 &&
- m_lastX <= m_cliprect.x2 &&
- m_lastY >= m_cliprect.y1 &&
- m_lastY <= m_cliprect.y2) {
- // push the last moveto onto the queue
- queue_push(agg::path_cmd_move_to, m_lastX, m_lastY);
- // flag that we need to emit it
- emit_moveto = true;
- }
- // update the internal state for this moveto
- m_initX = m_lastX = *x;
- m_initY = m_lastY = *y;
- m_has_init = true;
- m_moveto = true;
- m_was_clipped = false;
- // if the last command was moveto exit the loop to emit the code
- if (emit_moveto) {
- goto exit_loop;
- }
- // else, break and get the next point
- break;
-
- case agg::path_cmd_line_to:
- if (draw_clipped_line(m_lastX, m_lastY, *x, *y)) {
- m_lastX = *x;
- m_lastY = *y;
- goto exit_loop;
- }
- m_lastX = *x;
- m_lastY = *y;
- break;
-
- default:
- if (m_moveto) {
- queue_push(agg::path_cmd_move_to, m_lastX, m_lastY);
- m_moveto = false;
- }
-
- queue_push(code, *x, *y);
- m_lastX = *x;
- m_lastY = *y;
- goto exit_loop;
- }
- }
-
- exit_loop:
-
- if (queue_pop(&code, x, y)) {
- return code;
- }
-
- if (m_moveto && m_has_init &&
- m_lastX >= m_cliprect.x1 &&
- m_lastX <= m_cliprect.x2 &&
- m_lastY >= m_cliprect.y1 &&
- m_lastY <= m_cliprect.y2) {
- *x = m_lastX;
- *y = m_lastY;
- m_moveto = false;
- return agg::path_cmd_move_to;
- }
-
- return agg::path_cmd_stop;
- }
-};
-
-/************************************************************
- PathSnapper rounds vertices to their nearest center-pixels. This
- makes rectilinear paths (rectangles, horizontal and vertical lines
- etc.) look much cleaner.
-*/
-enum e_snap_mode {
- SNAP_AUTO,
- SNAP_FALSE,
- SNAP_TRUE
-};
-
-template <class VertexSource>
-class PathSnapper
-{
- private:
- VertexSource *m_source;
- bool m_snap;
- double m_snap_value;
-
- static bool should_snap(VertexSource &path, e_snap_mode snap_mode, unsigned total_vertices)
- {
- // If this contains only straight horizontal or vertical lines, it should be
- // snapped to the nearest pixels
- double x0 = 0, y0 = 0, x1 = 0, y1 = 0;
- unsigned code;
-
- switch (snap_mode) {
- case SNAP_AUTO:
- if (total_vertices > 1024) {
- return false;
- }
-
- code = path.vertex(&x0, &y0);
- if (code == agg::path_cmd_stop) {
- return false;
- }
-
- while ((code = path.vertex(&x1, &y1)) != agg::path_cmd_stop) {
- switch (code) {
- case agg::path_cmd_curve3:
- case agg::path_cmd_curve4:
- return false;
- case agg::path_cmd_line_to:
- if (fabs(x0 - x1) >= 1e-4 && fabs(y0 - y1) >= 1e-4) {
- return false;
- }
- }
- x0 = x1;
- y0 = y1;
- }
-
- return true;
- case SNAP_FALSE:
- return false;
- case SNAP_TRUE:
- return true;
- }
-
- return false;
- }
-
- public:
- /*
- snap_mode should be one of:
- - SNAP_AUTO: Examine the path to determine if it should be snapped
- - SNAP_TRUE: Force snapping
- - SNAP_FALSE: No snapping
- */
- PathSnapper(VertexSource &source,
- e_snap_mode snap_mode,
- unsigned total_vertices = 15,
- double stroke_width = 0.0)
- : m_source(&source)
- {
- m_snap = should_snap(source, snap_mode, total_vertices);
-
- if (m_snap) {
- int is_odd = mpl_round_to_int(stroke_width) % 2;
- m_snap_value = (is_odd) ? 0.5 : 0.0;
- }
-
- source.rewind(0);
- }
-
- inline void rewind(unsigned path_id)
- {
- m_source->rewind(path_id);
- }
-
- inline unsigned vertex(double *x, double *y)
- {
- unsigned code;
- code = m_source->vertex(x, y);
- if (m_snap && agg::is_vertex(code)) {
- *x = floor(*x + 0.5) + m_snap_value;
- *y = floor(*y + 0.5) + m_snap_value;
- }
- return code;
- }
-
- inline bool is_snapping()
- {
- return m_snap;
- }
-};
-
-/************************************************************
- PathSimplifier reduces the number of vertices in a dense path without
- changing its appearance.
-*/
-template <class VertexSource>
-class PathSimplifier : protected EmbeddedQueue<9>
-{
- public:
- /* Set simplify to true to perform simplification */
- PathSimplifier(VertexSource &source, bool do_simplify, double simplify_threshold)
- : m_source(&source),
- m_simplify(do_simplify),
- /* we square simplify_threshold so that we can compute
- norms without doing the square root every step. */
- m_simplify_threshold(simplify_threshold * simplify_threshold),
-
- m_moveto(true),
- m_after_moveto(false),
- m_clipped(false),
-
- // the x, y values from last iteration
- m_lastx(0.0),
- m_lasty(0.0),
-
- // the dx, dy comprising the original vector, used in conjunction
- // with m_currVecStart* to define the original vector.
- m_origdx(0.0),
- m_origdy(0.0),
-
- // the squared norm of the original vector
- m_origdNorm2(0.0),
-
- // maximum squared norm of vector in forward (parallel) direction
- m_dnorm2ForwardMax(0.0),
- // maximum squared norm of vector in backward (anti-parallel) direction
- m_dnorm2BackwardMax(0.0),
-
- // was the last point the furthest from lastWritten in the
- // forward (parallel) direction?
- m_lastForwardMax(false),
- // was the last point the furthest from lastWritten in the
- // backward (anti-parallel) direction?
- m_lastBackwardMax(false),
-
- // added to queue when _push is called
- m_nextX(0.0),
- m_nextY(0.0),
-
- // added to queue when _push is called if any backwards
- // (anti-parallel) vectors were observed
- m_nextBackwardX(0.0),
- m_nextBackwardY(0.0),
-
- // start of the current vector that is being simplified
- m_currVecStartX(0.0),
- m_currVecStartY(0.0)
- {
- // empty
- }
-
- inline void rewind(unsigned path_id)
- {
- queue_clear();
- m_moveto = true;
- m_source->rewind(path_id);
- }
-
- unsigned vertex(double *x, double *y)
- {
- unsigned cmd;
-
- /* The simplification algorithm doesn't support curves or compound paths
- so we just don't do it at all in that case... */
- if (!m_simplify) {
- return m_source->vertex(x, y);
- }
-
- /* idea: we can skip drawing many lines: we can combine
- sequential parallel lines into a
- single line instead of redrawing lines over the same
- points. The loop below works a bit like a state machine,
- where what it does depends on what it did in the last
- looping. To test whether sequential lines are close to
- parallel, I calculate the distance moved perpendicular to
- the last line. Once it gets too big, the lines cannot be
- combined. */
-
- /* This code was originally written by Allan Haldane and I
- have modified to work in-place -- meaning not creating an
- entirely new path list each time. In order to do that
- without too much additional code complexity, it keeps a
- small queue around so that multiple points can be emitted
- in a single call, and those points will be popped from the
- queue in subsequent calls. The following block will empty
- the queue before proceeding to the main loop below.
- -- Michael Droettboom */
-
- /* This code was originally written by Allan Haldane and
- updated by Michael Droettboom. I have modified it to
- handle anti-parallel vectors. This is done essentially
- the same way as parallel vectors, but requires a little
- additional book-keeping to track whether or not we have
- observed an anti-parallel vector during the current run.
- -- Kevin Rose */
-
- if (queue_pop(&cmd, x, y)) {
- return cmd;
- }
-
- /* The main simplification loop. The point is to consume only
- as many points as necessary until something has been added
- to the outbound queue, not to run through the entire path
- in one go. This eliminates the need to allocate and fill
- an entire additional path array on each draw. */
- while ((cmd = m_source->vertex(x, y)) != agg::path_cmd_stop) {
- /* if we are starting a new path segment, move to the first point
- + init */
-
- if (m_moveto || cmd == agg::path_cmd_move_to) {
- /* m_moveto check is not generally needed because
- m_source generates an initial moveto; but it is
- retained for safety in case circumstances arise
- where this is not true. */
- if (m_origdNorm2 != 0.0 && !m_after_moveto) {
- /* m_origdNorm2 is nonzero only if we have a
- vector; the m_after_moveto check ensures we
- push this vector to the queue only once. */
- _push(x, y);
- }
- m_after_moveto = true;
- m_lastx = *x;
- m_lasty = *y;
- m_moveto = false;
- m_origdNorm2 = 0.0;
- m_dnorm2BackwardMax = 0.0;
- m_clipped = true;
- if (queue_nonempty()) {
- /* If we did a push, empty the queue now. */
- break;
- }
- continue;
- }
- m_after_moveto = false;
-
- /* NOTE: We used to skip this very short segments, but if
- you have a lot of them cumulatively, you can miss
- maxima or minima in the data. */
-
- /* Don't render line segments less than one pixel long */
- /* if (fabs(*x - m_lastx) < 1.0 && fabs(*y - m_lasty) < 1.0) */
- /* { */
- /* continue; */
- /* } */
-
- /* if we have no orig vector, set it to this vector and
- continue. this orig vector is the reference vector we
- will build up the line to */
- if (m_origdNorm2 == 0.0) {
- if (m_clipped) {
- queue_push(agg::path_cmd_move_to, m_lastx, m_lasty);
- m_clipped = false;
- }
-
- m_origdx = *x - m_lastx;
- m_origdy = *y - m_lasty;
- m_origdNorm2 = m_origdx * m_origdx + m_origdy * m_origdy;
-
- // set all the variables to reflect this new orig vector
- m_dnorm2ForwardMax = m_origdNorm2;
- m_dnorm2BackwardMax = 0.0;
- m_lastForwardMax = true;
- m_lastBackwardMax = false;
-
- m_currVecStartX = m_lastx;
- m_currVecStartY = m_lasty;
- m_nextX = m_lastx = *x;
- m_nextY = m_lasty = *y;
- continue;
- }
-
- /* If got to here, then we have an orig vector and we just got
- a vector in the sequence. */
-
- /* Check that the perpendicular distance we have moved
- from the last written point compared to the line we are
- building is not too much. If o is the orig vector (we
- are building on), and v is the vector from the last
- written point to the current point, then the
- perpendicular vector is p = v - (o.v)o/(o.o)
- (here, a.b indicates the dot product of a and b). */
-
- /* get the v vector */
- double totdx = *x - m_currVecStartX;
- double totdy = *y - m_currVecStartY;
-
- /* get the dot product o.v */
- double totdot = m_origdx * totdx + m_origdy * totdy;
-
- /* get the para vector ( = (o.v)o/(o.o)) */
- double paradx = totdot * m_origdx / m_origdNorm2;
- double parady = totdot * m_origdy / m_origdNorm2;
-
- /* get the perp vector ( = v - para) */
- double perpdx = totdx - paradx;
- double perpdy = totdy - parady;
-
- /* get the squared norm of perp vector ( = p.p) */
- double perpdNorm2 = perpdx * perpdx + perpdy * perpdy;
-
- /* If the perpendicular vector is less than
- m_simplify_threshold pixels in size, then merge
- current x,y with the current vector */
- if (perpdNorm2 < m_simplify_threshold) {
- /* check if the current vector is parallel or
- anti-parallel to the orig vector. In either case,
- test if it is the longest of the vectors
- we are merging in that direction. If it is, then
- update the current vector in that direction. */
- double paradNorm2 = paradx * paradx + parady * parady;
-
- m_lastForwardMax = false;
- m_lastBackwardMax = false;
- if (totdot > 0.0) {
- if (paradNorm2 > m_dnorm2ForwardMax) {
- m_lastForwardMax = true;
- m_dnorm2ForwardMax = paradNorm2;
- m_nextX = *x;
- m_nextY = *y;
- }
- } else {
- if (paradNorm2 > m_dnorm2BackwardMax) {
- m_lastBackwardMax = true;
- m_dnorm2BackwardMax = paradNorm2;
- m_nextBackwardX = *x;
- m_nextBackwardY = *y;
- }
- }
-
- m_lastx = *x;
- m_lasty = *y;
- continue;
- }
-
- /* If we get here, then this vector was not similar enough to the
- line we are building, so we need to draw that line and start the
- next one. */
-
- /* If the line needs to extend in the opposite direction from the
- direction we are drawing in, move back to we start drawing from
- back there. */
- _push(x, y);
-
- break;
- }
-
- /* Fill the queue with the remaining vertices if we've finished the
- path in the above loop. */
- if (cmd == agg::path_cmd_stop) {
- if (m_origdNorm2 != 0.0) {
- queue_push((m_moveto || m_after_moveto) ? agg::path_cmd_move_to
- : agg::path_cmd_line_to,
- m_nextX,
- m_nextY);
- if (m_dnorm2BackwardMax > 0.0) {
- queue_push((m_moveto || m_after_moveto) ? agg::path_cmd_move_to
- : agg::path_cmd_line_to,
- m_nextBackwardX,
- m_nextBackwardY);
- }
- m_moveto = false;
- }
- queue_push((m_moveto || m_after_moveto) ? agg::path_cmd_move_to : agg::path_cmd_line_to,
- m_lastx,
- m_lasty);
- m_moveto = false;
- queue_push(agg::path_cmd_stop, 0.0, 0.0);
- }
-
- /* Return the first item in the queue, if any, otherwise
- indicate that we're done. */
- if (queue_pop(&cmd, x, y)) {
- return cmd;
- } else {
- return agg::path_cmd_stop;
- }
- }
-
- private:
- VertexSource *m_source;
- bool m_simplify;
- double m_simplify_threshold;
-
- bool m_moveto;
- bool m_after_moveto;
- bool m_clipped;
- double m_lastx, m_lasty;
-
- double m_origdx;
- double m_origdy;
- double m_origdNorm2;
- double m_dnorm2ForwardMax;
- double m_dnorm2BackwardMax;
- bool m_lastForwardMax;
- bool m_lastBackwardMax;
- double m_nextX;
- double m_nextY;
- double m_nextBackwardX;
- double m_nextBackwardY;
- double m_currVecStartX;
- double m_currVecStartY;
-
- inline void _push(double *x, double *y)
- {
- bool needToPushBack = (m_dnorm2BackwardMax > 0.0);
-
- /* If we observed any backward (anti-parallel) vectors, then
- we need to push both forward and backward vectors. */
- if (needToPushBack) {
- /* If the last vector seen was the maximum in the forward direction,
- then we need to push the forward after the backward. Otherwise,
- the last vector seen was the maximum in the backward direction,
- or somewhere in between, either way we are safe pushing forward
- before backward. */
- if (m_lastForwardMax) {
- queue_push(agg::path_cmd_line_to, m_nextBackwardX, m_nextBackwardY);
- queue_push(agg::path_cmd_line_to, m_nextX, m_nextY);
- } else {
- queue_push(agg::path_cmd_line_to, m_nextX, m_nextY);
- queue_push(agg::path_cmd_line_to, m_nextBackwardX, m_nextBackwardY);
- }
- } else {
- /* If we did not observe any backwards vectors, just push forward. */
- queue_push(agg::path_cmd_line_to, m_nextX, m_nextY);
- }
-
- /* If we clipped some segments between this line and the next line
- we are starting, we also need to move to the last point. */
- if (m_clipped) {
- queue_push(agg::path_cmd_move_to, m_lastx, m_lasty);
- } else if ((!m_lastForwardMax) && (!m_lastBackwardMax)) {
- /* If the last line was not the longest line, then move
- back to the end point of the last line in the
- sequence. Only do this if not clipped, since in that
- case lastx,lasty is not part of the line just drawn. */
-
- /* Would be move_to if not for the artifacts */
- queue_push(agg::path_cmd_line_to, m_lastx, m_lasty);
- }
-
- /* Now reset all the variables to get ready for the next line */
- m_origdx = *x - m_lastx;
- m_origdy = *y - m_lasty;
- m_origdNorm2 = m_origdx * m_origdx + m_origdy * m_origdy;
-
- m_dnorm2ForwardMax = m_origdNorm2;
- m_lastForwardMax = true;
- m_currVecStartX = m_queue[m_queue_write - 1].x;
- m_currVecStartY = m_queue[m_queue_write - 1].y;
- m_lastx = m_nextX = *x;
- m_lasty = m_nextY = *y;
- m_dnorm2BackwardMax = 0.0;
- m_lastBackwardMax = false;
-
- m_clipped = false;
- }
-};
-
-template <class VertexSource>
-class Sketch
-{
- public:
- /*
- scale: the scale of the wiggle perpendicular to the original
- line (in pixels)
-
- length: the base wavelength of the wiggle along the
- original line (in pixels)
-
- randomness: the factor that the sketch length will randomly
- shrink and expand.
- */
- Sketch(VertexSource &source, double scale, double length, double randomness)
- : m_source(&source),
- m_scale(scale),
- m_length(length),
- m_randomness(randomness),
- m_segmented(source),
- m_last_x(0.0),
- m_last_y(0.0),
- m_has_last(false),
- m_p(0.0),
- m_rand(0)
- {
- rewind(0);
- const double d_M_PI = 3.14159265358979323846;
- m_p_scale = (2.0 * d_M_PI) / (m_length * m_randomness);
- m_log_randomness = 2.0 * log(m_randomness);
- }
-
- unsigned vertex(double *x, double *y)
- {
- if (m_scale == 0.0) {
- return m_source->vertex(x, y);
- }
-
- unsigned code = m_segmented.vertex(x, y);
-
- if (code == agg::path_cmd_move_to) {
- m_has_last = false;
- m_p = 0.0;
- }
-
- if (m_has_last) {
- // We want the "cursor" along the sine wave to move at a
- // random rate.
- double d_rand = m_rand.get_double();
- // Original computation
- // p += pow(k, 2*rand - 1)
- // r = sin(p * c)
- // x86 computes pow(a, b) as exp(b*log(a))
- // First, move -1 out, so
- // p' += pow(k, 2*rand)
- // r = sin(p * c') where c' = c / k
- // Next, use x86 logic (will not be worse on other platforms as
- // the log is only computed once and pow and exp are, at worst,
- // the same)
- // So p+= exp(2*rand*log(k))
- // lk = 2*log(k)
- // p += exp(rand*lk)
- m_p += exp(d_rand * m_log_randomness);
- double den = m_last_x - *x;
- double num = m_last_y - *y;
- double len = num * num + den * den;
- m_last_x = *x;
- m_last_y = *y;
- if (len != 0) {
- len = sqrt(len);
- double r = sin(m_p * m_p_scale) * m_scale;
- double roverlen = r / len;
- *x += roverlen * num;
- *y -= roverlen * den;
- }
- } else {
- m_last_x = *x;
- m_last_y = *y;
- }
-
- m_has_last = true;
-
- return code;
- }
-
- inline void rewind(unsigned path_id)
- {
- m_has_last = false;
- m_p = 0.0;
- if (m_scale != 0.0) {
- m_rand.seed(0);
- m_segmented.rewind(path_id);
- } else {
- m_source->rewind(path_id);
- }
- }
-
- private:
- VertexSource *m_source;
- double m_scale;
- double m_length;
- double m_randomness;
- agg::conv_segmentator<VertexSource> m_segmented;
- double m_last_x;
- double m_last_y;
- bool m_has_last;
- double m_p;
- RandomNumberGenerator m_rand;
- double m_p_scale;
- double m_log_randomness;
-};
-
-#endif // MPL_PATH_CONVERTERS_H
diff --git a/contrib/python/matplotlib/py3/src/py_adaptors.h b/contrib/python/matplotlib/py3/src/py_adaptors.h
deleted file mode 100644
index 7722137dc6..0000000000
--- a/contrib/python/matplotlib/py3/src/py_adaptors.h
+++ /dev/null
@@ -1,248 +0,0 @@
-/* -*- mode: c++; c-basic-offset: 4 -*- */
-
-#ifndef MPL_PY_ADAPTORS_H
-#define MPL_PY_ADAPTORS_H
-#define PY_SSIZE_T_CLEAN
-/***************************************************************************
- * This module contains a number of C++ classes that adapt Python data
- * structures to C++ and Agg-friendly interfaces.
- */
-
-#include <Python.h>
-
-#include "numpy/arrayobject.h"
-
-#include "py_exceptions.h"
-
-extern "C" {
-int convert_path(PyObject *obj, void *pathp);
-}
-
-namespace py
-{
-
-/************************************************************
- * py::PathIterator acts as a bridge between Numpy and Agg. Given a
- * pair of Numpy arrays, vertices and codes, it iterates over
- * those vertices and codes, using the standard Agg vertex source
- * interface:
- *
- * unsigned vertex(double* x, double* y)
- */
-class PathIterator
-{
- /* We hold references to the Python objects, not just the
- underlying data arrays, so that Python reference counting
- can work.
- */
- PyArrayObject *m_vertices;
- PyArrayObject *m_codes;
-
- unsigned m_iterator;
- unsigned m_total_vertices;
-
- /* This class doesn't actually do any simplification, but we
- store the value here, since it is obtained from the Python
- object.
- */
- bool m_should_simplify;
- double m_simplify_threshold;
-
- public:
- inline PathIterator()
- : m_vertices(NULL),
- m_codes(NULL),
- m_iterator(0),
- m_total_vertices(0),
- m_should_simplify(false),
- m_simplify_threshold(1.0 / 9.0)
- {
- }
-
- inline PathIterator(PyObject *vertices,
- PyObject *codes,
- bool should_simplify,
- double simplify_threshold)
- : m_vertices(NULL), m_codes(NULL), m_iterator(0)
- {
- if (!set(vertices, codes, should_simplify, simplify_threshold))
- throw py::exception();
- }
-
- inline PathIterator(PyObject *vertices, PyObject *codes)
- : m_vertices(NULL), m_codes(NULL), m_iterator(0)
- {
- if (!set(vertices, codes))
- throw py::exception();
- }
-
- inline PathIterator(const PathIterator &other)
- {
- Py_XINCREF(other.m_vertices);
- m_vertices = other.m_vertices;
-
- Py_XINCREF(other.m_codes);
- m_codes = other.m_codes;
-
- m_iterator = 0;
- m_total_vertices = other.m_total_vertices;
-
- m_should_simplify = other.m_should_simplify;
- m_simplify_threshold = other.m_simplify_threshold;
- }
-
- ~PathIterator()
- {
- Py_XDECREF(m_vertices);
- Py_XDECREF(m_codes);
- }
-
- inline int
- set(PyObject *vertices, PyObject *codes, bool should_simplify, double simplify_threshold)
- {
- m_should_simplify = should_simplify;
- m_simplify_threshold = simplify_threshold;
-
- Py_XDECREF(m_vertices);
- m_vertices = (PyArrayObject *)PyArray_FromObject(vertices, NPY_DOUBLE, 2, 2);
-
- if (!m_vertices || PyArray_DIM(m_vertices, 1) != 2) {
- PyErr_SetString(PyExc_ValueError, "Invalid vertices array");
- return 0;
- }
-
- Py_XDECREF(m_codes);
- m_codes = NULL;
-
- if (codes != NULL && codes != Py_None) {
- m_codes = (PyArrayObject *)PyArray_FromObject(codes, NPY_UINT8, 1, 1);
-
- if (!m_codes || PyArray_DIM(m_codes, 0) != PyArray_DIM(m_vertices, 0)) {
- PyErr_SetString(PyExc_ValueError, "Invalid codes array");
- return 0;
- }
- }
-
- m_total_vertices = (unsigned)PyArray_DIM(m_vertices, 0);
- m_iterator = 0;
-
- return 1;
- }
-
- inline int set(PyObject *vertices, PyObject *codes)
- {
- return set(vertices, codes, false, 0.0);
- }
-
- inline unsigned vertex(double *x, double *y)
- {
- if (m_iterator >= m_total_vertices) {
- *x = 0.0;
- *y = 0.0;
- return agg::path_cmd_stop;
- }
-
- const size_t idx = m_iterator++;
-
- char *pair = (char *)PyArray_GETPTR2(m_vertices, idx, 0);
- *x = *(double *)pair;
- *y = *(double *)(pair + PyArray_STRIDE(m_vertices, 1));
-
- if (m_codes != NULL) {
- return (unsigned)(*(char *)PyArray_GETPTR1(m_codes, idx));
- } else {
- return idx == 0 ? agg::path_cmd_move_to : agg::path_cmd_line_to;
- }
- }
-
- inline void rewind(unsigned path_id)
- {
- m_iterator = path_id;
- }
-
- inline unsigned total_vertices() const
- {
- return m_total_vertices;
- }
-
- inline bool should_simplify() const
- {
- return m_should_simplify;
- }
-
- inline double simplify_threshold() const
- {
- return m_simplify_threshold;
- }
-
- inline bool has_codes() const
- {
- return m_codes != NULL;
- }
-
- inline void *get_id()
- {
- return (void *)m_vertices;
- }
-};
-
-class PathGenerator
-{
- PyObject *m_paths;
- Py_ssize_t m_npaths;
-
- public:
- typedef PathIterator path_iterator;
-
- PathGenerator() : m_paths(NULL), m_npaths(0) {}
-
- ~PathGenerator()
- {
- Py_XDECREF(m_paths);
- }
-
- int set(PyObject *obj)
- {
- if (!PySequence_Check(obj)) {
- return 0;
- }
-
- Py_XDECREF(m_paths);
- m_paths = obj;
- Py_INCREF(m_paths);
-
- m_npaths = PySequence_Size(m_paths);
-
- return 1;
- }
-
- Py_ssize_t num_paths() const
- {
- return m_npaths;
- }
-
- Py_ssize_t size() const
- {
- return m_npaths;
- }
-
- path_iterator operator()(size_t i)
- {
- path_iterator path;
- PyObject *item;
-
- item = PySequence_GetItem(m_paths, i % m_npaths);
- if (item == NULL) {
- throw py::exception();
- }
- if (!convert_path(item, &path)) {
- Py_DECREF(item);
- throw py::exception();
- }
- Py_DECREF(item);
- return path;
- }
-};
-}
-
-#endif
diff --git a/contrib/python/matplotlib/py3/src/py_converters.cpp b/contrib/python/matplotlib/py3/src/py_converters.cpp
deleted file mode 100644
index 04382c5f94..0000000000
--- a/contrib/python/matplotlib/py3/src/py_converters.cpp
+++ /dev/null
@@ -1,558 +0,0 @@
-#define NO_IMPORT_ARRAY
-#define PY_SSIZE_T_CLEAN
-#include "py_converters.h"
-#include "numpy_cpp.h"
-
-#include "agg_basics.h"
-#include "agg_color_rgba.h"
-#include "agg_math_stroke.h"
-
-extern "C" {
-
-static int convert_string_enum(PyObject *obj, const char *name, const char **names, int *values, int *result)
-{
- PyObject *bytesobj;
- char *str;
-
- if (obj == NULL || obj == Py_None) {
- return 1;
- }
-
- if (PyUnicode_Check(obj)) {
- bytesobj = PyUnicode_AsASCIIString(obj);
- if (bytesobj == NULL) {
- return 0;
- }
- } else if (PyBytes_Check(obj)) {
- Py_INCREF(obj);
- bytesobj = obj;
- } else {
- PyErr_Format(PyExc_TypeError, "%s must be str or bytes", name);
- return 0;
- }
-
- str = PyBytes_AsString(bytesobj);
- if (str == NULL) {
- Py_DECREF(bytesobj);
- return 0;
- }
-
- for ( ; *names != NULL; names++, values++) {
- if (strncmp(str, *names, 64) == 0) {
- *result = *values;
- Py_DECREF(bytesobj);
- return 1;
- }
- }
-
- PyErr_Format(PyExc_ValueError, "invalid %s value", name);
- Py_DECREF(bytesobj);
- return 0;
-}
-
-int convert_from_method(PyObject *obj, const char *name, converter func, void *p)
-{
- PyObject *value;
-
- value = PyObject_CallMethod(obj, name, NULL);
- if (value == NULL) {
- if (!PyObject_HasAttrString(obj, name)) {
- PyErr_Clear();
- return 1;
- }
- return 0;
- }
-
- if (!func(value, p)) {
- Py_DECREF(value);
- return 0;
- }
-
- Py_DECREF(value);
- return 1;
-}
-
-int convert_from_attr(PyObject *obj, const char *name, converter func, void *p)
-{
- PyObject *value;
-
- value = PyObject_GetAttrString(obj, name);
- if (value == NULL) {
- if (!PyObject_HasAttrString(obj, name)) {
- PyErr_Clear();
- return 1;
- }
- return 0;
- }
-
- if (!func(value, p)) {
- Py_DECREF(value);
- return 0;
- }
-
- Py_DECREF(value);
- return 1;
-}
-
-int convert_double(PyObject *obj, void *p)
-{
- double *val = (double *)p;
-
- *val = PyFloat_AsDouble(obj);
- if (PyErr_Occurred()) {
- return 0;
- }
-
- return 1;
-}
-
-int convert_bool(PyObject *obj, void *p)
-{
- bool *val = (bool *)p;
- switch (PyObject_IsTrue(obj)) {
- case 0: *val = false; break;
- case 1: *val = true; break;
- default: return 0; // errored.
- }
- return 1;
-}
-
-int convert_cap(PyObject *capobj, void *capp)
-{
- const char *names[] = {"butt", "round", "projecting", NULL};
- int values[] = {agg::butt_cap, agg::round_cap, agg::square_cap};
- int result = agg::butt_cap;
-
- if (!convert_string_enum(capobj, "capstyle", names, values, &result)) {
- return 0;
- }
-
- *(agg::line_cap_e *)capp = (agg::line_cap_e)result;
- return 1;
-}
-
-int convert_join(PyObject *joinobj, void *joinp)
-{
- const char *names[] = {"miter", "round", "bevel", NULL};
- int values[] = {agg::miter_join_revert, agg::round_join, agg::bevel_join};
- int result = agg::miter_join_revert;
-
- if (!convert_string_enum(joinobj, "joinstyle", names, values, &result)) {
- return 0;
- }
-
- *(agg::line_join_e *)joinp = (agg::line_join_e)result;
- return 1;
-}
-
-int convert_rect(PyObject *rectobj, void *rectp)
-{
- agg::rect_d *rect = (agg::rect_d *)rectp;
-
- if (rectobj == NULL || rectobj == Py_None) {
- rect->x1 = 0.0;
- rect->y1 = 0.0;
- rect->x2 = 0.0;
- rect->y2 = 0.0;
- } else {
- PyArrayObject *rect_arr = (PyArrayObject *)PyArray_ContiguousFromAny(
- rectobj, NPY_DOUBLE, 1, 2);
- if (rect_arr == NULL) {
- return 0;
- }
-
- if (PyArray_NDIM(rect_arr) == 2) {
- if (PyArray_DIM(rect_arr, 0) != 2 ||
- PyArray_DIM(rect_arr, 1) != 2) {
- PyErr_SetString(PyExc_ValueError, "Invalid bounding box");
- Py_DECREF(rect_arr);
- return 0;
- }
-
- } else { // PyArray_NDIM(rect_arr) == 1
- if (PyArray_DIM(rect_arr, 0) != 4) {
- PyErr_SetString(PyExc_ValueError, "Invalid bounding box");
- Py_DECREF(rect_arr);
- return 0;
- }
- }
-
- double *buff = (double *)PyArray_DATA(rect_arr);
- rect->x1 = buff[0];
- rect->y1 = buff[1];
- rect->x2 = buff[2];
- rect->y2 = buff[3];
-
- Py_DECREF(rect_arr);
- }
- return 1;
-}
-
-int convert_rgba(PyObject *rgbaobj, void *rgbap)
-{
- agg::rgba *rgba = (agg::rgba *)rgbap;
- PyObject *rgbatuple = NULL;
- int success = 1;
- if (rgbaobj == NULL || rgbaobj == Py_None) {
- rgba->r = 0.0;
- rgba->g = 0.0;
- rgba->b = 0.0;
- rgba->a = 0.0;
- } else {
- if (!(rgbatuple = PySequence_Tuple(rgbaobj))) {
- success = 0;
- goto exit;
- }
- rgba->a = 1.0;
- if (!PyArg_ParseTuple(
- rgbatuple, "ddd|d:rgba", &(rgba->r), &(rgba->g), &(rgba->b), &(rgba->a))) {
- success = 0;
- goto exit;
- }
- }
-exit:
- Py_XDECREF(rgbatuple);
- return success;
-}
-
-int convert_dashes(PyObject *dashobj, void *dashesp)
-{
- Dashes *dashes = (Dashes *)dashesp;
-
- double dash_offset = 0.0;
- PyObject *dashes_seq = NULL;
-
- if (!PyArg_ParseTuple(dashobj, "dO:dashes", &dash_offset, &dashes_seq)) {
- return 0;
- }
-
- if (dashes_seq == Py_None) {
- return 1;
- }
-
- if (!PySequence_Check(dashes_seq)) {
- PyErr_SetString(PyExc_TypeError, "Invalid dashes sequence");
- return 0;
- }
-
- Py_ssize_t nentries = PySequence_Size(dashes_seq);
- // If the dashpattern has odd length, iterate through it twice (in
- // accordance with the pdf/ps/svg specs).
- Py_ssize_t dash_pattern_length = (nentries % 2) ? 2 * nentries : nentries;
-
- for (Py_ssize_t i = 0; i < dash_pattern_length; ++i) {
- PyObject *item;
- double length;
- double skip;
-
- item = PySequence_GetItem(dashes_seq, i % nentries);
- if (item == NULL) {
- return 0;
- }
- length = PyFloat_AsDouble(item);
- if (PyErr_Occurred()) {
- Py_DECREF(item);
- return 0;
- }
- Py_DECREF(item);
-
- ++i;
-
- item = PySequence_GetItem(dashes_seq, i % nentries);
- if (item == NULL) {
- return 0;
- }
- skip = PyFloat_AsDouble(item);
- if (PyErr_Occurred()) {
- Py_DECREF(item);
- return 0;
- }
- Py_DECREF(item);
-
- dashes->add_dash_pair(length, skip);
- }
-
- dashes->set_dash_offset(dash_offset);
-
- return 1;
-}
-
-int convert_dashes_vector(PyObject *obj, void *dashesp)
-{
- DashesVector *dashes = (DashesVector *)dashesp;
-
- if (!PySequence_Check(obj)) {
- return 0;
- }
-
- Py_ssize_t n = PySequence_Size(obj);
-
- for (Py_ssize_t i = 0; i < n; ++i) {
- PyObject *item;
- Dashes subdashes;
-
- item = PySequence_GetItem(obj, i);
- if (item == NULL) {
- return 0;
- }
-
- if (!convert_dashes(item, &subdashes)) {
- Py_DECREF(item);
- return 0;
- }
- Py_DECREF(item);
-
- dashes->push_back(subdashes);
- }
-
- return 1;
-}
-
-int convert_trans_affine(PyObject *obj, void *transp)
-{
- agg::trans_affine *trans = (agg::trans_affine *)transp;
-
- /** If None assume identity transform. */
- if (obj == NULL || obj == Py_None) {
- return 1;
- }
-
- PyArrayObject *array = (PyArrayObject *)PyArray_ContiguousFromAny(obj, NPY_DOUBLE, 2, 2);
- if (array == NULL) {
- return 0;
- }
-
- if (PyArray_DIM(array, 0) == 3 && PyArray_DIM(array, 1) == 3) {
- double *buffer = (double *)PyArray_DATA(array);
- trans->sx = buffer[0];
- trans->shx = buffer[1];
- trans->tx = buffer[2];
-
- trans->shy = buffer[3];
- trans->sy = buffer[4];
- trans->ty = buffer[5];
-
- Py_DECREF(array);
- return 1;
- }
-
- Py_DECREF(array);
- PyErr_SetString(PyExc_ValueError, "Invalid affine transformation matrix");
- return 0;
-}
-
-int convert_path(PyObject *obj, void *pathp)
-{
- py::PathIterator *path = (py::PathIterator *)pathp;
-
- PyObject *vertices_obj = NULL;
- PyObject *codes_obj = NULL;
- PyObject *should_simplify_obj = NULL;
- PyObject *simplify_threshold_obj = NULL;
- bool should_simplify;
- double simplify_threshold;
-
- int status = 0;
-
- if (obj == NULL || obj == Py_None) {
- return 1;
- }
-
- vertices_obj = PyObject_GetAttrString(obj, "vertices");
- if (vertices_obj == NULL) {
- goto exit;
- }
-
- codes_obj = PyObject_GetAttrString(obj, "codes");
- if (codes_obj == NULL) {
- goto exit;
- }
-
- should_simplify_obj = PyObject_GetAttrString(obj, "should_simplify");
- if (should_simplify_obj == NULL) {
- goto exit;
- }
- switch (PyObject_IsTrue(should_simplify_obj)) {
- case 0: should_simplify = 0; break;
- case 1: should_simplify = 1; break;
- default: goto exit; // errored.
- }
-
- simplify_threshold_obj = PyObject_GetAttrString(obj, "simplify_threshold");
- if (simplify_threshold_obj == NULL) {
- goto exit;
- }
- simplify_threshold = PyFloat_AsDouble(simplify_threshold_obj);
- if (PyErr_Occurred()) {
- goto exit;
- }
-
- if (!path->set(vertices_obj, codes_obj, should_simplify, simplify_threshold)) {
- goto exit;
- }
-
- status = 1;
-
-exit:
- Py_XDECREF(vertices_obj);
- Py_XDECREF(codes_obj);
- Py_XDECREF(should_simplify_obj);
- Py_XDECREF(simplify_threshold_obj);
-
- return status;
-}
-
-int convert_pathgen(PyObject *obj, void *pathgenp)
-{
- py::PathGenerator *paths = (py::PathGenerator *)pathgenp;
- if (!paths->set(obj)) {
- PyErr_SetString(PyExc_TypeError, "Not an iterable of paths");
- return 0;
- }
- return 1;
-}
-
-int convert_clippath(PyObject *clippath_tuple, void *clippathp)
-{
- ClipPath *clippath = (ClipPath *)clippathp;
- py::PathIterator path;
- agg::trans_affine trans;
-
- if (clippath_tuple != NULL && clippath_tuple != Py_None) {
- if (!PyArg_ParseTuple(clippath_tuple,
- "O&O&:clippath",
- &convert_path,
- &clippath->path,
- &convert_trans_affine,
- &clippath->trans)) {
- return 0;
- }
- }
-
- return 1;
-}
-
-int convert_snap(PyObject *obj, void *snapp)
-{
- e_snap_mode *snap = (e_snap_mode *)snapp;
- if (obj == NULL || obj == Py_None) {
- *snap = SNAP_AUTO;
- } else {
- switch (PyObject_IsTrue(obj)) {
- case 0: *snap = SNAP_FALSE; break;
- case 1: *snap = SNAP_TRUE; break;
- default: return 0; // errored.
- }
- }
- return 1;
-}
-
-int convert_sketch_params(PyObject *obj, void *sketchp)
-{
- SketchParams *sketch = (SketchParams *)sketchp;
-
- if (obj == NULL || obj == Py_None) {
- sketch->scale = 0.0;
- } else if (!PyArg_ParseTuple(obj,
- "ddd:sketch_params",
- &sketch->scale,
- &sketch->length,
- &sketch->randomness)) {
- return 0;
- }
-
- return 1;
-}
-
-int convert_gcagg(PyObject *pygc, void *gcp)
-{
- GCAgg *gc = (GCAgg *)gcp;
-
- if (!(convert_from_attr(pygc, "_linewidth", &convert_double, &gc->linewidth) &&
- convert_from_attr(pygc, "_alpha", &convert_double, &gc->alpha) &&
- convert_from_attr(pygc, "_forced_alpha", &convert_bool, &gc->forced_alpha) &&
- convert_from_attr(pygc, "_rgb", &convert_rgba, &gc->color) &&
- convert_from_attr(pygc, "_antialiased", &convert_bool, &gc->isaa) &&
- convert_from_attr(pygc, "_capstyle", &convert_cap, &gc->cap) &&
- convert_from_attr(pygc, "_joinstyle", &convert_join, &gc->join) &&
- convert_from_method(pygc, "get_dashes", &convert_dashes, &gc->dashes) &&
- convert_from_attr(pygc, "_cliprect", &convert_rect, &gc->cliprect) &&
- convert_from_method(pygc, "get_clip_path", &convert_clippath, &gc->clippath) &&
- convert_from_method(pygc, "get_snap", &convert_snap, &gc->snap_mode) &&
- convert_from_method(pygc, "get_hatch_path", &convert_path, &gc->hatchpath) &&
- convert_from_method(pygc, "get_hatch_color", &convert_rgba, &gc->hatch_color) &&
- convert_from_method(pygc, "get_hatch_linewidth", &convert_double, &gc->hatch_linewidth) &&
- convert_from_method(pygc, "get_sketch_params", &convert_sketch_params, &gc->sketch))) {
- return 0;
- }
-
- return 1;
-}
-
-int convert_face(PyObject *color, GCAgg &gc, agg::rgba *rgba)
-{
- if (!convert_rgba(color, rgba)) {
- return 0;
- }
-
- if (color != NULL && color != Py_None) {
- if (gc.forced_alpha || PySequence_Size(color) == 3) {
- rgba->a = gc.alpha;
- }
- }
-
- return 1;
-}
-
-int convert_points(PyObject *obj, void *pointsp)
-{
- numpy::array_view<double, 2> *points = (numpy::array_view<double, 2> *)pointsp;
- if (obj == NULL || obj == Py_None) {
- return 1;
- }
- if (!points->set(obj)
- || (points->size() && !check_trailing_shape(*points, "points", 2))) {
- return 0;
- }
- return 1;
-}
-
-int convert_transforms(PyObject *obj, void *transp)
-{
- numpy::array_view<double, 3> *trans = (numpy::array_view<double, 3> *)transp;
- if (obj == NULL || obj == Py_None) {
- return 1;
- }
- if (!trans->set(obj)
- || (trans->size() && !check_trailing_shape(*trans, "transforms", 3, 3))) {
- return 0;
- }
- return 1;
-}
-
-int convert_bboxes(PyObject *obj, void *bboxp)
-{
- numpy::array_view<double, 3> *bbox = (numpy::array_view<double, 3> *)bboxp;
- if (obj == NULL || obj == Py_None) {
- return 1;
- }
- if (!bbox->set(obj)
- || (bbox->size() && !check_trailing_shape(*bbox, "bbox array", 2, 2))) {
- return 0;
- }
- return 1;
-}
-
-int convert_colors(PyObject *obj, void *colorsp)
-{
- numpy::array_view<double, 2> *colors = (numpy::array_view<double, 2> *)colorsp;
- if (obj == NULL || obj == Py_None) {
- return 1;
- }
- if (!colors->set(obj)
- || (colors->size() && !check_trailing_shape(*colors, "colors", 4))) {
- return 0;
- }
- return 1;
-}
-}
diff --git a/contrib/python/matplotlib/py3/src/py_converters.h b/contrib/python/matplotlib/py3/src/py_converters.h
deleted file mode 100644
index 2c9dc6d1b8..0000000000
--- a/contrib/python/matplotlib/py3/src/py_converters.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* -*- mode: c++; c-basic-offset: 4 -*- */
-
-#ifndef MPL_PY_CONVERTERS_H
-#define MPL_PY_CONVERTERS_H
-
-/***************************************************************************
- * This module contains a number of conversion functions from Python types
- * to C++ types. Most of them meet the Python "converter" signature:
- *
- * typedef int (*converter)(PyObject *, void *);
- *
- * and thus can be passed as conversion functions to PyArg_ParseTuple
- * and friends.
- */
-
-#include <Python.h>
-#include "_backend_agg_basic_types.h"
-
-extern "C" {
-typedef int (*converter)(PyObject *, void *);
-
-int convert_from_attr(PyObject *obj, const char *name, converter func, void *p);
-int convert_from_method(PyObject *obj, const char *name, converter func, void *p);
-
-int convert_double(PyObject *obj, void *p);
-int convert_bool(PyObject *obj, void *p);
-int convert_cap(PyObject *capobj, void *capp);
-int convert_join(PyObject *joinobj, void *joinp);
-int convert_rect(PyObject *rectobj, void *rectp);
-int convert_rgba(PyObject *rgbaocj, void *rgbap);
-int convert_dashes(PyObject *dashobj, void *gcp);
-int convert_dashes_vector(PyObject *obj, void *dashesp);
-int convert_trans_affine(PyObject *obj, void *transp);
-int convert_path(PyObject *obj, void *pathp);
-int convert_pathgen(PyObject *obj, void *pathgenp);
-int convert_clippath(PyObject *clippath_tuple, void *clippathp);
-int convert_snap(PyObject *obj, void *snapp);
-int convert_sketch_params(PyObject *obj, void *sketchp);
-int convert_gcagg(PyObject *pygc, void *gcp);
-int convert_points(PyObject *pygc, void *pointsp);
-int convert_transforms(PyObject *pygc, void *transp);
-int convert_bboxes(PyObject *pygc, void *bboxp);
-int convert_colors(PyObject *pygc, void *colorsp);
-
-int convert_face(PyObject *color, GCAgg &gc, agg::rgba *rgba);
-}
-
-#endif
diff --git a/contrib/python/matplotlib/py3/src/py_exceptions.h b/contrib/python/matplotlib/py3/src/py_exceptions.h
deleted file mode 100644
index c4accf2634..0000000000
--- a/contrib/python/matplotlib/py3/src/py_exceptions.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/* -*- mode: c++; c-basic-offset: 4 -*- */
-
-#ifndef MPL_PY_EXCEPTIONS_H
-#define MPL_PY_EXCEPTIONS_H
-
-#include <exception>
-#include <stdexcept>
-
-namespace py
-{
-class exception : public std::exception
-{
- public:
- const char *what() const throw()
- {
- return "python error has been set";
- }
-};
-}
-
-#define CALL_CPP_FULL(name, a, cleanup, errorcode) \
- try \
- { \
- a; \
- } \
- catch (const py::exception &) \
- { \
- { \
- cleanup; \
- } \
- return (errorcode); \
- } \
- catch (const std::bad_alloc &) \
- { \
- PyErr_Format(PyExc_MemoryError, "In %s: Out of memory", (name)); \
- { \
- cleanup; \
- } \
- return (errorcode); \
- } \
- catch (const std::overflow_error &e) \
- { \
- PyErr_Format(PyExc_OverflowError, "In %s: %s", (name), e.what()); \
- { \
- cleanup; \
- } \
- return (errorcode); \
- } \
- catch (const std::runtime_error &e) \
- { \
- PyErr_Format(PyExc_RuntimeError, "In %s: %s", (name), e.what()); \
- { \
- cleanup; \
- } \
- return (errorcode); \
- } \
- catch (...) \
- { \
- PyErr_Format(PyExc_RuntimeError, "Unknown exception in %s", (name)); \
- { \
- cleanup; \
- } \
- return (errorcode); \
- }
-
-#define CALL_CPP_CLEANUP(name, a, cleanup) CALL_CPP_FULL(name, a, cleanup, 0)
-
-#define CALL_CPP(name, a) CALL_CPP_FULL(name, a, , 0)
-
-#define CALL_CPP_INIT(name, a) CALL_CPP_FULL(name, a, , -1)
-
-#endif
diff --git a/contrib/python/matplotlib/py3/src/tri/_tri.cpp b/contrib/python/matplotlib/py3/src/tri/_tri.cpp
deleted file mode 100644
index 2674a3140b..0000000000
--- a/contrib/python/matplotlib/py3/src/tri/_tri.cpp
+++ /dev/null
@@ -1,2074 +0,0 @@
-/* This file contains liberal use of asserts to assist code development and
- * debugging. Standard matplotlib builds disable asserts so they cause no
- * performance reduction. To enable the asserts, you need to undefine the
- * NDEBUG macro, which is achieved by adding the following
- * undef_macros=['NDEBUG']
- * to the appropriate make_extension call in setupext.py, and then rebuilding.
- */
-#include "../mplutils.h"
-#include "_tri.h"
-
-#include <algorithm>
-#include <random>
-#include <set>
-
-
-TriEdge::TriEdge()
- : tri(-1), edge(-1)
-{}
-
-TriEdge::TriEdge(int tri_, int edge_)
- : tri(tri_), edge(edge_)
-{}
-
-bool TriEdge::operator<(const TriEdge& other) const
-{
- if (tri != other.tri)
- return tri < other.tri;
- else
- return edge < other.edge;
-}
-
-bool TriEdge::operator==(const TriEdge& other) const
-{
- return tri == other.tri && edge == other.edge;
-}
-
-bool TriEdge::operator!=(const TriEdge& other) const
-{
- return !operator==(other);
-}
-
-std::ostream& operator<<(std::ostream& os, const TriEdge& tri_edge)
-{
- return os << tri_edge.tri << ' ' << tri_edge.edge;
-}
-
-
-
-XY::XY()
-{}
-
-XY::XY(const double& x_, const double& y_)
- : x(x_), y(y_)
-{}
-
-double XY::angle() const
-{
- return atan2(y, x);
-}
-
-double XY::cross_z(const XY& other) const
-{
- return x*other.y - y*other.x;
-}
-
-bool XY::is_right_of(const XY& other) const
-{
- if (x == other.x)
- return y > other.y;
- else
- return x > other.x;
-}
-
-bool XY::operator==(const XY& other) const
-{
- return x == other.x && y == other.y;
-}
-
-bool XY::operator!=(const XY& other) const
-{
- return x != other.x || y != other.y;
-}
-
-XY XY::operator*(const double& multiplier) const
-{
- return XY(x*multiplier, y*multiplier);
-}
-
-const XY& XY::operator+=(const XY& other)
-{
- x += other.x;
- y += other.y;
- return *this;
-}
-
-const XY& XY::operator-=(const XY& other)
-{
- x -= other.x;
- y -= other.y;
- return *this;
-}
-
-XY XY::operator+(const XY& other) const
-{
- return XY(x + other.x, y + other.y);
-}
-
-XY XY::operator-(const XY& other) const
-{
- return XY(x - other.x, y - other.y);
-}
-
-std::ostream& operator<<(std::ostream& os, const XY& xy)
-{
- return os << '(' << xy.x << ' ' << xy.y << ')';
-}
-
-
-
-XYZ::XYZ(const double& x_, const double& y_, const double& z_)
- : x(x_), y(y_), z(z_)
-{}
-
-XYZ XYZ::cross(const XYZ& other) const
-{
- return XYZ(y*other.z - z*other.y,
- z*other.x - x*other.z,
- x*other.y - y*other.x);
-}
-
-double XYZ::dot(const XYZ& other) const
-{
- return x*other.x + y*other.y + z*other.z;
-}
-
-XYZ XYZ::operator-(const XYZ& other) const
-{
- return XYZ(x - other.x, y - other.y, z - other.z);
-}
-
-std::ostream& operator<<(std::ostream& os, const XYZ& xyz)
-{
- return os << '(' << xyz.x << ' ' << xyz.y << ' ' << xyz.z << ')';
-}
-
-
-
-BoundingBox::BoundingBox()
- : empty(true), lower(0.0, 0.0), upper(0.0, 0.0)
-{}
-
-void BoundingBox::add(const XY& point)
-{
- if (empty) {
- empty = false;
- lower = upper = point;
- } else {
- if (point.x < lower.x) lower.x = point.x;
- else if (point.x > upper.x) upper.x = point.x;
-
- if (point.y < lower.y) lower.y = point.y;
- else if (point.y > upper.y) upper.y = point.y;
- }
-}
-
-void BoundingBox::expand(const XY& delta)
-{
- if (!empty) {
- lower -= delta;
- upper += delta;
- }
-}
-
-
-
-ContourLine::ContourLine()
- : std::vector<XY>()
-{}
-
-void ContourLine::push_back(const XY& point)
-{
- if (empty() || point != back())
- std::vector<XY>::push_back(point);
-}
-
-void ContourLine::write() const
-{
- std::cout << "ContourLine of " << size() << " points:";
- for (const_iterator it = begin(); it != end(); ++it)
- std::cout << ' ' << *it;
- std::cout << std::endl;
-}
-
-
-
-void write_contour(const Contour& contour)
-{
- std::cout << "Contour of " << contour.size() << " lines." << std::endl;
- for (Contour::const_iterator it = contour.begin(); it != contour.end(); ++it)
- it->write();
-}
-
-
-
-Triangulation::Triangulation(const CoordinateArray& x,
- const CoordinateArray& y,
- const TriangleArray& triangles,
- const MaskArray& mask,
- const EdgeArray& edges,
- const NeighborArray& neighbors,
- bool correct_triangle_orientations)
- : _x(x),
- _y(y),
- _triangles(triangles),
- _mask(mask),
- _edges(edges),
- _neighbors(neighbors)
-{
- if (_x.ndim() != 1 || _y.ndim() != 1 || _x.shape(0) != _y.shape(0))
- throw std::invalid_argument("x and y must be 1D arrays of the same length");
-
- if (_triangles.ndim() != 2 || _triangles.shape(1) != 3)
- throw std::invalid_argument("triangles must be a 2D array of shape (?,3)");
-
- // Optional mask.
- if (_mask.size() > 0 &&
- (_mask.ndim() != 1 || _mask.shape(0) != _triangles.shape(0)))
- throw std::invalid_argument(
- "mask must be a 1D array with the same length as the triangles array");
-
- // Optional edges.
- if (_edges.size() > 0 &&
- (_edges.ndim() != 2 || _edges.shape(1) != 2))
- throw std::invalid_argument("edges must be a 2D array with shape (?,2)");
-
- // Optional neighbors.
- if (_neighbors.size() > 0 &&
- (_neighbors.ndim() != 2 || _neighbors.shape() != _triangles.shape()))
- throw std::invalid_argument(
- "neighbors must be a 2D array with the same shape as the triangles array");
-
- if (correct_triangle_orientations)
- correct_triangles();
-}
-
-void Triangulation::calculate_boundaries()
-{
- get_neighbors(); // Ensure _neighbors has been created.
-
- // Create set of all boundary TriEdges, which are those which do not
- // have a neighbor triangle.
- typedef std::set<TriEdge> BoundaryEdges;
- BoundaryEdges boundary_edges;
- for (int tri = 0; tri < get_ntri(); ++tri) {
- if (!is_masked(tri)) {
- for (int edge = 0; edge < 3; ++edge) {
- if (get_neighbor(tri, edge) == -1) {
- boundary_edges.insert(TriEdge(tri, edge));
- }
- }
- }
- }
-
- // Take any boundary edge and follow the boundary until return to start
- // point, removing edges from boundary_edges as they are used. At the same
- // time, initialise the _tri_edge_to_boundary_map.
- while (!boundary_edges.empty()) {
- // Start of new boundary.
- BoundaryEdges::iterator it = boundary_edges.begin();
- int tri = it->tri;
- int edge = it->edge;
- _boundaries.push_back(Boundary());
- Boundary& boundary = _boundaries.back();
-
- while (true) {
- boundary.push_back(TriEdge(tri, edge));
- boundary_edges.erase(it);
- _tri_edge_to_boundary_map[TriEdge(tri, edge)] =
- BoundaryEdge(_boundaries.size()-1, boundary.size()-1);
-
- // Move to next edge of current triangle.
- edge = (edge+1) % 3;
-
- // Find start point index of boundary edge.
- int point = get_triangle_point(tri, edge);
-
- // Find next TriEdge by traversing neighbors until find one
- // without a neighbor.
- while (get_neighbor(tri, edge) != -1) {
- tri = get_neighbor(tri, edge);
- edge = get_edge_in_triangle(tri, point);
- }
-
- if (TriEdge(tri,edge) == boundary.front())
- break; // Reached beginning of this boundary, so finished it.
- else
- it = boundary_edges.find(TriEdge(tri, edge));
- }
- }
-}
-
-void Triangulation::calculate_edges()
-{
- assert(!has_edges() && "Expected empty edges array");
-
- // Create set of all edges, storing them with start point index less than
- // end point index.
- typedef std::set<Edge> EdgeSet;
- EdgeSet edge_set;
- for (int tri = 0; tri < get_ntri(); ++tri) {
- if (!is_masked(tri)) {
- for (int edge = 0; edge < 3; edge++) {
- int start = get_triangle_point(tri, edge);
- int end = get_triangle_point(tri, (edge+1)%3);
- edge_set.insert(start > end ? Edge(start,end) : Edge(end,start));
- }
- }
- }
-
- // Convert to python _edges array.
- py::ssize_t dims[2] = {static_cast<py::ssize_t>(edge_set.size()), 2};
- _edges = EdgeArray(dims);
- auto edges = _edges.mutable_data();
-
- int i = 0;
- for (EdgeSet::const_iterator it = edge_set.begin(); it != edge_set.end(); ++it) {
- edges[i++] = it->start;
- edges[i++] = it->end;
- }
-}
-
-void Triangulation::calculate_neighbors()
-{
- assert(!has_neighbors() && "Expected empty neighbors array");
-
- // Create _neighbors array with shape (ntri,3) and initialise all to -1.
- py::ssize_t dims[2] = {get_ntri(), 3};
- _neighbors = NeighborArray(dims);
- auto* neighbors = _neighbors.mutable_data();
-
- int tri, edge;
- std::fill(neighbors, neighbors+3*get_ntri(), -1);
-
- // For each triangle edge (start to end point), find corresponding neighbor
- // edge from end to start point. Do this by traversing all edges and
- // storing them in a map from edge to TriEdge. If corresponding neighbor
- // edge is already in the map, don't need to store new edge as neighbor
- // already found.
- typedef std::map<Edge, TriEdge> EdgeToTriEdgeMap;
- EdgeToTriEdgeMap edge_to_tri_edge_map;
- for (tri = 0; tri < get_ntri(); ++tri) {
- if (!is_masked(tri)) {
- for (edge = 0; edge < 3; ++edge) {
- int start = get_triangle_point(tri, edge);
- int end = get_triangle_point(tri, (edge+1)%3);
- EdgeToTriEdgeMap::iterator it =
- edge_to_tri_edge_map.find(Edge(end,start));
- if (it == edge_to_tri_edge_map.end()) {
- // No neighbor edge exists in the edge_to_tri_edge_map, so
- // add this edge to it.
- edge_to_tri_edge_map[Edge(start,end)] = TriEdge(tri,edge);
- } else {
- // Neighbor edge found, set the two elements of _neighbors
- // and remove edge from edge_to_tri_edge_map.
- neighbors[3*tri + edge] = it->second.tri;
- neighbors[3*it->second.tri + it->second.edge] = tri;
- edge_to_tri_edge_map.erase(it);
- }
- }
- }
- }
-
- // Note that remaining edges in the edge_to_tri_edge_map correspond to
- // boundary edges, but the boundaries are calculated separately elsewhere.
-}
-
-Triangulation::TwoCoordinateArray Triangulation::calculate_plane_coefficients(
- const CoordinateArray& z)
-{
- if (z.ndim() != 1 || z.shape(0) != _x.shape(0))
- throw std::invalid_argument(
- "z must be a 1D array with the same length as the triangulation x and y arrays");
-
- int dims[2] = {get_ntri(), 3};
- Triangulation::TwoCoordinateArray planes_array(dims);
- auto planes = planes_array.mutable_unchecked<2>();
- auto triangles = _triangles.unchecked<2>();
- auto x = _x.unchecked<1>();
- auto y = _y.unchecked<1>();
- auto z_ptr = z.unchecked<1>();
-
- int point;
- for (int tri = 0; tri < get_ntri(); ++tri) {
- if (is_masked(tri)) {
- planes(tri, 0) = 0.0;
- planes(tri, 1) = 0.0;
- planes(tri, 2) = 0.0;
- }
- else {
- // Equation of plane for all points r on plane is r.normal = p
- // where normal is vector normal to the plane, and p is a
- // constant. Rewrite as
- // r_x*normal_x + r_y*normal_y + r_z*normal_z = p
- // and rearrange to give
- // r_z = (-normal_x/normal_z)*r_x + (-normal_y/normal_z)*r_y +
- // p/normal_z
- point = triangles(tri, 0);
- XYZ point0(x(point), y(point), z_ptr(point));
- point = triangles(tri, 1);
- XYZ side01 = XYZ(x(point), y(point), z_ptr(point)) - point0;
- point = triangles(tri, 2);
- XYZ side02 = XYZ(x(point), y(point), z_ptr(point)) - point0;
-
- XYZ normal = side01.cross(side02);
-
- if (normal.z == 0.0) {
- // Normal is in x-y plane which means triangle consists of
- // colinear points. To avoid dividing by zero, we use the
- // Moore-Penrose pseudo-inverse.
- double sum2 = (side01.x*side01.x + side01.y*side01.y +
- side02.x*side02.x + side02.y*side02.y);
- double a = (side01.x*side01.z + side02.x*side02.z) / sum2;
- double b = (side01.y*side01.z + side02.y*side02.z) / sum2;
- planes(tri, 0) = a;
- planes(tri, 1) = b;
- planes(tri, 2) = point0.z - a*point0.x - b*point0.y;
- }
- else {
- planes(tri, 0) = -normal.x / normal.z; // x
- planes(tri, 1) = -normal.y / normal.z; // y
- planes(tri, 2) = normal.dot(point0) / normal.z; // constant
- }
- }
- }
-
- return planes_array;
-}
-
-void Triangulation::correct_triangles()
-{
- auto triangles = _triangles.mutable_data();
- auto neighbors = _neighbors.mutable_data();
-
- for (int tri = 0; tri < get_ntri(); ++tri) {
- XY point0 = get_point_coords(triangles[3*tri]);
- XY point1 = get_point_coords(triangles[3*tri+1]);
- XY point2 = get_point_coords(triangles[3*tri+2]);
- if ( (point1 - point0).cross_z(point2 - point0) < 0.0) {
- // Triangle points are clockwise, so change them to anticlockwise.
- std::swap(triangles[3*tri+1], triangles[3*tri+2]);
- if (has_neighbors())
- std::swap(neighbors[3*tri+1], neighbors[3*tri+2]);
- }
- }
-}
-
-const Triangulation::Boundaries& Triangulation::get_boundaries() const
-{
- if (_boundaries.empty())
- const_cast<Triangulation*>(this)->calculate_boundaries();
- return _boundaries;
-}
-
-void Triangulation::get_boundary_edge(const TriEdge& triEdge,
- int& boundary,
- int& edge) const
-{
- get_boundaries(); // Ensure _tri_edge_to_boundary_map has been created.
- TriEdgeToBoundaryMap::const_iterator it =
- _tri_edge_to_boundary_map.find(triEdge);
- assert(it != _tri_edge_to_boundary_map.end() &&
- "TriEdge is not on a boundary");
- boundary = it->second.boundary;
- edge = it->second.edge;
-}
-
-int Triangulation::get_edge_in_triangle(int tri, int point) const
-{
- assert(tri >= 0 && tri < get_ntri() && "Triangle index out of bounds");
- assert(point >= 0 && point < get_npoints() && "Point index out of bounds.");
-
- auto triangles = _triangles.data();
-
- for (int edge = 0; edge < 3; ++edge) {
- if (triangles[3*tri + edge] == point)
- return edge;
- }
- return -1; // point is not in triangle.
-}
-
-Triangulation::EdgeArray& Triangulation::get_edges()
-{
- if (!has_edges())
- calculate_edges();
- return _edges;
-}
-
-int Triangulation::get_neighbor(int tri, int edge) const
-{
- assert(tri >= 0 && tri < get_ntri() && "Triangle index out of bounds");
- assert(edge >= 0 && edge < 3 && "Edge index out of bounds");
- if (!has_neighbors())
- const_cast<Triangulation&>(*this).calculate_neighbors();
- return _neighbors.data()[3*tri + edge];
-}
-
-TriEdge Triangulation::get_neighbor_edge(int tri, int edge) const
-{
- int neighbor_tri = get_neighbor(tri, edge);
- if (neighbor_tri == -1)
- return TriEdge(-1,-1);
- else
- return TriEdge(neighbor_tri,
- get_edge_in_triangle(neighbor_tri,
- get_triangle_point(tri,
- (edge+1)%3)));
-}
-
-Triangulation::NeighborArray& Triangulation::get_neighbors()
-{
- if (!has_neighbors())
- calculate_neighbors();
- return _neighbors;
-}
-
-int Triangulation::get_npoints() const
-{
- return _x.shape(0);
-}
-
-int Triangulation::get_ntri() const
-{
- return _triangles.shape(0);
-}
-
-XY Triangulation::get_point_coords(int point) const
-{
- assert(point >= 0 && point < get_npoints() && "Point index out of bounds.");
- return XY(_x.data()[point], _y.data()[point]);
-}
-
-int Triangulation::get_triangle_point(int tri, int edge) const
-{
- assert(tri >= 0 && tri < get_ntri() && "Triangle index out of bounds");
- assert(edge >= 0 && edge < 3 && "Edge index out of bounds");
- return _triangles.data()[3*tri + edge];
-}
-
-int Triangulation::get_triangle_point(const TriEdge& tri_edge) const
-{
- return get_triangle_point(tri_edge.tri, tri_edge.edge);
-}
-
-bool Triangulation::has_edges() const
-{
- return _edges.size() > 0;
-}
-
-bool Triangulation::has_mask() const
-{
- return _mask.size() > 0;
-}
-
-bool Triangulation::has_neighbors() const
-{
- return _neighbors.size() > 0;
-}
-
-bool Triangulation::is_masked(int tri) const
-{
- assert(tri >= 0 && tri < get_ntri() && "Triangle index out of bounds.");
- return has_mask() && _mask.data()[tri];
-}
-
-void Triangulation::set_mask(const MaskArray& mask)
-{
- if (mask.size() > 0 &&
- (mask.ndim() != 1 || mask.shape(0) != _triangles.shape(0)))
- throw std::invalid_argument(
- "mask must be a 1D array with the same length as the triangles array");
-
- _mask = mask;
-
- // Clear derived fields so they are recalculated when needed.
- _edges = EdgeArray();
- _neighbors = NeighborArray();
- _boundaries.clear();
-}
-
-void Triangulation::write_boundaries() const
-{
- const Boundaries& bs = get_boundaries();
- std::cout << "Number of boundaries: " << bs.size() << std::endl;
- for (Boundaries::const_iterator it = bs.begin(); it != bs.end(); ++it) {
- const Boundary& b = *it;
- std::cout << " Boundary of " << b.size() << " points: ";
- for (Boundary::const_iterator itb = b.begin(); itb != b.end(); ++itb) {
- std::cout << *itb << ", ";
- }
- std::cout << std::endl;
- }
-}
-
-
-
-TriContourGenerator::TriContourGenerator(Triangulation& triangulation,
- const CoordinateArray& z)
- : _triangulation(triangulation),
- _z(z),
- _interior_visited(2*_triangulation.get_ntri()),
- _boundaries_visited(0),
- _boundaries_used(0)
-{
- if (_z.ndim() != 1 || _z.shape(0) != _triangulation.get_npoints())
- throw std::invalid_argument(
- "z must be a 1D array with the same length as the x and y arrays");
-}
-
-void TriContourGenerator::clear_visited_flags(bool include_boundaries)
-{
- // Clear _interiorVisited.
- std::fill(_interior_visited.begin(), _interior_visited.end(), false);
-
- if (include_boundaries) {
- if (_boundaries_visited.empty()) {
- const Boundaries& boundaries = get_boundaries();
-
- // Initialise _boundaries_visited.
- _boundaries_visited.reserve(boundaries.size());
- for (Boundaries::const_iterator it = boundaries.begin();
- it != boundaries.end(); ++it)
- _boundaries_visited.push_back(BoundaryVisited(it->size()));
-
- // Initialise _boundaries_used.
- _boundaries_used = BoundariesUsed(boundaries.size());
- }
-
- // Clear _boundaries_visited.
- for (BoundariesVisited::iterator it = _boundaries_visited.begin();
- it != _boundaries_visited.end(); ++it)
- std::fill(it->begin(), it->end(), false);
-
- // Clear _boundaries_used.
- std::fill(_boundaries_used.begin(), _boundaries_used.end(), false);
- }
-}
-
-py::tuple TriContourGenerator::contour_line_to_segs_and_kinds(const Contour& contour)
-{
- // Convert all of the lines generated by a call to create_contour() into
- // their Python equivalents for return to the calling function.
- // A line is either a closed line loop (in which case the last point is
- // identical to the first) or an open line strip. Two NumPy arrays are
- // created for each line:
- // vertices is a double array of shape (npoints, 2) containing the (x, y)
- // coordinates of the points in the line
- // codes is a uint8 array of shape (npoints,) containing the 'kind codes'
- // which are defined in the Path class
- // and they are appended to the Python lists vertices_list and codes_list
- // respectively for return to the Python calling function.
-
- py::list vertices_list(contour.size());
- py::list codes_list(contour.size());
-
- for (Contour::size_type i = 0; i < contour.size(); ++i) {
- const ContourLine& contour_line = contour[i];
- py::ssize_t npoints = static_cast<py::ssize_t>(contour_line.size());
-
- py::ssize_t segs_dims[2] = {npoints, 2};
- CoordinateArray segs(segs_dims);
- double* segs_ptr = segs.mutable_data();
-
- py::ssize_t codes_dims[1] = {npoints};
- CodeArray codes(codes_dims);
- unsigned char* codes_ptr = codes.mutable_data();
-
- for (ContourLine::const_iterator it = contour_line.begin();
- it != contour_line.end(); ++it) {
- *segs_ptr++ = it->x;
- *segs_ptr++ = it->y;
- *codes_ptr++ = (it == contour_line.begin() ? MOVETO : LINETO);
- }
-
- // Closed line loop has identical first and last (x, y) points.
- if (contour_line.size() > 1 &&
- contour_line.front() == contour_line.back())
- *(codes_ptr-1) = CLOSEPOLY;
-
- vertices_list[i] = segs;
- codes_list[i] = codes;
- }
-
- return py::make_tuple(vertices_list, codes_list);
-}
-
-py::tuple TriContourGenerator::contour_to_segs_and_kinds(const Contour& contour)
-{
- // Convert all of the polygons generated by a call to
- // create_filled_contour() into their Python equivalents for return to the
- // calling function. All of the polygons' points and kinds codes are
- // combined into single NumPy arrays for each; this avoids having
- // to determine which polygons are holes as this will be determined by the
- // renderer. If there are ntotal points in all of the polygons, the two
- // NumPy arrays created are:
- // vertices is a double array of shape (ntotal, 2) containing the (x, y)
- // coordinates of the points in the polygons
- // codes is a uint8 array of shape (ntotal,) containing the 'kind codes'
- // which are defined in the Path class
- // and they are returned in the Python lists vertices_list and codes_list
- // respectively.
-
- Contour::const_iterator line;
- ContourLine::const_iterator point;
-
- // Find total number of points in all contour lines.
- py::ssize_t n_points = 0;
- for (line = contour.begin(); line != contour.end(); ++line)
- n_points += static_cast<py::ssize_t>(line->size());
-
- // Create segs array for point coordinates.
- py::ssize_t segs_dims[2] = {n_points, 2};
- TwoCoordinateArray segs(segs_dims);
- double* segs_ptr = segs.mutable_data();
-
- // Create kinds array for code types.
- py::ssize_t codes_dims[1] = {n_points};
- CodeArray codes(codes_dims);
- unsigned char* codes_ptr = codes.mutable_data();
-
- for (line = contour.begin(); line != contour.end(); ++line) {
- for (point = line->begin(); point != line->end(); point++) {
- *segs_ptr++ = point->x;
- *segs_ptr++ = point->y;
- *codes_ptr++ = (point == line->begin() ? MOVETO : LINETO);
- }
-
- if (line->size() > 1)
- *(codes_ptr-1) = CLOSEPOLY;
- }
-
- py::list vertices_list(1);
- vertices_list[0] = segs;
-
- py::list codes_list(1);
- codes_list[0] = codes;
-
- return py::make_tuple(vertices_list, codes_list);
-}
-
-py::tuple TriContourGenerator::create_contour(const double& level)
-{
- clear_visited_flags(false);
- Contour contour;
-
- find_boundary_lines(contour, level);
- find_interior_lines(contour, level, false, false);
-
- return contour_line_to_segs_and_kinds(contour);
-}
-
-py::tuple TriContourGenerator::create_filled_contour(const double& lower_level,
- const double& upper_level)
-{
- if (lower_level >= upper_level)
- throw std::invalid_argument("filled contour levels must be increasing");
-
- clear_visited_flags(true);
- Contour contour;
-
- find_boundary_lines_filled(contour, lower_level, upper_level);
- find_interior_lines(contour, lower_level, false, true);
- find_interior_lines(contour, upper_level, true, true);
-
- return contour_to_segs_and_kinds(contour);
-}
-
-XY TriContourGenerator::edge_interp(int tri, int edge, const double& level)
-{
- return interp(_triangulation.get_triangle_point(tri, edge),
- _triangulation.get_triangle_point(tri, (edge+1)%3),
- level);
-}
-
-void TriContourGenerator::find_boundary_lines(Contour& contour,
- const double& level)
-{
- // Traverse boundaries to find starting points for all contour lines that
- // intersect the boundaries. For each starting point found, follow the
- // line to its end before continuing.
- const Triangulation& triang = _triangulation;
- const Boundaries& boundaries = get_boundaries();
- for (Boundaries::const_iterator it = boundaries.begin();
- it != boundaries.end(); ++it) {
- const Boundary& boundary = *it;
- bool startAbove, endAbove = false;
- for (Boundary::const_iterator itb = boundary.begin();
- itb != boundary.end(); ++itb) {
- if (itb == boundary.begin())
- startAbove = get_z(triang.get_triangle_point(*itb)) >= level;
- else
- startAbove = endAbove;
- endAbove = get_z(triang.get_triangle_point(itb->tri,
- (itb->edge+1)%3)) >= level;
- if (startAbove && !endAbove) {
- // This boundary edge is the start point for a contour line,
- // so follow the line.
- contour.push_back(ContourLine());
- ContourLine& contour_line = contour.back();
- TriEdge tri_edge = *itb;
- follow_interior(contour_line, tri_edge, true, level, false);
- }
- }
- }
-}
-
-void TriContourGenerator::find_boundary_lines_filled(Contour& contour,
- const double& lower_level,
- const double& upper_level)
-{
- // Traverse boundaries to find starting points for all contour lines that
- // intersect the boundaries. For each starting point found, follow the
- // line to its end before continuing.
- const Triangulation& triang = _triangulation;
- const Boundaries& boundaries = get_boundaries();
- for (Boundaries::size_type i = 0; i < boundaries.size(); ++i) {
- const Boundary& boundary = boundaries[i];
- for (Boundary::size_type j = 0; j < boundary.size(); ++j) {
- if (!_boundaries_visited[i][j]) {
- // z values of start and end of this boundary edge.
- double z_start = get_z(triang.get_triangle_point(boundary[j]));
- double z_end = get_z(triang.get_triangle_point(
- boundary[j].tri, (boundary[j].edge+1)%3));
-
- // Does this boundary edge's z increase through upper level
- // and/or decrease through lower level?
- bool incr_upper = (z_start < upper_level && z_end >= upper_level);
- bool decr_lower = (z_start >= lower_level && z_end < lower_level);
-
- if (decr_lower || incr_upper) {
- // Start point for contour line, so follow it.
- contour.push_back(ContourLine());
- ContourLine& contour_line = contour.back();
- TriEdge start_tri_edge = boundary[j];
- TriEdge tri_edge = start_tri_edge;
-
- // Traverse interior and boundaries until return to start.
- bool on_upper = incr_upper;
- do {
- follow_interior(contour_line, tri_edge, true,
- on_upper ? upper_level : lower_level, on_upper);
- on_upper = follow_boundary(contour_line, tri_edge,
- lower_level, upper_level, on_upper);
- } while (tri_edge != start_tri_edge);
-
- // Close polygon.
- contour_line.push_back(contour_line.front());
- }
- }
- }
- }
-
- // Add full boundaries that lie between the lower and upper levels. These
- // are boundaries that have not been touched by an internal contour line
- // which are stored in _boundaries_used.
- for (Boundaries::size_type i = 0; i < boundaries.size(); ++i) {
- if (!_boundaries_used[i]) {
- const Boundary& boundary = boundaries[i];
- double z = get_z(triang.get_triangle_point(boundary[0]));
- if (z >= lower_level && z < upper_level) {
- contour.push_back(ContourLine());
- ContourLine& contour_line = contour.back();
- for (Boundary::size_type j = 0; j < boundary.size(); ++j)
- contour_line.push_back(triang.get_point_coords(
- triang.get_triangle_point(boundary[j])));
-
- // Close polygon.
- contour_line.push_back(contour_line.front());
- }
- }
- }
-}
-
-void TriContourGenerator::find_interior_lines(Contour& contour,
- const double& level,
- bool on_upper,
- bool filled)
-{
- const Triangulation& triang = _triangulation;
- int ntri = triang.get_ntri();
- for (int tri = 0; tri < ntri; ++tri) {
- int visited_index = (on_upper ? tri+ntri : tri);
-
- if (_interior_visited[visited_index] || triang.is_masked(tri))
- continue; // Triangle has already been visited or is masked.
-
- _interior_visited[visited_index] = true;
-
- // Determine edge via which to leave this triangle.
- int edge = get_exit_edge(tri, level, on_upper);
- assert(edge >= -1 && edge < 3 && "Invalid exit edge");
- if (edge == -1)
- continue; // Contour does not pass through this triangle.
-
- // Found start of new contour line loop.
- contour.push_back(ContourLine());
- ContourLine& contour_line = contour.back();
- TriEdge tri_edge = triang.get_neighbor_edge(tri, edge);
- follow_interior(contour_line, tri_edge, false, level, on_upper);
-
- // Close line loop
- contour_line.push_back(contour_line.front());
- }
-}
-
-bool TriContourGenerator::follow_boundary(ContourLine& contour_line,
- TriEdge& tri_edge,
- const double& lower_level,
- const double& upper_level,
- bool on_upper)
-{
- const Triangulation& triang = _triangulation;
- const Boundaries& boundaries = get_boundaries();
-
- // Have TriEdge to start at, need equivalent boundary edge.
- int boundary, edge;
- triang.get_boundary_edge(tri_edge, boundary, edge);
- _boundaries_used[boundary] = true;
-
- bool stop = false;
- bool first_edge = true;
- double z_start, z_end = 0;
- while (!stop)
- {
- assert(!_boundaries_visited[boundary][edge] && "Boundary already visited");
- _boundaries_visited[boundary][edge] = true;
-
- // z values of start and end points of boundary edge.
- if (first_edge)
- z_start = get_z(triang.get_triangle_point(tri_edge));
- else
- z_start = z_end;
- z_end = get_z(triang.get_triangle_point(tri_edge.tri,
- (tri_edge.edge+1)%3));
-
- if (z_end > z_start) { // z increasing.
- if (!(!on_upper && first_edge) &&
- z_end >= lower_level && z_start < lower_level) {
- stop = true;
- on_upper = false;
- } else if (z_end >= upper_level && z_start < upper_level) {
- stop = true;
- on_upper = true;
- }
- } else { // z decreasing.
- if (!(on_upper && first_edge) &&
- z_start >= upper_level && z_end < upper_level) {
- stop = true;
- on_upper = true;
- } else if (z_start >= lower_level && z_end < lower_level) {
- stop = true;
- on_upper = false;
- }
- }
-
- first_edge = false;
-
- if (!stop) {
- // Move to next boundary edge, adding point to contour line.
- edge = (edge+1) % (int)boundaries[boundary].size();
- tri_edge = boundaries[boundary][edge];
- contour_line.push_back(triang.get_point_coords(
- triang.get_triangle_point(tri_edge)));
- }
- }
-
- return on_upper;
-}
-
-void TriContourGenerator::follow_interior(ContourLine& contour_line,
- TriEdge& tri_edge,
- bool end_on_boundary,
- const double& level,
- bool on_upper)
-{
- int& tri = tri_edge.tri;
- int& edge = tri_edge.edge;
-
- // Initial point.
- contour_line.push_back(edge_interp(tri, edge, level));
-
- while (true) {
- int visited_index = tri;
- if (on_upper)
- visited_index += _triangulation.get_ntri();
-
- // Check for end not on boundary.
- if (!end_on_boundary && _interior_visited[visited_index])
- break; // Reached start point, so return.
-
- // Determine edge by which to leave this triangle.
- edge = get_exit_edge(tri, level, on_upper);
- assert(edge >= 0 && edge < 3 && "Invalid exit edge");
-
- _interior_visited[visited_index] = true;
-
- // Append new point to point set.
- assert(edge >= 0 && edge < 3 && "Invalid triangle edge");
- contour_line.push_back(edge_interp(tri, edge, level));
-
- // Move to next triangle.
- TriEdge next_tri_edge = _triangulation.get_neighbor_edge(tri,edge);
-
- // Check if ending on a boundary.
- if (end_on_boundary && next_tri_edge.tri == -1)
- break;
-
- tri_edge = next_tri_edge;
- assert(tri_edge.tri != -1 && "Invalid triangle for internal loop");
- }
-}
-
-const TriContourGenerator::Boundaries& TriContourGenerator::get_boundaries() const
-{
- return _triangulation.get_boundaries();
-}
-
-int TriContourGenerator::get_exit_edge(int tri,
- const double& level,
- bool on_upper) const
-{
- assert(tri >= 0 && tri < _triangulation.get_ntri() &&
- "Triangle index out of bounds.");
-
- unsigned int config =
- (get_z(_triangulation.get_triangle_point(tri, 0)) >= level) |
- (get_z(_triangulation.get_triangle_point(tri, 1)) >= level) << 1 |
- (get_z(_triangulation.get_triangle_point(tri, 2)) >= level) << 2;
-
- if (on_upper) config = 7-config;
-
- switch (config) {
- case 0: return -1;
- case 1: return 2;
- case 2: return 0;
- case 3: return 2;
- case 4: return 1;
- case 5: return 1;
- case 6: return 0;
- case 7: return -1;
- default: assert(0 && "Invalid config value"); return -1;
- }
-}
-
-const double& TriContourGenerator::get_z(int point) const
-{
- assert(point >= 0 && point < _triangulation.get_npoints() &&
- "Point index out of bounds.");
- return _z.data()[point];
-}
-
-XY TriContourGenerator::interp(int point1,
- int point2,
- const double& level) const
-{
- assert(point1 >= 0 && point1 < _triangulation.get_npoints() &&
- "Point index 1 out of bounds.");
- assert(point2 >= 0 && point2 < _triangulation.get_npoints() &&
- "Point index 2 out of bounds.");
- assert(point1 != point2 && "Identical points");
- double fraction = (get_z(point2) - level) / (get_z(point2) - get_z(point1));
- return _triangulation.get_point_coords(point1)*fraction +
- _triangulation.get_point_coords(point2)*(1.0 - fraction);
-}
-
-
-
-TrapezoidMapTriFinder::TrapezoidMapTriFinder(Triangulation& triangulation)
- : _triangulation(triangulation),
- _points(0),
- _tree(0)
-{}
-
-TrapezoidMapTriFinder::~TrapezoidMapTriFinder()
-{
- clear();
-}
-
-bool
-TrapezoidMapTriFinder::add_edge_to_tree(const Edge& edge)
-{
- std::vector<Trapezoid*> trapezoids;
- if (!find_trapezoids_intersecting_edge(edge, trapezoids))
- return false;
- assert(!trapezoids.empty() && "No trapezoids intersect edge");
-
- const Point* p = edge.left;
- const Point* q = edge.right;
- Trapezoid* left_old = 0; // old trapezoid to the left.
- Trapezoid* left_below = 0; // below trapezoid to the left.
- Trapezoid* left_above = 0; // above trapezoid to the left.
-
- // Iterate through trapezoids intersecting edge from left to right.
- // Replace each old trapezoid with 2+ new trapezoids, and replace its
- // corresponding nodes in the search tree with new nodes.
- size_t ntraps = trapezoids.size();
- for (size_t i = 0; i < ntraps; ++i) {
- Trapezoid* old = trapezoids[i]; // old trapezoid to replace.
- bool start_trap = (i == 0);
- bool end_trap = (i == ntraps-1);
- bool have_left = (start_trap && edge.left != old->left);
- bool have_right = (end_trap && edge.right != old->right);
-
- // Old trapezoid is replaced by up to 4 new trapezoids: left is to the
- // left of the start point p, below/above are below/above the edge
- // inserted, and right is to the right of the end point q.
- Trapezoid* left = 0;
- Trapezoid* below = 0;
- Trapezoid* above = 0;
- Trapezoid* right = 0;
-
- // There are 4 different cases here depending on whether the old
- // trapezoid in question is the start and/or end trapezoid of those
- // that intersect the edge inserted. There is some code duplication
- // here but it is much easier to understand this way rather than
- // interleave the 4 different cases with many more if-statements.
- if (start_trap && end_trap) {
- // Edge intersects a single trapezoid.
- if (have_left)
- left = new Trapezoid(old->left, p, old->below, old->above);
- below = new Trapezoid(p, q, old->below, edge);
- above = new Trapezoid(p, q, edge, old->above);
- if (have_right)
- right = new Trapezoid(q, old->right, old->below, old->above);
-
- // Set pairs of trapezoid neighbours.
- if (have_left) {
- left->set_lower_left(old->lower_left);
- left->set_upper_left(old->upper_left);
- left->set_lower_right(below);
- left->set_upper_right(above);
- }
- else {
- below->set_lower_left(old->lower_left);
- above->set_upper_left(old->upper_left);
- }
-
- if (have_right) {
- right->set_lower_right(old->lower_right);
- right->set_upper_right(old->upper_right);
- below->set_lower_right(right);
- above->set_upper_right(right);
- }
- else {
- below->set_lower_right(old->lower_right);
- above->set_upper_right(old->upper_right);
- }
- }
- else if (start_trap) {
- // Old trapezoid is the first of 2+ trapezoids that the edge
- // intersects.
- if (have_left)
- left = new Trapezoid(old->left, p, old->below, old->above);
- below = new Trapezoid(p, old->right, old->below, edge);
- above = new Trapezoid(p, old->right, edge, old->above);
-
- // Set pairs of trapezoid neighbours.
- if (have_left) {
- left->set_lower_left(old->lower_left);
- left->set_upper_left(old->upper_left);
- left->set_lower_right(below);
- left->set_upper_right(above);
- }
- else {
- below->set_lower_left(old->lower_left);
- above->set_upper_left(old->upper_left);
- }
-
- below->set_lower_right(old->lower_right);
- above->set_upper_right(old->upper_right);
- }
- else if (end_trap) {
- // Old trapezoid is the last of 2+ trapezoids that the edge
- // intersects.
- if (left_below->below == old->below) {
- below = left_below;
- below->right = q;
- }
- else
- below = new Trapezoid(old->left, q, old->below, edge);
-
- if (left_above->above == old->above) {
- above = left_above;
- above->right = q;
- }
- else
- above = new Trapezoid(old->left, q, edge, old->above);
-
- if (have_right)
- right = new Trapezoid(q, old->right, old->below, old->above);
-
- // Set pairs of trapezoid neighbours.
- if (have_right) {
- right->set_lower_right(old->lower_right);
- right->set_upper_right(old->upper_right);
- below->set_lower_right(right);
- above->set_upper_right(right);
- }
- else {
- below->set_lower_right(old->lower_right);
- above->set_upper_right(old->upper_right);
- }
-
- // Connect to new trapezoids replacing prevOld.
- if (below != left_below) {
- below->set_upper_left(left_below);
- if (old->lower_left == left_old)
- below->set_lower_left(left_below);
- else
- below->set_lower_left(old->lower_left);
- }
-
- if (above != left_above) {
- above->set_lower_left(left_above);
- if (old->upper_left == left_old)
- above->set_upper_left(left_above);
- else
- above->set_upper_left(old->upper_left);
- }
- }
- else { // Middle trapezoid.
- // Old trapezoid is neither the first nor last of the 3+ trapezoids
- // that the edge intersects.
- if (left_below->below == old->below) {
- below = left_below;
- below->right = old->right;
- }
- else
- below = new Trapezoid(old->left, old->right, old->below, edge);
-
- if (left_above->above == old->above) {
- above = left_above;
- above->right = old->right;
- }
- else
- above = new Trapezoid(old->left, old->right, edge, old->above);
-
- // Connect to new trapezoids replacing prevOld.
- if (below != left_below) { // below is new.
- below->set_upper_left(left_below);
- if (old->lower_left == left_old)
- below->set_lower_left(left_below);
- else
- below->set_lower_left(old->lower_left);
- }
-
- if (above != left_above) { // above is new.
- above->set_lower_left(left_above);
- if (old->upper_left == left_old)
- above->set_upper_left(left_above);
- else
- above->set_upper_left(old->upper_left);
- }
-
- below->set_lower_right(old->lower_right);
- above->set_upper_right(old->upper_right);
- }
-
- // Create new nodes to add to search tree. Below and above trapezoids
- // may already have owning trapezoid nodes, in which case reuse them.
- Node* new_top_node = new Node(
- &edge,
- below == left_below ? below->trapezoid_node : new Node(below),
- above == left_above ? above->trapezoid_node : new Node(above));
- if (have_right)
- new_top_node = new Node(q, new_top_node, new Node(right));
- if (have_left)
- new_top_node = new Node(p, new Node(left), new_top_node);
-
- // Insert new_top_node in correct position or positions in search tree.
- Node* old_node = old->trapezoid_node;
- if (old_node == _tree)
- _tree = new_top_node;
- else
- old_node->replace_with(new_top_node);
-
- // old_node has been removed from all of its parents and is no longer
- // needed.
- assert(old_node->has_no_parents() && "Node should have no parents");
- delete old_node;
-
- // Clearing up.
- if (!end_trap) {
- // Prepare for next loop.
- left_old = old;
- left_above = above;
- left_below = below;
- }
- }
-
- return true;
-}
-
-void
-TrapezoidMapTriFinder::clear()
-{
- delete [] _points;
- _points = 0;
-
- _edges.clear();
-
- delete _tree;
- _tree = 0;
-}
-
-TrapezoidMapTriFinder::TriIndexArray
-TrapezoidMapTriFinder::find_many(const CoordinateArray& x,
- const CoordinateArray& y)
-{
- if (x.ndim() != 1 || x.shape(0) != y.shape(0))
- throw std::invalid_argument(
- "x and y must be array-like with same shape");
-
- // Create integer array to return.
- auto n = x.shape(0);
- TriIndexArray tri_indices_array(n);
- auto tri_indices = tri_indices_array.mutable_unchecked<1>();
- auto x_data = x.data();
- auto y_data = y.data();
-
- // Fill returned array.
- for (py::ssize_t i = 0; i < n; ++i)
- tri_indices(i) = find_one(XY(x_data[i], y_data[i]));
-
- return tri_indices_array;
-}
-
-int
-TrapezoidMapTriFinder::find_one(const XY& xy)
-{
- const Node* node = _tree->search(xy);
- assert(node != 0 && "Search tree for point returned null node");
- return node->get_tri();
-}
-
-bool
-TrapezoidMapTriFinder::find_trapezoids_intersecting_edge(
- const Edge& edge,
- std::vector<Trapezoid*>& trapezoids)
-{
- // This is the FollowSegment algorithm of de Berg et al, with some extra
- // checks to deal with simple colinear (i.e. invalid) triangles.
- trapezoids.clear();
- Trapezoid* trapezoid = _tree->search(edge);
- if (trapezoid == 0) {
- assert(trapezoid != 0 && "search(edge) returns null trapezoid");
- return false;
- }
-
- trapezoids.push_back(trapezoid);
- while (edge.right->is_right_of(*trapezoid->right)) {
- int orient = edge.get_point_orientation(*trapezoid->right);
- if (orient == 0) {
- if (edge.point_below == trapezoid->right)
- orient = +1;
- else if (edge.point_above == trapezoid->right)
- orient = -1;
- else {
- assert(0 && "Unable to deal with point on edge");
- return false;
- }
- }
-
- if (orient == -1)
- trapezoid = trapezoid->lower_right;
- else if (orient == +1)
- trapezoid = trapezoid->upper_right;
-
- if (trapezoid == 0) {
- assert(0 && "Expected trapezoid neighbor");
- return false;
- }
- trapezoids.push_back(trapezoid);
- }
-
- return true;
-}
-
-py::list
-TrapezoidMapTriFinder::get_tree_stats()
-{
- NodeStats stats;
- _tree->get_stats(0, stats);
-
- py::list ret(7);
- ret[0] = stats.node_count;
- ret[1] = stats.unique_nodes.size(),
- ret[2] = stats.trapezoid_count,
- ret[3] = stats.unique_trapezoid_nodes.size(),
- ret[4] = stats.max_parent_count,
- ret[5] = stats.max_depth,
- ret[6] = stats.sum_trapezoid_depth / stats.trapezoid_count;
- return ret;
-}
-
-void
-TrapezoidMapTriFinder::initialize()
-{
- clear();
- const Triangulation& triang = _triangulation;
-
- // Set up points array, which contains all of the points in the
- // triangulation plus the 4 corners of the enclosing rectangle.
- int npoints = triang.get_npoints();
- _points = new Point[npoints + 4];
- BoundingBox bbox;
- for (int i = 0; i < npoints; ++i) {
- XY xy = triang.get_point_coords(i);
- // Avoid problems with -0.0 values different from 0.0
- if (xy.x == -0.0)
- xy.x = 0.0;
- if (xy.y == -0.0)
- xy.y = 0.0;
- _points[i] = Point(xy);
- bbox.add(xy);
- }
-
- // Last 4 points are corner points of enclosing rectangle. Enclosing
- // rectangle made slightly larger in case corner points are already in the
- // triangulation.
- if (bbox.empty) {
- bbox.add(XY(0.0, 0.0));
- bbox.add(XY(1.0, 1.0));
- }
- else {
- const double small = 0.1; // Any value > 0.0
- bbox.expand( (bbox.upper - bbox.lower)*small );
- }
- _points[npoints ] = Point(bbox.lower); // SW point.
- _points[npoints+1] = Point(bbox.upper.x, bbox.lower.y); // SE point.
- _points[npoints+2] = Point(bbox.lower.x, bbox.upper.y); // NW point.
- _points[npoints+3] = Point(bbox.upper); // NE point.
-
- // Set up edges array.
- // First the bottom and top edges of the enclosing rectangle.
- _edges.push_back(Edge(&_points[npoints], &_points[npoints+1],-1,-1,0,0));
- _edges.push_back(Edge(&_points[npoints+2],&_points[npoints+3],-1,-1,0,0));
-
- // Add all edges in the triangulation that point to the right. Do not
- // explicitly include edges that point to the left as the neighboring
- // triangle will supply that, unless there is no such neighbor.
- int ntri = triang.get_ntri();
- for (int tri = 0; tri < ntri; ++tri) {
- if (!triang.is_masked(tri)) {
- for (int edge = 0; edge < 3; ++edge) {
- Point* start = _points + triang.get_triangle_point(tri,edge);
- Point* end = _points +
- triang.get_triangle_point(tri,(edge+1)%3);
- Point* other = _points +
- triang.get_triangle_point(tri,(edge+2)%3);
- TriEdge neighbor = triang.get_neighbor_edge(tri,edge);
- if (end->is_right_of(*start)) {
- const Point* neighbor_point_below = (neighbor.tri == -1) ?
- 0 : _points + triang.get_triangle_point(
- neighbor.tri, (neighbor.edge+2)%3);
- _edges.push_back(Edge(start, end, neighbor.tri, tri,
- neighbor_point_below, other));
- }
- else if (neighbor.tri == -1)
- _edges.push_back(Edge(end, start, tri, -1, other, 0));
-
- // Set triangle associated with start point if not already set.
- if (start->tri == -1)
- start->tri = tri;
- }
- }
- }
-
- // Initial trapezoid is enclosing rectangle.
- _tree = new Node(new Trapezoid(&_points[npoints], &_points[npoints+1],
- _edges[0], _edges[1]));
- _tree->assert_valid(false);
-
- // Randomly shuffle all edges other than first 2.
- std::mt19937 rng(1234);
- std::shuffle(_edges.begin()+2, _edges.end(), rng);
-
- // Add edges, one at a time, to tree.
- size_t nedges = _edges.size();
- for (size_t index = 2; index < nedges; ++index) {
- if (!add_edge_to_tree(_edges[index]))
- throw std::runtime_error("Triangulation is invalid");
- _tree->assert_valid(index == nedges-1);
- }
-}
-
-void
-TrapezoidMapTriFinder::print_tree()
-{
- assert(_tree != 0 && "Null Node tree");
- _tree->print();
-}
-
-TrapezoidMapTriFinder::Edge::Edge(const Point* left_,
- const Point* right_,
- int triangle_below_,
- int triangle_above_,
- const Point* point_below_,
- const Point* point_above_)
- : left(left_),
- right(right_),
- triangle_below(triangle_below_),
- triangle_above(triangle_above_),
- point_below(point_below_),
- point_above(point_above_)
-{
- assert(left != 0 && "Null left point");
- assert(right != 0 && "Null right point");
- assert(right->is_right_of(*left) && "Incorrect point order");
- assert(triangle_below >= -1 && "Invalid triangle below index");
- assert(triangle_above >= -1 && "Invalid triangle above index");
-}
-
-int
-TrapezoidMapTriFinder::Edge::get_point_orientation(const XY& xy) const
-{
- double cross_z = (xy - *left).cross_z(*right - *left);
- return (cross_z > 0.0) ? +1 : ((cross_z < 0.0) ? -1 : 0);
-}
-
-double
-TrapezoidMapTriFinder::Edge::get_slope() const
-{
- // Divide by zero is acceptable here.
- XY diff = *right - *left;
- return diff.y / diff.x;
-}
-
-double
-TrapezoidMapTriFinder::Edge::get_y_at_x(const double& x) const
-{
- if (left->x == right->x) {
- // If edge is vertical, return lowest y from left point.
- assert(x == left->x && "x outside of edge");
- return left->y;
- }
- else {
- // Equation of line: left + lambda*(right - left) = xy.
- // i.e. left.x + lambda(right.x - left.x) = x and similar for y.
- double lambda = (x - left->x) / (right->x - left->x);
- assert(lambda >= 0 && lambda <= 1.0 && "Lambda out of bounds");
- return left->y + lambda*(right->y - left->y);
- }
-}
-
-bool
-TrapezoidMapTriFinder::Edge::has_point(const Point* point) const
-{
- assert(point != 0 && "Null point");
- return (left == point || right == point);
-}
-
-bool
-TrapezoidMapTriFinder::Edge::operator==(const Edge& other) const
-{
- return this == &other;
-}
-
-void
-TrapezoidMapTriFinder::Edge::print_debug() const
-{
- std::cout << "Edge " << *this << " tri_below=" << triangle_below
- << " tri_above=" << triangle_above << std::endl;
-}
-
-TrapezoidMapTriFinder::Node::Node(const Point* point, Node* left, Node* right)
- : _type(Type_XNode)
-{
- assert(point != 0 && "Invalid point");
- assert(left != 0 && "Invalid left node");
- assert(right != 0 && "Invalid right node");
- _union.xnode.point = point;
- _union.xnode.left = left;
- _union.xnode.right = right;
- left->add_parent(this);
- right->add_parent(this);
-}
-
-TrapezoidMapTriFinder::Node::Node(const Edge* edge, Node* below, Node* above)
- : _type(Type_YNode)
-{
- assert(edge != 0 && "Invalid edge");
- assert(below != 0 && "Invalid below node");
- assert(above != 0 && "Invalid above node");
- _union.ynode.edge = edge;
- _union.ynode.below = below;
- _union.ynode.above = above;
- below->add_parent(this);
- above->add_parent(this);
-}
-
-TrapezoidMapTriFinder::Node::Node(Trapezoid* trapezoid)
- : _type(Type_TrapezoidNode)
-{
- assert(trapezoid != 0 && "Null Trapezoid");
- _union.trapezoid = trapezoid;
- trapezoid->trapezoid_node = this;
-}
-
-TrapezoidMapTriFinder::Node::~Node()
-{
- switch (_type) {
- case Type_XNode:
- if (_union.xnode.left->remove_parent(this))
- delete _union.xnode.left;
- if (_union.xnode.right->remove_parent(this))
- delete _union.xnode.right;
- break;
- case Type_YNode:
- if (_union.ynode.below->remove_parent(this))
- delete _union.ynode.below;
- if (_union.ynode.above->remove_parent(this))
- delete _union.ynode.above;
- break;
- case Type_TrapezoidNode:
- delete _union.trapezoid;
- break;
- }
-}
-
-void
-TrapezoidMapTriFinder::Node::add_parent(Node* parent)
-{
- assert(parent != 0 && "Null parent");
- assert(parent != this && "Cannot be parent of self");
- assert(!has_parent(parent) && "Parent already in collection");
- _parents.push_back(parent);
-}
-
-void
-TrapezoidMapTriFinder::Node::assert_valid(bool tree_complete) const
-{
-#ifndef NDEBUG
- // Check parents.
- for (Parents::const_iterator it = _parents.begin();
- it != _parents.end(); ++it) {
- Node* parent = *it;
- assert(parent != this && "Cannot be parent of self");
- assert(parent->has_child(this) && "Parent missing child");
- }
-
- // Check children, and recurse.
- switch (_type) {
- case Type_XNode:
- assert(_union.xnode.left != 0 && "Null left child");
- assert(_union.xnode.left->has_parent(this) && "Incorrect parent");
- assert(_union.xnode.right != 0 && "Null right child");
- assert(_union.xnode.right->has_parent(this) && "Incorrect parent");
- _union.xnode.left->assert_valid(tree_complete);
- _union.xnode.right->assert_valid(tree_complete);
- break;
- case Type_YNode:
- assert(_union.ynode.below != 0 && "Null below child");
- assert(_union.ynode.below->has_parent(this) && "Incorrect parent");
- assert(_union.ynode.above != 0 && "Null above child");
- assert(_union.ynode.above->has_parent(this) && "Incorrect parent");
- _union.ynode.below->assert_valid(tree_complete);
- _union.ynode.above->assert_valid(tree_complete);
- break;
- case Type_TrapezoidNode:
- assert(_union.trapezoid != 0 && "Null trapezoid");
- assert(_union.trapezoid->trapezoid_node == this &&
- "Incorrect trapezoid node");
- _union.trapezoid->assert_valid(tree_complete);
- break;
- }
-#endif
-}
-
-void
-TrapezoidMapTriFinder::Node::get_stats(int depth,
- NodeStats& stats) const
-{
- stats.node_count++;
- if (depth > stats.max_depth)
- stats.max_depth = depth;
- bool new_node = stats.unique_nodes.insert(this).second;
- if (new_node)
- stats.max_parent_count = std::max(stats.max_parent_count,
- static_cast<long>(_parents.size()));
-
- switch (_type) {
- case Type_XNode:
- _union.xnode.left->get_stats(depth+1, stats);
- _union.xnode.right->get_stats(depth+1, stats);
- break;
- case Type_YNode:
- _union.ynode.below->get_stats(depth+1, stats);
- _union.ynode.above->get_stats(depth+1, stats);
- break;
- default: // Type_TrapezoidNode:
- stats.unique_trapezoid_nodes.insert(this);
- stats.trapezoid_count++;
- stats.sum_trapezoid_depth += depth;
- break;
- }
-}
-
-int
-TrapezoidMapTriFinder::Node::get_tri() const
-{
- switch (_type) {
- case Type_XNode:
- return _union.xnode.point->tri;
- case Type_YNode:
- if (_union.ynode.edge->triangle_above != -1)
- return _union.ynode.edge->triangle_above;
- else
- return _union.ynode.edge->triangle_below;
- default: // Type_TrapezoidNode:
- assert(_union.trapezoid->below.triangle_above ==
- _union.trapezoid->above.triangle_below &&
- "Inconsistent triangle indices from trapezoid edges");
- return _union.trapezoid->below.triangle_above;
- }
-}
-
-bool
-TrapezoidMapTriFinder::Node::has_child(const Node* child) const
-{
- assert(child != 0 && "Null child node");
- switch (_type) {
- case Type_XNode:
- return (_union.xnode.left == child || _union.xnode.right == child);
- case Type_YNode:
- return (_union.ynode.below == child ||
- _union.ynode.above == child);
- default: // Type_TrapezoidNode:
- return false;
- }
-}
-
-bool
-TrapezoidMapTriFinder::Node::has_no_parents() const
-{
- return _parents.empty();
-}
-
-bool
-TrapezoidMapTriFinder::Node::has_parent(const Node* parent) const
-{
- return (std::find(_parents.begin(), _parents.end(), parent) !=
- _parents.end());
-}
-
-void
-TrapezoidMapTriFinder::Node::print(int depth /* = 0 */) const
-{
- for (int i = 0; i < depth; ++i) std::cout << " ";
- switch (_type) {
- case Type_XNode:
- std::cout << "XNode " << *_union.xnode.point << std::endl;
- _union.xnode.left->print(depth + 1);
- _union.xnode.right->print(depth + 1);
- break;
- case Type_YNode:
- std::cout << "YNode " << *_union.ynode.edge << std::endl;
- _union.ynode.below->print(depth + 1);
- _union.ynode.above->print(depth + 1);
- break;
- case Type_TrapezoidNode:
- std::cout << "Trapezoid ll="
- << _union.trapezoid->get_lower_left_point() << " lr="
- << _union.trapezoid->get_lower_right_point() << " ul="
- << _union.trapezoid->get_upper_left_point() << " ur="
- << _union.trapezoid->get_upper_right_point() << std::endl;
- break;
- }
-}
-
-bool
-TrapezoidMapTriFinder::Node::remove_parent(Node* parent)
-{
- assert(parent != 0 && "Null parent");
- assert(parent != this && "Cannot be parent of self");
- Parents::iterator it = std::find(_parents.begin(), _parents.end(), parent);
- assert(it != _parents.end() && "Parent not in collection");
- _parents.erase(it);
- return _parents.empty();
-}
-
-void
-TrapezoidMapTriFinder::Node::replace_child(Node* old_child, Node* new_child)
-{
- switch (_type) {
- case Type_XNode:
- assert((_union.xnode.left == old_child ||
- _union.xnode.right == old_child) && "Not a child Node");
- assert(new_child != 0 && "Null child node");
- if (_union.xnode.left == old_child)
- _union.xnode.left = new_child;
- else
- _union.xnode.right = new_child;
- break;
- case Type_YNode:
- assert((_union.ynode.below == old_child ||
- _union.ynode.above == old_child) && "Not a child node");
- assert(new_child != 0 && "Null child node");
- if (_union.ynode.below == old_child)
- _union.ynode.below = new_child;
- else
- _union.ynode.above = new_child;
- break;
- case Type_TrapezoidNode:
- assert(0 && "Invalid type for this operation");
- break;
- }
- old_child->remove_parent(this);
- new_child->add_parent(this);
-}
-
-void
-TrapezoidMapTriFinder::Node::replace_with(Node* new_node)
-{
- assert(new_node != 0 && "Null replacement node");
- // Replace child of each parent with new_node. As each has parent has its
- // child replaced it is removed from the _parents collection.
- while (!_parents.empty())
- _parents.front()->replace_child(this, new_node);
-}
-
-const TrapezoidMapTriFinder::Node*
-TrapezoidMapTriFinder::Node::search(const XY& xy)
-{
- switch (_type) {
- case Type_XNode:
- if (xy == *_union.xnode.point)
- return this;
- else if (xy.is_right_of(*_union.xnode.point))
- return _union.xnode.right->search(xy);
- else
- return _union.xnode.left->search(xy);
- case Type_YNode: {
- int orient = _union.ynode.edge->get_point_orientation(xy);
- if (orient == 0)
- return this;
- else if (orient < 0)
- return _union.ynode.above->search(xy);
- else
- return _union.ynode.below->search(xy);
- }
- default: // Type_TrapezoidNode:
- return this;
- }
-}
-
-TrapezoidMapTriFinder::Trapezoid*
-TrapezoidMapTriFinder::Node::search(const Edge& edge)
-{
- switch (_type) {
- case Type_XNode:
- if (edge.left == _union.xnode.point)
- return _union.xnode.right->search(edge);
- else {
- if (edge.left->is_right_of(*_union.xnode.point))
- return _union.xnode.right->search(edge);
- else
- return _union.xnode.left->search(edge);
- }
- case Type_YNode:
- if (edge.left == _union.ynode.edge->left) {
- // Coinciding left edge points.
- if (edge.get_slope() == _union.ynode.edge->get_slope()) {
- if (_union.ynode.edge->triangle_above ==
- edge.triangle_below)
- return _union.ynode.above->search(edge);
- else if (_union.ynode.edge->triangle_below ==
- edge.triangle_above)
- return _union.ynode.below->search(edge);
- else {
- assert(0 &&
- "Invalid triangulation, common left points");
- return 0;
- }
- }
- if (edge.get_slope() > _union.ynode.edge->get_slope())
- return _union.ynode.above->search(edge);
- else
- return _union.ynode.below->search(edge);
- }
- else if (edge.right == _union.ynode.edge->right) {
- // Coinciding right edge points.
- if (edge.get_slope() == _union.ynode.edge->get_slope()) {
- if (_union.ynode.edge->triangle_above ==
- edge.triangle_below)
- return _union.ynode.above->search(edge);
- else if (_union.ynode.edge->triangle_below ==
- edge.triangle_above)
- return _union.ynode.below->search(edge);
- else {
- assert(0 &&
- "Invalid triangulation, common right points");
- return 0;
- }
- }
- if (edge.get_slope() > _union.ynode.edge->get_slope())
- return _union.ynode.below->search(edge);
- else
- return _union.ynode.above->search(edge);
- }
- else {
- int orient =
- _union.ynode.edge->get_point_orientation(*edge.left);
- if (orient == 0) {
- // edge.left lies on _union.ynode.edge
- if (_union.ynode.edge->point_above != 0 &&
- edge.has_point(_union.ynode.edge->point_above))
- orient = -1;
- else if (_union.ynode.edge->point_below != 0 &&
- edge.has_point(_union.ynode.edge->point_below))
- orient = +1;
- else {
- assert(0 && "Invalid triangulation, point on edge");
- return 0;
- }
- }
- if (orient < 0)
- return _union.ynode.above->search(edge);
- else
- return _union.ynode.below->search(edge);
- }
- default: // Type_TrapezoidNode:
- return _union.trapezoid;
- }
-}
-
-TrapezoidMapTriFinder::Trapezoid::Trapezoid(const Point* left_,
- const Point* right_,
- const Edge& below_,
- const Edge& above_)
- : left(left_), right(right_), below(below_), above(above_),
- lower_left(0), lower_right(0), upper_left(0), upper_right(0),
- trapezoid_node(0)
-{
- assert(left != 0 && "Null left point");
- assert(right != 0 && "Null right point");
- assert(right->is_right_of(*left) && "Incorrect point order");
-}
-
-void
-TrapezoidMapTriFinder::Trapezoid::assert_valid(bool tree_complete) const
-{
-#ifndef NDEBUG
- assert(left != 0 && "Null left point");
- assert(right != 0 && "Null right point");
-
- if (lower_left != 0) {
- assert(lower_left->below == below &&
- lower_left->lower_right == this &&
- "Incorrect lower_left trapezoid");
- assert(get_lower_left_point() == lower_left->get_lower_right_point() &&
- "Incorrect lower left point");
- }
-
- if (lower_right != 0) {
- assert(lower_right->below == below &&
- lower_right->lower_left == this &&
- "Incorrect lower_right trapezoid");
- assert(get_lower_right_point() == lower_right->get_lower_left_point() &&
- "Incorrect lower right point");
- }
-
- if (upper_left != 0) {
- assert(upper_left->above == above &&
- upper_left->upper_right == this &&
- "Incorrect upper_left trapezoid");
- assert(get_upper_left_point() == upper_left->get_upper_right_point() &&
- "Incorrect upper left point");
- }
-
- if (upper_right != 0) {
- assert(upper_right->above == above &&
- upper_right->upper_left == this &&
- "Incorrect upper_right trapezoid");
- assert(get_upper_right_point() == upper_right->get_upper_left_point() &&
- "Incorrect upper right point");
- }
-
- assert(trapezoid_node != 0 && "Null trapezoid_node");
-
- if (tree_complete) {
- assert(below.triangle_above == above.triangle_below &&
- "Inconsistent triangle indices from trapezoid edges");
- }
-#endif
-}
-
-XY
-TrapezoidMapTriFinder::Trapezoid::get_lower_left_point() const
-{
- double x = left->x;
- return XY(x, below.get_y_at_x(x));
-}
-
-XY
-TrapezoidMapTriFinder::Trapezoid::get_lower_right_point() const
-{
- double x = right->x;
- return XY(x, below.get_y_at_x(x));
-}
-
-XY
-TrapezoidMapTriFinder::Trapezoid::get_upper_left_point() const
-{
- double x = left->x;
- return XY(x, above.get_y_at_x(x));
-}
-
-XY
-TrapezoidMapTriFinder::Trapezoid::get_upper_right_point() const
-{
- double x = right->x;
- return XY(x, above.get_y_at_x(x));
-}
-
-void
-TrapezoidMapTriFinder::Trapezoid::print_debug() const
-{
- std::cout << "Trapezoid " << this
- << " left=" << *left
- << " right=" << *right
- << " below=" << below
- << " above=" << above
- << " ll=" << lower_left
- << " lr=" << lower_right
- << " ul=" << upper_left
- << " ur=" << upper_right
- << " node=" << trapezoid_node
- << " llp=" << get_lower_left_point()
- << " lrp=" << get_lower_right_point()
- << " ulp=" << get_upper_left_point()
- << " urp=" << get_upper_right_point() << std::endl;
-}
-
-void
-TrapezoidMapTriFinder::Trapezoid::set_lower_left(Trapezoid* lower_left_)
-{
- lower_left = lower_left_;
- if (lower_left != 0)
- lower_left->lower_right = this;
-}
-
-void
-TrapezoidMapTriFinder::Trapezoid::set_lower_right(Trapezoid* lower_right_)
-{
- lower_right = lower_right_;
- if (lower_right != 0)
- lower_right->lower_left = this;
-}
-
-void
-TrapezoidMapTriFinder::Trapezoid::set_upper_left(Trapezoid* upper_left_)
-{
- upper_left = upper_left_;
- if (upper_left != 0)
- upper_left->upper_right = this;
-}
-
-void
-TrapezoidMapTriFinder::Trapezoid::set_upper_right(Trapezoid* upper_right_)
-{
- upper_right = upper_right_;
- if (upper_right != 0)
- upper_right->upper_left = this;
-}
diff --git a/contrib/python/matplotlib/py3/src/tri/_tri.h b/contrib/python/matplotlib/py3/src/tri/_tri.h
deleted file mode 100644
index c176b4c0e8..0000000000
--- a/contrib/python/matplotlib/py3/src/tri/_tri.h
+++ /dev/null
@@ -1,799 +0,0 @@
-/*
- * Unstructured triangular grid functions, particularly contouring.
- *
- * There are two main classes: Triangulation and TriContourGenerator.
- *
- * Triangulation
- * -------------
- * Triangulation is an unstructured triangular grid with npoints and ntri
- * triangles. It consists of point x and y coordinates, and information about
- * the triangulation stored in an integer array of shape (ntri,3) called
- * triangles. Each triangle is represented by three point indices (in the
- * range 0 to npoints-1) that comprise the triangle, ordered anticlockwise.
- * There is an optional mask of length ntri which can be used to mask out
- * triangles and has the same result as removing those triangles from the
- * 'triangles' array.
- *
- * A particular edge of a triangulation is termed a TriEdge, which is a
- * triangle index and an edge index in the range 0 to 2. TriEdge(tri,edge)
- * refers to the edge that starts at point index triangles(tri,edge) and ends
- * at point index triangles(tri,(edge+1)%3).
- *
- * Various derived fields are calculated when they are first needed. The
- * triangle connectivity is stored in a neighbors array of shape (ntri,3) such
- * that neighbors(tri,edge) is the index of the triangle that adjoins the
- * TriEdge(tri,edge), or -1 if there is no such neighbor.
- *
- * A triangulation has one or more boundaries, each of which is a 1D array of
- * the TriEdges that comprise the boundary, in order following the boundary
- * with non-masked triangles on the left.
- *
- * TriContourGenerator
- * -------------------
- * A TriContourGenerator generates contours for a particular Triangulation.
- * The process followed is different for non-filled and filled contours, with
- * one and two contour levels respectively. In both cases boundary contour
- * lines are found first, then interior lines.
- *
- * Boundary lines start and end on a boundary. They are found by traversing
- * the triangulation boundary edges until a suitable start point is found, and
- * then the contour line is followed across the interior of the triangulation
- * until it ends on another boundary edge. For a non-filled contour this
- * completes a line, whereas a filled contour continues by following the
- * boundary around until either another boundary start point is found or the
- * start of the contour line is reached. Filled contour generation stores
- * boolean flags to indicate which boundary edges have already been traversed
- * so that they are not dealt with twice. Similar flags are used to indicate
- * which triangles have been used when following interior lines.
- *
- * Interior lines do not intersect any boundaries. They are found by
- * traversing all triangles that have not yet been visited until a suitable
- * starting point is found, and then the contour line is followed across the
- * interior of the triangulation until it returns to the start point. For
- * filled contours this process is repeated for both lower and upper contour
- * levels, and the direction of traversal is reversed for upper contours.
- *
- * Working out in which direction a contour line leaves a triangle uses the
- * a lookup table. A triangle has three points, each of which has a z-value
- * which is either less than the contour level or not. Hence there are 8
- * configurations to deal with, 2 of which do not have a contour line (all
- * points below or above (including the same as) the contour level) and 6 that
- * do. See the function get_exit_edge for details.
- */
-#ifndef MPL_TRI_H
-#define MPL_TRI_H
-
-#include <pybind11/pybind11.h>
-#include <pybind11/numpy.h>
-
-#include <iostream>
-#include <list>
-#include <map>
-#include <set>
-#include <vector>
-
-namespace py = pybind11;
-
-
-/* An edge of a triangle consisting of an triangle index in the range 0 to
- * ntri-1 and an edge index in the range 0 to 2. Edge i goes from the
- * triangle's point i to point (i+1)%3. */
-struct TriEdge
-{
- TriEdge();
- TriEdge(int tri_, int edge_);
- bool operator<(const TriEdge& other) const;
- bool operator==(const TriEdge& other) const;
- bool operator!=(const TriEdge& other) const;
- friend std::ostream& operator<<(std::ostream& os, const TriEdge& tri_edge);
-
- int tri, edge;
-};
-
-// 2D point with x,y coordinates.
-struct XY
-{
- XY();
- XY(const double& x_, const double& y_);
- double angle() const; // Angle in radians with respect to x-axis.
- double cross_z(const XY& other) const; // z-component of cross product.
- bool is_right_of(const XY& other) const; // Compares x then y.
- bool operator==(const XY& other) const;
- bool operator!=(const XY& other) const;
- XY operator*(const double& multiplier) const;
- const XY& operator+=(const XY& other);
- const XY& operator-=(const XY& other);
- XY operator+(const XY& other) const;
- XY operator-(const XY& other) const;
- friend std::ostream& operator<<(std::ostream& os, const XY& xy);
-
- double x, y;
-};
-
-// 3D point with x,y,z coordinates.
-struct XYZ
-{
- XYZ(const double& x_, const double& y_, const double& z_);
- XYZ cross(const XYZ& other) const;
- double dot(const XYZ& other) const;
- XYZ operator-(const XYZ& other) const;
- friend std::ostream& operator<<(std::ostream& os, const XYZ& xyz);
-
- double x, y, z;
-};
-
-// 2D bounding box, which may be empty.
-class BoundingBox
-{
-public:
- BoundingBox();
- void add(const XY& point);
- void expand(const XY& delta);
-
- // Consider these member variables read-only.
- bool empty;
- XY lower, upper;
-};
-
-/* A single line of a contour, which may be a closed line loop or an open line
- * strip. Identical adjacent points are avoided using push_back(), and a closed
- * line loop should also not have identical first and last points. */
-class ContourLine : public std::vector<XY>
-{
-public:
- ContourLine();
- void push_back(const XY& point);
- void write() const;
-};
-
-// A Contour is a collection of zero or more ContourLines.
-typedef std::vector<ContourLine> Contour;
-
-// Debug contour writing function.
-void write_contour(const Contour& contour);
-
-
-
-
-/* Triangulation with npoints points and ntri triangles. Derived fields are
- * calculated when they are first needed. */
-class Triangulation
-{
-public:
- typedef py::array_t<double, py::array::c_style | py::array::forcecast> CoordinateArray;
- typedef py::array_t<double, py::array::c_style | py::array::forcecast> TwoCoordinateArray;
- typedef py::array_t<int, py::array::c_style | py::array::forcecast> TriangleArray;
- typedef py::array_t<bool, py::array::c_style | py::array::forcecast> MaskArray;
- typedef py::array_t<int, py::array::c_style | py::array::forcecast> EdgeArray;
- typedef py::array_t<int, py::array::c_style | py::array::forcecast> NeighborArray;
-
- /* A single boundary is a vector of the TriEdges that make up that boundary
- * following it around with unmasked triangles on the left. */
- typedef std::vector<TriEdge> Boundary;
- typedef std::vector<Boundary> Boundaries;
-
- /* Constructor with optional mask, edges and neighbors. The latter two
- * are calculated when first needed.
- * x: double array of shape (npoints) of points' x-coordinates.
- * y: double array of shape (npoints) of points' y-coordinates.
- * triangles: int array of shape (ntri,3) of triangle point indices.
- * Those ordered clockwise are changed to be anticlockwise.
- * mask: Optional bool array of shape (ntri) indicating which triangles
- * are masked.
- * edges: Optional int array of shape (?,2) of start and end point
- * indices, each edge (start,end and end,start) appearing only
- * once.
- * neighbors: Optional int array of shape (ntri,3) indicating which
- * triangles are the neighbors of which TriEdges, or -1 if
- * there is no such neighbor.
- * correct_triangle_orientations: Whether or not should correct triangle
- * orientations so that vertices are
- * ordered anticlockwise. */
- Triangulation(const CoordinateArray& x,
- const CoordinateArray& y,
- const TriangleArray& triangles,
- const MaskArray& mask,
- const EdgeArray& edges,
- const NeighborArray& neighbors,
- bool correct_triangle_orientations);
-
- /* Calculate plane equation coefficients for all unmasked triangles from
- * the point (x,y) coordinates and point z-array of shape (npoints) passed
- * in via the args. Returned array has shape (npoints,3) and allows
- * z-value at (x,y) coordinates in triangle tri to be calculated using
- * z = array[tri,0]*x + array[tri,1]*y + array[tri,2]. */
- TwoCoordinateArray calculate_plane_coefficients(const CoordinateArray& z);
-
- // Return the boundaries collection, creating it if necessary.
- const Boundaries& get_boundaries() const;
-
- // Return which boundary and boundary edge the specified TriEdge is.
- void get_boundary_edge(const TriEdge& triEdge,
- int& boundary,
- int& edge) const;
-
- /* Return the edges array, creating it if necessary. */
- EdgeArray& get_edges();
-
- /* Return the triangle index of the neighbor of the specified triangle
- * edge. */
- int get_neighbor(int tri, int edge) const;
-
- /* Return the TriEdge that is the neighbor of the specified triangle edge,
- * or TriEdge(-1,-1) if there is no such neighbor. */
- TriEdge get_neighbor_edge(int tri, int edge) const;
-
- /* Return the neighbors array, creating it if necessary. */
- NeighborArray& get_neighbors();
-
- // Return the number of points in this triangulation.
- int get_npoints() const;
-
- // Return the number of triangles in this triangulation.
- int get_ntri() const;
-
- /* Return the index of the point that is at the start of the specified
- * triangle edge. */
- int get_triangle_point(int tri, int edge) const;
- int get_triangle_point(const TriEdge& tri_edge) const;
-
- // Return the coordinates of the specified point index.
- XY get_point_coords(int point) const;
-
- // Indicates if the specified triangle is masked or not.
- bool is_masked(int tri) const;
-
- /* Set or clear the mask array. Clears various derived fields so they are
- * recalculated when next needed.
- * mask: bool array of shape (ntri) indicating which triangles are
- * masked, or an empty array to clear mask. */
- void set_mask(const MaskArray& mask);
-
- // Debug function to write boundaries.
- void write_boundaries() const;
-
-private:
- // An edge of a triangulation, composed of start and end point indices.
- struct Edge
- {
- Edge() : start(-1), end(-1) {}
- Edge(int start_, int end_) : start(start_), end(end_) {}
- bool operator<(const Edge& other) const {
- return start != other.start ? start < other.start : end < other.end;
- }
- int start, end;
- };
-
- /* An edge of a boundary of a triangulation, composed of a boundary index
- * and an edge index within that boundary. Used to index into the
- * boundaries collection to obtain the corresponding TriEdge. */
- struct BoundaryEdge
- {
- BoundaryEdge() : boundary(-1), edge(-1) {}
- BoundaryEdge(int boundary_, int edge_)
- : boundary(boundary_), edge(edge_) {}
- int boundary, edge;
- };
-
- /* Calculate the boundaries collection. Should normally be accessed via
- * get_boundaries(), which will call this function if necessary. */
- void calculate_boundaries();
-
- /* Calculate the edges array. Should normally be accessed via
- * get_edges(), which will call this function if necessary. */
- void calculate_edges();
-
- /* Calculate the neighbors array. Should normally be accessed via
- * get_neighbors(), which will call this function if necessary. */
- void calculate_neighbors();
-
- /* Correct each triangle so that the vertices are ordered in an
- * anticlockwise manner. */
- void correct_triangles();
-
- /* Determine which edge index (0,1 or 2) the specified point index is in
- * the specified triangle, or -1 if the point is not in the triangle. */
- int get_edge_in_triangle(int tri, int point) const;
-
- bool has_edges() const;
-
- bool has_mask() const;
-
- bool has_neighbors() const;
-
-
- // Variables shared with python, always set.
- CoordinateArray _x, _y; // double array (npoints).
- TriangleArray _triangles; // int array (ntri,3) of triangle point indices,
- // ordered anticlockwise.
-
- // Variables shared with python, may be unset (size == 0).
- MaskArray _mask; // bool array (ntri).
-
- // Derived variables shared with python, may be unset (size == 0).
- // If unset, are recalculated when needed.
- EdgeArray _edges; // int array (?,2) of start & end point indices.
- NeighborArray _neighbors; // int array (ntri,3), neighbor triangle indices
- // or -1 if no neighbor.
-
- // Variables internal to C++ only.
- Boundaries _boundaries;
-
- // Map used to look up BoundaryEdges from TriEdges. Normally accessed via
- // get_boundary_edge().
- typedef std::map<TriEdge, BoundaryEdge> TriEdgeToBoundaryMap;
- TriEdgeToBoundaryMap _tri_edge_to_boundary_map;
-};
-
-
-
-// Contour generator for a triangulation.
-class TriContourGenerator
-{
-public:
- typedef Triangulation::CoordinateArray CoordinateArray;
- typedef Triangulation::TwoCoordinateArray TwoCoordinateArray;
- typedef py::array_t<unsigned char> CodeArray;
-
- /* Constructor.
- * triangulation: Triangulation to generate contours for.
- * z: Double array of shape (npoints) of z-values at triangulation
- * points. */
- TriContourGenerator(Triangulation& triangulation,
- const CoordinateArray& z);
-
- /* Create and return a non-filled contour.
- * level: Contour level.
- * Returns new python list [segs0, segs1, ...] where
- * segs0: double array of shape (?,2) of point coordinates of first
- * contour line, etc. */
- py::tuple create_contour(const double& level);
-
- /* Create and return a filled contour.
- * lower_level: Lower contour level.
- * upper_level: Upper contour level.
- * Returns new python tuple (segs, kinds) where
- * segs: double array of shape (n_points,2) of all point coordinates,
- * kinds: ubyte array of shape (n_points) of all point code types. */
- py::tuple create_filled_contour(const double& lower_level,
- const double& upper_level);
-
-private:
- typedef Triangulation::Boundary Boundary;
- typedef Triangulation::Boundaries Boundaries;
-
- /* Clear visited flags.
- * include_boundaries: Whether to clear boundary flags or not, which are
- * only used for filled contours. */
- void clear_visited_flags(bool include_boundaries);
-
- /* Convert a non-filled Contour from C++ to Python.
- * Returns new python tuple ([segs0, segs1, ...], [kinds0, kinds1...])
- * where
- * segs0: double array of shape (n_points,2) of point coordinates of first
- * contour line, etc.
- * kinds0: ubyte array of shape (n_points) of kinds codes of first contour
- * line, etc. */
- py::tuple contour_line_to_segs_and_kinds(const Contour& contour);
-
- /* Convert a filled Contour from C++ to Python.
- * Returns new python tuple ([segs], [kinds]) where
- * segs: double array of shape (n_points,2) of all point coordinates,
- * kinds: ubyte array of shape (n_points) of all point code types. */
- py::tuple contour_to_segs_and_kinds(const Contour& contour);
-
- /* Return the point on the specified TriEdge that intersects the specified
- * level. */
- XY edge_interp(int tri, int edge, const double& level);
-
- /* Find and follow non-filled contour lines that start and end on a
- * boundary of the Triangulation.
- * contour: Contour to add new lines to.
- * level: Contour level. */
- void find_boundary_lines(Contour& contour,
- const double& level);
-
- /* Find and follow filled contour lines at either of the specified contour
- * levels that start and end of a boundary of the Triangulation.
- * contour: Contour to add new lines to.
- * lower_level: Lower contour level.
- * upper_level: Upper contour level. */
- void find_boundary_lines_filled(Contour& contour,
- const double& lower_level,
- const double& upper_level);
-
- /* Find and follow lines at the specified contour level that are
- * completely in the interior of the Triangulation and hence do not
- * intersect any boundary.
- * contour: Contour to add new lines to.
- * level: Contour level.
- * on_upper: Whether on upper or lower contour level.
- * filled: Whether contours are filled or not. */
- void find_interior_lines(Contour& contour,
- const double& level,
- bool on_upper,
- bool filled);
-
- /* Follow contour line around boundary of the Triangulation from the
- * specified TriEdge to its end which can be on either the lower or upper
- * levels. Only used for filled contours.
- * contour_line: Contour line to append new points to.
- * tri_edge: On entry, TriEdge to start from. On exit, TriEdge that is
- * finished on.
- * lower_level: Lower contour level.
- * upper_level: Upper contour level.
- * on_upper: Whether starts on upper level or not.
- * Return true if finishes on upper level, false if lower. */
- bool follow_boundary(ContourLine& contour_line,
- TriEdge& tri_edge,
- const double& lower_level,
- const double& upper_level,
- bool on_upper);
-
- /* Follow contour line across interior of Triangulation.
- * contour_line: Contour line to append new points to.
- * tri_edge: On entry, TriEdge to start from. On exit, TriEdge that is
- * finished on.
- * end_on_boundary: Whether this line ends on a boundary, or loops back
- * upon itself.
- * level: Contour level to follow.
- * on_upper: Whether following upper or lower contour level. */
- void follow_interior(ContourLine& contour_line,
- TriEdge& tri_edge,
- bool end_on_boundary,
- const double& level,
- bool on_upper);
-
- // Return the Triangulation boundaries.
- const Boundaries& get_boundaries() const;
-
- /* Return the edge by which the a level leaves a particular triangle,
- * which is 0, 1 or 2 if the contour passes through the triangle or -1
- * otherwise.
- * tri: Triangle index.
- * level: Contour level to follow.
- * on_upper: Whether following upper or lower contour level. */
- int get_exit_edge(int tri, const double& level, bool on_upper) const;
-
- // Return the z-value at the specified point index.
- const double& get_z(int point) const;
-
- /* Return the point at which the a level intersects the line connecting the
- * two specified point indices. */
- XY interp(int point1, int point2, const double& level) const;
-
-
-
- // Variables shared with python, always set.
- Triangulation _triangulation;
- CoordinateArray _z; // double array (npoints).
-
- // Variables internal to C++ only.
- typedef std::vector<bool> InteriorVisited; // Size 2*ntri
- typedef std::vector<bool> BoundaryVisited;
- typedef std::vector<BoundaryVisited> BoundariesVisited;
- typedef std::vector<bool> BoundariesUsed;
-
- InteriorVisited _interior_visited;
- BoundariesVisited _boundaries_visited; // Only used for filled contours.
- BoundariesUsed _boundaries_used; // Only used for filled contours.
-};
-
-
-
-/* TriFinder class implemented using the trapezoid map algorithm from the book
- * "Computational Geometry, Algorithms and Applications", second edition, by
- * M. de Berg, M. van Kreveld, M. Overmars and O. Schwarzkopf.
- *
- * The domain of interest is composed of vertical-sided trapezoids that are
- * bounded to the left and right by points of the triangulation, and below and
- * above by edges of the triangulation. Each triangle is represented by 1 or
- * more of these trapezoids. Edges are inserted one a time in a random order.
- *
- * As the trapezoid map is created, a search tree is also created which allows
- * fast lookup O(log N) of the trapezoid containing the point of interest.
- * There are 3 types of node in the search tree: all leaf nodes represent
- * trapezoids and all branch nodes have 2 child nodes and are either x-nodes or
- * y-nodes. X-nodes represent points in the triangulation, and their 2 children
- * refer to those parts of the search tree to the left and right of the point.
- * Y-nodes represent edges in the triangulation, and their 2 children refer to
- * those parts of the search tree below and above the edge.
- *
- * Nodes can be repeated throughout the search tree, and each is reference
- * counted through the multiple parent nodes it is a child of.
- *
- * The algorithm is only intended to work with valid triangulations, i.e. it
- * must not contain duplicate points, triangles formed from colinear points, or
- * overlapping triangles. It does have some tolerance to triangles formed from
- * colinear points but only in the simplest of cases. No explicit testing of
- * the validity of the triangulation is performed as this is a computationally
- * more complex task than the trifinding itself. */
-class TrapezoidMapTriFinder
-{
-public:
- typedef Triangulation::CoordinateArray CoordinateArray;
- typedef py::array_t<int, py::array::c_style | py::array::forcecast> TriIndexArray;
-
- /* Constructor. A separate call to initialize() is required to initialize
- * the object before use.
- * triangulation: Triangulation to find triangles in. */
- TrapezoidMapTriFinder(Triangulation& triangulation);
-
- ~TrapezoidMapTriFinder();
-
- /* Return an array of triangle indices. Takes 1D arrays x and y of
- * point coordinates, and returns an array of the same size containing the
- * indices of the triangles at those points. */
- TriIndexArray find_many(const CoordinateArray& x, const CoordinateArray& y);
-
- /* Return a reference to a new python list containing the following
- * statistics about the tree:
- * 0: number of nodes (tree size)
- * 1: number of unique nodes (number of unique Node objects in tree)
- * 2: number of trapezoids (tree leaf nodes)
- * 3: number of unique trapezoids
- * 4: maximum parent count (max number of times a node is repeated in
- * tree)
- * 5: maximum depth of tree (one more than the maximum number of
- * comparisons needed to search through the tree)
- * 6: mean of all trapezoid depths (one more than the average number of
- * comparisons needed to search through the tree) */
- py::list get_tree_stats();
-
- /* Initialize this object before use. May be called multiple times, if,
- * for example, the triangulation is changed by setting the mask. */
- void initialize();
-
- // Print the search tree as text to stdout; useful for debug purposes.
- void print_tree();
-
-private:
- /* A Point consists of x,y coordinates as well as the index of a triangle
- * associated with the point, so that a search at this point's coordinates
- * can return a valid triangle index. */
- struct Point : XY
- {
- Point() : XY(), tri(-1) {}
- Point(const double& x, const double& y) : XY(x,y), tri(-1) {}
- explicit Point(const XY& xy) : XY(xy), tri(-1) {}
-
- int tri;
- };
-
- /* An Edge connects two Points, left and right. It is always true that
- * right->is_right_of(*left). Stores indices of triangles below and above
- * the Edge which are used to map from trapezoid to triangle index. Also
- * stores pointers to the 3rd points of the below and above triangles,
- * which are only used to disambiguate triangles with colinear points. */
- struct Edge
- {
- Edge(const Point* left_,
- const Point* right_,
- int triangle_below_,
- int triangle_above_,
- const Point* point_below_,
- const Point* point_above_);
-
- // Return -1 if point to left of edge, 0 if on edge, +1 if to right.
- int get_point_orientation(const XY& xy) const;
-
- // Return slope of edge, even if vertical (divide by zero is OK here).
- double get_slope() const;
-
- /* Return y-coordinate of point on edge with specified x-coordinate.
- * x must be within the x-limits of this edge. */
- double get_y_at_x(const double& x) const;
-
- // Return true if the specified point is either of the edge end points.
- bool has_point(const Point* point) const;
-
- bool operator==(const Edge& other) const;
-
- friend std::ostream& operator<<(std::ostream& os, const Edge& edge)
- {
- return os << *edge.left << "->" << *edge.right;
- }
-
- void print_debug() const;
-
-
- const Point* left; // Not owned.
- const Point* right; // Not owned.
- int triangle_below; // Index of triangle below (to right of) Edge.
- int triangle_above; // Index of triangle above (to left of) Edge.
- const Point* point_below; // Used only for resolving ambiguous cases;
- const Point* point_above; // is 0 if corresponding triangle is -1
- };
-
- class Node; // Forward declaration.
-
- // Helper structure used by TrapezoidMapTriFinder::get_tree_stats.
- struct NodeStats
- {
- NodeStats()
- : node_count(0), trapezoid_count(0), max_parent_count(0),
- max_depth(0), sum_trapezoid_depth(0.0)
- {}
-
- long node_count, trapezoid_count, max_parent_count, max_depth;
- double sum_trapezoid_depth;
- std::set<const Node*> unique_nodes, unique_trapezoid_nodes;
- };
-
- struct Trapezoid; // Forward declaration.
-
- /* Node of the trapezoid map search tree. There are 3 possible types:
- * Type_XNode, Type_YNode and Type_TrapezoidNode. Data members are
- * represented using a union: an XNode has a Point and 2 child nodes
- * (left and right of the point), a YNode has an Edge and 2 child nodes
- * (below and above the edge), and a TrapezoidNode has a Trapezoid.
- * Each Node has multiple parents so it can appear in the search tree
- * multiple times without having to create duplicate identical Nodes.
- * The parent collection acts as a reference count to the number of times
- * a Node occurs in the search tree. When the parent count is reduced to
- * zero a Node can be safely deleted. */
- class Node
- {
- public:
- Node(const Point* point, Node* left, Node* right);// Type_XNode.
- Node(const Edge* edge, Node* below, Node* above); // Type_YNode.
- Node(Trapezoid* trapezoid); // Type_TrapezoidNode.
-
- ~Node();
-
- void add_parent(Node* parent);
-
- /* Recurse through the search tree and assert that everything is valid.
- * Reduces to a no-op if NDEBUG is defined. */
- void assert_valid(bool tree_complete) const;
-
- // Recurse through the tree to return statistics about it.
- void get_stats(int depth, NodeStats& stats) const;
-
- // Return the index of the triangle corresponding to this node.
- int get_tri() const;
-
- bool has_child(const Node* child) const;
- bool has_no_parents() const;
- bool has_parent(const Node* parent) const;
-
- /* Recurse through the tree and print a textual representation to
- * stdout. Argument depth used to indent for readability. */
- void print(int depth = 0) const;
-
- /* Remove a parent from this Node. Return true if no parents remain
- * so that this Node can be deleted. */
- bool remove_parent(Node* parent);
-
- void replace_child(Node* old_child, Node* new_child);
-
- // Replace this node with the specified new_node in all parents.
- void replace_with(Node* new_node);
-
- /* Recursive search through the tree to find the Node containing the
- * specified XY point. */
- const Node* search(const XY& xy);
-
- /* Recursive search through the tree to find the Trapezoid containing
- * the left endpoint of the specified Edge. Return 0 if fails, which
- * can only happen if the triangulation is invalid. */
- Trapezoid* search(const Edge& edge);
-
- /* Copy constructor and assignment operator defined but not implemented
- * to prevent objects being copied. */
- Node(const Node& other);
- Node& operator=(const Node& other);
-
- private:
- typedef enum {
- Type_XNode,
- Type_YNode,
- Type_TrapezoidNode
- } Type;
- Type _type;
-
- union {
- struct {
- const Point* point; // Not owned.
- Node* left; // Owned.
- Node* right; // Owned.
- } xnode;
- struct {
- const Edge* edge; // Not owned.
- Node* below; // Owned.
- Node* above; // Owned.
- } ynode;
- Trapezoid* trapezoid; // Owned.
- } _union;
-
- typedef std::list<Node*> Parents;
- Parents _parents; // Not owned.
- };
-
- /* A Trapezoid is bounded by Points to left and right, and Edges below and
- * above. Has up to 4 neighboring Trapezoids to lower/upper left/right.
- * Lower left neighbor is Trapezoid to left that shares the below Edge, or
- * is 0 if there is no such Trapezoid (and similar for other neighbors).
- * To obtain the index of the triangle corresponding to a particular
- * Trapezoid, use the Edge member variables below.triangle_above or
- * above.triangle_below. */
- struct Trapezoid
- {
- Trapezoid(const Point* left_,
- const Point* right_,
- const Edge& below_,
- const Edge& above_);
-
- /* Assert that this Trapezoid is valid. Reduces to a no-op if NDEBUG
- * is defined. */
- void assert_valid(bool tree_complete) const;
-
- /* Return one of the 4 corner points of this Trapezoid. Only used for
- * debugging purposes. */
- XY get_lower_left_point() const;
- XY get_lower_right_point() const;
- XY get_upper_left_point() const;
- XY get_upper_right_point() const;
-
- void print_debug() const;
-
- /* Set one of the 4 neighbor trapezoids and the corresponding reverse
- * Trapezoid of the new neighbor (if it is not 0), so that they are
- * consistent. */
- void set_lower_left(Trapezoid* lower_left_);
- void set_lower_right(Trapezoid* lower_right_);
- void set_upper_left(Trapezoid* upper_left_);
- void set_upper_right(Trapezoid* upper_right_);
-
- /* Copy constructor and assignment operator defined but not implemented
- * to prevent objects being copied. */
- Trapezoid(const Trapezoid& other);
- Trapezoid& operator=(const Trapezoid& other);
-
-
- const Point* left; // Not owned.
- const Point* right; // Not owned.
- const Edge& below;
- const Edge& above;
-
- // 4 neighboring trapezoids, can be 0, not owned.
- Trapezoid* lower_left; // Trapezoid to left that shares below
- Trapezoid* lower_right; // Trapezoid to right that shares below
- Trapezoid* upper_left; // Trapezoid to left that shares above
- Trapezoid* upper_right; // Trapezoid to right that shares above
-
- Node* trapezoid_node; // Node that owns this Trapezoid.
- };
-
-
- // Add the specified Edge to the search tree, returning true if successful.
- bool add_edge_to_tree(const Edge& edge);
-
- // Clear all memory allocated by this object.
- void clear();
-
- // Return the triangle index at the specified point, or -1 if no triangle.
- int find_one(const XY& xy);
-
- /* Determine the trapezoids that the specified Edge intersects, returning
- * true if successful. */
- bool find_trapezoids_intersecting_edge(const Edge& edge,
- std::vector<Trapezoid*>& trapezoids);
-
-
-
- // Variables shared with python, always set.
- Triangulation& _triangulation;
-
- // Variables internal to C++ only.
- Point* _points; // Array of all points in triangulation plus corners of
- // enclosing rectangle. Owned.
-
- typedef std::vector<Edge> Edges;
- Edges _edges; // All Edges in triangulation plus bottom and top Edges of
- // enclosing rectangle.
-
- Node* _tree; // Root node of the trapezoid map search tree. Owned.
-};
-
-#endif
diff --git a/contrib/python/matplotlib/py3/src/tri/_tri_wrapper.cpp b/contrib/python/matplotlib/py3/src/tri/_tri_wrapper.cpp
deleted file mode 100644
index 1b0c3d7555..0000000000
--- a/contrib/python/matplotlib/py3/src/tri/_tri_wrapper.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-#include "_tri.h"
-
-PYBIND11_MODULE(_tri, m) {
- py::class_<Triangulation>(m, "Triangulation")
- .def(py::init<const Triangulation::CoordinateArray&,
- const Triangulation::CoordinateArray&,
- const Triangulation::TriangleArray&,
- const Triangulation::MaskArray&,
- const Triangulation::EdgeArray&,
- const Triangulation::NeighborArray&,
- bool>(),
- py::arg("x"),
- py::arg("y"),
- py::arg("triangles"),
- py::arg("mask"),
- py::arg("edges"),
- py::arg("neighbors"),
- py::arg("correct_triangle_orientations"),
- "Create a new C++ Triangulation object.\n"
- "This should not be called directly, use the python class\n"
- "matplotlib.tri.Triangulation instead.\n")
- .def("calculate_plane_coefficients", &Triangulation::calculate_plane_coefficients,
- "Calculate plane equation coefficients for all unmasked triangles.")
- .def("get_edges", &Triangulation::get_edges,
- "Return edges array.")
- .def("get_neighbors", &Triangulation::get_neighbors,
- "Return neighbors array.")
- .def("set_mask", &Triangulation::set_mask,
- "Set or clear the mask array.");
-
- py::class_<TriContourGenerator>(m, "TriContourGenerator")
- .def(py::init<Triangulation&,
- const TriContourGenerator::CoordinateArray&>(),
- py::arg("triangulation"),
- py::arg("z"),
- "Create a new C++ TriContourGenerator object.\n"
- "This should not be called directly, use the functions\n"
- "matplotlib.axes.tricontour and tricontourf instead.\n")
- .def("create_contour", &TriContourGenerator::create_contour,
- "Create and return a non-filled contour.")
- .def("create_filled_contour", &TriContourGenerator::create_filled_contour,
- "Create and return a filled contour.");
-
- py::class_<TrapezoidMapTriFinder>(m, "TrapezoidMapTriFinder")
- .def(py::init<Triangulation&>(),
- py::arg("triangulation"),
- "Create a new C++ TrapezoidMapTriFinder object.\n"
- "This should not be called directly, use the python class\n"
- "matplotlib.tri.TrapezoidMapTriFinder instead.\n")
- .def("find_many", &TrapezoidMapTriFinder::find_many,
- "Find indices of triangles containing the point coordinates (x, y).")
- .def("get_tree_stats", &TrapezoidMapTriFinder::get_tree_stats,
- "Return statistics about the tree used by the trapezoid map.")
- .def("initialize", &TrapezoidMapTriFinder::initialize,
- "Initialize this object, creating the trapezoid map from the triangulation.")
- .def("print_tree", &TrapezoidMapTriFinder::print_tree,
- "Print the search tree as text to stdout; useful for debug purposes.");
-}