diff options
author | maxim-yurchuk <maxim-yurchuk@yandex-team.com> | 2025-02-11 13:26:52 +0300 |
---|---|---|
committer | maxim-yurchuk <maxim-yurchuk@yandex-team.com> | 2025-02-11 13:57:59 +0300 |
commit | f895bba65827952ed934b2b46f9a45e30a191fd2 (patch) | |
tree | 03260c906d9ec41cdc03e2a496b15d407459cec0 /contrib/python/matplotlib/py2/src | |
parent | 5f7060466f7b9707818c2091e1a25c14f33c3474 (diff) | |
download | ydb-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/py2/src')
39 files changed, 0 insertions, 20648 deletions
diff --git a/contrib/python/matplotlib/py2/src/_backend_agg.cpp b/contrib/python/matplotlib/py2/src/_backend_agg.cpp deleted file mode 100644 index 3dc35f6782..0000000000 --- a/contrib/python/matplotlib/py2/src/_backend_agg.cpp +++ /dev/null @@ -1,234 +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, 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(width * height * 4), - pixBuffer(NULL), - renderingBuffer(), - alphaBuffer(NULL), - alphaMaskRenderingBuffer(), - alphaMask(alphaMaskRenderingBuffer), - pixfmtAlphaMask(alphaMaskRenderingBuffer), - rendererBaseAlphaMask(), - rendererAlphaMask(), - scanlineAlphaMask(), - slineP8(), - slineBin(), - pixFmt(), - rendererBase(), - rendererAA(), - rendererBin(), - theRasterizer(8192), - 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 ®ion) -{ - 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 ®ion, 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) -{ - typedef agg::conv_transform<py::PathIterator> transformed_path_t; - typedef agg::conv_curve<transformed_path_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); - curve_t curved_clippath(transformed_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::tostring_rgb(uint8_t *buf) -{ - // "Return the rendered buffer as an RGB string" - - int row_len = width * 3; - - agg::rendering_buffer renderingBufferTmp; - renderingBufferTmp.attach(buf, width, height, row_len); - - agg::color_conv(&renderingBufferTmp, &renderingBuffer, agg::color_conv_rgba32_to_rgb24()); -} - -void RendererAgg::tostring_argb(uint8_t *buf) -{ - //"Return the rendered buffer as an RGB string"; - - int row_len = width * 4; - - agg::rendering_buffer renderingBufferTmp; - renderingBufferTmp.attach(buf, width, height, row_len); - agg::color_conv(&renderingBufferTmp, &renderingBuffer, agg::color_conv_rgba32_to_argb32()); -} - -void RendererAgg::tostring_bgra(uint8_t *buf) -{ - //"Return the rendered buffer as an RGB string"; - - int row_len = width * 4; - - agg::rendering_buffer renderingBufferTmp; - renderingBufferTmp.attach(buf, width, height, row_len); - - agg::color_conv(&renderingBufferTmp, &renderingBuffer, agg::color_conv_rgba32_to_bgra32()); -} - -agg::rect_i RendererAgg::get_content_extents() -{ - agg::rect_i r(width, height, 0, 0); - - // Looks at the alpha channel to find the minimum extents of the image - unsigned char *pixel = pixBuffer + 3; - for (int y = 0; y < (int)height; ++y) { - for (int x = 0; x < (int)width; ++x) { - if (*pixel) { - if (x < r.x1) - r.x1 = x; - if (y < r.y1) - r.y1 = y; - if (x > r.x2) - r.x2 = x; - if (y > r.y2) - r.y2 = y; - } - pixel += 4; - } - } - - if (r.x1 == width && r.x2 == 0) { - // The buffer is completely empty. - r.x1 = r.y1 = r.x2 = r.y2 = 0; - } else { - r.x1 = std::max(0, r.x1); - r.y1 = std::max(0, r.y1); - r.x2 = std::min(r.x2 + 1, (int)width); - r.y2 = std::min(r.y2 + 1, (int)height); - } - - return r; -} - -void RendererAgg::clear() -{ - //"clear the rendered buffer"; - - rendererBase.clear(_fill_color); -} diff --git a/contrib/python/matplotlib/py2/src/_backend_agg.h b/contrib/python/matplotlib/py2/src/_backend_agg.h deleted file mode 100644 index 53b73f179b..0000000000 --- a/contrib/python/matplotlib/py2/src/_backend_agg.h +++ /dev/null @@ -1,1294 +0,0 @@ -/* -*- mode: c++; c-basic-offset: 4 -*- */ - -/* _backend_agg.h -*/ - -#ifndef __BACKEND_AGG_H__ -#define __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. agg::buffer is -// a class in the swig wrapper -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, - e_offset_position offset_position); - - 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); - - void tostring_rgb(uint8_t *buf); - void tostring_argb(uint8_t *buf); - void tostring_bgra(uint8_t *buf); - agg::rect_i get_content_extents(); - void clear(); - - BufferRegion *copy_from_bbox(agg::rect_d in_rect); - void restore_region(BufferRegion ®); - void restore_region(BufferRegion ®ion, 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); - - 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, - e_offset_position offset_position, - int check_snap, - int has_curves); - - 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); - } - - // 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); - - 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() && !path.has_curves(); - 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_curves()); - clipped_t clipped(nan_removed, clip && !path.has_curves(), 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_curves()); - 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); - - 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; - - fig.init(0, 0, width, height); - text.init(x, y - image.dim(0), 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(int(mpl_round(gc.cliprect.x1)), - int(mpl_round(height - gc.cliprect.y2)), - int(mpl_round(gc.cliprect.x2)), - int(mpl_round(height - gc.cliprect.y1))); - text.clip(clip); - } - - if (text.x2 > text.x1) { - for (int yi = text.y1; yi < text.y2; ++yi) { - pixFmt.blend_solid_hspan(text.x1, yi, (text.x2 - text.x1), gc.color, - &image(yi - (y - image.dim(0)), text.x1 - x)); - } - } - } -} - -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); - - 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, - e_offset_position offset_position, - int check_snap, - int has_curves) -{ - 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); - - // Set some defaults, assuming no face or edge - gc.linewidth = 0.0; - facepair_t face; - face.first = Nfacecolors != 0; - agg::trans_affine trans; - - 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); - if (offset_position == OFFSET_POSITION_DATA) { - trans = agg::trans_affine_translation(xo, yo) * trans; - } else { - 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]; - } - } - - bool do_clip = !face.first && !gc.has_hatchpath() && !has_curves; - - if (check_snap) { - gc.isaa = antialiaseds(i % Naa); - - transformed_path_t tpath(path, trans); - nan_removed_t nan_removed(tpath, true, has_curves); - clipped_t clipped(nan_removed, do_clip && !has_curves, width, height); - snapped_t snapped( - clipped, gc.snap_mode, path.total_vertices(), points_to_pixels(gc.linewidth)); - if (has_curves) { - 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_curves); - clipped_t clipped(nan_removed, do_clip, width, height); - if (has_curves) { - 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, - e_offset_position offset_position) -{ - _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, - offset_position, - 1, - 1); -} - -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 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; - ColorArray *edgecolors_ptr = &edgecolors; - - if (edgecolors.size() == 0) { - if (antialiased) { - edgecolors_ptr = &facecolors; - } - } - - _draw_path_collection_generic(gc, - master_transform, - gc.cliprect, - gc.clippath.path, - gc.clippath.trans, - path_generator, - transforms, - offsets, - offset_trans, - facecolors, - *edgecolors_ptr, - linewidths, - linestyles, - antialiaseds, - OFFSET_POSITION_FIGURE, - 0, - 0); -} - -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]); - } - - 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); - - _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); - - 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/py2/src/_backend_agg_basic_types.h b/contrib/python/matplotlib/py2/src/_backend_agg_basic_types.h deleted file mode 100644 index 74a318e7d2..0000000000 --- a/contrib/python/matplotlib/py2/src/_backend_agg_basic_types.h +++ /dev/null @@ -1,127 +0,0 @@ -#ifndef __BACKEND_AGG_BASIC_TYPES_H__ -#define __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) - { - for (dash_t::const_iterator i = dashes.begin(); i != dashes.end(); ++i) { - double val0 = i->first; - double val1 = i->second; - val0 = val0 * dpi / 72.0; - val1 = val1 * dpi / 72.0; - if (!isaa) { - val0 = (int)val0 + 0.5; - val1 = (int)val1 + 0.5; - } - stroke.add_dash(val0, val1); - } - stroke.dash_start(get_dash_offset() * dpi / 72.0); - } -}; - -typedef std::vector<Dashes> DashesVector; - -enum e_offset_position { - OFFSET_POSITION_FIGURE, - OFFSET_POSITION_DATA -}; - -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(); - } - - private: - // prevent copying - GCAgg(const GCAgg &); - GCAgg &operator=(const GCAgg &); -}; - -#endif diff --git a/contrib/python/matplotlib/py2/src/_backend_agg_wrapper.cpp b/contrib/python/matplotlib/py2/src/_backend_agg_wrapper.cpp deleted file mode 100644 index ea6c7b1267..0000000000 --- a/contrib/python/matplotlib/py2/src/_backend_agg_wrapper.cpp +++ /dev/null @@ -1,777 +0,0 @@ -#include "mplutils.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; - -typedef struct -{ - PyObject_HEAD - BufferRegion *x; - Py_ssize_t shape[3]; - Py_ssize_t strides[3]; - Py_ssize_t suboffsets[3]; -} PyBufferRegion; - - -/********************************************************************** - * 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, PyObject *kwds) -{ - return PyBytes_FromStringAndSize((const char *)self->x->get_data(), - 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, PyObject *kwds) -{ - 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, PyObject *kwds) -{ - 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, PyObject *kwds) -{ - 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, PyObject *kwds) -{ - PyObject *bufobj; - uint8_t *buf; - - bufobj = PyBytes_FromStringAndSize(NULL, self->x->get_height() * self->x->get_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 = self->x->get_width() * 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 PyBufferRegionType; - -static PyTypeObject *PyBufferRegion_init_type(PyObject *m, PyTypeObject *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; - memset(&buffer_procs, 0, sizeof(PyBufferProcs)); - buffer_procs.bf_getbuffer = (getbufferproc)PyBufferRegion_get_buffer; - - memset(type, 0, sizeof(PyTypeObject)); - type->tp_name = "matplotlib.backends._backend_agg.BufferRegion"; - type->tp_basicsize = sizeof(PyBufferRegion); - type->tp_dealloc = (destructor)PyBufferRegion_dealloc; - type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_NEWBUFFER; - type->tp_methods = methods; - type->tp_new = PyBufferRegion_new; - type->tp_as_buffer = &buffer_procs; - - if (PyType_Ready(type) < 0) { - return NULL; - } - - /* Don't need to add to module, since you can't create buffer - regions directly from Python */ - - return type; -} - -/********************************************************************** - * 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, PyObject *kwds) -{ - 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, PyObject *kwds) -{ - 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, PyObject *kwds) -{ - 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, PyObject *kwds) -{ - 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, PyObject *kwds) -{ - GCAgg gc; - agg::trans_affine master_transform; - PyObject *pathobj; - 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; - e_offset_position offset_position; - - if (!PyArg_ParseTuple(args, - "O&O&OO&O&O&O&O&O&O&O&OO&:draw_path_collection", - &convert_gcagg, - &gc, - &convert_trans_affine, - &master_transform, - &pathobj, - &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, - &convert_offset_position, - &offset_position)) { - return NULL; - } - - try - { - py::PathGenerator path(pathobj); - - CALL_CPP("draw_path_collection", - (self->x->draw_path_collection(gc, - master_transform, - path, - transforms, - offsets, - offset_trans, - facecolors, - edgecolors, - linewidths, - dashes, - antialiaseds, - offset_position))); - } - catch (const py::exception &) - { - return NULL; - } - - Py_RETURN_NONE; -} - -static PyObject *PyRendererAgg_draw_quad_mesh(PyRendererAgg *self, PyObject *args, PyObject *kwds) -{ - 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; - int antialiased; - numpy::array_view<const double, 2> edgecolors; - - if (!PyArg_ParseTuple(args, - "O&O&IIO&O&O&O&iO&: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, - &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, PyObject *kwds) -{ - 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 be a 3x2 array, got %" NPY_INTP_FMT "x%" 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 be a 3x4 array, got %" NPY_INTP_FMT "x%" 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, PyObject *kwds) -{ - 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() != 0 && (points.dim(1) != 3 || points.dim(2) != 2)) { - PyErr_Format(PyExc_ValueError, - "points must be a Nx3x2 array, got %" NPY_INTP_FMT "x%" NPY_INTP_FMT "x%" NPY_INTP_FMT, - points.dim(0), points.dim(1), points.dim(2)); - return NULL; - } - - if (colors.size() != 0 && (colors.dim(1) != 3 || colors.dim(2) != 4)) { - PyErr_Format(PyExc_ValueError, - "colors must be a Nx3x4 array, got %" NPY_INTP_FMT "x%" NPY_INTP_FMT "x%" NPY_INTP_FMT, - colors.dim(0), colors.dim(1), colors.dim(2)); - return NULL; - } - - if (points.size() != colors.size()) { - PyErr_Format(PyExc_ValueError, - "points and colors arrays must be the same length, got %" NPY_INTP_FMT " and %" NPY_INTP_FMT, - 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; -} - -static PyObject *PyRendererAgg_tostring_rgb(PyRendererAgg *self, PyObject *args, PyObject *kwds) -{ - PyObject *buffobj = NULL; - - buffobj = PyBytes_FromStringAndSize(NULL, self->x->get_width() * self->x->get_height() * 3); - if (buffobj == NULL) { - return NULL; - } - - CALL_CPP_CLEANUP("tostring_rgb", - (self->x->tostring_rgb((uint8_t *)PyBytes_AS_STRING(buffobj))), - Py_DECREF(buffobj)); - - return buffobj; -} - -static PyObject *PyRendererAgg_tostring_argb(PyRendererAgg *self, PyObject *args, PyObject *kwds) -{ - PyObject *buffobj = NULL; - - buffobj = PyBytes_FromStringAndSize(NULL, self->x->get_width() * self->x->get_height() * 4); - if (buffobj == NULL) { - return NULL; - } - - CALL_CPP_CLEANUP("tostring_argb", - (self->x->tostring_argb((uint8_t *)PyBytes_AS_STRING(buffobj))), - Py_DECREF(buffobj)); - - return buffobj; -} - -static PyObject *PyRendererAgg_tostring_bgra(PyRendererAgg *self, PyObject *args, PyObject *kwds) -{ - PyObject *buffobj = NULL; - - buffobj = PyBytes_FromStringAndSize(NULL, self->x->get_width() * self->x->get_height() * 4); - if (buffobj == NULL) { - return NULL; - } - - CALL_CPP_CLEANUP("to_string_bgra", - (self->x->tostring_bgra((uint8_t *)PyBytes_AS_STRING(buffobj))), - Py_DECREF(buffobj)); - - return buffobj; -} - -static PyObject * -PyRendererAgg_get_content_extents(PyRendererAgg *self, PyObject *args, PyObject *kwds) -{ - agg::rect_i extents; - - CALL_CPP("get_content_extents", (extents = self->x->get_content_extents())); - - return Py_BuildValue( - "iiii", extents.x1, extents.y1, extents.x2 - extents.x1, extents.y2 - extents.y1); -} - -static PyObject *PyRendererAgg_buffer_rgba(PyRendererAgg *self, PyObject *args, PyObject *kwds) -{ -#if PY3K - return PyBytes_FromStringAndSize((const char *)self->x->pixBuffer, - self->x->get_width() * self->x->get_height() * 4); -#else - return PyBuffer_FromReadWriteMemory(self->x->pixBuffer, - self->x->get_width() * self->x->get_height() * 4); -#endif -} - -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 = self->x->get_width() * 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, PyObject *kwds) -{ - CALL_CPP("clear", self->x->clear()); - - Py_RETURN_NONE; -} - -static PyObject *PyRendererAgg_copy_from_bbox(PyRendererAgg *self, PyObject *args, PyObject *kwds) -{ - 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, PyObject *kwds) -{ - PyBufferRegion *regobj; - int xx1 = 0, yy1 = 0, xx2 = 0, yy2 = 0, x = 0, y = 0; - - if (!PyArg_ParseTuple(args, - "O!|iiiiii:restore_region", - &PyBufferRegionType, - ®obj, - &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; -} - -PyTypeObject PyRendererAggType; - -static PyTypeObject *PyRendererAgg_init_type(PyObject *m, PyTypeObject *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}, - - {"tostring_rgb", (PyCFunction)PyRendererAgg_tostring_rgb, METH_NOARGS, NULL}, - {"tostring_argb", (PyCFunction)PyRendererAgg_tostring_argb, METH_NOARGS, NULL}, - {"tostring_bgra", (PyCFunction)PyRendererAgg_tostring_bgra, METH_NOARGS, NULL}, - {"get_content_extents", (PyCFunction)PyRendererAgg_get_content_extents, METH_NOARGS, NULL}, - {"buffer_rgba", (PyCFunction)PyRendererAgg_buffer_rgba, METH_NOARGS, 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; - memset(&buffer_procs, 0, sizeof(PyBufferProcs)); - buffer_procs.bf_getbuffer = (getbufferproc)PyRendererAgg_get_buffer; - - memset(type, 0, sizeof(PyTypeObject)); - type->tp_name = "matplotlib.backends._backend_agg.RendererAgg"; - type->tp_basicsize = sizeof(PyRendererAgg); - type->tp_dealloc = (destructor)PyRendererAgg_dealloc; - type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_NEWBUFFER; - type->tp_methods = methods; - type->tp_init = (initproc)PyRendererAgg_init; - type->tp_new = PyRendererAgg_new; - type->tp_as_buffer = &buffer_procs; - - if (PyType_Ready(type) < 0) { - return NULL; - } - - if (PyModule_AddObject(m, "RendererAgg", (PyObject *)type)) { - return NULL; - } - - return type; -} - -extern "C" { - -#if PY3K -static struct PyModuleDef moduledef = { - PyModuleDef_HEAD_INIT, - "_backend_agg", - NULL, - 0, - NULL, - NULL, - NULL, - NULL, - NULL -}; - -#define INITERROR return NULL - -PyMODINIT_FUNC PyInit__backend_agg(void) - -#else -#define INITERROR return - -PyMODINIT_FUNC init_backend_agg(void) -#endif - -{ - PyObject *m; - -#if PY3K - m = PyModule_Create(&moduledef); -#else - m = Py_InitModule3("_backend_agg", NULL, NULL); -#endif - - if (m == NULL) { - INITERROR; - } - - import_array(); - - if (!PyRendererAgg_init_type(m, &PyRendererAggType)) { - INITERROR; - } - - if (!PyBufferRegion_init_type(m, &PyBufferRegionType)) { - INITERROR; - } - -#if PY3K - return m; -#endif -} - -} // extern "C" diff --git a/contrib/python/matplotlib/py2/src/_backend_gdk.c b/contrib/python/matplotlib/py2/src/_backend_gdk.c deleted file mode 100644 index 8314219cca..0000000000 --- a/contrib/python/matplotlib/py2/src/_backend_gdk.c +++ /dev/null @@ -1,72 +0,0 @@ -/* -*- mode: C; c-basic-offset: 4 -*- - * C extensions for backend_gdk - */ - -#include "Python.h" -#include "numpy/arrayobject.h" - -#include <pygtk/pygtk.h> - -static PyTypeObject *_PyGdkPixbuf_Type; -#define PyGdkPixbuf_Type (*_PyGdkPixbuf_Type) - -static PyObject *pixbuf_get_pixels_array(PyObject *self, PyObject *args) -{ - /* 1) read in Python pixbuf, get the underlying gdk_pixbuf */ - PyGObject *py_pixbuf; - GdkPixbuf *gdk_pixbuf; - PyArrayObject *array; - npy_intp dims[3] = { 0, 0, 3 }; - npy_intp strides[3]; - - if (!PyArg_ParseTuple(args, "O!:pixbuf_get_pixels_array", &PyGdkPixbuf_Type, &py_pixbuf)) - return NULL; - - gdk_pixbuf = GDK_PIXBUF(py_pixbuf->obj); - - /* 2) same as pygtk/gtk/gdk.c _wrap_gdk_pixbuf_get_pixels_array() - * with 'self' changed to py_pixbuf - */ - - dims[0] = gdk_pixbuf_get_height(gdk_pixbuf); - dims[1] = gdk_pixbuf_get_width(gdk_pixbuf); - if (gdk_pixbuf_get_has_alpha(gdk_pixbuf)) - dims[2] = 4; - - strides[0] = gdk_pixbuf_get_rowstride(gdk_pixbuf); - strides[1] = dims[2]; - strides[2] = 1; - - array = (PyArrayObject*) - PyArray_New(&PyArray_Type, 3, dims, NPY_UBYTE, strides, - (void*)gdk_pixbuf_get_pixels(gdk_pixbuf), 1, - NPY_ARRAY_WRITEABLE, NULL); - - if (array == NULL) - return NULL; - - /* the array holds a ref to the pixbuf pixels through this wrapper*/ - Py_INCREF(py_pixbuf); - if (PyArray_SetBaseObject(array, (PyObject *)py_pixbuf) == -1) { - Py_DECREF(py_pixbuf); - Py_DECREF(array); - return NULL; - } - return PyArray_Return(array); -} - -static PyMethodDef _backend_gdk_functions[] = { - { "pixbuf_get_pixels_array", (PyCFunction)pixbuf_get_pixels_array, METH_VARARGS }, - { NULL, NULL, 0 } -}; - -PyMODINIT_FUNC init_backend_gdk(void) -{ - PyObject *mod; - mod = Py_InitModule("matplotlib.backends._backend_gdk", _backend_gdk_functions); - import_array(); - init_pygtk(); - - mod = PyImport_ImportModule("gtk.gdk"); - _PyGdkPixbuf_Type = (PyTypeObject *)PyObject_GetAttrString(mod, "Pixbuf"); -} diff --git a/contrib/python/matplotlib/py2/src/_contour.cpp b/contrib/python/matplotlib/py2/src/_contour.cpp deleted file mode 100644 index aecb442c7e..0000000000 --- a/contrib/python/matplotlib/py2/src/_contour.cpp +++ /dev/null @@ -1,1790 +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. -#define NO_IMPORT_ARRAY - -#include "src/mplutils.h" -#include "src/_contour.h" -#include <algorithm> - - -// 'kind' codes. -#define MOVETO 1 -#define LINETO 2 -#define CLOSEPOLY 79 - -// Point indices from current quad index. -#define POINT_SW (quad) -#define POINT_SE (quad+1) -#define POINT_NW (quad+_nx) -#define POINT_NE (quad+_nx+1) - -// CacheItem masks, only accessed directly to set. To read, use accessors -// detailed below. 1 and 2 refer to level indices (lower and upper). -#define MASK_Z_LEVEL 0x0003 // Combines the following two. -#define MASK_Z_LEVEL_1 0x0001 // z > lower_level. -#define MASK_Z_LEVEL_2 0x0002 // z > upper_level. -#define MASK_VISITED_1 0x0004 // Algorithm has visited this quad. -#define MASK_VISITED_2 0x0008 -#define MASK_SADDLE_1 0x0010 // quad is a saddle quad. -#define MASK_SADDLE_2 0x0020 -#define MASK_SADDLE_LEFT_1 0x0040 // Contours turn left at saddle quad. -#define MASK_SADDLE_LEFT_2 0x0080 -#define MASK_SADDLE_START_SW_1 0x0100 // Next visit starts on S or W edge. -#define MASK_SADDLE_START_SW_2 0x0200 -#define MASK_BOUNDARY_S 0x0400 // S edge of quad is a boundary. -#define MASK_BOUNDARY_W 0x0800 // W edge of quad is a boundary. -// EXISTS_QUAD bit is always used, but the 4 EXISTS_CORNER are only used if -// _corner_mask is true. Only one of EXISTS_QUAD or EXISTS_??_CORNER is ever -// set per quad, hence not using unique bits for each; care is needed when -// testing for these flags as they overlap. -#define MASK_EXISTS_QUAD 0x1000 // All of quad exists (is not masked). -#define MASK_EXISTS_SW_CORNER 0x2000 // SW corner exists, NE corner is masked. -#define MASK_EXISTS_SE_CORNER 0x3000 -#define MASK_EXISTS_NW_CORNER 0x4000 -#define MASK_EXISTS_NE_CORNER 0x5000 -#define MASK_EXISTS 0x7000 // Combines all 5 EXISTS masks. - -// The following are only needed for filled contours. -#define MASK_VISITED_S 0x10000 // Algorithm has visited S boundary. -#define MASK_VISITED_W 0x20000 // Algorithm has visited W boundary. -#define MASK_VISITED_CORNER 0x40000 // Algorithm has visited corner edge. - - -// Accessors for various CacheItem masks. li is shorthand for level_index. -#define Z_LEVEL(quad) (_cache[quad] & MASK_Z_LEVEL) -#define Z_NE Z_LEVEL(POINT_NE) -#define Z_NW Z_LEVEL(POINT_NW) -#define Z_SE Z_LEVEL(POINT_SE) -#define Z_SW Z_LEVEL(POINT_SW) -#define VISITED(quad,li) (_cache[quad] & (li==1 ? MASK_VISITED_1 : MASK_VISITED_2)) -#define VISITED_S(quad) (_cache[quad] & MASK_VISITED_S) -#define VISITED_W(quad) (_cache[quad] & MASK_VISITED_W) -#define VISITED_CORNER(quad) (_cache[quad] & MASK_VISITED_CORNER) -#define SADDLE(quad,li) (_cache[quad] & (li==1 ? MASK_SADDLE_1 : MASK_SADDLE_2)) -#define SADDLE_LEFT(quad,li) (_cache[quad] & (li==1 ? MASK_SADDLE_LEFT_1 : MASK_SADDLE_LEFT_2)) -#define SADDLE_START_SW(quad,li) (_cache[quad] & (li==1 ? MASK_SADDLE_START_SW_1 : MASK_SADDLE_START_SW_2)) -#define BOUNDARY_S(quad) (_cache[quad] & MASK_BOUNDARY_S) -#define BOUNDARY_W(quad) (_cache[quad] & MASK_BOUNDARY_W) -#define BOUNDARY_N(quad) BOUNDARY_S(quad+_nx) -#define BOUNDARY_E(quad) BOUNDARY_W(quad+1) -#define EXISTS_QUAD(quad) ((_cache[quad] & MASK_EXISTS) == MASK_EXISTS_QUAD) -#define EXISTS_NONE(quad) ((_cache[quad] & MASK_EXISTS) == 0) -// The following are only used if _corner_mask is true. -#define EXISTS_SW_CORNER(quad) ((_cache[quad] & MASK_EXISTS) == MASK_EXISTS_SW_CORNER) -#define EXISTS_SE_CORNER(quad) ((_cache[quad] & MASK_EXISTS) == MASK_EXISTS_SE_CORNER) -#define EXISTS_NW_CORNER(quad) ((_cache[quad] & MASK_EXISTS) == MASK_EXISTS_NW_CORNER) -#define EXISTS_NE_CORNER(quad) ((_cache[quad] & MASK_EXISTS) == MASK_EXISTS_NE_CORNER) -#define EXISTS_ANY_CORNER(quad) (!EXISTS_NONE(quad) && !EXISTS_QUAD(quad)) -#define EXISTS_W_EDGE(quad) (EXISTS_QUAD(quad) || EXISTS_SW_CORNER(quad) || EXISTS_NW_CORNER(quad)) -#define EXISTS_E_EDGE(quad) (EXISTS_QUAD(quad) || EXISTS_SE_CORNER(quad) || EXISTS_NE_CORNER(quad)) -#define EXISTS_S_EDGE(quad) (EXISTS_QUAD(quad) || EXISTS_SW_CORNER(quad) || EXISTS_SE_CORNER(quad)) -#define EXISTS_N_EDGE(quad) (EXISTS_QUAD(quad) || EXISTS_NW_CORNER(quad) || EXISTS_NE_CORNER(quad)) -// Note that EXISTS_NE_CORNER(quad) is equivalent to BOUNDARY_SW(quad), etc. - - - -QuadEdge::QuadEdge() - : quad(-1), edge(Edge_None) -{} - -QuadEdge::QuadEdge(long quad_, Edge edge_) - : quad(quad_), edge(edge_) -{} - -bool QuadEdge::operator<(const QuadEdge& other) const -{ - if (quad != other.quad) - return quad < other.quad; - else - return edge < other.edge; -} - -bool QuadEdge::operator==(const QuadEdge& other) const -{ - return quad == other.quad && edge == other.edge; -} - -bool QuadEdge::operator!=(const QuadEdge& other) const -{ - return !operator==(other); -} - -std::ostream& operator<<(std::ostream& os, const QuadEdge& quad_edge) -{ - return os << quad_edge.quad << ' ' << quad_edge.edge; -} - - -// conflict with code from matplotlib/tri/_tri.cpp -#if 0 -XY::XY() -{} - -XY::XY(const double& x_, const double& y_) - : x(x_), y(y_) -{} - -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 << ')'; -} -#endif - - -ContourLine::ContourLine(bool is_hole) - : std::vector<XY>(), - _is_hole(is_hole), - _parent(0) -{} - -void ContourLine::add_child(ContourLine* child) -{ - assert(!_is_hole && "Cannot add_child to a hole"); - assert(child != 0 && "Null child ContourLine"); - _children.push_back(child); -} - -void ContourLine::clear_parent() -{ - assert(is_hole() && "Cannot clear parent of non-hole"); - assert(_parent != 0 && "Null parent ContourLine"); - _parent = 0; -} - -const ContourLine::Children& ContourLine::get_children() const -{ - assert(!_is_hole && "Cannot get_children of a hole"); - return _children; -} - -const ContourLine* ContourLine::get_parent() const -{ - assert(_is_hole && "Cannot get_parent of a non-hole"); - return _parent; -} - -ContourLine* ContourLine::get_parent() -{ - assert(_is_hole && "Cannot get_parent of a non-hole"); - return _parent; -} - -bool ContourLine::is_hole() const -{ - return _is_hole; -} - -// conflict with code from matplotlib/tri/_tri.cpp -#if 0 -void ContourLine::push_back(const XY& point) -{ - if (empty() || point != back()) - std::vector<XY>::push_back(point); -} -#endif - -void ContourLine::set_parent(ContourLine* parent) -{ - assert(_is_hole && "Cannot set parent of a non-hole"); - assert(parent != 0 && "Null parent ContourLine"); - _parent = parent; -} - -// conflict with code from matplotlib/tri/_tri.cpp -#if 0 -void ContourLine::write() const -{ - std::cout << "ContourLine " << this << " of " << size() << " points:"; - for (const_iterator it = begin(); it != end(); ++it) - std::cout << ' ' << *it; - if (is_hole()) - std::cout << " hole, parent=" << get_parent(); - else { - std::cout << " not hole"; - if (!_children.empty()) { - std::cout << ", children="; - for (Children::const_iterator it = _children.begin(); - it != _children.end(); ++it) - std::cout << *it << ' '; - } - } - std::cout << std::endl; -} -#endif - - -Contour::Contour() -{} - -Contour::~Contour() -{ - delete_contour_lines(); -} - -void Contour::delete_contour_lines() -{ - for (iterator line_it = begin(); line_it != end(); ++line_it) { - delete *line_it; - *line_it = 0; - } - std::vector<ContourLine*>::clear(); -} - -void Contour::write() const -{ - std::cout << "Contour of " << size() << " lines." << std::endl; - for (const_iterator it = begin(); it != end(); ++it) - (*it)->write(); -} - - - -ParentCache::ParentCache(long nx, long x_chunk_points, long y_chunk_points) - : _nx(nx), - _x_chunk_points(x_chunk_points), - _y_chunk_points(y_chunk_points), - _lines(0), // Initialised when first needed. - _istart(0), - _jstart(0) -{ - assert(_x_chunk_points > 0 && _y_chunk_points > 0 && - "Chunk sizes must be positive"); -} - -ContourLine* ParentCache::get_parent(long quad) -{ - long index = quad_to_index(quad); - ContourLine* parent = _lines[index]; - while (parent == 0) { - index -= _x_chunk_points; - assert(index >= 0 && "Failed to find parent in chunk ParentCache"); - parent = _lines[index]; - } - assert(parent != 0 && "Failed to find parent in chunk ParentCache"); - return parent; -} - -long ParentCache::quad_to_index(long quad) const -{ - long i = quad % _nx; - long j = quad / _nx; - long index = (i-_istart) + (j-_jstart)*_x_chunk_points; - - assert(i >= _istart && i < _istart + _x_chunk_points && - "i-index outside chunk"); - assert(j >= _jstart && j < _jstart + _y_chunk_points && - "j-index outside chunk"); - assert(index >= 0 && index < static_cast<long>(_lines.size()) && - "ParentCache index outside chunk"); - - return index; -} - -void ParentCache::set_chunk_starts(long istart, long jstart) -{ - assert(istart >= 0 && jstart >= 0 && - "Chunk start indices cannot be negative"); - _istart = istart; - _jstart = jstart; - if (_lines.empty()) - _lines.resize(_x_chunk_points*_y_chunk_points, 0); - else - std::fill(_lines.begin(), _lines.end(), (ContourLine*)0); -} - -void ParentCache::set_parent(long quad, ContourLine& contour_line) -{ - assert(!_lines.empty() && - "Accessing ParentCache before it has been initialised"); - long index = quad_to_index(quad); - if (_lines[index] == 0) - _lines[index] = (contour_line.is_hole() ? contour_line.get_parent() - : &contour_line); -} - - - -QuadContourGenerator::QuadContourGenerator(const CoordinateArray& x, - const CoordinateArray& y, - const CoordinateArray& z, - const MaskArray& mask, - bool corner_mask, - long chunk_size) - : _x(x), - _y(y), - _z(z), - _nx(static_cast<long>(_x.dim(1))), - _ny(static_cast<long>(_x.dim(0))), - _n(_nx*_ny), - _corner_mask(corner_mask), - _chunk_size(chunk_size > 0 ? std::min(chunk_size, std::max(_nx, _ny)-1) - : std::max(_nx, _ny)-1), - _nxchunk(calc_chunk_count(_nx)), - _nychunk(calc_chunk_count(_ny)), - _chunk_count(_nxchunk*_nychunk), - _cache(new CacheItem[_n]), - _parent_cache(_nx, - chunk_size > 0 ? chunk_size+1 : _nx, - chunk_size > 0 ? chunk_size+1 : _ny) -{ - assert(!_x.empty() && !_y.empty() && !_z.empty() && "Empty array"); - assert(_y.dim(0) == _x.dim(0) && _y.dim(1) == _x.dim(1) && - "Different-sized y and x arrays"); - assert(_z.dim(0) == _x.dim(0) && _z.dim(1) == _x.dim(1) && - "Different-sized z and x arrays"); - assert((mask.empty() || - (mask.dim(0) == _x.dim(0) && mask.dim(1) == _x.dim(1))) && - "Different-sized mask and x arrays"); - - init_cache_grid(mask); -} - -QuadContourGenerator::~QuadContourGenerator() -{ - delete [] _cache; -} - -void QuadContourGenerator::append_contour_line_to_vertices( - ContourLine& contour_line, - PyObject* vertices_list) const -{ - assert(vertices_list != 0 && "Null python vertices_list"); - - // Convert ContourLine to python equivalent, and clear it. - npy_intp dims[2] = {static_cast<npy_intp>(contour_line.size()), 2}; - numpy::array_view<double, 2> line(dims); - npy_intp i = 0; - for (ContourLine::const_iterator point = contour_line.begin(); - point != contour_line.end(); ++point, ++i) { - line(i, 0) = point->x; - line(i, 1) = point->y; - } - if (PyList_Append(vertices_list, line.pyobj_steal())) { - Py_XDECREF(vertices_list); - throw std::runtime_error("Unable to add contour line to vertices_list"); - } - - contour_line.clear(); -} - -void QuadContourGenerator::append_contour_to_vertices_and_codes( - Contour& contour, - PyObject* vertices_list, - PyObject* codes_list) const -{ - assert(vertices_list != 0 && "Null python vertices_list"); - assert(codes_list != 0 && "Null python codes_list"); - - // Convert Contour to python equivalent, and clear it. - for (Contour::iterator line_it = contour.begin(); line_it != contour.end(); - ++line_it) { - ContourLine& line = **line_it; - if (line.is_hole()) { - // If hole has already been converted to python its parent will be - // set to 0 and it can be deleted. - if (line.get_parent() != 0) { - delete *line_it; - *line_it = 0; - } - } - else { - // Non-holes are converted to python together with their child - // holes so that they are rendered correctly. - ContourLine::const_iterator point; - ContourLine::Children::const_iterator children_it; - - const ContourLine::Children& children = line.get_children(); - npy_intp npoints = static_cast<npy_intp>(line.size() + 1); - for (children_it = children.begin(); children_it != children.end(); - ++children_it) - npoints += static_cast<npy_intp>((*children_it)->size() + 1); - - npy_intp vertices_dims[2] = {npoints, 2}; - numpy::array_view<double, 2> vertices(vertices_dims); - double* vertices_ptr = vertices.data(); - - npy_intp codes_dims[1] = {npoints}; - numpy::array_view<unsigned char, 1> codes(codes_dims); - unsigned char* codes_ptr = codes.data(); - - for (point = line.begin(); point != line.end(); ++point) { - *vertices_ptr++ = point->x; - *vertices_ptr++ = point->y; - *codes_ptr++ = (point == line.begin() ? MOVETO : LINETO); - } - point = line.begin(); - *vertices_ptr++ = point->x; - *vertices_ptr++ = point->y; - *codes_ptr++ = CLOSEPOLY; - - for (children_it = children.begin(); children_it != children.end(); - ++children_it) { - ContourLine& child = **children_it; - for (point = child.begin(); point != child.end(); ++point) { - *vertices_ptr++ = point->x; - *vertices_ptr++ = point->y; - *codes_ptr++ = (point == child.begin() ? MOVETO : LINETO); - } - point = child.begin(); - *vertices_ptr++ = point->x; - *vertices_ptr++ = point->y; - *codes_ptr++ = CLOSEPOLY; - - child.clear_parent(); // To indicate it can be deleted. - } - - if (PyList_Append(vertices_list, vertices.pyobj_steal()) || - PyList_Append(codes_list, codes.pyobj_steal())) { - Py_XDECREF(vertices_list); - Py_XDECREF(codes_list); - contour.delete_contour_lines(); - throw std::runtime_error("Unable to add contour line to vertices and codes lists"); - } - - delete *line_it; - *line_it = 0; - } - } - - // Delete remaining contour lines. - contour.delete_contour_lines(); -} - -long QuadContourGenerator::calc_chunk_count(long point_count) const -{ - assert(point_count > 0 && "point count must be positive"); - assert(_chunk_size > 0 && "Chunk size must be positive"); - - if (_chunk_size > 0) { - long count = (point_count-1) / _chunk_size; - if (count*_chunk_size < point_count-1) - ++count; - - assert(count >= 1 && "Invalid chunk count"); - return count; - } - else - return 1; -} - -PyObject* QuadContourGenerator::create_contour(const double& level) -{ - init_cache_levels(level, level); - - PyObject* vertices_list = PyList_New(0); - if (vertices_list == 0) - throw std::runtime_error("Failed to create Python list"); - - // Lines that start and end on boundaries. - long ichunk, jchunk, istart, iend, jstart, jend; - for (long ijchunk = 0; ijchunk < _chunk_count; ++ijchunk) { - get_chunk_limits(ijchunk, ichunk, jchunk, istart, iend, jstart, jend); - - for (long j = jstart; j < jend; ++j) { - long quad_end = iend + j*_nx; - for (long quad = istart + j*_nx; quad < quad_end; ++quad) { - if (EXISTS_NONE(quad) || VISITED(quad,1)) continue; - - if (BOUNDARY_S(quad) && Z_SW >= 1 && Z_SE < 1 && - start_line(vertices_list, quad, Edge_S, level)) continue; - - if (BOUNDARY_W(quad) && Z_NW >= 1 && Z_SW < 1 && - start_line(vertices_list, quad, Edge_W, level)) continue; - - if (BOUNDARY_N(quad) && Z_NE >= 1 && Z_NW < 1 && - start_line(vertices_list, quad, Edge_N, level)) continue; - - if (BOUNDARY_E(quad) && Z_SE >= 1 && Z_NE < 1 && - start_line(vertices_list, quad, Edge_E, level)) continue; - - if (_corner_mask) { - // Equates to NE boundary. - if (EXISTS_SW_CORNER(quad) && Z_SE >= 1 && Z_NW < 1 && - start_line(vertices_list, quad, Edge_NE, level)) continue; - - // Equates to NW boundary. - if (EXISTS_SE_CORNER(quad) && Z_NE >= 1 && Z_SW < 1 && - start_line(vertices_list, quad, Edge_NW, level)) continue; - - // Equates to SE boundary. - if (EXISTS_NW_CORNER(quad) && Z_SW >= 1 && Z_NE < 1 && - start_line(vertices_list, quad, Edge_SE, level)) continue; - - // Equates to SW boundary. - if (EXISTS_NE_CORNER(quad) && Z_NW >= 1 && Z_SE < 1 && - start_line(vertices_list, quad, Edge_SW, level)) continue; - } - } - } - } - - // Internal loops. - ContourLine contour_line(false); // Reused for each contour line. - for (long ijchunk = 0; ijchunk < _chunk_count; ++ijchunk) { - get_chunk_limits(ijchunk, ichunk, jchunk, istart, iend, jstart, jend); - - for (long j = jstart; j < jend; ++j) { - long quad_end = iend + j*_nx; - for (long quad = istart + j*_nx; quad < quad_end; ++quad) { - if (EXISTS_NONE(quad) || VISITED(quad,1)) - continue; - - Edge start_edge = get_start_edge(quad, 1); - if (start_edge == Edge_None) - continue; - - QuadEdge quad_edge(quad, start_edge); - QuadEdge start_quad_edge(quad_edge); - - // To obtain output identical to that produced by legacy code, - // sometimes need to ignore the first point and add it on the - // end instead. - bool ignore_first = (start_edge == Edge_N); - follow_interior(contour_line, quad_edge, 1, level, - !ignore_first, &start_quad_edge, 1, false); - if (ignore_first && !contour_line.empty()) - contour_line.push_back(contour_line.front()); - append_contour_line_to_vertices(contour_line, vertices_list); - - // Repeat if saddle point but not visited. - if (SADDLE(quad,1) && !VISITED(quad,1)) - --quad; - } - } - } - - return vertices_list; -} - -PyObject* QuadContourGenerator::create_filled_contour(const double& lower_level, - const double& upper_level) -{ - init_cache_levels(lower_level, upper_level); - - Contour contour; - - PyObject* vertices = PyList_New(0); - if (vertices == 0) - throw std::runtime_error("Failed to create Python list"); - - PyObject* codes = PyList_New(0); - if (codes == 0) { - Py_XDECREF(vertices); - throw std::runtime_error("Failed to create Python list"); - } - - long ichunk, jchunk, istart, iend, jstart, jend; - for (long ijchunk = 0; ijchunk < _chunk_count; ++ijchunk) { - get_chunk_limits(ijchunk, ichunk, jchunk, istart, iend, jstart, jend); - _parent_cache.set_chunk_starts(istart, jstart); - - for (long j = jstart; j < jend; ++j) { - long quad_end = iend + j*_nx; - for (long quad = istart + j*_nx; quad < quad_end; ++quad) { - if (!EXISTS_NONE(quad)) - single_quad_filled(contour, quad, lower_level, upper_level); - } - } - - // Clear VISITED_W and VISITED_S flags that are reused by later chunks. - if (jchunk < _nychunk-1) { - long quad_end = iend + jend*_nx; - for (long quad = istart + jend*_nx; quad < quad_end; ++quad) - _cache[quad] &= ~MASK_VISITED_S; - } - - if (ichunk < _nxchunk-1) { - long quad_end = iend + jend*_nx; - for (long quad = iend + jstart*_nx; quad < quad_end; quad += _nx) - _cache[quad] &= ~MASK_VISITED_W; - } - - // Create python objects to return for this chunk. - append_contour_to_vertices_and_codes(contour, vertices, codes); - } - - PyObject* tuple = PyTuple_New(2); - if (tuple == 0) { - Py_XDECREF(vertices); - Py_XDECREF(codes); - throw std::runtime_error("Failed to create Python tuple"); - } - - // No error checking here as filling in a brand new pre-allocated tuple. - PyTuple_SET_ITEM(tuple, 0, vertices); - PyTuple_SET_ITEM(tuple, 1, codes); - - return tuple; -} - -XY QuadContourGenerator::edge_interp(const QuadEdge& quad_edge, - const double& level) -{ - assert(quad_edge.quad >= 0 && quad_edge.quad < _n && - "Quad index out of bounds"); - assert(quad_edge.edge != Edge_None && "Invalid edge"); - return interp(get_edge_point_index(quad_edge, true), - get_edge_point_index(quad_edge, false), - level); -} - -unsigned int QuadContourGenerator::follow_boundary( - ContourLine& contour_line, - QuadEdge& quad_edge, - const double& lower_level, - const double& upper_level, - unsigned int level_index, - const QuadEdge& start_quad_edge) -{ - assert(quad_edge.quad >= 0 && quad_edge.quad < _n && - "Quad index out of bounds"); - assert(quad_edge.edge != Edge_None && "Invalid edge"); - assert(is_edge_a_boundary(quad_edge) && "Not a boundary edge"); - assert((level_index == 1 || level_index == 2) && - "level index must be 1 or 2"); - assert(start_quad_edge.quad >= 0 && start_quad_edge.quad < _n && - "Start quad index out of bounds"); - assert(start_quad_edge.edge != Edge_None && "Invalid start edge"); - - // Only called for filled contours, so always updates _parent_cache. - unsigned int end_level = 0; - bool first_edge = true; - bool stop = false; - long& quad = quad_edge.quad; - - while (true) { - // Levels of start and end points of quad_edge. - unsigned int start_level = - (first_edge ? Z_LEVEL(get_edge_point_index(quad_edge, true)) - : end_level); - long end_point = get_edge_point_index(quad_edge, false); - end_level = Z_LEVEL(end_point); - - if (level_index == 1) { - if (start_level <= level_index && end_level == 2) { - // Increasing z, switching levels from 1 to 2. - level_index = 2; - stop = true; - } - else if (start_level >= 1 && end_level == 0) { - // Decreasing z, keeping same level. - stop = true; - } - } - else { // level_index == 2 - if (start_level <= level_index && end_level == 2) { - // Increasing z, keeping same level. - stop = true; - } - else if (start_level >= 1 && end_level == 0) { - // Decreasing z, switching levels from 2 to 1. - level_index = 1; - stop = true; - } - } - - if (!first_edge && !stop && quad_edge == start_quad_edge) - // Return if reached start point of contour line. Do this before - // checking/setting VISITED flags as will already have been - // visited. - break; - - switch (quad_edge.edge) { - case Edge_E: - assert(!VISITED_W(quad+1) && "Already visited"); - _cache[quad+1] |= MASK_VISITED_W; - break; - case Edge_N: - assert(!VISITED_S(quad+_nx) && "Already visited"); - _cache[quad+_nx] |= MASK_VISITED_S; - break; - case Edge_W: - assert(!VISITED_W(quad) && "Already visited"); - _cache[quad] |= MASK_VISITED_W; - break; - case Edge_S: - assert(!VISITED_S(quad) && "Already visited"); - _cache[quad] |= MASK_VISITED_S; - break; - case Edge_NE: - case Edge_NW: - case Edge_SW: - case Edge_SE: - assert(!VISITED_CORNER(quad) && "Already visited"); - _cache[quad] |= MASK_VISITED_CORNER; - break; - default: - assert(0 && "Invalid Edge"); - break; - } - - if (stop) { - // Exiting boundary to enter interior. - contour_line.push_back(edge_interp(quad_edge, - level_index == 1 ? lower_level - : upper_level)); - break; - } - - move_to_next_boundary_edge(quad_edge); - - // Just moved to new quad edge, so label parent of start of quad edge. - switch (quad_edge.edge) { - case Edge_W: - case Edge_SW: - case Edge_S: - case Edge_SE: - if (!EXISTS_SE_CORNER(quad)) - _parent_cache.set_parent(quad, contour_line); - break; - case Edge_E: - case Edge_NE: - case Edge_N: - case Edge_NW: - if (!EXISTS_SW_CORNER(quad)) - _parent_cache.set_parent(quad + 1, contour_line); - break; - default: - assert(0 && "Invalid edge"); - break; - } - - // Add point to contour. - contour_line.push_back(get_point_xy(end_point)); - - if (first_edge) - first_edge = false; - } - - return level_index; -} - -void QuadContourGenerator::follow_interior(ContourLine& contour_line, - QuadEdge& quad_edge, - unsigned int level_index, - const double& level, - bool want_initial_point, - const QuadEdge* start_quad_edge, - unsigned int start_level_index, - bool set_parents) -{ - assert(quad_edge.quad >= 0 && quad_edge.quad < _n && - "Quad index out of bounds."); - assert(quad_edge.edge != Edge_None && "Invalid edge"); - assert((level_index == 1 || level_index == 2) && - "level index must be 1 or 2"); - assert((start_quad_edge == 0 || - (start_quad_edge->quad >= 0 && start_quad_edge->quad < _n)) && - "Start quad index out of bounds."); - assert((start_quad_edge == 0 || start_quad_edge->edge != Edge_None) && - "Invalid start edge"); - assert((start_level_index == 1 || start_level_index == 2) && - "start level index must be 1 or 2"); - - long& quad = quad_edge.quad; - Edge& edge = quad_edge.edge; - - if (want_initial_point) - contour_line.push_back(edge_interp(quad_edge, level)); - - CacheItem visited_mask = (level_index == 1 ? MASK_VISITED_1 : MASK_VISITED_2); - CacheItem saddle_mask = (level_index == 1 ? MASK_SADDLE_1 : MASK_SADDLE_2); - Dir dir = Dir_Straight; - - while (true) { - assert(!EXISTS_NONE(quad) && "Quad does not exist"); - assert(!(_cache[quad] & visited_mask) && "Quad already visited"); - - // Determine direction to move to next quad. If the quad is already - // labelled as a saddle quad then the direction is easily read from - // the cache. Otherwise the direction is determined differently - // depending on whether the quad is a corner quad or not. - - if (_cache[quad] & saddle_mask) { - // Already identified as a saddle quad, so direction is easy. - dir = (SADDLE_LEFT(quad,level_index) ? Dir_Left : Dir_Right); - _cache[quad] |= visited_mask; - } - else if (EXISTS_ANY_CORNER(quad)) { - // Need z-level of point opposite the entry edge, as that - // determines whether contour turns left or right. - long point_opposite = -1; - switch (edge) { - case Edge_E: - point_opposite = (EXISTS_SE_CORNER(quad) ? POINT_SW - : POINT_NW); - break; - case Edge_N: - point_opposite = (EXISTS_NW_CORNER(quad) ? POINT_SW - : POINT_SE); - break; - case Edge_W: - point_opposite = (EXISTS_SW_CORNER(quad) ? POINT_SE - : POINT_NE); - break; - case Edge_S: - point_opposite = (EXISTS_SW_CORNER(quad) ? POINT_NW - : POINT_NE); - break; - case Edge_NE: point_opposite = POINT_SW; break; - case Edge_NW: point_opposite = POINT_SE; break; - case Edge_SW: point_opposite = POINT_NE; break; - case Edge_SE: point_opposite = POINT_NW; break; - default: assert(0 && "Invalid edge"); break; - } - assert(point_opposite != -1 && "Failed to find opposite point"); - - // Lower-level polygons (level_index == 1) always have higher - // values to the left of the contour. Upper-level contours - // (level_index == 2) are reversed, which is what the fancy XOR - // does below. - if ((Z_LEVEL(point_opposite) >= level_index) ^ (level_index == 2)) - dir = Dir_Right; - else - dir = Dir_Left; - _cache[quad] |= visited_mask; - } - else { - // Calculate configuration of this quad. - long point_left = -1, point_right = -1; - switch (edge) { - case Edge_E: point_left = POINT_SW; point_right = POINT_NW; break; - case Edge_N: point_left = POINT_SE; point_right = POINT_SW; break; - case Edge_W: point_left = POINT_NE; point_right = POINT_SE; break; - case Edge_S: point_left = POINT_NW; point_right = POINT_NE; break; - default: assert(0 && "Invalid edge"); break; - } - - unsigned int config = (Z_LEVEL(point_left) >= level_index) << 1 | - (Z_LEVEL(point_right) >= level_index); - - // Upper level (level_index == 2) polygons are reversed compared to - // lower level ones, i.e. higher values on the right rather than - // the left. - if (level_index == 2) - config = 3 - config; - - // Calculate turn direction to move to next quad along contour line. - if (config == 1) { - // New saddle quad, set up cache bits for it. - double zmid = 0.25*(get_point_z(POINT_SW) + - get_point_z(POINT_SE) + - get_point_z(POINT_NW) + - get_point_z(POINT_NE)); - _cache[quad] |= (level_index == 1 ? MASK_SADDLE_1 : MASK_SADDLE_2); - if ((zmid > level) ^ (level_index == 2)) { - dir = Dir_Right; - } - else { - dir = Dir_Left; - _cache[quad] |= (level_index == 1 ? MASK_SADDLE_LEFT_1 - : MASK_SADDLE_LEFT_2); - } - if (edge == Edge_N || edge == Edge_E) { - // Next visit to this quad must start on S or W. - _cache[quad] |= (level_index == 1 ? MASK_SADDLE_START_SW_1 - : MASK_SADDLE_START_SW_2); - } - } - else { - // Normal (non-saddle) quad. - dir = (config == 0 ? Dir_Left - : (config == 3 ? Dir_Right : Dir_Straight)); - _cache[quad] |= visited_mask; - } - } - - // Use dir to determine exit edge. - edge = get_exit_edge(quad_edge, dir); - - if (set_parents) { - if (edge == Edge_E) - _parent_cache.set_parent(quad+1, contour_line); - else if (edge == Edge_W) - _parent_cache.set_parent(quad, contour_line); - } - - // Add new point to contour line. - contour_line.push_back(edge_interp(quad_edge, level)); - - // Stop if reached boundary. - if (is_edge_a_boundary(quad_edge)) - break; - - move_to_next_quad(quad_edge); - assert(quad_edge.quad >= 0 && quad_edge.quad < _n && - "Quad index out of bounds"); - - // Return if reached start point of contour line. - if (start_quad_edge != 0 && - quad_edge == *start_quad_edge && - level_index == start_level_index) - break; - } -} - -void QuadContourGenerator::get_chunk_limits(long ijchunk, - long& ichunk, - long& jchunk, - long& istart, - long& iend, - long& jstart, - long& jend) -{ - assert(ijchunk >= 0 && ijchunk < _chunk_count && "ijchunk out of bounds"); - ichunk = ijchunk % _nxchunk; - jchunk = ijchunk / _nxchunk; - istart = ichunk*_chunk_size; - iend = (ichunk == _nxchunk-1 ? _nx : (ichunk+1)*_chunk_size); - jstart = jchunk*_chunk_size; - jend = (jchunk == _nychunk-1 ? _ny : (jchunk+1)*_chunk_size); -} - -Edge QuadContourGenerator::get_corner_start_edge(long quad, - unsigned int level_index) const -{ - assert(quad >= 0 && quad < _n && "Quad index out of bounds"); - assert((level_index == 1 || level_index == 2) && - "level index must be 1 or 2"); - assert(EXISTS_ANY_CORNER(quad) && "Quad is not a corner"); - - // Diagram for NE corner. Rotate for other corners. - // - // edge12 - // point1 +---------+ point2 - // \ | - // \ | edge23 - // edge31 \ | - // \ | - // + point3 - // - long point1, point2, point3; - Edge edge12, edge23, edge31; - switch (_cache[quad] & MASK_EXISTS) { - case MASK_EXISTS_SW_CORNER: - point1 = POINT_SE; point2 = POINT_SW; point3 = POINT_NW; - edge12 = Edge_S; edge23 = Edge_W; edge31 = Edge_NE; - break; - case MASK_EXISTS_SE_CORNER: - point1 = POINT_NE; point2 = POINT_SE; point3 = POINT_SW; - edge12 = Edge_E; edge23 = Edge_S; edge31 = Edge_NW; - break; - case MASK_EXISTS_NW_CORNER: - point1 = POINT_SW; point2 = POINT_NW; point3 = POINT_NE; - edge12 = Edge_W; edge23 = Edge_N; edge31 = Edge_SE; - break; - case MASK_EXISTS_NE_CORNER: - point1 = POINT_NW; point2 = POINT_NE; point3 = POINT_SE; - edge12 = Edge_N; edge23 = Edge_E; edge31 = Edge_SW; - break; - default: - assert(0 && "Invalid EXISTS for quad"); - return Edge_None; - } - - unsigned int config = (Z_LEVEL(point1) >= level_index) << 2 | - (Z_LEVEL(point2) >= level_index) << 1 | - (Z_LEVEL(point3) >= level_index); - - // Upper level (level_index == 2) polygons are reversed compared to lower - // level ones, i.e. higher values on the right rather than the left. - if (level_index == 2) - config = 7 - config; - - switch (config) { - case 0: return Edge_None; - case 1: return edge23; - case 2: return edge12; - case 3: return edge12; - case 4: return edge31; - case 5: return edge23; - case 6: return edge31; - case 7: return Edge_None; - default: assert(0 && "Invalid config"); return Edge_None; - } -} - -long QuadContourGenerator::get_edge_point_index(const QuadEdge& quad_edge, - bool start) const -{ - assert(quad_edge.quad >= 0 && quad_edge.quad < _n && - "Quad index out of bounds"); - assert(quad_edge.edge != Edge_None && "Invalid edge"); - - // Edges are ordered anticlockwise around their quad, as indicated by - // directions of arrows in diagrams below. - // Full quad NW corner (others similar) - // - // POINT_NW Edge_N POINT_NE POINT_NW Edge_N POINT_NE - // +----<-----+ +----<-----+ - // | | | / - // | | | quad / - // Edge_W V quad ^ Edge_E Edge_W V ^ - // | | | / Edge_SE - // | | | / - // +---->-----+ + - // POINT_SW Edge_S POINT_SE POINT_SW - // - const long& quad = quad_edge.quad; - switch (quad_edge.edge) { - case Edge_E: return (start ? POINT_SE : POINT_NE); - case Edge_N: return (start ? POINT_NE : POINT_NW); - case Edge_W: return (start ? POINT_NW : POINT_SW); - case Edge_S: return (start ? POINT_SW : POINT_SE); - case Edge_NE: return (start ? POINT_SE : POINT_NW); - case Edge_NW: return (start ? POINT_NE : POINT_SW); - case Edge_SW: return (start ? POINT_NW : POINT_SE); - case Edge_SE: return (start ? POINT_SW : POINT_NE); - default: assert(0 && "Invalid edge"); return 0; - } -} - -Edge QuadContourGenerator::get_exit_edge(const QuadEdge& quad_edge, - Dir dir) const -{ - assert(quad_edge.quad >= 0 && quad_edge.quad < _n && - "Quad index out of bounds"); - assert(quad_edge.edge != Edge_None && "Invalid edge"); - - const long& quad = quad_edge.quad; - const Edge& edge = quad_edge.edge; - if (EXISTS_ANY_CORNER(quad)) { - // Corner directions are always left or right. A corner is a triangle, - // entered via one edge so the other two edges are the left and right - // ones. - switch (edge) { - case Edge_E: - return (EXISTS_SE_CORNER(quad) - ? (dir == Dir_Left ? Edge_S : Edge_NW) - : (dir == Dir_Right ? Edge_N : Edge_SW)); - case Edge_N: - return (EXISTS_NW_CORNER(quad) - ? (dir == Dir_Right ? Edge_W : Edge_SE) - : (dir == Dir_Left ? Edge_E : Edge_SW)); - case Edge_W: - return (EXISTS_SW_CORNER(quad) - ? (dir == Dir_Right ? Edge_S : Edge_NE) - : (dir == Dir_Left ? Edge_N : Edge_SE)); - case Edge_S: - return (EXISTS_SW_CORNER(quad) - ? (dir == Dir_Left ? Edge_W : Edge_NE) - : (dir == Dir_Right ? Edge_E : Edge_NW)); - case Edge_NE: return (dir == Dir_Left ? Edge_S : Edge_W); - case Edge_NW: return (dir == Dir_Left ? Edge_E : Edge_S); - case Edge_SW: return (dir == Dir_Left ? Edge_N : Edge_E); - case Edge_SE: return (dir == Dir_Left ? Edge_W : Edge_N); - default: assert(0 && "Invalid edge"); return Edge_None; - } - } - else { - // A full quad has four edges, entered via one edge so that other three - // edges correspond to left, straight and right directions. - switch (edge) { - case Edge_E: - return (dir == Dir_Left ? Edge_S : - (dir == Dir_Right ? Edge_N : Edge_W)); - case Edge_N: - return (dir == Dir_Left ? Edge_E : - (dir == Dir_Right ? Edge_W : Edge_S)); - case Edge_W: - return (dir == Dir_Left ? Edge_N : - (dir == Dir_Right ? Edge_S : Edge_E)); - case Edge_S: - return (dir == Dir_Left ? Edge_W : - (dir == Dir_Right ? Edge_E : Edge_N)); - default: assert(0 && "Invalid edge"); return Edge_None; - } - } -} - -XY QuadContourGenerator::get_point_xy(long point) const -{ - assert(point >= 0 && point < _n && "Point index out of bounds."); - return XY(_x.data()[static_cast<npy_intp>(point)], - _y.data()[static_cast<npy_intp>(point)]); -} - -const double& QuadContourGenerator::get_point_z(long point) const -{ - assert(point >= 0 && point < _n && "Point index out of bounds."); - return _z.data()[static_cast<npy_intp>(point)]; -} - -Edge QuadContourGenerator::get_quad_start_edge(long quad, - unsigned int level_index) const -{ - assert(quad >= 0 && quad < _n && "Quad index out of bounds"); - assert((level_index == 1 || level_index == 2) && - "level index must be 1 or 2"); - assert(EXISTS_QUAD(quad) && "Quad does not exist"); - - unsigned int config = (Z_NW >= level_index) << 3 | - (Z_NE >= level_index) << 2 | - (Z_SW >= level_index) << 1 | - (Z_SE >= level_index); - - // Upper level (level_index == 2) polygons are reversed compared to lower - // level ones, i.e. higher values on the right rather than the left. - if (level_index == 2) - config = 15 - config; - - switch (config) { - case 0: return Edge_None; - case 1: return Edge_E; - case 2: return Edge_S; - case 3: return Edge_E; - case 4: return Edge_N; - case 5: return Edge_N; - case 6: - // If already identified as a saddle quad then the start edge is - // read from the cache. Otherwise return either valid start edge - // and the subsequent call to follow_interior() will correctly set - // up saddle bits in cache. - if (!SADDLE(quad,level_index) || SADDLE_START_SW(quad,level_index)) - return Edge_S; - else - return Edge_N; - case 7: return Edge_N; - case 8: return Edge_W; - case 9: - // See comment for 6 above. - if (!SADDLE(quad,level_index) || SADDLE_START_SW(quad,level_index)) - return Edge_W; - else - return Edge_E; - case 10: return Edge_S; - case 11: return Edge_E; - case 12: return Edge_W; - case 13: return Edge_W; - case 14: return Edge_S; - case 15: return Edge_None; - default: assert(0 && "Invalid config"); return Edge_None; - } -} - -Edge QuadContourGenerator::get_start_edge(long quad, - unsigned int level_index) const -{ - if (EXISTS_ANY_CORNER(quad)) - return get_corner_start_edge(quad, level_index); - else - return get_quad_start_edge(quad, level_index); -} - -void QuadContourGenerator::init_cache_grid(const MaskArray& mask) -{ - long i, j, quad; - - if (mask.empty()) { - // No mask, easy to calculate quad existence and boundaries together. - quad = 0; - for (j = 0; j < _ny; ++j) { - for (i = 0; i < _nx; ++i, ++quad) { - _cache[quad] = 0; - - if (i < _nx-1 && j < _ny-1) - _cache[quad] |= MASK_EXISTS_QUAD; - - if ((i % _chunk_size == 0 || i == _nx-1) && j < _ny-1) - _cache[quad] |= MASK_BOUNDARY_W; - - if ((j % _chunk_size == 0 || j == _ny-1) && i < _nx-1) - _cache[quad] |= MASK_BOUNDARY_S; - } - } - } - else { - // Casting avoids problem when sizeof(bool) != sizeof(npy_bool). - const npy_bool* mask_ptr = - reinterpret_cast<const npy_bool*>(mask.data()); - - // Have mask so use two stages. - // Stage 1, determine if quads/corners exist. - quad = 0; - for (j = 0; j < _ny; ++j) { - for (i = 0; i < _nx; ++i, ++quad) { - _cache[quad] = 0; - - if (i < _nx-1 && j < _ny-1) { - unsigned int config = mask_ptr[POINT_NW] << 3 | - mask_ptr[POINT_NE] << 2 | - mask_ptr[POINT_SW] << 1 | - mask_ptr[POINT_SE]; - - if (_corner_mask) { - switch (config) { - case 0: _cache[quad] = MASK_EXISTS_QUAD; break; - case 1: _cache[quad] = MASK_EXISTS_NW_CORNER; break; - case 2: _cache[quad] = MASK_EXISTS_NE_CORNER; break; - case 4: _cache[quad] = MASK_EXISTS_SW_CORNER; break; - case 8: _cache[quad] = MASK_EXISTS_SE_CORNER; break; - default: - // Do nothing, quad is masked out. - break; - } - } - else if (config == 0) - _cache[quad] = MASK_EXISTS_QUAD; - } - } - } - - // Stage 2, calculate W and S boundaries. For each quad use boundary - // data already calculated for quads to W and S, so must iterate - // through quads in correct order (increasing i and j indices). - // Cannot use boundary data for quads to E and N as have not yet - // calculated it. - quad = 0; - for (j = 0; j < _ny; ++j) { - for (i = 0; i < _nx; ++i, ++quad) { - if (_corner_mask) { - bool W_exists_none = (i == 0 || EXISTS_NONE(quad-1)); - bool S_exists_none = (j == 0 || EXISTS_NONE(quad-_nx)); - bool W_exists_E_edge = (i > 0 && EXISTS_E_EDGE(quad-1)); - bool S_exists_N_edge = (j > 0 && EXISTS_N_EDGE(quad-_nx)); - - if ((EXISTS_W_EDGE(quad) && W_exists_none) || - (EXISTS_NONE(quad) && W_exists_E_edge) || - (i % _chunk_size == 0 && EXISTS_W_EDGE(quad) && - W_exists_E_edge)) - _cache[quad] |= MASK_BOUNDARY_W; - - if ((EXISTS_S_EDGE(quad) && S_exists_none) || - (EXISTS_NONE(quad) && S_exists_N_edge) || - (j % _chunk_size == 0 && EXISTS_S_EDGE(quad) && - S_exists_N_edge)) - _cache[quad] |= MASK_BOUNDARY_S; - } - else { - bool W_exists_quad = (i > 0 && EXISTS_QUAD(quad-1)); - bool S_exists_quad = (j > 0 && EXISTS_QUAD(quad-_nx)); - - if ((EXISTS_QUAD(quad) != W_exists_quad) || - (i % _chunk_size == 0 && EXISTS_QUAD(quad) && - W_exists_quad)) - _cache[quad] |= MASK_BOUNDARY_W; - - if ((EXISTS_QUAD(quad) != S_exists_quad) || - (j % _chunk_size == 0 && EXISTS_QUAD(quad) && - S_exists_quad)) - _cache[quad] |= MASK_BOUNDARY_S; - } - } - } - } -} - -void QuadContourGenerator::init_cache_levels(const double& lower_level, - const double& upper_level) -{ - assert(upper_level >= lower_level && - "upper and lower levels are wrong way round"); - - bool two_levels = (lower_level != upper_level); - CacheItem keep_mask = - (_corner_mask ? MASK_EXISTS | MASK_BOUNDARY_S | MASK_BOUNDARY_W - : MASK_EXISTS_QUAD | MASK_BOUNDARY_S | MASK_BOUNDARY_W); - - if (two_levels) { - const double* z_ptr = _z.data(); - for (long quad = 0; quad < _n; ++quad, ++z_ptr) { - _cache[quad] &= keep_mask; - if (*z_ptr > upper_level) - _cache[quad] |= MASK_Z_LEVEL_2; - else if (*z_ptr > lower_level) - _cache[quad] |= MASK_Z_LEVEL_1; - } - } - else { - const double* z_ptr = _z.data(); - for (long quad = 0; quad < _n; ++quad, ++z_ptr) { - _cache[quad] &= keep_mask; - if (*z_ptr > lower_level) - _cache[quad] |= MASK_Z_LEVEL_1; - } - } -} - -XY QuadContourGenerator::interp( - long point1, long point2, const double& level) const -{ - assert(point1 >= 0 && point1 < _n && "Point index 1 out of bounds."); - assert(point2 >= 0 && point2 < _n && "Point index 2 out of bounds."); - assert(point1 != point2 && "Identical points"); - double fraction = (get_point_z(point2) - level) / - (get_point_z(point2) - get_point_z(point1)); - return get_point_xy(point1)*fraction + get_point_xy(point2)*(1.0 - fraction); -} - -bool QuadContourGenerator::is_edge_a_boundary(const QuadEdge& quad_edge) const -{ - assert(quad_edge.quad >= 0 && quad_edge.quad < _n && - "Quad index out of bounds"); - assert(quad_edge.edge != Edge_None && "Invalid edge"); - - switch (quad_edge.edge) { - case Edge_E: return BOUNDARY_E(quad_edge.quad); - case Edge_N: return BOUNDARY_N(quad_edge.quad); - case Edge_W: return BOUNDARY_W(quad_edge.quad); - case Edge_S: return BOUNDARY_S(quad_edge.quad); - case Edge_NE: return EXISTS_SW_CORNER(quad_edge.quad); - case Edge_NW: return EXISTS_SE_CORNER(quad_edge.quad); - case Edge_SW: return EXISTS_NE_CORNER(quad_edge.quad); - case Edge_SE: return EXISTS_NW_CORNER(quad_edge.quad); - default: assert(0 && "Invalid edge"); return true; - } -} - -void QuadContourGenerator::move_to_next_boundary_edge(QuadEdge& quad_edge) const -{ - assert(is_edge_a_boundary(quad_edge) && "QuadEdge is not a boundary"); - - long& quad = quad_edge.quad; - Edge& edge = quad_edge.edge; - - quad = get_edge_point_index(quad_edge, false); - - // quad is now such that POINT_SW is the end point of the quad_edge passed - // to this function. - - // To find the next boundary edge, first attempt to turn left 135 degrees - // and if that edge is a boundary then move to it. If not, attempt to turn - // left 90 degrees, then left 45 degrees, then straight on, etc, until can - // move. - // First determine which edge to attempt first. - int index = 0; - switch (edge) { - case Edge_E: index = 0; break; - case Edge_SE: index = 1; break; - case Edge_S: index = 2; break; - case Edge_SW: index = 3; break; - case Edge_W: index = 4; break; - case Edge_NW: index = 5; break; - case Edge_N: index = 6; break; - case Edge_NE: index = 7; break; - default: assert(0 && "Invalid edge"); break; - } - - // If _corner_mask not set, only need to consider odd index in loop below. - if (!_corner_mask) - ++index; - - // Try each edge in turn until a boundary is found. - int start_index = index; - do - { - switch (index) { - case 0: - if (EXISTS_SE_CORNER(quad-_nx-1)) { // Equivalent to BOUNDARY_NW - quad -= _nx+1; - edge = Edge_NW; - return; - } - break; - case 1: - if (BOUNDARY_N(quad-_nx-1)) { - quad -= _nx+1; - edge = Edge_N; - return; - } - break; - case 2: - if (EXISTS_SW_CORNER(quad-1)) { // Equivalent to BOUNDARY_NE - quad -= 1; - edge = Edge_NE; - return; - } - break; - case 3: - if (BOUNDARY_E(quad-1)) { - quad -= 1; - edge = Edge_E; - return; - } - break; - case 4: - if (EXISTS_NW_CORNER(quad)) { // Equivalent to BOUNDARY_SE - edge = Edge_SE; - return; - } - break; - case 5: - if (BOUNDARY_S(quad)) { - edge = Edge_S; - return; - } - break; - case 6: - if (EXISTS_NE_CORNER(quad-_nx)) { // Equivalent to BOUNDARY_SW - quad -= _nx; - edge = Edge_SW; - return; - } - break; - case 7: - if (BOUNDARY_W(quad-_nx)) { - quad -= _nx; - edge = Edge_W; - return; - } - break; - default: assert(0 && "Invalid index"); break; - } - - if (_corner_mask) - index = (index + 1) % 8; - else - index = (index + 2) % 8; - } while (index != start_index); - - assert(0 && "Failed to find next boundary edge"); -} - -void QuadContourGenerator::move_to_next_quad(QuadEdge& quad_edge) const -{ - assert(quad_edge.quad >= 0 && quad_edge.quad < _n && - "Quad index out of bounds"); - assert(quad_edge.edge != Edge_None && "Invalid edge"); - - // Move from quad_edge.quad to the neighbouring quad in the direction - // specified by quad_edge.edge. - switch (quad_edge.edge) { - case Edge_E: quad_edge.quad += 1; quad_edge.edge = Edge_W; break; - case Edge_N: quad_edge.quad += _nx; quad_edge.edge = Edge_S; break; - case Edge_W: quad_edge.quad -= 1; quad_edge.edge = Edge_E; break; - case Edge_S: quad_edge.quad -= _nx; quad_edge.edge = Edge_N; break; - default: assert(0 && "Invalid edge"); break; - } -} - -void QuadContourGenerator::single_quad_filled(Contour& contour, - long quad, - const double& lower_level, - const double& upper_level) -{ - assert(quad >= 0 && quad < _n && "Quad index out of bounds"); - - // Order of checking is important here as can have different ContourLines - // from both lower and upper levels in the same quad. First check the S - // edge, then move up the quad to the N edge checking as required. - - // Possible starts from S boundary. - if (BOUNDARY_S(quad) && EXISTS_S_EDGE(quad)) { - - // Lower-level start from S boundary into interior. - if (!VISITED_S(quad) && Z_SW >= 1 && Z_SE == 0) - contour.push_back(start_filled(quad, Edge_S, 1, NotHole, Interior, - lower_level, upper_level)); - - // Upper-level start from S boundary into interior. - if (!VISITED_S(quad) && Z_SW < 2 && Z_SE == 2) - contour.push_back(start_filled(quad, Edge_S, 2, NotHole, Interior, - lower_level, upper_level)); - - // Lower-level start following S boundary from W to E. - if (!VISITED_S(quad) && Z_SW <= 1 && Z_SE == 1) - contour.push_back(start_filled(quad, Edge_S, 1, NotHole, Boundary, - lower_level, upper_level)); - - // Upper-level start following S boundary from W to E. - if (!VISITED_S(quad) && Z_SW == 2 && Z_SE == 1) - contour.push_back(start_filled(quad, Edge_S, 2, NotHole, Boundary, - lower_level, upper_level)); - } - - // Possible starts from W boundary. - if (BOUNDARY_W(quad) && EXISTS_W_EDGE(quad)) { - - // Lower-level start from W boundary into interior. - if (!VISITED_W(quad) && Z_NW >= 1 && Z_SW == 0) - contour.push_back(start_filled(quad, Edge_W, 1, NotHole, Interior, - lower_level, upper_level)); - - // Upper-level start from W boundary into interior. - if (!VISITED_W(quad) && Z_NW < 2 && Z_SW == 2) - contour.push_back(start_filled(quad, Edge_W, 2, NotHole, Interior, - lower_level, upper_level)); - - // Lower-level start following W boundary from N to S. - if (!VISITED_W(quad) && Z_NW <= 1 && Z_SW == 1) - contour.push_back(start_filled(quad, Edge_W, 1, NotHole, Boundary, - lower_level, upper_level)); - - // Upper-level start following W boundary from N to S. - if (!VISITED_W(quad) && Z_NW == 2 && Z_SW == 1) - contour.push_back(start_filled(quad, Edge_W, 2, NotHole, Boundary, - lower_level, upper_level)); - } - - // Possible starts from NE boundary. - if (EXISTS_SW_CORNER(quad)) { // i.e. BOUNDARY_NE - - // Lower-level start following NE boundary from SE to NW, hole. - if (!VISITED_CORNER(quad) && Z_NW == 1 && Z_SE == 1) - contour.push_back(start_filled(quad, Edge_NE, 1, Hole, Boundary, - lower_level, upper_level)); - } - // Possible starts from SE boundary. - else if (EXISTS_NW_CORNER(quad)) { // i.e. BOUNDARY_SE - - // Lower-level start from N to SE. - if (!VISITED(quad,1) && Z_NW == 0 && Z_SW == 0 && Z_NE >= 1) - contour.push_back(start_filled(quad, Edge_N, 1, NotHole, Interior, - lower_level, upper_level)); - - // Upper-level start from SE to N, hole. - if (!VISITED(quad,2) && Z_NW < 2 && Z_SW < 2 && Z_NE == 2) - contour.push_back(start_filled(quad, Edge_SE, 2, Hole, Interior, - lower_level, upper_level)); - - // Upper-level start from N to SE. - if (!VISITED(quad,2) && Z_NW == 2 && Z_SW == 2 && Z_NE < 2) - contour.push_back(start_filled(quad, Edge_N, 2, NotHole, Interior, - lower_level, upper_level)); - - // Lower-level start from SE to N, hole. - if (!VISITED(quad,1) && Z_NW >= 1 && Z_SW >= 1 && Z_NE == 0) - contour.push_back(start_filled(quad, Edge_SE, 1, Hole, Interior, - lower_level, upper_level)); - } - // Possible starts from NW boundary. - else if (EXISTS_SE_CORNER(quad)) { // i.e. BOUNDARY_NW - - // Lower-level start from NW to E. - if (!VISITED(quad,1) && Z_SW == 0 && Z_SE == 0 && Z_NE >= 1) - contour.push_back(start_filled(quad, Edge_NW, 1, NotHole, Interior, - lower_level, upper_level)); - - // Upper-level start from E to NW, hole. - if (!VISITED(quad,2) && Z_SW < 2 && Z_SE < 2 && Z_NE == 2) - contour.push_back(start_filled(quad, Edge_E, 2, Hole, Interior, - lower_level, upper_level)); - - // Upper-level start from NW to E. - if (!VISITED(quad,2) && Z_SW == 2 && Z_SE == 2 && Z_NE < 2) - contour.push_back(start_filled(quad, Edge_NW, 2, NotHole, Interior, - lower_level, upper_level)); - - // Lower-level start from E to NW, hole. - if (!VISITED(quad,1) && Z_SW >= 1 && Z_SE >= 1 && Z_NE == 0) - contour.push_back(start_filled(quad, Edge_E, 1, Hole, Interior, - lower_level, upper_level)); - } - // Possible starts from SW boundary. - else if (EXISTS_NE_CORNER(quad)) { // i.e. BOUNDARY_SW - - // Lower-level start from SW boundary into interior. - if (!VISITED_CORNER(quad) && Z_NW >= 1 && Z_SE == 0) - contour.push_back(start_filled(quad, Edge_SW, 1, NotHole, Interior, - lower_level, upper_level)); - - // Upper-level start from SW boundary into interior. - if (!VISITED_CORNER(quad) && Z_NW < 2 && Z_SE == 2) - contour.push_back(start_filled(quad, Edge_SW, 2, NotHole, Interior, - lower_level, upper_level)); - - // Lower-level start following SW boundary from NW to SE. - if (!VISITED_CORNER(quad) && Z_NW <= 1 && Z_SE == 1) - contour.push_back(start_filled(quad, Edge_SW, 1, NotHole, Boundary, - lower_level, upper_level)); - - // Upper-level start following SW boundary from NW to SE. - if (!VISITED_CORNER(quad) && Z_NW == 2 && Z_SE == 1) - contour.push_back(start_filled(quad, Edge_SW, 2, NotHole, Boundary, - lower_level, upper_level)); - } - - // A full (unmasked) quad can only have a start on the NE corner, i.e. from - // N to E (lower level) or E to N (upper level). Any other start will have - // already been created in a call to this function for a prior quad so we - // don't need to test for it again here. - // - // The situation is complicated by the possibility that the quad is a - // saddle quad, in which case a contour line starting on the N could leave - // by either the W or the E. We only need to consider those leaving E. - // - // A NE corner can also have a N to E or E to N start. - if (EXISTS_QUAD(quad) || EXISTS_NE_CORNER(quad)) { - - // Lower-level start from N to E. - if (!VISITED(quad,1) && Z_NW == 0 && Z_SE == 0 && Z_NE >= 1 && - (!SADDLE(quad,1) || SADDLE_LEFT(quad,1))) - contour.push_back(start_filled(quad, Edge_N, 1, NotHole, Interior, - lower_level, upper_level)); - - // Upper-level start from E to N, hole. - if (!VISITED(quad,2) && Z_NW < 2 && Z_SE < 2 && Z_NE == 2 && - (!SADDLE(quad,2) || !SADDLE_LEFT(quad,2))) - contour.push_back(start_filled(quad, Edge_E, 2, Hole, Interior, - lower_level, upper_level)); - - // Upper-level start from N to E. - if (!VISITED(quad,2) && Z_NW == 2 && Z_SE == 2 && Z_NE < 2 && - (!SADDLE(quad,2) || SADDLE_LEFT(quad,2))) - contour.push_back(start_filled(quad, Edge_N, 2, NotHole, Interior, - lower_level, upper_level)); - - // Lower-level start from E to N, hole. - if (!VISITED(quad,1) && Z_NW >= 1 && Z_SE >= 1 && Z_NE == 0 && - (!SADDLE(quad,1) || !SADDLE_LEFT(quad,1))) - contour.push_back(start_filled(quad, Edge_E, 1, Hole, Interior, - lower_level, upper_level)); - - // All possible contours passing through the interior of this quad - // should have already been created, so assert this. - assert((VISITED(quad,1) || get_start_edge(quad, 1) == Edge_None) && - "Found start of contour that should have already been created"); - assert((VISITED(quad,2) || get_start_edge(quad, 2) == Edge_None) && - "Found start of contour that should have already been created"); - } - - // Lower-level start following N boundary from E to W, hole. - // This is required for an internal masked region which is a hole in a - // surrounding contour line. - if (BOUNDARY_N(quad) && EXISTS_N_EDGE(quad) && - !VISITED_S(quad+_nx) && Z_NW == 1 && Z_NE == 1) - contour.push_back(start_filled(quad, Edge_N, 1, Hole, Boundary, - lower_level, upper_level)); -} - -ContourLine* QuadContourGenerator::start_filled( - long quad, - Edge edge, - unsigned int start_level_index, - HoleOrNot hole_or_not, - BoundaryOrInterior boundary_or_interior, - const double& lower_level, - const double& upper_level) -{ - assert(quad >= 0 && quad < _n && "Quad index out of bounds"); - assert(edge != Edge_None && "Invalid edge"); - assert((start_level_index == 1 || start_level_index == 2) && - "start level index must be 1 or 2"); - - ContourLine* contour_line = new ContourLine(hole_or_not == Hole); - if (hole_or_not == Hole) { - // Find and set parent ContourLine. - ContourLine* parent = _parent_cache.get_parent(quad + 1); - assert(parent != 0 && "Failed to find parent ContourLine"); - contour_line->set_parent(parent); - parent->add_child(contour_line); - } - - QuadEdge quad_edge(quad, edge); - const QuadEdge start_quad_edge(quad_edge); - unsigned int level_index = start_level_index; - - // If starts on interior, can only finish on interior. - // If starts on boundary, can only finish on boundary. - - while (true) { - if (boundary_or_interior == Interior) { - double level = (level_index == 1 ? lower_level : upper_level); - follow_interior(*contour_line, quad_edge, level_index, level, - false, &start_quad_edge, start_level_index, true); - } - else { - level_index = follow_boundary( - *contour_line, quad_edge, lower_level, - upper_level, level_index, start_quad_edge); - } - - if (quad_edge == start_quad_edge && (boundary_or_interior == Boundary || - level_index == start_level_index)) - break; - - if (boundary_or_interior == Boundary) - boundary_or_interior = Interior; - else - boundary_or_interior = Boundary; - } - - return contour_line; -} - -bool QuadContourGenerator::start_line( - PyObject* vertices_list, long quad, Edge edge, const double& level) -{ - assert(vertices_list != 0 && "Null python vertices list"); - assert(is_edge_a_boundary(QuadEdge(quad, edge)) && - "QuadEdge is not a boundary"); - - QuadEdge quad_edge(quad, edge); - ContourLine contour_line(false); - follow_interior(contour_line, quad_edge, 1, level, true, 0, 1, false); - append_contour_line_to_vertices(contour_line, vertices_list); - return VISITED(quad,1); -} - -void QuadContourGenerator::write_cache(bool grid_only) const -{ - std::cout << "-----------------------------------------------" << std::endl; - for (long quad = 0; quad < _n; ++quad) - write_cache_quad(quad, grid_only); - std::cout << "-----------------------------------------------" << std::endl; -} - -void QuadContourGenerator::write_cache_quad(long quad, bool grid_only) const -{ - long j = quad / _nx; - long i = quad - j*_nx; - std::cout << quad << ": i=" << i << " j=" << j - << " EXISTS=" << EXISTS_QUAD(quad); - if (_corner_mask) - std::cout << " CORNER=" << EXISTS_SW_CORNER(quad) << EXISTS_SE_CORNER(quad) - << EXISTS_NW_CORNER(quad) << EXISTS_NE_CORNER(quad); - std::cout << " BNDY=" << (BOUNDARY_S(quad)>0) << (BOUNDARY_W(quad)>0); - if (!grid_only) { - std::cout << " Z=" << Z_LEVEL(quad) - << " SAD=" << (SADDLE(quad,1)>0) << (SADDLE(quad,2)>0) - << " LEFT=" << (SADDLE_LEFT(quad,1)>0) << (SADDLE_LEFT(quad,2)>0) - << " NW=" << (SADDLE_START_SW(quad,1)>0) << (SADDLE_START_SW(quad,2)>0) - << " VIS=" << (VISITED(quad,1)>0) << (VISITED(quad,2)>0) - << (VISITED_S(quad)>0) << (VISITED_W(quad)>0) - << (VISITED_CORNER(quad)>0); - } - std::cout << std::endl; -} diff --git a/contrib/python/matplotlib/py2/src/_contour.h b/contrib/python/matplotlib/py2/src/_contour.h deleted file mode 100644 index e01c3bc732..0000000000 --- a/contrib/python/matplotlib/py2/src/_contour.h +++ /dev/null @@ -1,530 +0,0 @@ -/* - * QuadContourGenerator - * -------------------- - * A QuadContourGenerator generates contours for scalar fields defined on - * quadrilateral grids. A single QuadContourGenerator object can create both - * line contours (at single levels) and filled contours (between pairs of - * levels) for the same field. - * - * A field to be contoured has nx, ny points in the x- and y-directions - * respectively. The quad grid is defined by x and y arrays of shape(ny, nx), - * and the field itself is the z array also of shape(ny, nx). There is an - * optional boolean mask; if it exists then it also has shape(ny, nx). The - * mask applies to grid points rather than quads. - * - * How quads are masked based on the point mask is determined by the boolean - * 'corner_mask' flag. If false then any quad that has one or more of its four - * corner points masked is itself masked. If true the behaviour is the same - * except that any quad which has exactly one of its four corner points masked - * has only the triangular corner (half of the quad) adjacent to that point - * masked; the opposite triangular corner has three unmasked points and is not - * masked. - * - * By default the entire domain of nx*ny points is contoured together which can - * result in some very long polygons. The alternative is to break up the - * domain into subdomains or 'chunks' of smaller size, each of which is - * independently contoured. The size of these chunks is controlled by the - * 'nchunk' (or 'chunk_size') parameter. Chunking not only results in shorter - * polygons but also requires slightly less RAM. It can result in rendering - * artifacts though, depending on backend, antialiased flag and alpha value. - * - * Notation - * -------- - * i and j are array indices in the x- and y-directions respectively. Although - * a single element of an array z can be accessed using z[j][i] or z(j,i), it - * is often convenient to use the single quad index z[quad], where - * quad = i + j*nx - * and hence - * i = quad % nx - * j = quad / nx - * - * Rather than referring to x- and y-directions, compass directions are used - * instead such that W, E, S, N refer to the -x, +x, -y, +y directions - * respectively. To move one quad to the E you would therefore add 1 to the - * quad index, to move one quad to the N you would add nx to the quad index. - * - * Cache - * ----- - * Lots of information that is reused during contouring is stored as single - * bits in a mesh-sized cache, indexed by quad. Each quad's cache entry stores - * information about the quad itself such as if it is masked, and about the - * point at the SW corner of the quad, and about the W and S edges. Hence - * information about each point and each edge is only stored once in the cache. - * - * Cache information is divided into two types: that which is constant over the - * lifetime of the QuadContourGenerator, and that which changes for each - * contouring operation. The former is all grid-specific information such - * as quad and corner masks, and which edges are boundaries, either between - * masked and non-masked regions or between adjacent chunks. The latter - * includes whether points lie above or below the current contour levels, plus - * some flags to indicate how the contouring is progressing. - * - * Line Contours - * ------------- - * A line contour connects points with the same z-value. Each point of such a - * contour occurs on an edge of the grid, at a point linearly interpolated to - * the contour z-level from the z-values at the end points of the edge. The - * direction of a line contour is such that higher values are to the left of - * the contour, so any edge that the contour passes through will have a left- - * hand end point with z > contour level and a right-hand end point with - * z <= contour level. - * - * Line contours are of two types. Firstly there are open line strips that - * start on a boundary, traverse the interior of the domain and end on a - * boundary. Secondly there are closed line loops that occur completely within - * the interior of the domain and do not touch a boundary. - * - * The QuadContourGenerator makes two sweeps through the grid to generate line - * contours for a particular level. In the first sweep it looks only for start - * points that occur on boundaries, and when it finds one it follows the - * contour through the interior until it finishes on another boundary edge. - * Each quad that is visited by the algorithm has a 'visited' flag set in the - * cache to indicate that the quad does not need to be visited again. In the - * second sweep all non-visited quads are checked to see if they contain part - * of an interior closed loop, and again each time one is found it is followed - * through the domain interior until it returns back to its start quad and is - * therefore completed. - * - * The situation is complicated by saddle quads that have two opposite corners - * with z >= contour level and the other two corners with z < contour level. - * These therefore contain two segments of a line contour, and the visited - * flags take account of this by only being set on the second visit. On the - * first visit a number of saddle flags are set in the cache to indicate which - * one of the two segments has been completed so far. - * - * Filled Contours - * --------------- - * Filled contours are produced between two contour levels and are always - * closed polygons. They can occur completely within the interior of the - * domain without touching a boundary, following either the lower or upper - * contour levels. Those on the lower level are exactly like interior line - * contours with higher values on the left. Those on the upper level are - * reversed such that higher values are on the right. - * - * Filled contours can also involve a boundary in which case they consist of - * one or more sections along a boundary and one or more sections through the - * interior. Interior sections can be on either level, and again those on the - * upper level have higher values on the right. Boundary sections can remain - * on either contour level or switch between the two. - * - * Once the start of a filled contour is found, the algorithm is similar to - * that for line contours in that it follows the contour to its end, which - * because filled contours are always closed polygons will be by returning - * back to the start. However, because two levels must be considered, each - * level has its own set of saddle and visited flags and indeed some extra - * visited flags for boundary edges. - * - * The major complication for filled contours is that some polygons can be - * holes (with points ordered clockwise) within other polygons (with points - * ordered anticlockwise). When it comes to rendering filled contours each - * non-hole polygon must be rendered along with its zero or more contained - * holes or the rendering will not be correct. The filled contour finding - * algorithm could progress pretty much as the line contour algorithm does, - * taking each polygon as it is found, but then at the end there would have to - * be an extra step to identify the parent non-hole polygon for each hole. - * This is not a particularly onerous task but it does not scale well and can - * easily dominate the execution time of the contour finding for even modest - * problems. It is much better to identity each hole's parent non-hole during - * the sweep algorithm. - * - * This requirement dictates the order that filled contours are identified. As - * the algorithm sweeps up through the grid, every time a polygon passes - * through a quad a ParentCache object is updated with the new possible parent. - * When a new hole polygon is started, the ParentCache is used to find the - * first possible parent in the same quad or to the S of it. Great care is - * needed each time a new quad is checked to see if a new polygon should be - * started, as a single quad can have multiple polygon starts, e.g. a quad - * could be a saddle quad for both lower and upper contour levels, meaning it - * has four contour line segments passing through it which could all be from - * different polygons. The S-most polygon must be started first, then the next - * S-most and so on until the N-most polygon is started in that quad. - */ -#ifndef _CONTOUR_H -#define _CONTOUR_H - -#include "src/numpy_cpp.h" -#include <stdint.h> -#include <list> -#include <iostream> -#include <vector> - - -// Edge of a quad including diagonal edges of masked quads if _corner_mask true. -typedef enum -{ - // Listing values here so easier to check for debug purposes. - Edge_None = -1, - Edge_E = 0, - Edge_N = 1, - Edge_W = 2, - Edge_S = 3, - // The following are only used if _corner_mask is true. - Edge_NE = 4, - Edge_NW = 5, - Edge_SW = 6, - Edge_SE = 7 -} Edge; - -// Combination of a quad and an edge of that quad. -// An invalid quad edge has quad of -1. -struct QuadEdge -{ - QuadEdge(); - QuadEdge(long quad_, Edge edge_); - bool operator<(const QuadEdge& other) const; - bool operator==(const QuadEdge& other) const; - bool operator!=(const QuadEdge& other) const; - friend std::ostream& operator<<(std::ostream& os, - const QuadEdge& quad_edge); - - long quad; - Edge edge; -}; - -// 2D point with x,y coordinates. -struct XY -{ - XY(); - XY(const double& x_, const double& 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; -}; - -// 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(). -// A ContourLine is either a hole (points ordered clockwise) or it is not -// (points ordered anticlockwise). Each hole has a parent ContourLine that is -// not a hole; each non-hole contains zero or more child holes. A non-hole and -// its child holes must be rendered together to obtain the correct results. -class ContourLine : public std::vector<XY> -{ -public: - typedef std::list<ContourLine*> Children; - - ContourLine(bool is_hole); - void add_child(ContourLine* child); - void clear_parent(); - const Children& get_children() const; - const ContourLine* get_parent() const; - ContourLine* get_parent(); - bool is_hole() const; - void push_back(const XY& point); - void set_parent(ContourLine* parent); - void write() const; - -private: - bool _is_hole; - ContourLine* _parent; // Only set if is_hole, not owned. - Children _children; // Only set if !is_hole, not owned. -}; - - -// A Contour is a collection of zero or more ContourLines. -class Contour : public std::vector<ContourLine*> -{ -public: - Contour(); - virtual ~Contour(); - void delete_contour_lines(); - void write() const; -}; - - -// Single chunk of ContourLine parents, indexed by quad. As a chunk's filled -// contours are created, the ParentCache is updated each time a ContourLine -// passes through each quad. When a new ContourLine is created, if it is a -// hole its parent ContourLine is read from the ParentCache by looking at the -// start quad, then each quad to the S in turn until a non-zero ContourLine is -// found. -class ParentCache -{ -public: - ParentCache(long nx, long x_chunk_points, long y_chunk_points); - ContourLine* get_parent(long quad); - void set_chunk_starts(long istart, long jstart); - void set_parent(long quad, ContourLine& contour_line); - -private: - long quad_to_index(long quad) const; - - long _nx; - long _x_chunk_points, _y_chunk_points; // Number of points not quads. - std::vector<ContourLine*> _lines; // Not owned. - long _istart, _jstart; -}; - - -// See overview of algorithm at top of file. -class QuadContourGenerator -{ -public: - typedef numpy::array_view<const double, 2> CoordinateArray; - typedef numpy::array_view<const bool, 2> MaskArray; - - // Constructor with optional mask. - // x, y, z: double arrays of shape (ny,nx). - // mask: boolean array, ether empty (if no mask), or of shape (ny,nx). - // corner_mask: flag for different masking behaviour. - // chunk_size: 0 for no chunking, or +ve integer for size of chunks that - // the domain is subdivided into. - QuadContourGenerator(const CoordinateArray& x, - const CoordinateArray& y, - const CoordinateArray& z, - const MaskArray& mask, - bool corner_mask, - long chunk_size); - - // Destructor. - ~QuadContourGenerator(); - - // Create and return polygons for a line (i.e. non-filled) contour at the - // specified level. - PyObject* create_contour(const double& level); - - // Create and return polygons for a filled contour between the two - // specified levels. - PyObject* create_filled_contour(const double& lower_level, - const double& upper_level); - -private: - // Typedef for following either a boundary of the domain or the interior; - // clearer than using a boolean. - typedef enum - { - Boundary, - Interior - } BoundaryOrInterior; - - // Typedef for direction of movement from one quad to the next. - typedef enum - { - Dir_Right = -1, - Dir_Straight = 0, - Dir_Left = +1 - } Dir; - - // Typedef for a polygon being a hole or not; clearer than using a boolean. - typedef enum - { - NotHole, - Hole - } HoleOrNot; - - // Append a C++ ContourLine to the end of a python list. Used for line - // contours where each ContourLine is converted to a separate numpy array - // of (x,y) points. - // Clears the ContourLine too. - void append_contour_line_to_vertices(ContourLine& contour_line, - PyObject* vertices_list) const; - - // Append a C++ Contour to the end of two python lists. Used for filled - // contours where each non-hole ContourLine and its child holes are - // represented by a numpy array of (x,y) points and a second numpy array of - // 'kinds' or 'codes' that indicates where the points array is split into - // individual polygons. - // Clears the Contour too, freeing each ContourLine as soon as possible - // for minimum RAM usage. - void append_contour_to_vertices_and_codes(Contour& contour, - PyObject* vertices_list, - PyObject* codes_list) const; - - // Return number of chunks that fit in the specified point_count. - long calc_chunk_count(long point_count) const; - - // Return the point on the specified QuadEdge that intersects the specified - // level. - XY edge_interp(const QuadEdge& quad_edge, const double& level); - - // Follow a contour along a boundary, appending points to the ContourLine - // as it progresses. Only called for filled contours. Stops when the - // contour leaves the boundary to move into the interior of the domain, or - // when the start_quad_edge is reached in which case the ContourLine is a - // completed closed loop. Always adds the end point of each boundary edge - // to the ContourLine, regardless of whether moving to another boundary - // edge or leaving the boundary into the interior. Never adds the start - // point of the first boundary edge to the ContourLine. - // contour_line: ContourLine to append points to. - // quad_edge: on entry the QuadEdge to start from, on exit the QuadEdge - // that is stopped on. - // lower_level: lower contour z-value. - // upper_level: upper contour z-value. - // level_index: level index started on (1 = lower, 2 = upper level). - // start_quad_edge: QuadEdge that the ContourLine started from, which is - // used to check if the ContourLine is finished. - // Returns the end level_index. - unsigned int follow_boundary(ContourLine& contour_line, - QuadEdge& quad_edge, - const double& lower_level, - const double& upper_level, - unsigned int level_index, - const QuadEdge& start_quad_edge); - - // Follow a contour across the interior of the domain, appending points to - // the ContourLine as it progresses. Called for both line and filled - // contours. Stops when the contour reaches a boundary or, if the - // start_quad_edge is specified, when quad_edge == start_quad_edge and - // level_index == start_level_index. Always adds the end point of each - // quad traversed to the ContourLine; only adds the start point of the - // first quad if want_initial_point flag is true. - // contour_line: ContourLine to append points to. - // quad_edge: on entry the QuadEdge to start from, on exit the QuadEdge - // that is stopped on. - // level_index: level index started on (1 = lower, 2 = upper level). - // level: contour z-value. - // want_initial_point: whether want to append the initial point to the - // ContourLine or not. - // start_quad_edge: the QuadEdge that the ContourLine started from to - // check if the ContourLine is finished, or 0 if no check should occur. - // start_level_index: the level_index that the ContourLine started from. - // set_parents: whether should set ParentCache as it progresses or not. - // This is true for filled contours, false for line contours. - void follow_interior(ContourLine& contour_line, - QuadEdge& quad_edge, - unsigned int level_index, - const double& level, - bool want_initial_point, - const QuadEdge* start_quad_edge, - unsigned int start_level_index, - bool set_parents); - - // Return the index limits of a particular chunk. - void get_chunk_limits(long ijchunk, - long& ichunk, - long& jchunk, - long& istart, - long& iend, - long& jstart, - long& jend); - - // Check if a contour starts within the specified corner quad on the - // specified level_index, and if so return the start edge. Otherwise - // return Edge_None. - Edge get_corner_start_edge(long quad, unsigned int level_index) const; - - // Return index of point at start or end of specified QuadEdge, assuming - // anticlockwise ordering around non-masked quads. - long get_edge_point_index(const QuadEdge& quad_edge, bool start) const; - - // Return the edge to exit a quad from, given the specified entry quad_edge - // and direction to move in. - Edge get_exit_edge(const QuadEdge& quad_edge, Dir dir) const; - - // Return the (x,y) coordinates of the specified point index. - XY get_point_xy(long point) const; - - // Return the z-value of the specified point index. - const double& get_point_z(long point) const; - - // Check if a contour starts within the specified non-corner quad on the - // specified level_index, and if so return the start edge. Otherwise - // return Edge_None. - Edge get_quad_start_edge(long quad, unsigned int level_index) const; - - // Check if a contour starts within the specified quad, whether it is a - // corner or a full quad, and if so return the start edge. Otherwise - // return Edge_None. - Edge get_start_edge(long quad, unsigned int level_index) const; - - // Initialise the cache to contain grid information that is constant - // across the lifetime of this object, i.e. does not vary between calls to - // create_contour() and create_filled_contour(). - void init_cache_grid(const MaskArray& mask); - - // Initialise the cache with information that is specific to contouring the - // specified two levels. The levels are the same for contour lines, - // different for filled contours. - void init_cache_levels(const double& lower_level, - const double& upper_level); - - // Return the (x,y) point at which the level intersects the line connecting - // the two specified point indices. - XY interp(long point1, long point2, const double& level) const; - - // Return true if the specified QuadEdge is a boundary, i.e. is either an - // edge between a masked and non-masked quad/corner or is a chunk boundary. - bool is_edge_a_boundary(const QuadEdge& quad_edge) const; - - // Follow a boundary from one QuadEdge to the next in an anticlockwise - // manner around the non-masked region. - void move_to_next_boundary_edge(QuadEdge& quad_edge) const; - - // Move from the quad specified by quad_edge.quad to the neighbouring quad - // by crossing the edge specified by quad_edge.edge. - void move_to_next_quad(QuadEdge& quad_edge) const; - - // Check for filled contours starting within the specified quad and - // complete any that are found, appending them to the specified Contour. - void single_quad_filled(Contour& contour, - long quad, - const double& lower_level, - const double& upper_level); - - // Start and complete a filled contour line. - // quad: index of quad to start ContourLine in. - // edge: edge of quad to start ContourLine from. - // start_level_index: the level_index that the ContourLine starts from. - // hole_or_not: whether the ContourLine is a hole or not. - // boundary_or_interior: whether the ContourLine starts on a boundary or - // the interior. - // lower_level: lower contour z-value. - // upper_level: upper contour z-value. - // Returns newly created ContourLine. - ContourLine* start_filled(long quad, - Edge edge, - unsigned int start_level_index, - HoleOrNot hole_or_not, - BoundaryOrInterior boundary_or_interior, - const double& lower_level, - const double& upper_level); - - // Start and complete a line contour that both starts and end on a - // boundary, traversing the interior of the domain. - // vertices_list: Python list that the ContourLine should be appended to. - // quad: index of quad to start ContourLine in. - // edge: boundary edge to start ContourLine from. - // level: contour z-value. - // Returns true if the start quad does not need to be visited again, i.e. - // VISITED(quad,1). - bool start_line(PyObject* vertices_list, - long quad, - Edge edge, - const double& level); - - // Debug function that writes the cache status to stdout. - void write_cache(bool grid_only = false) const; - - // Debug function that writes that cache status for a single quad to - // stdout. - void write_cache_quad(long quad, bool grid_only) const; - - - - // Note that mask is not stored as once it has been used to initialise the - // cache it is no longer needed. - CoordinateArray _x, _y, _z; - long _nx, _ny; // Number of points in each direction. - long _n; // Total number of points (and hence quads). - - bool _corner_mask; - long _chunk_size; // Number of quads per chunk (not points). - // Always > 0, unlike python nchunk which is 0 - // for no chunking. - - long _nxchunk, _nychunk; // Number of chunks in each direction. - long _chunk_count; // Total number of chunks. - - typedef uint32_t CacheItem; - CacheItem* _cache; - - ParentCache _parent_cache; // On W quad sides. -}; - -#endif // _CONTOUR_H diff --git a/contrib/python/matplotlib/py2/src/_contour_wrapper.cpp b/contrib/python/matplotlib/py2/src/_contour_wrapper.cpp deleted file mode 100644 index eedc8a1aec..0000000000 --- a/contrib/python/matplotlib/py2/src/_contour_wrapper.cpp +++ /dev/null @@ -1,203 +0,0 @@ -#include "src/_contour.h" -#include "src/mplutils.h" -#include "src/py_exceptions.h" - -/* QuadContourGenerator */ - -typedef struct -{ - PyObject_HEAD - QuadContourGenerator* ptr; -} PyQuadContourGenerator; - -static PyTypeObject PyQuadContourGeneratorType; - -static PyObject* PyQuadContourGenerator_new(PyTypeObject* type, PyObject* args, PyObject* kwds) -{ - PyQuadContourGenerator* self; - self = (PyQuadContourGenerator*)type->tp_alloc(type, 0); - self->ptr = NULL; - return (PyObject*)self; -} - -const char* PyQuadContourGenerator_init__doc__ = - "QuadContourGenerator(x, y, z, mask, corner_mask, chunk_size)\n" - "\n" - "Create a new C++ QuadContourGenerator object\n"; - -static int PyQuadContourGenerator_init(PyQuadContourGenerator* self, PyObject* args, PyObject* kwds) -{ - QuadContourGenerator::CoordinateArray x, y, z; - QuadContourGenerator::MaskArray mask; - int corner_mask; - long chunk_size; - - if (!PyArg_ParseTuple(args, "O&O&O&O&il", - &x.converter_contiguous, &x, - &y.converter_contiguous, &y, - &z.converter_contiguous, &z, - &mask.converter_contiguous, &mask, - &corner_mask, - &chunk_size)) { - return -1; - } - - if (x.empty() || y.empty() || z.empty() || - y.dim(0) != x.dim(0) || z.dim(0) != x.dim(0) || - y.dim(1) != x.dim(1) || z.dim(1) != x.dim(1)) { - PyErr_SetString(PyExc_ValueError, - "x, y and z must all be 2D arrays with the same dimensions"); - return -1; - } - - if (z.dim(0) < 2 || z.dim(1) < 2) { - PyErr_SetString(PyExc_ValueError, - "x, y and z must all be at least 2x2 arrays"); - return -1; - } - - // Mask array is optional, if set must be same size as other arrays. - if (!mask.empty() && (mask.dim(0) != x.dim(0) || mask.dim(1) != x.dim(1))) { - PyErr_SetString(PyExc_ValueError, - "If mask is set it must be a 2D array with the same dimensions as x."); - return -1; - } - - CALL_CPP_INIT("QuadContourGenerator", - (self->ptr = new QuadContourGenerator( - x, y, z, mask, corner_mask, chunk_size))); - return 0; -} - -static void PyQuadContourGenerator_dealloc(PyQuadContourGenerator* self) -{ - delete self->ptr; - Py_TYPE(self)->tp_free((PyObject *)self); -} - -const char* PyQuadContourGenerator_create_contour__doc__ = - "create_contour(level)\n" - "\n" - "Create and return a non-filled contour."; - -static PyObject* PyQuadContourGenerator_create_contour(PyQuadContourGenerator* self, PyObject* args, PyObject* kwds) -{ - double level; - if (!PyArg_ParseTuple(args, "d:create_contour", &level)) { - return NULL; - } - - PyObject* result; - CALL_CPP("create_contour", (result = self->ptr->create_contour(level))); - return result; -} - -const char* PyQuadContourGenerator_create_filled_contour__doc__ = - "create_filled_contour(lower_level, upper_level)\n" - "\n" - "Create and return a filled contour"; - -static PyObject* PyQuadContourGenerator_create_filled_contour(PyQuadContourGenerator* self, PyObject* args, PyObject* kwds) -{ - double lower_level, upper_level; - if (!PyArg_ParseTuple(args, "dd:create_filled_contour", - &lower_level, &upper_level)) { - return NULL; - } - - if (lower_level >= upper_level) - { - PyErr_SetString(PyExc_ValueError, - "filled contour levels must be increasing"); - return NULL; - } - - PyObject* result; - CALL_CPP("create_filled_contour", - (result = self->ptr->create_filled_contour(lower_level, - upper_level))); - return result; -} - -static PyTypeObject* PyQuadContourGenerator_init_type(PyObject* m, PyTypeObject* type) -{ - static PyMethodDef methods[] = { - {"create_contour", (PyCFunction)PyQuadContourGenerator_create_contour, METH_VARARGS, PyQuadContourGenerator_create_contour__doc__}, - {"create_filled_contour", (PyCFunction)PyQuadContourGenerator_create_filled_contour, METH_VARARGS, PyQuadContourGenerator_create_filled_contour__doc__}, - {NULL} - }; - - memset(type, 0, sizeof(PyTypeObject)); - type->tp_name = "matplotlib.QuadContourGenerator"; - type->tp_doc = PyQuadContourGenerator_init__doc__; - type->tp_basicsize = sizeof(PyQuadContourGenerator); - type->tp_dealloc = (destructor)PyQuadContourGenerator_dealloc; - type->tp_flags = Py_TPFLAGS_DEFAULT; - type->tp_methods = methods; - type->tp_new = PyQuadContourGenerator_new; - type->tp_init = (initproc)PyQuadContourGenerator_init; - - if (PyType_Ready(type) < 0) { - return NULL; - } - - if (PyModule_AddObject(m, "QuadContourGenerator", (PyObject*)type)) { - return NULL; - } - - return type; -} - - -/* Module */ - -extern "C" { - -#if PY3K -static struct PyModuleDef moduledef = { - PyModuleDef_HEAD_INIT, - "_contour", - NULL, - 0, - NULL, - NULL, - NULL, - NULL, - NULL -}; - -#define INITERROR return NULL - -PyMODINIT_FUNC PyInit__contour(void) - -#else -#define INITERROR return - -PyMODINIT_FUNC init_contour(void) -#endif - -{ - PyObject *m; - -#if PY3K - m = PyModule_Create(&moduledef); -#else - m = Py_InitModule3("_contour", NULL, NULL); -#endif - - if (m == NULL) { - INITERROR; - } - - if (!PyQuadContourGenerator_init_type(m, &PyQuadContourGeneratorType)) { - INITERROR; - } - - import_array(); - -#if PY3K - return m; -#endif -} - -} // extern "C" diff --git a/contrib/python/matplotlib/py2/src/_gtkagg.cpp b/contrib/python/matplotlib/py2/src/_gtkagg.cpp deleted file mode 100644 index 2d6a1cec13..0000000000 --- a/contrib/python/matplotlib/py2/src/_gtkagg.cpp +++ /dev/null @@ -1,155 +0,0 @@ -/* -*- mode: c++; c-basic-offset: 4 -*- */ - -#include <pygobject.h> -#include <pygtk/pygtk.h> - -#include <vector> - -#include "agg_basics.h" -#include "agg_pixfmt_rgba.h" -#include "agg_renderer_base.h" -#include "agg_rendering_buffer.h" - -#include "numpy_cpp.h" -#include "py_converters.h" - -static PyObject *Py_agg_to_gtk_drawable(PyObject *self, PyObject *args, PyObject *kwds) -{ - typedef agg::pixfmt_rgba32_plain pixfmt; - typedef agg::renderer_base<pixfmt> renderer_base; - - PyGObject *py_drawable; - numpy::array_view<agg::int8u, 3> buffer; - agg::rect_d rect; - - // args are gc, renderer, bbox where bbox is a transforms BBox - // (possibly None). If bbox is None, blit the entire agg buffer - // to gtk. If bbox is not None, blit only the region defined by - // the bbox - - if (!PyArg_ParseTuple(args, - "OO&O&:agg_to_gtk_drawable", - &py_drawable, - &buffer.converter, - &buffer, - &convert_rect, - &rect)) { - return NULL; - } - - if (buffer.dim(2) != 4) { - PyErr_SetString(PyExc_ValueError, "Invalid image buffer. Must be NxMx4."); - return NULL; - } - - GdkDrawable *drawable = GDK_DRAWABLE(py_drawable->obj); - GdkGC *gc = gdk_gc_new(drawable); - - int srcstride = buffer.dim(1) * 4; - int srcwidth = buffer.dim(1); - int srcheight = buffer.dim(0); - - // these three will be overridden below - int destx = 0; - int desty = 0; - int destwidth = 1; - int destheight = 1; - int deststride = 1; - - std::vector<agg::int8u> destbuffer; - agg::int8u *destbufferptr; - - if (rect.x1 == 0.0 && rect.x2 == 0.0 && rect.y1 == 0.0 && rect.y2 == 0.0) { - // bbox is None; copy the entire image - destbufferptr = (agg::int8u *)buffer.data(); - destwidth = srcwidth; - destheight = srcheight; - deststride = srcstride; - } else { - destx = (int)rect.x1; - desty = srcheight - (int)rect.y2; - destwidth = (int)(rect.x2 - rect.x1); - destheight = (int)(rect.y2 - rect.y1); - deststride = destwidth * 4; - destbuffer.resize(destheight * deststride, 0); - destbufferptr = &destbuffer.front(); - - agg::rendering_buffer destrbuf; - destrbuf.attach(destbufferptr, destwidth, destheight, deststride); - pixfmt destpf(destrbuf); - renderer_base destrb(destpf); - - agg::rendering_buffer srcrbuf; - srcrbuf.attach((agg::int8u *)buffer.data(), buffer.dim(1), buffer.dim(0), buffer.dim(1) * 4); - - agg::rect_base<int> region(destx, desty, (int)rect.x2, srcheight - (int)rect.y1); - destrb.copy_from(srcrbuf, ®ion, -destx, -desty); - } - - gdk_draw_rgb_32_image(drawable, - gc, - destx, - desty, - destwidth, - destheight, - GDK_RGB_DITHER_NORMAL, - destbufferptr, - deststride); - - gdk_gc_destroy(gc); - - Py_RETURN_NONE; -} - -static PyMethodDef module_methods[] = { - {"agg_to_gtk_drawable", (PyCFunction)Py_agg_to_gtk_drawable, METH_VARARGS, NULL}, - NULL -}; - -extern "C" { - -#if PY3K - static struct PyModuleDef moduledef = { - PyModuleDef_HEAD_INIT, - "_gtkagg", - NULL, - 0, - module_methods, - NULL, - NULL, - NULL, - NULL - }; - -#define INITERROR return NULL - - PyMODINIT_FUNC PyInit__gtkagg(void) - -#else -#define INITERROR return - - PyMODINIT_FUNC init_gtkagg(void) -#endif - - { - PyObject *m; - -#if PY3K - m = PyModule_Create(&moduledef); -#else - m = Py_InitModule3("_gtkagg", module_methods, NULL); -#endif - - if (m == NULL) { - INITERROR; - } - - init_pygobject(); - init_pygtk(); - import_array(); - -#if PY3K - return m; -#endif - } -} diff --git a/contrib/python/matplotlib/py2/src/_image.cpp b/contrib/python/matplotlib/py2/src/_image.cpp deleted file mode 100644 index 8fc386fccb..0000000000 --- a/contrib/python/matplotlib/py2/src/_image.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/* -*- mode: c++; c-basic-offset: 4 -*- */ - -#define NO_IMPORT_ARRAY - -#include <math.h> - -// utilities for irregular grids -void _bin_indices_middle( - unsigned int *irows, int nrows, const float *ys1, unsigned long ny, float dy, float y_min) -{ - int i, j, j_last; - unsigned int *rowstart = irows; - const float *ys2 = ys1 + 1; - const float *yl = ys1 + ny; - float yo = y_min + dy / 2.0; - float ym = 0.5f * (*ys1 + *ys2); - // y/rows - j = 0; - j_last = j; - for (i = 0; i < nrows; i++, yo += dy, rowstart++) { - while (ys2 != yl && yo > ym) { - ys1 = ys2; - ys2 = ys1 + 1; - ym = 0.5f * (*ys1 + *ys2); - j++; - } - *rowstart = j - j_last; - j_last = j; - } -} - -void _bin_indices_middle_linear(float *arows, - unsigned int *irows, - int nrows, - const float *y, - unsigned long ny, - float dy, - float y_min) -{ - int i; - int ii = 0; - int iilast = (int)ny - 1; - float sc = 1 / dy; - int iy0 = (int)floor(sc * (y[ii] - y_min)); - int iy1 = (int)floor(sc * (y[ii + 1] - y_min)); - float invgap = 1.0f / (iy1 - iy0); - for (i = 0; i < nrows && i <= iy0; i++) { - irows[i] = 0; - arows[i] = 1.0; - } - for (; i < nrows; i++) { - while (i > iy1 && ii < iilast) { - ii++; - iy0 = iy1; - iy1 = (int)floor(sc * (y[ii + 1] - y_min)); - invgap = 1.0f / (iy1 - iy0); - } - if (i >= iy0 && i <= iy1) { - irows[i] = ii; - arows[i] = (iy1 - i) * invgap; - } else - break; - } - for (; i < nrows; i++) { - irows[i] = iilast - 1; - arows[i] = 0.0; - } -} - -void _bin_indices(int *irows, int nrows, const double *y, unsigned long ny, double sc, double offs) -{ - int i; - if (sc * (y[ny - 1] - y[0]) > 0) { - int ii = 0; - int iilast = (int)ny - 1; - int iy0 = (int)floor(sc * (y[ii] - offs)); - int iy1 = (int)floor(sc * (y[ii + 1] - offs)); - for (i = 0; i < nrows && i < iy0; i++) { - irows[i] = -1; - } - for (; i < nrows; i++) { - while (i > iy1 && ii < iilast) { - ii++; - iy0 = iy1; - iy1 = (int)floor(sc * (y[ii + 1] - offs)); - } - if (i >= iy0 && i <= iy1) - irows[i] = ii; - else - break; - } - for (; i < nrows; i++) { - irows[i] = -1; - } - } else { - int iilast = (int)ny - 1; - int ii = iilast; - int iy0 = (int)floor(sc * (y[ii] - offs)); - int iy1 = (int)floor(sc * (y[ii - 1] - offs)); - for (i = 0; i < nrows && i < iy0; i++) { - irows[i] = -1; - } - for (; i < nrows; i++) { - while (i > iy1 && ii > 1) { - ii--; - iy0 = iy1; - iy1 = (int)floor(sc * (y[ii - 1] - offs)); - } - if (i >= iy0 && i <= iy1) - irows[i] = ii - 1; - else - break; - } - for (; i < nrows; i++) { - irows[i] = -1; - } - } -} - -void _bin_indices_linear( - float *arows, int *irows, int nrows, double *y, unsigned long ny, double sc, double offs) -{ - int i; - if (sc * (y[ny - 1] - y[0]) > 0) { - int ii = 0; - int iilast = (int)ny - 1; - int iy0 = (int)floor(sc * (y[ii] - offs)); - int iy1 = (int)floor(sc * (y[ii + 1] - offs)); - float invgap = 1.0 / (iy1 - iy0); - for (i = 0; i < nrows && i < iy0; i++) { - irows[i] = -1; - } - for (; i < nrows; i++) { - while (i > iy1 && ii < iilast) { - ii++; - iy0 = iy1; - iy1 = (int)floor(sc * (y[ii + 1] - offs)); - invgap = 1.0 / (iy1 - iy0); - } - if (i >= iy0 && i <= iy1) { - irows[i] = ii; - arows[i] = (iy1 - i) * invgap; - } else - break; - } - for (; i < nrows; i++) { - irows[i] = -1; - } - } else { - int iilast = (int)ny - 1; - int ii = iilast; - int iy0 = (int)floor(sc * (y[ii] - offs)); - int iy1 = (int)floor(sc * (y[ii - 1] - offs)); - float invgap = 1.0 / (iy1 - iy0); - for (i = 0; i < nrows && i < iy0; i++) { - irows[i] = -1; - } - for (; i < nrows; i++) { - while (i > iy1 && ii > 1) { - ii--; - iy0 = iy1; - iy1 = (int)floor(sc * (y[ii - 1] - offs)); - invgap = 1.0 / (iy1 - iy0); - } - if (i >= iy0 && i <= iy1) { - irows[i] = ii - 1; - arows[i] = (i - iy0) * invgap; - } else - break; - } - for (; i < nrows; i++) { - irows[i] = -1; - } - } -} diff --git a/contrib/python/matplotlib/py2/src/_image.h b/contrib/python/matplotlib/py2/src/_image.h deleted file mode 100644 index 629714d2ec..0000000000 --- a/contrib/python/matplotlib/py2/src/_image.h +++ /dev/null @@ -1,200 +0,0 @@ -/* -*- mode: c++; c-basic-offset: 4 -*- */ - -/* image.h - * - */ - -#ifndef _IMAGE_H -#define _IMAGE_H - -#include <vector> - - -// utilities for irregular grids -void _bin_indices_middle( - unsigned int *irows, int nrows, const float *ys1, unsigned long ny, float dy, float y_min); -void _bin_indices_middle_linear(float *arows, - unsigned int *irows, - int nrows, - const float *y, - unsigned long ny, - float dy, - float y_min); -void _bin_indices(int *irows, int nrows, const double *y, unsigned long ny, double sc, double offs); -void _bin_indices_linear( - float *arows, int *irows, int nrows, double *y, unsigned long ny, double sc, double offs); - -template <class CoordinateArray, class ColorArray, class OutputArray> -void pcolor(CoordinateArray &x, - CoordinateArray &y, - ColorArray &d, - unsigned int rows, - unsigned int cols, - float bounds[4], - int interpolation, - OutputArray &out) -{ - if (rows >= 32768 || cols >= 32768) { - throw std::runtime_error("rows and cols must both be less than 32768"); - } - - float x_min = bounds[0]; - float x_max = bounds[1]; - float y_min = bounds[2]; - float y_max = bounds[3]; - float width = x_max - x_min; - float height = y_max - y_min; - float dx = width / ((float)cols); - float dy = height / ((float)rows); - - // Check we have something to output to - if (rows == 0 || cols == 0) { - throw std::runtime_error("Cannot scale to zero size"); - } - - if (d.dim(2) != 4) { - throw std::runtime_error("data must be in RGBA format"); - } - - // Check dimensions match - unsigned long nx = x.dim(0); - unsigned long ny = y.dim(0); - if (nx != (unsigned long)d.dim(1) || ny != (unsigned long)d.dim(0)) { - throw std::runtime_error("data and axis dimensions do not match"); - } - - // Allocate memory for pointer arrays - std::vector<unsigned int> rowstarts(rows); - std::vector<unsigned int> colstarts(cols); - - // Calculate the pointer arrays to map input x to output x - unsigned int i, j; - unsigned int *colstart = &colstarts[0]; - unsigned int *rowstart = &rowstarts[0]; - const float *xs1 = x.data(); - const float *ys1 = y.data(); - - // Copy data to output buffer - const unsigned char *start; - const unsigned char *inposition; - size_t inrowsize = nx * 4; - size_t rowsize = cols * 4; - unsigned char *position = (unsigned char *)out.data(); - unsigned char *oldposition = NULL; - start = d.data(); - - if (interpolation == NEAREST) { - _bin_indices_middle(colstart, cols, xs1, nx, dx, x_min); - _bin_indices_middle(rowstart, rows, ys1, ny, dy, y_min); - for (i = 0; i < rows; i++, rowstart++) { - if (i > 0 && *rowstart == 0) { - memcpy(position, oldposition, rowsize * sizeof(unsigned char)); - oldposition = position; - position += rowsize; - } else { - oldposition = position; - start += *rowstart * inrowsize; - inposition = start; - for (j = 0, colstart = &colstarts[0]; j < cols; j++, position += 4, colstart++) { - inposition += *colstart * 4; - memcpy(position, inposition, 4 * sizeof(unsigned char)); - } - } - } - } else if (interpolation == BILINEAR) { - std::vector<float> acols(cols); - std::vector<float> arows(rows); - - _bin_indices_middle_linear(&acols[0], colstart, cols, xs1, nx, dx, x_min); - _bin_indices_middle_linear(&arows[0], rowstart, rows, ys1, ny, dy, y_min); - double a00, a01, a10, a11, alpha, beta; - - // Copy data to output buffer - for (i = 0; i < rows; i++) { - for (j = 0; j < cols; j++) { - alpha = arows[i]; - beta = acols[j]; - - a00 = alpha * beta; - a01 = alpha * (1.0 - beta); - a10 = (1.0 - alpha) * beta; - a11 = 1.0 - a00 - a01 - a10; - - for (size_t k = 0; k < 4; ++k) { - position[k] = - d(rowstart[i], colstart[j], k) * a00 + - d(rowstart[i], colstart[j] + 1, k) * a01 + - d(rowstart[i] + 1, colstart[j], k) * a10 + - d(rowstart[i] + 1, colstart[j] + 1, k) * a11; - } - position += 4; - } - } - } -} - -template <class CoordinateArray, class ColorArray, class Color, class OutputArray> -void pcolor2(CoordinateArray &x, - CoordinateArray &y, - ColorArray &d, - unsigned int rows, - unsigned int cols, - float bounds[4], - Color &bg, - OutputArray &out) -{ - double x_left = bounds[0]; - double x_right = bounds[1]; - double y_bot = bounds[2]; - double y_top = bounds[3]; - - // Check we have something to output to - if (rows == 0 || cols == 0) { - throw std::runtime_error("rows or cols is zero; there are no pixels"); - } - - if (d.dim(2) != 4) { - throw std::runtime_error("data must be in RGBA format"); - } - - // Check dimensions match - unsigned long nx = x.dim(0); - unsigned long ny = y.dim(0); - if (nx != (unsigned long)d.dim(1) + 1 || ny != (unsigned long)d.dim(0) + 1) { - throw std::runtime_error("data and axis bin boundary dimensions are incompatible"); - } - - if (bg.dim(0) != 4) { - throw std::runtime_error("bg must be in RGBA format"); - } - - std::vector<int> irows(rows); - std::vector<int> jcols(cols); - - // Calculate the pointer arrays to map input x to output x - size_t i, j; - const double *x0 = x.data(); - const double *y0 = y.data(); - double sx = cols / (x_right - x_left); - double sy = rows / (y_top - y_bot); - _bin_indices(&jcols[0], cols, x0, nx, sx, x_left); - _bin_indices(&irows[0], rows, y0, ny, sy, y_bot); - - // Copy data to output buffer - unsigned char *position = (unsigned char *)out.data(); - - for (i = 0; i < rows; i++) { - for (j = 0; j < cols; j++) { - if (irows[i] == -1 || jcols[j] == -1) { - memcpy(position, (const unsigned char *)bg.data(), 4 * sizeof(unsigned char)); - } else { - for (size_t k = 0; k < 4; ++k) { - position[k] = d(irows[i], jcols[j], k); - } - } - position += 4; - } - } -} - -#endif diff --git a/contrib/python/matplotlib/py2/src/_image_resample.h b/contrib/python/matplotlib/py2/src/_image_resample.h deleted file mode 100644 index 86cbef0324..0000000000 --- a/contrib/python/matplotlib/py2/src/_image_resample.h +++ /dev/null @@ -1,1013 +0,0 @@ -/* -*- mode: c++; c-basic-offset: 4 -*- */ - -#ifndef RESAMPLE_H -#define 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" - -// Based on: - -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.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://www.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; - - -template <typename T> -class type_mapping; - - -template <> class type_mapping<agg::rgba8> -{ - public: - typedef agg::rgba8 color_type; - typedef fixed_blender_rgba_plain<color_type, agg::order_rgba> blender_type; - typedef fixed_blender_rgba_pre<color_type, agg::order_rgba> pre_blender_type; - typedef agg::pixfmt_alpha_blend_rgba<blender_type, agg::rendering_buffer> pixfmt_type; - typedef agg::pixfmt_alpha_blend_rgba<pre_blender_type, agg::rendering_buffer> pixfmt_pre_type; - - template <typename A> - struct span_gen_affine_type - { - typedef agg::span_image_resample_rgba_affine<A> type; - }; - - template <typename A, typename B> - struct span_gen_filter_type - { - typedef agg::span_image_filter_rgba<A, B> type; - }; - - template <typename A, typename B> - struct span_gen_nn_type - { - typedef agg::span_image_filter_rgba_nn<A, B> type; - }; -}; - - -template <> class type_mapping<agg::rgba16> -{ - public: - typedef agg::rgba16 color_type; - typedef fixed_blender_rgba_plain<color_type, agg::order_rgba> blender_type; - typedef fixed_blender_rgba_pre<color_type, agg::order_rgba> pre_blender_type; - typedef agg::pixfmt_alpha_blend_rgba<blender_type, agg::rendering_buffer> pixfmt_type; - typedef agg::pixfmt_alpha_blend_rgba<pre_blender_type, agg::rendering_buffer> pixfmt_pre_type; - - template <typename A> - struct span_gen_affine_type - { - typedef agg::span_image_resample_rgba_affine<A> type; - }; - - template <typename A, typename B> - struct span_gen_filter_type - { - typedef agg::span_image_filter_rgba<A, B> type; - }; - - template <typename A, typename B> - struct span_gen_nn_type - { - typedef agg::span_image_filter_rgba_nn<A, B> type; - }; -}; - - -template <> class type_mapping<agg::rgba32> -{ - public: - typedef agg::rgba32 color_type; - typedef agg::blender_rgba_plain<color_type, agg::order_rgba> blender_type; - typedef agg::blender_rgba_pre<color_type, agg::order_rgba> pre_blender_type; - typedef agg::pixfmt_alpha_blend_rgba<blender_type, agg::rendering_buffer> pixfmt_type; - typedef agg::pixfmt_alpha_blend_rgba<pre_blender_type, agg::rendering_buffer> pixfmt_pre_type; - - template <typename A> - struct span_gen_affine_type - { - typedef agg::span_image_resample_rgba_affine<A> type; - }; - - template <typename A, typename B> - struct span_gen_filter_type - { - typedef agg::span_image_filter_rgba<A, B> type; - }; - - template <typename A, typename B> - struct span_gen_nn_type - { - typedef agg::span_image_filter_rgba_nn<A, B> type; - }; -}; - - -template <> class type_mapping<agg::rgba64> -{ - public: - typedef agg::rgba64 color_type; - typedef agg::blender_rgba_plain<color_type, agg::order_rgba> blender_type; - typedef agg::blender_rgba_pre<color_type, agg::order_rgba> pre_blender_type; - typedef agg::pixfmt_alpha_blend_rgba<blender_type, agg::rendering_buffer> pixfmt_type; - typedef agg::pixfmt_alpha_blend_rgba<pre_blender_type, agg::rendering_buffer> pixfmt_pre_type; - - template <typename A> - struct span_gen_affine_type - { - typedef agg::span_image_resample_rgba_affine<A> type; - }; - - template <typename A, typename B> - struct span_gen_filter_type - { - typedef agg::span_image_filter_rgba<A, B> type; - }; - - template <typename A, typename B> - struct span_gen_nn_type - { - typedef agg::span_image_filter_rgba_nn<A, B> type; - }; -}; - - -template <> class type_mapping<double> -{ - public: - typedef agg::gray64 color_type; - typedef agg::blender_gray<color_type> blender_type; - typedef agg::pixfmt_alpha_blend_gray<blender_type, agg::rendering_buffer> pixfmt_type; - typedef pixfmt_type pixfmt_pre_type; - - template <typename A> - struct span_gen_affine_type - { - typedef agg::span_image_resample_gray_affine<A> type; - }; - - template <typename A, typename B> - struct span_gen_filter_type - { - typedef agg::span_image_filter_gray<A, B> type; - }; - - template <typename A, typename B> - struct span_gen_nn_type - { - typedef agg::span_image_filter_gray_nn<A, B> type; - }; -}; - - -template <> class type_mapping<float> -{ - public: - typedef agg::gray32 color_type; - typedef agg::blender_gray<color_type> blender_type; - typedef agg::pixfmt_alpha_blend_gray<blender_type, agg::rendering_buffer> pixfmt_type; - typedef pixfmt_type pixfmt_pre_type; - - template <typename A> - struct span_gen_affine_type - { - typedef agg::span_image_resample_gray_affine<A> type; - }; - - template <typename A, typename B> - struct span_gen_filter_type - { - typedef agg::span_image_filter_gray<A, B> type; - }; - - template <typename A, typename B> - struct span_gen_nn_type - { - typedef agg::span_image_filter_gray_nn<A, B> type; - }; -}; - - -template <> class type_mapping<unsigned short> -{ - public: - typedef agg::gray16 color_type; - typedef agg::blender_gray<color_type> blender_type; - typedef agg::pixfmt_alpha_blend_gray<blender_type, agg::rendering_buffer> pixfmt_type; - typedef pixfmt_type pixfmt_pre_type; - - template <typename A> - struct span_gen_affine_type - { - typedef agg::span_image_resample_gray_affine<A> type; - }; - - template <typename A, typename B> - struct span_gen_filter_type - { - typedef agg::span_image_filter_gray<A, B> type; - }; - - template <typename A, typename B> - struct span_gen_nn_type - { - typedef agg::span_image_filter_gray_nn<A, B> type; - }; -}; - - -template <> class type_mapping<unsigned char> -{ - public: - typedef agg::gray8 color_type; - typedef agg::blender_gray<color_type> blender_type; - typedef agg::pixfmt_alpha_blend_gray<blender_type, agg::rendering_buffer> pixfmt_type; - typedef pixfmt_type pixfmt_pre_type; - - template <typename A> - struct span_gen_affine_type - { - typedef agg::span_image_resample_gray_affine<A> type; - }; - - template <typename A, typename B> - struct span_gen_filter_type - { - typedef agg::span_image_filter_gray<A, B> type; - }; - - template <typename A, typename B> - struct span_gen_nn_type - { - typedef agg::span_image_filter_gray_nn<A, B> type; - }; -}; - - - -template<class 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; - double norm; - double radius; - double alpha; -}; - - -static void get_filter(const resample_params_t ¶ms, - 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<class T> -void resample( - const T *input, int in_width, int in_height, - T *output, int out_width, int out_height, - resample_params_t ¶ms) -{ - typedef type_mapping<T> type_mapping_t; - - typedef typename type_mapping_t::pixfmt_type input_pixfmt_t; - typedef typename type_mapping_t::pixfmt_type output_pixfmt_t; - - typedef agg::renderer_base<output_pixfmt_t> renderer_t; - typedef agg::rasterizer_scanline_aa<agg::rasterizer_sl_clip_dbl> rasterizer_t; - - typedef agg::wrap_mode_reflect reflect_t; - typedef agg::image_accessor_wrap<input_pixfmt_t, reflect_t, reflect_t> image_accessor_t; - - typedef agg::span_allocator<typename type_mapping_t::color_type> span_alloc_t; - typedef span_conv_alpha<typename type_mapping_t::color_type> span_conv_alpha_t; - - typedef agg::span_interpolator_linear<> affine_interpolator_t; - typedef agg::span_interpolator_adaptor<agg::span_interpolator_linear<>, lookup_distortion> - arbitrary_interpolator_t; - - 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 * sizeof(T)); - 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 * sizeof(T)); - 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) { - typedef typename type_mapping_t::template span_gen_nn_type<image_accessor_t, affine_interpolator_t>::type span_gen_t; - typedef agg::span_converter<span_gen_t, span_conv_alpha_t> span_conv_t; - typedef agg::renderer_scanline_aa<renderer_t, span_alloc_t, span_conv_t> nn_renderer_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 { - typedef typename type_mapping_t::template span_gen_nn_type<image_accessor_t, arbitrary_interpolator_t>::type span_gen_t; - typedef agg::span_converter<span_gen_t, span_conv_alpha_t> span_conv_t; - typedef agg::renderer_scanline_aa<renderer_t, span_alloc_t, span_conv_t> nn_renderer_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) { - typedef typename type_mapping_t::template span_gen_affine_type<image_accessor_t>::type span_gen_t; - typedef agg::span_converter<span_gen_t, span_conv_alpha_t> span_conv_t; - typedef agg::renderer_scanline_aa<renderer_t, span_alloc_t, span_conv_t> int_renderer_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 { - typedef typename type_mapping_t::template span_gen_filter_type<image_accessor_t, arbitrary_interpolator_t>::type span_gen_t; - typedef agg::span_converter<span_gen_t, span_conv_alpha_t> span_conv_t; - typedef agg::renderer_scanline_aa<renderer_t, span_alloc_t, span_conv_t> int_renderer_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 /* RESAMPLE_H */ diff --git a/contrib/python/matplotlib/py2/src/_image_wrapper.cpp b/contrib/python/matplotlib/py2/src/_image_wrapper.cpp deleted file mode 100644 index ee0bfe84c7..0000000000 --- a/contrib/python/matplotlib/py2/src/_image_wrapper.cpp +++ /dev/null @@ -1,510 +0,0 @@ -#include "mplutils.h" -#include "_image_resample.h" -#include "_image.h" -#include "py_converters.h" - - -#ifndef NPY_1_7_API_VERSION -#define NPY_ARRAY_C_CONTIGUOUS NPY_C_CONTIGUOUS -#endif - - -/********************************************************************** - * Free functions - * */ - -const char* image_resample__doc__ = -"resample(input_array, output_array, matrix, interpolation=NEAREST, alpha=1.0, norm=0, radius=1)\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 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 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\n" -" array.\n\n" - -"interpolation : int, optional\n" -" The interpolation method. Must be one of the following constants\n" -" defined in this module:\n\n" - -" NEAREST (default), 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, optional\n" -" The level of transparency to apply. 1.0 is completely opaque.\n" -" 0.0 is completely transparent.\n\n" - -"norm : float, optional\n" -" The norm for the interpolation function. Default is 0.\n\n" - -"radius: float, optional\n" -" The radius of the kernel, if method is SINC, LANCZOS or BLACKMAN.\n" -" Default is 1.\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, (char *)"inverted", (char *)"", 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, (char *)"transform", (char *)"O", - (char *)input_mesh.pyobj(), NULL); - - 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_array = NULL; - PyObject *py_output_array = NULL; - PyObject *py_transform = NULL; - resample_params_t params; - int resample_; - - PyArrayObject *input_array = NULL; - PyArrayObject *output_array = NULL; - PyArrayObject *transform_mesh_array = NULL; - - params.transform_mesh = NULL; - - const char *kwlist[] = { - "input_array", "output_array", "transform", "interpolation", - "resample", "alpha", "norm", "radius", NULL }; - - if (!PyArg_ParseTupleAndKeywords( - args, kwargs, "OOO|iiddd:resample", (char **)kwlist, - &py_input_array, &py_output_array, &py_transform, - ¶ms.interpolation, &resample_, ¶ms.alpha, ¶ms.norm, - ¶ms.radius)) { - return NULL; - } - - if (params.interpolation < 0 || params.interpolation >= _n_interpolation) { - PyErr_Format(PyExc_ValueError, "invalid interpolation value %d", - params.interpolation); - goto error; - } - - params.resample = (resample_ != 0); - - input_array = (PyArrayObject *)PyArray_FromAny( - py_input_array, NULL, 2, 3, NPY_ARRAY_C_CONTIGUOUS, NULL); - if (input_array == NULL) { - goto error; - } - - output_array = (PyArrayObject *)PyArray_FromAny( - py_output_array, NULL, 2, 3, NPY_ARRAY_C_CONTIGUOUS, NULL); - if (output_array == NULL) { - 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 == NULL) { - 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, ¶ms.affine)) { - goto error; - } - params.is_affine = true; - } else { - transform_mesh_array = _get_transform_mesh( - py_transform, PyArray_DIMS(output_array)); - if (transform_mesh_array == NULL) { - goto error; - } - params.transform_mesh = (double *)PyArray_DATA(transform_mesh_array); - params.is_affine = false; - } - } - - if (PyArray_NDIM(input_array) != PyArray_NDIM(output_array)) { - PyErr_Format( - PyExc_ValueError, - "Mismatched number of dimensions. Got %d and %d.", - PyArray_NDIM(input_array), PyArray_NDIM(output_array)); - goto error; - } - - if (PyArray_TYPE(input_array) != PyArray_TYPE(output_array)) { - PyErr_SetString(PyExc_ValueError, "Mismatched types"); - goto error; - } - - if (PyArray_NDIM(input_array) == 3) { - if (PyArray_DIM(output_array, 2) != 4) { - PyErr_SetString( - PyExc_ValueError, - "Output array must be RGBA"); - goto error; - } - - if (PyArray_DIM(input_array, 2) == 4) { - switch(PyArray_TYPE(input_array)) { - case NPY_BYTE: - case NPY_UINT8: - Py_BEGIN_ALLOW_THREADS - resample( - (agg::rgba8 *)PyArray_DATA(input_array), - PyArray_DIM(input_array, 1), - PyArray_DIM(input_array, 0), - (agg::rgba8 *)PyArray_DATA(output_array), - PyArray_DIM(output_array, 1), - PyArray_DIM(output_array, 0), - params); - Py_END_ALLOW_THREADS - break; - case NPY_UINT16: - case NPY_INT16: - Py_BEGIN_ALLOW_THREADS - resample( - (agg::rgba16 *)PyArray_DATA(input_array), - PyArray_DIM(input_array, 1), - PyArray_DIM(input_array, 0), - (agg::rgba16 *)PyArray_DATA(output_array), - PyArray_DIM(output_array, 1), - PyArray_DIM(output_array, 0), - params); - Py_END_ALLOW_THREADS - break; - case NPY_FLOAT32: - Py_BEGIN_ALLOW_THREADS - resample( - (agg::rgba32 *)PyArray_DATA(input_array), - PyArray_DIM(input_array, 1), - PyArray_DIM(input_array, 0), - (agg::rgba32 *)PyArray_DATA(output_array), - PyArray_DIM(output_array, 1), - PyArray_DIM(output_array, 0), - params); - Py_END_ALLOW_THREADS - break; - case NPY_FLOAT64: - Py_BEGIN_ALLOW_THREADS - resample( - (agg::rgba64 *)PyArray_DATA(input_array), - PyArray_DIM(input_array, 1), - PyArray_DIM(input_array, 0), - (agg::rgba64 *)PyArray_DATA(output_array), - PyArray_DIM(output_array, 1), - PyArray_DIM(output_array, 0), - params); - Py_END_ALLOW_THREADS - break; - default: - PyErr_SetString( - PyExc_ValueError, - "3-dimensional arrays must be of dtype unsigned byte, " - "unsigned short, float32 or float64"); - goto error; - } - } else { - PyErr_Format( - PyExc_ValueError, - "If 3-dimensional, array must be RGBA. Got %" NPY_INTP_FMT " planes.", - PyArray_DIM(input_array, 2)); - goto error; - } - } else { // NDIM == 2 - switch (PyArray_TYPE(input_array)) { - case NPY_DOUBLE: - Py_BEGIN_ALLOW_THREADS - resample( - (double *)PyArray_DATA(input_array), - PyArray_DIM(input_array, 1), - PyArray_DIM(input_array, 0), - (double *)PyArray_DATA(output_array), - PyArray_DIM(output_array, 1), - PyArray_DIM(output_array, 0), - params); - Py_END_ALLOW_THREADS - break; - case NPY_FLOAT: - Py_BEGIN_ALLOW_THREADS - resample( - (float *)PyArray_DATA(input_array), - PyArray_DIM(input_array, 1), - PyArray_DIM(input_array, 0), - (float *)PyArray_DATA(output_array), - PyArray_DIM(output_array, 1), - PyArray_DIM(output_array, 0), - params); - Py_END_ALLOW_THREADS - break; - case NPY_UINT8: - case NPY_BYTE: - Py_BEGIN_ALLOW_THREADS - resample( - (unsigned char *)PyArray_DATA(input_array), - PyArray_DIM(input_array, 1), - PyArray_DIM(input_array, 0), - (unsigned char *)PyArray_DATA(output_array), - PyArray_DIM(output_array, 1), - PyArray_DIM(output_array, 0), - params); - Py_END_ALLOW_THREADS - break; - case NPY_UINT16: - case NPY_INT16: - Py_BEGIN_ALLOW_THREADS - resample( - (unsigned short *)PyArray_DATA(input_array), - PyArray_DIM(input_array, 1), - PyArray_DIM(input_array, 0), - (unsigned short *)PyArray_DATA(output_array), - PyArray_DIM(output_array, 1), - PyArray_DIM(output_array, 0), - params); - Py_END_ALLOW_THREADS - break; - default: - PyErr_SetString(PyExc_ValueError, "Unsupported dtype"); - goto error; - } - } - - Py_DECREF(input_array); - Py_XDECREF(transform_mesh_array); - return (PyObject *)output_array; - - error: - Py_XDECREF(input_array); - Py_XDECREF(output_array); - Py_XDECREF(transform_mesh_array); - return NULL; -} - - -const char *image_pcolor__doc__ = - "pcolor(x, y, data, rows, cols, bounds)\n" - "\n" - "Generate a pseudo-color image from data on a non-uniform grid using\n" - "nearest neighbour or linear interpolation.\n" - "bounds = (x_min, x_max, y_min, y_max)\n" - "interpolation = NEAREST or BILINEAR \n"; - -static PyObject *image_pcolor(PyObject *self, PyObject *args, PyObject *kwds) -{ - numpy::array_view<const float, 1> x; - numpy::array_view<const float, 1> y; - numpy::array_view<const agg::int8u, 3> d; - npy_intp rows, cols; - float bounds[4]; - int interpolation; - - if (!PyArg_ParseTuple(args, - "O&O&O&nn(ffff)i:pcolor", - &x.converter, - &x, - &y.converter, - &y, - &d.converter_contiguous, - &d, - &rows, - &cols, - &bounds[0], - &bounds[1], - &bounds[2], - &bounds[3], - &interpolation)) { - return NULL; - } - - npy_intp dim[3] = {rows, cols, 4}; - numpy::array_view<const agg::int8u, 3> output(dim); - - CALL_CPP("pcolor", (pcolor(x, y, d, rows, cols, bounds, interpolation, output))); - - return output.pyobj(); -} - -const char *image_pcolor2__doc__ = - "pcolor2(x, y, data, rows, cols, bounds, bg)\n" - "\n" - "Generate a pseudo-color image from data on a non-uniform grid\n" - "specified by its cell boundaries.\n" - "bounds = (x_left, x_right, y_bot, y_top)\n" - "bg = ndarray of 4 uint8 representing background rgba\n"; - -static PyObject *image_pcolor2(PyObject *self, PyObject *args, PyObject *kwds) -{ - numpy::array_view<const double, 1> x; - numpy::array_view<const double, 1> y; - numpy::array_view<const agg::int8u, 3> d; - npy_intp rows, cols; - float bounds[4]; - numpy::array_view<const agg::int8u, 1> bg; - - if (!PyArg_ParseTuple(args, - "O&O&O&nn(ffff)O&:pcolor2", - &x.converter_contiguous, - &x, - &y.converter_contiguous, - &y, - &d.converter_contiguous, - &d, - &rows, - &cols, - &bounds[0], - &bounds[1], - &bounds[2], - &bounds[3], - &bg.converter, - &bg)) { - return NULL; - } - - npy_intp dim[3] = {rows, cols, 4}; - numpy::array_view<const agg::int8u, 3> output(dim); - - CALL_CPP("pcolor2", (pcolor2(x, y, d, rows, cols, bounds, bg, output))); - - return output.pyobj(); -} - -static PyMethodDef module_functions[] = { - {"resample", (PyCFunction)image_resample, METH_VARARGS|METH_KEYWORDS, image_resample__doc__}, - {"pcolor", (PyCFunction)image_pcolor, METH_VARARGS, image_pcolor__doc__}, - {"pcolor2", (PyCFunction)image_pcolor2, METH_VARARGS, image_pcolor2__doc__}, - {NULL} -}; - -extern "C" { - -#if PY3K -static struct PyModuleDef moduledef = { - PyModuleDef_HEAD_INIT, - "_image", - NULL, - 0, - module_functions, - NULL, - NULL, - NULL, - NULL -}; - -#define INITERROR return NULL - -PyMODINIT_FUNC PyInit__image(void) - -#else -#define INITERROR return - -PyMODINIT_FUNC init_image(void) -#endif - -{ - PyObject *m; - -#if PY3K - m = PyModule_Create(&moduledef); -#else - m = Py_InitModule3("_image", module_functions, NULL); -#endif - - if (m == NULL) { - INITERROR; - } - - 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)) { - INITERROR; - } - - import_array(); - -#if PY3K - return m; -#endif -} - -} // extern "C" diff --git a/contrib/python/matplotlib/py2/src/_macosx.m b/contrib/python/matplotlib/py2/src/_macosx.m deleted file mode 100644 index 8f44f1eb0c..0000000000 --- a/contrib/python/matplotlib/py2/src/_macosx.m +++ /dev/null @@ -1,3174 +0,0 @@ -#include <Cocoa/Cocoa.h> -#include <ApplicationServices/ApplicationServices.h> -#include <sys/socket.h> -#include <Python.h> - -#define PYOSINPUTHOOK_REPETITIVE 1 /* Remove this once Python is fixed */ - -#if PY_MAJOR_VERSION >= 3 -#define PY3K 1 -#else -#define PY3K 0 -#endif - -/* Proper way to check for the OS X version we are compiling for, from - http://developer.apple.com/documentation/DeveloperTools/Conceptual/cross_development */ -#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 -#define COMPILING_FOR_10_6 -#endif -#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 -#define COMPILING_FOR_10_7 -#endif -#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 10100 -#define COMPILING_FOR_10_10 -#endif - - -/* CGFloat was defined in Mac OS X 10.5 */ -#ifndef CGFLOAT_DEFINED -#define CGFloat float -#endif - - -/* Various NSApplicationDefined event subtypes */ -#define STOP_EVENT_LOOP 2 -#define WINDOW_CLOSING 3 - - -/* Keep track of number of windows present - Needed to know when to stop the NSApp */ -static long FigureWindowCount = 0; - -/* -------------------------- Helper function ---------------------------- */ - -static void -_stdin_callback(CFReadStreamRef stream, CFStreamEventType eventType, void* info) -{ - CFRunLoopRef runloop = info; - CFRunLoopStop(runloop); -} - -static int sigint_fd = -1; - -static void _sigint_handler(int sig) -{ - const char c = 'i'; - write(sigint_fd, &c, 1); -} - -static void _sigint_callback(CFSocketRef s, - CFSocketCallBackType type, - CFDataRef address, - const void * data, - void *info) -{ - char c; - int* interrupted = info; - CFSocketNativeHandle handle = CFSocketGetNative(s); - CFRunLoopRef runloop = CFRunLoopGetCurrent(); - read(handle, &c, 1); - *interrupted = 1; - CFRunLoopStop(runloop); -} - -static CGEventRef _eventtap_callback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) -{ - CFRunLoopRef runloop = refcon; - CFRunLoopStop(runloop); - return event; -} - -static int wait_for_stdin(void) -{ - int interrupted = 0; - const UInt8 buffer[] = "/dev/fd/0"; - const CFIndex n = (CFIndex)strlen((char*)buffer); - CFRunLoopRef runloop = CFRunLoopGetCurrent(); - CFURLRef url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, - buffer, - n, - false); - CFReadStreamRef stream = CFReadStreamCreateWithFile(kCFAllocatorDefault, - url); - CFRelease(url); - - CFReadStreamOpen(stream); -#ifdef PYOSINPUTHOOK_REPETITIVE - if (!CFReadStreamHasBytesAvailable(stream)) - /* This is possible because of how PyOS_InputHook is called from Python */ - { -#endif - int error; - int channel[2]; - CFSocketRef sigint_socket = NULL; - PyOS_sighandler_t py_sigint_handler = NULL; - CFStreamClientContext clientContext = {0, NULL, NULL, NULL, NULL}; - clientContext.info = runloop; - CFReadStreamSetClient(stream, - kCFStreamEventHasBytesAvailable, - _stdin_callback, - &clientContext); - CFReadStreamScheduleWithRunLoop(stream, runloop, kCFRunLoopDefaultMode); - error = socketpair(AF_UNIX, SOCK_STREAM, 0, channel); - if (error==0) - { - CFSocketContext context; - context.version = 0; - context.info = &interrupted; - context.retain = NULL; - context.release = NULL; - context.copyDescription = NULL; - fcntl(channel[0], F_SETFL, O_WRONLY | O_NONBLOCK); - sigint_socket = CFSocketCreateWithNative( - kCFAllocatorDefault, - channel[1], - kCFSocketReadCallBack, - _sigint_callback, - &context); - if (sigint_socket) - { - CFRunLoopSourceRef source; - source = CFSocketCreateRunLoopSource(kCFAllocatorDefault, - sigint_socket, - 0); - CFRelease(sigint_socket); - if (source) - { - CFRunLoopAddSource(runloop, source, kCFRunLoopDefaultMode); - CFRelease(source); - sigint_fd = channel[0]; - py_sigint_handler = PyOS_setsig(SIGINT, _sigint_handler); - } - } - } - - NSEvent* event; - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - while (true) { - while (true) { - event = [NSApp nextEventMatchingMask: NSAnyEventMask - untilDate: [NSDate distantPast] - inMode: NSDefaultRunLoopMode - dequeue: YES]; - if (!event) break; - [NSApp sendEvent: event]; - } - CFRunLoopRun(); - if (interrupted || CFReadStreamHasBytesAvailable(stream)) break; - } - [pool release]; - - if (py_sigint_handler) PyOS_setsig(SIGINT, py_sigint_handler); - CFReadStreamUnscheduleFromRunLoop(stream, - runloop, - kCFRunLoopCommonModes); - if (sigint_socket) CFSocketInvalidate(sigint_socket); - if (error==0) { - close(channel[0]); - close(channel[1]); - } -#ifdef PYOSINPUTHOOK_REPETITIVE - } -#endif - CFReadStreamClose(stream); - CFRelease(stream); - if (interrupted) { - errno = EINTR; - raise(SIGINT); - return -1; - } - return 1; -} - -/* ---------------------------- Cocoa classes ---------------------------- */ - -@interface WindowServerConnectionManager : NSObject -{ -} -+ (WindowServerConnectionManager*)sharedManager; -- (void)launch:(NSNotification*)notification; -@end - -@interface Window : NSWindow -{ PyObject* manager; -} -- (Window*)initWithContentRect:(NSRect)rect styleMask:(unsigned int)mask backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation withManager: (PyObject*)theManager; -- (NSRect)constrainFrameRect:(NSRect)rect toScreen:(NSScreen*)screen; -- (BOOL)closeButtonPressed; -- (void)dealloc; -@end - -@interface ToolWindow : NSWindow -{ -} -- (ToolWindow*)initWithContentRect:(NSRect)rect master:(NSWindow*)window; -- (void)masterCloses:(NSNotification*)notification; -- (void)close; -@end - -#ifdef COMPILING_FOR_10_6 -@interface View : NSView <NSWindowDelegate> -#else -@interface View : NSView -#endif -{ PyObject* canvas; - NSRect rubberband; - BOOL inside; - NSTrackingRectTag tracking; - @public double device_scale; -} -- (void)dealloc; -- (void)drawRect:(NSRect)rect; -- (void)windowDidResize:(NSNotification*)notification; -- (View*)initWithFrame:(NSRect)rect; -- (void)setCanvas: (PyObject*)newCanvas; -- (void)windowWillClose:(NSNotification*)notification; -- (BOOL)windowShouldClose:(NSNotification*)notification; -- (BOOL)isFlipped; -- (void)mouseEntered:(NSEvent*)event; -- (void)mouseExited:(NSEvent*)event; -- (void)mouseDown:(NSEvent*)event; -- (void)mouseUp:(NSEvent*)event; -- (void)mouseDragged:(NSEvent*)event; -- (void)mouseMoved:(NSEvent*)event; -- (void)rightMouseDown:(NSEvent*)event; -- (void)rightMouseUp:(NSEvent*)event; -- (void)rightMouseDragged:(NSEvent*)event; -- (void)otherMouseDown:(NSEvent*)event; -- (void)otherMouseUp:(NSEvent*)event; -- (void)otherMouseDragged:(NSEvent*)event; -- (void)setRubberband:(NSRect)rect; -- (void)removeRubberband; -- (const char*)convertKeyEvent:(NSEvent*)event; -- (void)keyDown:(NSEvent*)event; -- (void)keyUp:(NSEvent*)event; -- (void)scrollWheel:(NSEvent *)event; -- (BOOL)acceptsFirstResponder; -//- (void)flagsChanged:(NSEvent*)event; -@end - -@interface ScrollableButton : NSButton -{ - SEL scrollWheelUpAction; - SEL scrollWheelDownAction; -} -- (void)setScrollWheelUpAction:(SEL)action; -- (void)setScrollWheelDownAction:(SEL)action; -- (void)scrollWheel:(NSEvent *)event; -@end - -@interface MenuItem: NSMenuItem -{ int index; -} -+ (MenuItem*)menuItemWithTitle:(NSString*)title; -+ (MenuItem*)menuItemSelectAll; -+ (MenuItem*)menuItemInvertAll; -+ (MenuItem*)menuItemForAxis:(int)i; -- (void)toggle:(id)sender; -- (void)selectAll:(id)sender; -- (void)invertAll:(id)sender; -- (int)index; -@end - -/* ---------------------------- Python classes ---------------------------- */ - -static CGFloat _get_device_scale(CGContextRef cr) -{ - CGSize pixelSize = CGContextConvertSizeToDeviceSpace(cr, CGSizeMake(1, 1)); - return pixelSize.width; -} - -typedef struct { - PyObject_HEAD - View* view; -} FigureCanvas; - -static PyObject* -FigureCanvas_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - FigureCanvas *self = (FigureCanvas*)type->tp_alloc(type, 0); - if (!self) return NULL; - self->view = [View alloc]; - return (PyObject*)self; -} - -static int -FigureCanvas_init(FigureCanvas *self, PyObject *args, PyObject *kwds) -{ - int width; - int height; - if(!self->view) - { - PyErr_SetString(PyExc_RuntimeError, "NSView* is NULL"); - return -1; - } - - if(!PyArg_ParseTuple(args, "ii", &width, &height)) return -1; - - NSRect rect = NSMakeRect(0.0, 0.0, width, height); - self->view = [self->view initWithFrame: rect]; - [self->view setCanvas: (PyObject*)self]; - return 0; -} - -static void -FigureCanvas_dealloc(FigureCanvas* self) -{ - if (self->view) - { - [self->view setCanvas: NULL]; - [self->view release]; - } - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static PyObject* -FigureCanvas_repr(FigureCanvas* self) -{ -#if PY3K - return PyUnicode_FromFormat("FigureCanvas object %p wrapping NSView %p", - (void*)self, (void*)(self->view)); -#else - return PyString_FromFormat("FigureCanvas object %p wrapping NSView %p", - (void*)self, (void*)(self->view)); -#endif -} - -static PyObject* -FigureCanvas_draw(FigureCanvas* self) -{ - View* view = self->view; - - if(view) /* The figure may have been closed already */ - { - /* Whereas drawRect creates its own autorelease pool, apparently - * [view display] also needs one. Create and release it here. */ - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - [view display]; - [pool release]; - } - - Py_RETURN_NONE; -} - -static PyObject* -FigureCanvas_invalidate(FigureCanvas* self) -{ - View* view = self->view; - if(!view) - { - PyErr_SetString(PyExc_RuntimeError, "NSView* is NULL"); - return NULL; - } - [view setNeedsDisplay: YES]; - Py_RETURN_NONE; -} - -static PyObject* -FigureCanvas_flush_events(FigureCanvas* self) -{ - View* view = self->view; - if(!view) - { - PyErr_SetString(PyExc_RuntimeError, "NSView* is NULL"); - return NULL; - } - [view displayIfNeeded]; - Py_RETURN_NONE; -} - -static PyObject* -FigureCanvas_set_rubberband(FigureCanvas* self, PyObject *args) -{ - View* view = self->view; - int x0, y0, x1, y1; - NSRect rubberband; - if(!view) - { - PyErr_SetString(PyExc_RuntimeError, "NSView* is NULL"); - return NULL; - } - if(!PyArg_ParseTuple(args, "iiii", &x0, &y0, &x1, &y1)) return NULL; - - x0 /= view->device_scale; - x1 /= view->device_scale; - y0 /= view->device_scale; - y1 /= view->device_scale; - - if (x1 > x0) - { - rubberband.origin.x = x0; - rubberband.size.width = x1 - x0; - } - else - { - rubberband.origin.x = x1; - rubberband.size.width = x0 - x1; - } - if (y1 > y0) - { - rubberband.origin.y = y0; - rubberband.size.height = y1 - y0; - } - else - { - rubberband.origin.y = y1; - rubberband.size.height = y0 - y1; - } - - [view setRubberband: rubberband]; - Py_RETURN_NONE; -} - -static PyObject* -FigureCanvas_remove_rubberband(FigureCanvas* self) -{ - View* view = self->view; - if(!view) - { - PyErr_SetString(PyExc_RuntimeError, "NSView* is NULL"); - return NULL; - } - [view removeRubberband]; - Py_RETURN_NONE; -} - -static NSImage* _read_ppm_image(PyObject* obj) -{ - int width; - int height; - const char* data; - int n; - int i; - NSBitmapImageRep* bitmap; - unsigned char* bitmapdata; - - if (!obj) return NULL; - if (!PyTuple_Check(obj)) return NULL; - if (!PyArg_ParseTuple(obj, "iit#", &width, &height, &data, &n)) return NULL; - if (width*height*3 != n) return NULL; /* RGB image uses 3 colors / pixel */ - - bitmap = [[NSBitmapImageRep alloc] - initWithBitmapDataPlanes: NULL - pixelsWide: width - pixelsHigh: height - bitsPerSample: 8 - samplesPerPixel: 3 - hasAlpha: NO - isPlanar: NO - colorSpaceName: NSDeviceRGBColorSpace - bitmapFormat: 0 - bytesPerRow: width*3 - bitsPerPixel: 24]; - if (!bitmap) return NULL; - bitmapdata = [bitmap bitmapData]; - for (i = 0; i < n; i++) bitmapdata[i] = data[i]; - - NSSize size = NSMakeSize(width, height); - NSImage* image = [[NSImage alloc] initWithSize: size]; - if (image) [image addRepresentation: bitmap]; - - [bitmap release]; - - return image; -} - -static PyObject* -FigureCanvas_start_event_loop(FigureCanvas* self, PyObject* args, PyObject* keywords) -{ - float timeout = 0.0; - - static char* kwlist[] = {"timeout", NULL}; - if(!PyArg_ParseTupleAndKeywords(args, keywords, "f", kwlist, &timeout)) - return NULL; - - int error; - int interrupted = 0; - int channel[2]; - CFSocketRef sigint_socket = NULL; - PyOS_sighandler_t py_sigint_handler = NULL; - - CFRunLoopRef runloop = CFRunLoopGetCurrent(); - - error = pipe(channel); - if (error==0) - { - CFSocketContext context = {0, NULL, NULL, NULL, NULL}; - fcntl(channel[1], F_SETFL, O_WRONLY | O_NONBLOCK); - - context.info = &interrupted; - sigint_socket = CFSocketCreateWithNative(kCFAllocatorDefault, - channel[0], - kCFSocketReadCallBack, - _sigint_callback, - &context); - if (sigint_socket) - { - CFRunLoopSourceRef source; - source = CFSocketCreateRunLoopSource(kCFAllocatorDefault, - sigint_socket, - 0); - CFRelease(sigint_socket); - if (source) - { - CFRunLoopAddSource(runloop, source, kCFRunLoopDefaultMode); - CFRelease(source); - sigint_fd = channel[1]; - py_sigint_handler = PyOS_setsig(SIGINT, _sigint_handler); - } - } - else - close(channel[0]); - } - - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSDate* date = - (timeout > 0.0) ? [NSDate dateWithTimeIntervalSinceNow: timeout] - : [NSDate distantFuture]; - while (true) - { NSEvent* event = [NSApp nextEventMatchingMask: NSAnyEventMask - untilDate: date - inMode: NSDefaultRunLoopMode - dequeue: YES]; - if (!event || [event type]==NSApplicationDefined) break; - [NSApp sendEvent: event]; - } - [pool release]; - - if (py_sigint_handler) PyOS_setsig(SIGINT, py_sigint_handler); - - if (sigint_socket) CFSocketInvalidate(sigint_socket); - if (error==0) close(channel[1]); - if (interrupted) raise(SIGINT); - - Py_RETURN_NONE; -} - -static PyObject* -FigureCanvas_stop_event_loop(FigureCanvas* self) -{ - NSEvent* event = [NSEvent otherEventWithType: NSApplicationDefined - location: NSZeroPoint - modifierFlags: 0 - timestamp: 0.0 - windowNumber: 0 - context: nil - subtype: STOP_EVENT_LOOP - data1: 0 - data2: 0]; - [NSApp postEvent: event atStart: true]; - Py_RETURN_NONE; -} - -static PyMethodDef FigureCanvas_methods[] = { - {"draw", - (PyCFunction)FigureCanvas_draw, - METH_NOARGS, - "Draws the canvas." - }, - {"invalidate", - (PyCFunction)FigureCanvas_invalidate, - METH_NOARGS, - "Invalidates the canvas." - }, - {"flush_events", - (PyCFunction)FigureCanvas_flush_events, - METH_NOARGS, - "Flush the GUI events for the figure." - }, - {"set_rubberband", - (PyCFunction)FigureCanvas_set_rubberband, - METH_VARARGS, - "Specifies a new rubberband rectangle and invalidates it." - }, - {"remove_rubberband", - (PyCFunction)FigureCanvas_remove_rubberband, - METH_NOARGS, - "Removes the current rubberband rectangle." - }, - {"start_event_loop", - (PyCFunction)FigureCanvas_start_event_loop, - METH_KEYWORDS | METH_VARARGS, - "Runs the event loop until the timeout or until stop_event_loop is called.\n", - }, - {"stop_event_loop", - (PyCFunction)FigureCanvas_stop_event_loop, - METH_NOARGS, - "Stops the event loop that was started by start_event_loop.\n", - }, - {NULL} /* Sentinel */ -}; - -static char FigureCanvas_doc[] = -"A FigureCanvas object wraps a Cocoa NSView object.\n"; - -static PyTypeObject FigureCanvasType = { - PyVarObject_HEAD_INIT(NULL, 0) - "_macosx.FigureCanvas", /*tp_name*/ - sizeof(FigureCanvas), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)FigureCanvas_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - (reprfunc)FigureCanvas_repr, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - FigureCanvas_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - FigureCanvas_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)FigureCanvas_init, /* tp_init */ - 0, /* tp_alloc */ - FigureCanvas_new, /* tp_new */ -}; - -typedef struct { - PyObject_HEAD - Window* window; -} FigureManager; - -static PyObject* -FigureManager_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - Window* window = [Window alloc]; - if (!window) return NULL; - FigureManager *self = (FigureManager*)type->tp_alloc(type, 0); - if (!self) - { - [window release]; - return NULL; - } - self->window = window; - ++FigureWindowCount; - return (PyObject*)self; -} - -static int -FigureManager_init(FigureManager *self, PyObject *args, PyObject *kwds) -{ - NSRect rect; - Window* window; - View* view; - const char* title; - PyObject* size; - int width, height; - PyObject* obj; - FigureCanvas* canvas; - - if(!self->window) - { - PyErr_SetString(PyExc_RuntimeError, "NSWindow* is NULL"); - return -1; - } - - if(!PyArg_ParseTuple(args, "Os", &obj, &title)) return -1; - - canvas = (FigureCanvas*)obj; - view = canvas->view; - if (!view) /* Something really weird going on */ - { - PyErr_SetString(PyExc_RuntimeError, "NSView* is NULL"); - return -1; - } - - size = PyObject_CallMethod(obj, "get_width_height", ""); - if(!size) return -1; - if(!PyArg_ParseTuple(size, "ii", &width, &height)) - { Py_DECREF(size); - return -1; - } - Py_DECREF(size); - - rect.origin.x = 100; - rect.origin.y = 350; - rect.size.height = height; - rect.size.width = width; - - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - self->window = [self->window initWithContentRect: rect - styleMask: NSTitledWindowMask - | NSClosableWindowMask - | NSResizableWindowMask - | NSMiniaturizableWindowMask - backing: NSBackingStoreBuffered - defer: YES - withManager: (PyObject*)self]; - window = self->window; - [window setTitle: [NSString stringWithCString: title - encoding: NSASCIIStringEncoding]]; - - [window setAcceptsMouseMovedEvents: YES]; - [window setDelegate: view]; - [window makeFirstResponder: view]; - [[window contentView] addSubview: view]; - - [pool release]; - return 0; -} - -static PyObject* -FigureManager_repr(FigureManager* self) -{ -#if PY3K - return PyUnicode_FromFormat("FigureManager object %p wrapping NSWindow %p", - (void*) self, (void*)(self->window)); -#else - return PyString_FromFormat("FigureManager object %p wrapping NSWindow %p", - (void*) self, (void*)(self->window)); -#endif -} - -static void -FigureManager_dealloc(FigureManager* self) -{ - Window* window = self->window; - if(window) - { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - [window close]; - [pool release]; - } - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static PyObject* -FigureManager_show(FigureManager* self) -{ - Window* window = self->window; - if(window) - { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - [window makeKeyAndOrderFront: nil]; - [window orderFrontRegardless]; - [pool release]; - } - Py_RETURN_NONE; -} - -static PyObject* -FigureManager_destroy(FigureManager* self) -{ - Window* window = self->window; - if(window) - { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - [window close]; - [pool release]; - self->window = NULL; - } - Py_RETURN_NONE; -} - -static PyObject* -FigureManager_set_window_title(FigureManager* self, - PyObject *args, PyObject *kwds) -{ - char* title; - if(!PyArg_ParseTuple(args, "es", "UTF-8", &title)) - return NULL; - - Window* window = self->window; - if(window) - { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSString* ns_title = [[[NSString alloc] - initWithCString: title - encoding: NSUTF8StringEncoding] autorelease]; - [window setTitle: ns_title]; - [pool release]; - } - PyMem_Free(title); - Py_RETURN_NONE; -} - -static PyObject* -FigureManager_get_window_title(FigureManager* self) -{ - Window* window = self->window; - PyObject* result = NULL; - if(window) - { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSString* title = [window title]; - if (title) { - const char* cTitle = [title UTF8String]; - result = PyUnicode_FromString(cTitle); - } - [pool release]; - } - if (result) { - return result; - } else { - Py_RETURN_NONE; - } -} - -static PyMethodDef FigureManager_methods[] = { - {"show", - (PyCFunction)FigureManager_show, - METH_NOARGS, - "Shows the window associated with the figure manager." - }, - {"destroy", - (PyCFunction)FigureManager_destroy, - METH_NOARGS, - "Closes the window associated with the figure manager." - }, - {"set_window_title", - (PyCFunction)FigureManager_set_window_title, - METH_VARARGS, - "Sets the title of the window associated with the figure manager." - }, - {"get_window_title", - (PyCFunction)FigureManager_get_window_title, - METH_NOARGS, - "Returns the title of the window associated with the figure manager." - }, - {NULL} /* Sentinel */ -}; - -static char FigureManager_doc[] = -"A FigureManager object wraps a Cocoa NSWindow object.\n"; - -static PyTypeObject FigureManagerType = { - PyVarObject_HEAD_INIT(NULL, 0) - "_macosx.FigureManager", /*tp_name*/ - sizeof(FigureManager), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)FigureManager_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - (reprfunc)FigureManager_repr, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - FigureManager_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - FigureManager_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)FigureManager_init, /* tp_init */ - 0, /* tp_alloc */ - FigureManager_new, /* tp_new */ -}; - -@interface NavigationToolbarHandler : NSObject -{ PyObject* toolbar; -} -- (NavigationToolbarHandler*)initWithToolbar:(PyObject*)toolbar; --(void)left:(id)sender; --(void)right:(id)sender; --(void)up:(id)sender; --(void)down:(id)sender; --(void)zoominx:(id)sender; --(void)zoominy:(id)sender; --(void)zoomoutx:(id)sender; --(void)zoomouty:(id)sender; -@end - -typedef struct { - PyObject_HEAD - NSPopUpButton* menu; - NavigationToolbarHandler* handler; -} NavigationToolbar; - -@implementation NavigationToolbarHandler -- (NavigationToolbarHandler*)initWithToolbar:(PyObject*)theToolbar -{ [self init]; - toolbar = theToolbar; - return self; -} - --(void)left:(id)sender -{ PyObject* result; - PyGILState_STATE gstate; - gstate = PyGILState_Ensure(); - result = PyObject_CallMethod(toolbar, "panx", "i", -1); - if(result) - Py_DECREF(result); - else - PyErr_Print(); - PyGILState_Release(gstate); -} - --(void)right:(id)sender -{ PyObject* result; - PyGILState_STATE gstate; - gstate = PyGILState_Ensure(); - result = PyObject_CallMethod(toolbar, "panx", "i", 1); - if(result) - Py_DECREF(result); - else - PyErr_Print(); - PyGILState_Release(gstate); -} - --(void)up:(id)sender -{ PyObject* result; - PyGILState_STATE gstate; - gstate = PyGILState_Ensure(); - result = PyObject_CallMethod(toolbar, "pany", "i", 1); - if(result) - Py_DECREF(result); - else - PyErr_Print(); - PyGILState_Release(gstate); -} - --(void)down:(id)sender -{ PyObject* result; - PyGILState_STATE gstate; - gstate = PyGILState_Ensure(); - result = PyObject_CallMethod(toolbar, "pany", "i", -1); - if(result) - Py_DECREF(result); - else - PyErr_Print(); - PyGILState_Release(gstate); -} - --(void)zoominx:(id)sender -{ PyObject* result; - PyGILState_STATE gstate; - gstate = PyGILState_Ensure(); - result = PyObject_CallMethod(toolbar, "zoomx", "i", 1); - if(result) - Py_DECREF(result); - else - PyErr_Print(); - PyGILState_Release(gstate); -} - --(void)zoomoutx:(id)sender -{ PyObject* result; - PyGILState_STATE gstate; - gstate = PyGILState_Ensure(); - result = PyObject_CallMethod(toolbar, "zoomx", "i", -1); - if(result) - Py_DECREF(result); - else - PyErr_Print(); - PyGILState_Release(gstate); -} - --(void)zoominy:(id)sender -{ PyObject* result; - PyGILState_STATE gstate; - gstate = PyGILState_Ensure(); - result = PyObject_CallMethod(toolbar, "zoomy", "i", 1); - if(result) - Py_DECREF(result); - else - PyErr_Print(); - PyGILState_Release(gstate); -} - --(void)zoomouty:(id)sender -{ PyObject* result; - PyGILState_STATE gstate; - gstate = PyGILState_Ensure(); - result = PyObject_CallMethod(toolbar, "zoomy", "i", -1); - if(result) - Py_DECREF(result); - else - PyErr_Print(); - PyGILState_Release(gstate); -} - --(void)save_figure:(id)sender -{ PyObject* result; - PyGILState_STATE gstate; - gstate = PyGILState_Ensure(); - result = PyObject_CallMethod(toolbar, "save_figure", ""); - if(result) - Py_DECREF(result); - else - PyErr_Print(); - PyGILState_Release(gstate); -} -@end - -static PyObject* -NavigationToolbar_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - NavigationToolbarHandler* handler = [NavigationToolbarHandler alloc]; - if (!handler) return NULL; - NavigationToolbar *self = (NavigationToolbar*)type->tp_alloc(type, 0); - if (!self) - { [handler release]; - return NULL; - } - self->handler = handler; - return (PyObject*)self; -} - -static int -NavigationToolbar_init(NavigationToolbar *self, PyObject *args, PyObject *kwds) -{ - int i; - NSRect rect; - - const float smallgap = 2; - const float biggap = 10; - const int height = 32; - - PyObject* images; - PyObject* obj; - - FigureCanvas* canvas; - View* view; - - obj = PyObject_GetAttrString((PyObject*)self, "canvas"); - if (obj==NULL) - { - PyErr_SetString(PyExc_AttributeError, "Attempt to install toolbar for NULL canvas"); - return -1; - } - Py_DECREF(obj); /* Don't increase the reference count */ - if (!PyObject_IsInstance(obj, (PyObject*) &FigureCanvasType)) - { - PyErr_SetString(PyExc_TypeError, "Attempt to install toolbar for object that is not a FigureCanvas"); - return -1; - } - canvas = (FigureCanvas*)obj; - view = canvas->view; - if(!view) - { - PyErr_SetString(PyExc_RuntimeError, "NSView* is NULL"); - return -1; - } - - if(!PyArg_ParseTuple(args, "O", &images)) return -1; - if(!PyDict_Check(images)) return -1; - - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSRect bounds = [view bounds]; - NSWindow* window = [view window]; - - bounds.origin.y += height; - [view setFrame: bounds]; - - bounds.size.height += height; - [window setContentSize: bounds.size]; - - char* imagenames[9] = {"stock_left", - "stock_right", - "stock_zoom-in", - "stock_zoom-out", - "stock_up", - "stock_down", - "stock_zoom-in", - "stock_zoom-out", - "stock_save_as"}; - - NSString* tooltips[9] = { - @"Pan left with click or wheel mouse (bidirectional)", - @"Pan right with click or wheel mouse (bidirectional)", - @"Zoom In X (shrink the x axis limits) with click or wheel mouse (bidirectional)", - @"Zoom Out X (expand the x axis limits) with click or wheel mouse (bidirectional)", - @"Pan up with click or wheel mouse (bidirectional)", - @"Pan down with click or wheel mouse (bidirectional)", - @"Zoom in Y (shrink the y axis limits) with click or wheel mouse (bidirectional)", - @"Zoom Out Y (expand the y axis limits) with click or wheel mouse (bidirectional)", - @"Save the figure"}; - - SEL actions[9] = {@selector(left:), - @selector(right:), - @selector(zoominx:), - @selector(zoomoutx:), - @selector(up:), - @selector(down:), - @selector(zoominy:), - @selector(zoomouty:), - @selector(save_figure:)}; - - SEL scroll_actions[9][2] = {{@selector(left:), @selector(right:)}, - {@selector(left:), @selector(right:)}, - {@selector(zoominx:), @selector(zoomoutx:)}, - {@selector(zoominx:), @selector(zoomoutx:)}, - {@selector(up:), @selector(down:)}, - {@selector(up:), @selector(down:)}, - {@selector(zoominy:), @selector(zoomouty:)}, - {@selector(zoominy:), @selector(zoomouty:)}, - {nil,nil}, - }; - - - rect.size.width = 120; - rect.size.height = 24; - rect.origin.x = biggap; - rect.origin.y = 0.5*(height - rect.size.height); - self->menu = [[NSPopUpButton alloc] initWithFrame: rect - pullsDown: YES]; - [self->menu setAutoenablesItems: NO]; - [[window contentView] addSubview: self->menu]; - [self->menu release]; - rect.origin.x += rect.size.width + biggap; - rect.size.width = 24; - - self->handler = [self->handler initWithToolbar: (PyObject*)self]; - for (i = 0; i < 9; i++) - { - NSButton* button; - SEL scrollWheelUpAction = scroll_actions[i][0]; - SEL scrollWheelDownAction = scroll_actions[i][1]; - if (scrollWheelUpAction && scrollWheelDownAction) - { - ScrollableButton* scrollable_button = [ScrollableButton alloc]; - [scrollable_button initWithFrame: rect]; - [scrollable_button setScrollWheelUpAction: scrollWheelUpAction]; - [scrollable_button setScrollWheelDownAction: scrollWheelDownAction]; - button = (NSButton*)scrollable_button; - } - else - { - button = [NSButton alloc]; - [button initWithFrame: rect]; - } - PyObject* imagedata = PyDict_GetItemString(images, imagenames[i]); - NSImage* image = _read_ppm_image(imagedata); - [button setBezelStyle: NSShadowlessSquareBezelStyle]; - [button setButtonType: NSMomentaryLightButton]; - if(image) - { - [button setImage: image]; - [image release]; - } - [button setToolTip: tooltips[i]]; - [button setTarget: self->handler]; - [button setAction: actions[i]]; - [[window contentView] addSubview: button]; - [button release]; - rect.origin.x += rect.size.width + smallgap; - } - [[window contentView] display]; - [pool release]; - - return 0; -} - -static void -NavigationToolbar_dealloc(NavigationToolbar *self) -{ - [self->handler release]; - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static PyObject* -NavigationToolbar_repr(NavigationToolbar* self) -{ -#if PY3K - return PyUnicode_FromFormat("NavigationToolbar object %p", (void*)self); -#else - return PyString_FromFormat("NavigationToolbar object %p", (void*)self); -#endif -} - -static char NavigationToolbar_doc[] = -"NavigationToolbar\n"; - -static PyObject* -NavigationToolbar_update (NavigationToolbar* self) -{ - int n; - NSPopUpButton* button = self->menu; - if (!button) - { - PyErr_SetString(PyExc_RuntimeError, "Menu button is NULL"); - return NULL; - } - - PyObject* canvas = PyObject_GetAttrString((PyObject*)self, "canvas"); - if (canvas==NULL) - { - PyErr_SetString(PyExc_AttributeError, "Failed to find canvas"); - return NULL; - } - Py_DECREF(canvas); /* Don't keep a reference here */ - PyObject* figure = PyObject_GetAttrString(canvas, "figure"); - if (figure==NULL) - { - PyErr_SetString(PyExc_AttributeError, "Failed to find figure"); - return NULL; - } - Py_DECREF(figure); /* Don't keep a reference here */ - PyObject* axes = PyObject_GetAttrString(figure, "axes"); - if (axes==NULL) - { - PyErr_SetString(PyExc_AttributeError, "Failed to find figure axes"); - return NULL; - } - Py_DECREF(axes); /* Don't keep a reference here */ - if (!PyList_Check(axes)) - { - PyErr_SetString(PyExc_TypeError, "Figure axes is not a list"); - return NULL; - } - n = PyList_GET_SIZE(axes); - - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - [button removeAllItems]; - - NSMenu* menu = [button menu]; - [menu addItem: [MenuItem menuItemWithTitle: @"Axes"]]; - - if (n==0) - { - [button setEnabled: NO]; - } - else - { - int i; - [menu addItem: [MenuItem menuItemSelectAll]]; - [menu addItem: [MenuItem menuItemInvertAll]]; - [menu addItem: [NSMenuItem separatorItem]]; - for (i = 0; i < n; i++) - { - [menu addItem: [MenuItem menuItemForAxis: i]]; - } - [button setEnabled: YES]; - } - [pool release]; - Py_RETURN_NONE; -} - -static PyObject* -NavigationToolbar_get_active (NavigationToolbar* self) -{ - NSPopUpButton* button = self->menu; - if (!button) - { - PyErr_SetString(PyExc_RuntimeError, "Menu button is NULL"); - return NULL; - } - NSMenu* menu = [button menu]; - NSArray* items = [menu itemArray]; - size_t n = [items count]; - int* states = calloc(n, sizeof(int)); - if (!states) - { - PyErr_SetString(PyExc_RuntimeError, "calloc failed"); - return NULL; - } - int i; - unsigned int m = 0; - NSEnumerator* enumerator = [items objectEnumerator]; - MenuItem* item; - while ((item = [enumerator nextObject])) - { - if ([item isSeparatorItem]) continue; - i = [item index]; - if (i < 0) continue; - if ([item state]==NSOnState) - { - states[i] = 1; - m++; - } - } - Py_ssize_t list_index = 0; - PyObject* list = PyList_New(m); - - size_t state_index; - for (state_index = 0; state_index < n; state_index++) - { - if(states[state_index]==1) - { - PyList_SET_ITEM(list, list_index++, PyLong_FromSize_t(state_index)); - } - } - free(states); - return list; -} - -static PyMethodDef NavigationToolbar_methods[] = { - {"update", - (PyCFunction)NavigationToolbar_update, - METH_NOARGS, - "Updates the toolbar menu." - }, - {"get_active", - (PyCFunction)NavigationToolbar_get_active, - METH_NOARGS, - "Returns a list of integers identifying which items in the menu are selected." - }, - {NULL} /* Sentinel */ -}; - -static PyTypeObject NavigationToolbarType = { - PyVarObject_HEAD_INIT(NULL, 0) - "_macosx.NavigationToolbar", /*tp_name*/ - sizeof(NavigationToolbar), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)NavigationToolbar_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - (reprfunc)NavigationToolbar_repr, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - NavigationToolbar_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - NavigationToolbar_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)NavigationToolbar_init, /* tp_init */ - 0, /* tp_alloc */ - NavigationToolbar_new, /* tp_new */ -}; - -@interface NavigationToolbar2Handler : NSObject -{ PyObject* toolbar; - NSButton* panbutton; - NSButton* zoombutton; -} -- (NavigationToolbar2Handler*)initWithToolbar:(PyObject*)toolbar; -- (void)installCallbacks:(SEL[7])actions forButtons: (NSButton*[7])buttons; -- (void)home:(id)sender; -- (void)back:(id)sender; -- (void)forward:(id)sender; -- (void)pan:(id)sender; -- (void)zoom:(id)sender; -- (void)configure_subplots:(id)sender; -- (void)save_figure:(id)sender; -@end - -typedef struct { - PyObject_HEAD - NSPopUpButton* menu; - NSText* messagebox; - NavigationToolbar2Handler* handler; -} NavigationToolbar2; - -@implementation NavigationToolbar2Handler -- (NavigationToolbar2Handler*)initWithToolbar:(PyObject*)theToolbar -{ [self init]; - toolbar = theToolbar; - return self; -} - -- (void)installCallbacks:(SEL[7])actions forButtons: (NSButton*[7])buttons -{ - int i; - for (i = 0; i < 7; i++) - { - SEL action = actions[i]; - NSButton* button = buttons[i]; - [button setTarget: self]; - [button setAction: action]; - if (action==@selector(pan:)) panbutton = button; - if (action==@selector(zoom:)) zoombutton = button; - } -} - --(void)home:(id)sender -{ PyObject* result; - PyGILState_STATE gstate; - gstate = PyGILState_Ensure(); - result = PyObject_CallMethod(toolbar, "home", ""); - if(result) - Py_DECREF(result); - else - PyErr_Print(); - PyGILState_Release(gstate); -} - --(void)back:(id)sender -{ PyObject* result; - PyGILState_STATE gstate; - gstate = PyGILState_Ensure(); - result = PyObject_CallMethod(toolbar, "back", ""); - if(result) - Py_DECREF(result); - else - PyErr_Print(); - PyGILState_Release(gstate); -} - --(void)forward:(id)sender -{ PyObject* result; - PyGILState_STATE gstate; - gstate = PyGILState_Ensure(); - result = PyObject_CallMethod(toolbar, "forward", ""); - if(result) - Py_DECREF(result); - else - PyErr_Print(); - PyGILState_Release(gstate); -} - --(void)pan:(id)sender -{ PyObject* result; - PyGILState_STATE gstate; - if ([sender state]) - { - if (zoombutton) [zoombutton setState: NO]; - } - gstate = PyGILState_Ensure(); - result = PyObject_CallMethod(toolbar, "pan", ""); - if(result) - Py_DECREF(result); - else - PyErr_Print(); - PyGILState_Release(gstate); -} - --(void)zoom:(id)sender -{ PyObject* result; - PyGILState_STATE gstate; - if ([sender state]) - { - if (panbutton) [panbutton setState: NO]; - } - gstate = PyGILState_Ensure(); - result = PyObject_CallMethod(toolbar, "zoom", ""); - if(result) - Py_DECREF(result); - else - PyErr_Print(); - PyGILState_Release(gstate); -} - --(void)configure_subplots:(id)sender -{ PyObject* canvas; - View* view; - PyObject* size; - NSRect rect; - int width, height; - - rect.origin.x = 100; - rect.origin.y = 350; - PyGILState_STATE gstate = PyGILState_Ensure(); - PyObject* master = PyObject_GetAttrString(toolbar, "canvas"); - if (master==nil) - { - PyErr_Print(); - PyGILState_Release(gstate); - return; - } - canvas = PyObject_CallMethod(toolbar, "prepare_configure_subplots", ""); - if(!canvas) - { - PyErr_Print(); - Py_DECREF(master); - PyGILState_Release(gstate); - return; - } - - view = ((FigureCanvas*)canvas)->view; - if (!view) /* Something really weird going on */ - { - PyErr_SetString(PyExc_RuntimeError, "NSView* is NULL"); - PyErr_Print(); - Py_DECREF(canvas); - Py_DECREF(master); - PyGILState_Release(gstate); - return; - } - - size = PyObject_CallMethod(canvas, "get_width_height", ""); - Py_DECREF(canvas); - if(!size) - { - PyErr_Print(); - Py_DECREF(master); - PyGILState_Release(gstate); - return; - } - - int ok = PyArg_ParseTuple(size, "ii", &width, &height); - Py_DECREF(size); - if (!ok) - { - PyErr_Print(); - Py_DECREF(master); - PyGILState_Release(gstate); - return; - } - - NSWindow* mw = [((FigureCanvas*)master)->view window]; - Py_DECREF(master); - PyGILState_Release(gstate); - - rect.size.width = width; - rect.size.height = height; - - ToolWindow* window = [ [ToolWindow alloc] initWithContentRect: rect - master: mw]; - [window setContentView: view]; - [view release]; - [window makeKeyAndOrderFront: nil]; -} - --(void)save_figure:(id)sender -{ PyObject* result; - PyGILState_STATE gstate; - gstate = PyGILState_Ensure(); - result = PyObject_CallMethod(toolbar, "save_figure", ""); - if(result) - Py_DECREF(result); - else - PyErr_Print(); - PyGILState_Release(gstate); -} -@end - -static PyObject* -NavigationToolbar2_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - NavigationToolbar2Handler* handler = [NavigationToolbar2Handler alloc]; - if (!handler) return NULL; - NavigationToolbar2 *self = (NavigationToolbar2*)type->tp_alloc(type, 0); - if (!self) - { - [handler release]; - return NULL; - } - self->handler = handler; - return (PyObject*)self; -} - -static int -NavigationToolbar2_init(NavigationToolbar2 *self, PyObject *args, PyObject *kwds) -{ - PyObject* obj; - FigureCanvas* canvas; - View* view; - - int i; - NSRect rect; - NSSize size; - NSSize scale; - - const float gap = 2; - const int height = 36; - const int imagesize = 24; - - const char* basedir; - - obj = PyObject_GetAttrString((PyObject*)self, "canvas"); - if (obj==NULL) - { - PyErr_SetString(PyExc_AttributeError, "Attempt to install toolbar for NULL canvas"); - return -1; - } - Py_DECREF(obj); /* Don't increase the reference count */ - if (!PyObject_IsInstance(obj, (PyObject*) &FigureCanvasType)) - { - PyErr_SetString(PyExc_TypeError, "Attempt to install toolbar for object that is not a FigureCanvas"); - return -1; - } - canvas = (FigureCanvas*)obj; - view = canvas->view; - if(!view) - { - PyErr_SetString(PyExc_RuntimeError, "NSView* is NULL"); - return -1; - } - - if(!PyArg_ParseTuple(args, "s", &basedir)) return -1; - - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSRect bounds = [view bounds]; - NSWindow* window = [view window]; - - bounds.origin.y += height; - [view setFrame: bounds]; - - bounds.size.height += height; - [window setContentSize: bounds.size]; - - NSString* dir = [NSString stringWithCString: basedir - encoding: NSASCIIStringEncoding]; - - NSButton* buttons[7]; - - NSString* images[7] = {@"home.pdf", - @"back.pdf", - @"forward.pdf", - @"move.pdf", - @"zoom_to_rect.pdf", - @"subplots.pdf", - @"filesave.pdf"}; - - NSString* tooltips[7] = {@"Reset original view", - @"Back to previous view", - @"Forward to next view", - @"Pan axes with left mouse, zoom with right", - @"Zoom to rectangle", - @"Configure subplots", - @"Save the figure"}; - - SEL actions[7] = {@selector(home:), - @selector(back:), - @selector(forward:), - @selector(pan:), - @selector(zoom:), - @selector(configure_subplots:), - @selector(save_figure:)}; - - NSButtonType buttontypes[7] = {NSMomentaryLightButton, - NSMomentaryLightButton, - NSMomentaryLightButton, - NSPushOnPushOffButton, - NSPushOnPushOffButton, - NSMomentaryLightButton, - NSMomentaryLightButton}; - - rect.origin.x = 0; - rect.origin.y = 0; - rect.size.width = imagesize; - rect.size.height = imagesize; -#ifdef COMPILING_FOR_10_7 - rect = [window convertRectToBacking: rect]; -#endif - size = rect.size; - scale.width = imagesize / size.width; - scale.height = imagesize / size.height; - - rect.size.width = 32; - rect.size.height = 32; - rect.origin.x = gap; - rect.origin.y = 0.5*(height - rect.size.height); - - for (i = 0; i < 7; i++) - { - NSString* filename = [dir stringByAppendingPathComponent: images[i]]; - NSImage* image = [[NSImage alloc] initWithContentsOfFile: filename]; - buttons[i] = [[NSButton alloc] initWithFrame: rect]; - [image setSize: size]; - [buttons[i] setBezelStyle: NSShadowlessSquareBezelStyle]; - [buttons[i] setButtonType: buttontypes[i]]; - [buttons[i] setImage: image]; - [buttons[i] scaleUnitSquareToSize: scale]; - [buttons[i] setImagePosition: NSImageOnly]; - [buttons[i] setToolTip: tooltips[i]]; - [[window contentView] addSubview: buttons[i]]; - [buttons[i] release]; - [image release]; - rect.origin.x += rect.size.width + gap; - } - - self->handler = [self->handler initWithToolbar: (PyObject*)self]; - [self->handler installCallbacks: actions forButtons: buttons]; - - NSFont* font = [NSFont systemFontOfSize: 0.0]; - rect.size.width = 300; - rect.size.height = 0; - rect.origin.x += height; - NSText* messagebox = [[NSText alloc] initWithFrame: rect]; - [messagebox setFont: font]; - [messagebox setDrawsBackground: NO]; - [messagebox setSelectable: NO]; - /* if selectable, the messagebox can become first responder, - * which is not supposed to happen */ - rect = [messagebox frame]; - rect.origin.y = 0.5 * (height - rect.size.height); - [messagebox setFrameOrigin: rect.origin]; - [[window contentView] addSubview: messagebox]; - [messagebox release]; - [[window contentView] display]; - - [pool release]; - - self->messagebox = messagebox; - return 0; -} - -static void -NavigationToolbar2_dealloc(NavigationToolbar2 *self) -{ - [self->handler release]; - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static PyObject* -NavigationToolbar2_repr(NavigationToolbar2* self) -{ -#if PY3K - return PyUnicode_FromFormat("NavigationToolbar2 object %p", (void*)self); -#else - return PyString_FromFormat("NavigationToolbar2 object %p", (void*)self); -#endif -} - -static char NavigationToolbar2_doc[] = -"NavigationToolbar2\n"; - -static PyObject* -NavigationToolbar2_set_message(NavigationToolbar2 *self, PyObject* args) -{ - const char* message; - -#if PY3K - if(!PyArg_ParseTuple(args, "y", &message)) return NULL; -#else - if(!PyArg_ParseTuple(args, "s", &message)) return NULL; -#endif - - NSText* messagebox = self->messagebox; - - if (messagebox) - { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSString* text = [NSString stringWithUTF8String: message]; - [messagebox setString: text]; - [pool release]; - } - - Py_RETURN_NONE; -} - -static PyMethodDef NavigationToolbar2_methods[] = { - {"set_message", - (PyCFunction)NavigationToolbar2_set_message, - METH_VARARGS, - "Set the message to be displayed on the toolbar." - }, - {NULL} /* Sentinel */ -}; - -static PyTypeObject NavigationToolbar2Type = { - PyVarObject_HEAD_INIT(NULL, 0) - "_macosx.NavigationToolbar2", /*tp_name*/ - sizeof(NavigationToolbar2), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)NavigationToolbar2_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - (reprfunc)NavigationToolbar2_repr, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - NavigationToolbar2_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - NavigationToolbar2_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - (initproc)NavigationToolbar2_init, /* tp_init */ - 0, /* tp_alloc */ - NavigationToolbar2_new, /* tp_new */ -}; - -static PyObject* -choose_save_file(PyObject* unused, PyObject* args) -{ - int result; - const char* title; - char* default_filename; - if(!PyArg_ParseTuple(args, "ses", &title, "UTF-8", &default_filename)) - return NULL; - - NSSavePanel* panel = [NSSavePanel savePanel]; - [panel setTitle: [NSString stringWithCString: title - encoding: NSASCIIStringEncoding]]; - NSString* ns_default_filename = - [[NSString alloc] - initWithCString: default_filename - encoding: NSUTF8StringEncoding]; - PyMem_Free(default_filename); -#ifdef COMPILING_FOR_10_6 - [panel setNameFieldStringValue: ns_default_filename]; - result = [panel runModal]; -#else - result = [panel runModalForDirectory: nil file: ns_default_filename]; -#endif - [ns_default_filename release]; -#ifdef COMPILING_FOR_10_10 - if (result == NSModalResponseOK) -#else - if (result == NSOKButton) -#endif - { -#ifdef COMPILING_FOR_10_6 - NSURL* url = [panel URL]; - NSString* filename = [url path]; - if (!filename) { - PyErr_SetString(PyExc_RuntimeError, "Failed to obtain filename"); - return 0; - } -#else - NSString* filename = [panel filename]; -#endif - unsigned int n = [filename length]; - unichar* buffer = malloc(n*sizeof(unichar)); - [filename getCharacters: buffer]; -#if PY3K - PyObject* string = PyUnicode_FromKindAndData(PyUnicode_2BYTE_KIND, buffer, n); -#else - PyObject* string = PyUnicode_FromUnicode(buffer, n); -#endif - free(buffer); - return string; - } - Py_RETURN_NONE; -} - -static PyObject* -set_cursor(PyObject* unused, PyObject* args) -{ - int i; - if(!PyArg_ParseTuple(args, "i", &i)) return NULL; - switch (i) - { case 0: [[NSCursor pointingHandCursor] set]; break; - case 1: [[NSCursor arrowCursor] set]; break; - case 2: [[NSCursor crosshairCursor] set]; break; - case 3: [[NSCursor openHandCursor] set]; break; - /* OSX handles busy state itself so no need to set a cursor here */ - case 4: break; - default: return NULL; - } - Py_RETURN_NONE; -} - -@implementation WindowServerConnectionManager -static WindowServerConnectionManager *sharedWindowServerConnectionManager = nil; - -+ (WindowServerConnectionManager *)sharedManager -{ - if (sharedWindowServerConnectionManager == nil) - { - sharedWindowServerConnectionManager = [[super allocWithZone:NULL] init]; - } - return sharedWindowServerConnectionManager; -} - -+ (id)allocWithZone:(NSZone *)zone -{ - return [[self sharedManager] retain]; -} - -+ (id)copyWithZone:(NSZone *)zone -{ - return self; -} - -+ (id)retain -{ - return self; -} - -- (NSUInteger)retainCount -{ - return NSUIntegerMax; //denotes an object that cannot be released -} - -- (oneway void)release -{ - // Don't release a singleton object -} - -- (id)autorelease -{ - return self; -} - -- (void)launch:(NSNotification*)notification -{ - CFRunLoopRef runloop; - CFMachPortRef port; - CFRunLoopSourceRef source; - NSDictionary* dictionary = [notification userInfo]; - if (! [[dictionary valueForKey:@"NSApplicationName"] - isEqualToString:@"Python"]) - return; - NSNumber* psnLow = [dictionary valueForKey: @"NSApplicationProcessSerialNumberLow"]; - NSNumber* psnHigh = [dictionary valueForKey: @"NSApplicationProcessSerialNumberHigh"]; - ProcessSerialNumber psn; - psn.highLongOfPSN = [psnHigh intValue]; - psn.lowLongOfPSN = [psnLow intValue]; - runloop = CFRunLoopGetCurrent(); - port = CGEventTapCreateForPSN(&psn, - kCGHeadInsertEventTap, - kCGEventTapOptionListenOnly, - kCGEventMaskForAllEvents, - &_eventtap_callback, - runloop); - source = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, - port, - 0); - CFRunLoopAddSource(runloop, source, kCFRunLoopDefaultMode); - CFRelease(port); -} -@end - -@implementation Window -- (Window*)initWithContentRect:(NSRect)rect styleMask:(unsigned int)mask backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation withManager: (PyObject*)theManager -{ - self = [super initWithContentRect: rect - styleMask: mask - backing: bufferingType - defer: deferCreation]; - manager = theManager; - Py_INCREF(manager); - return self; -} - -- (NSRect)constrainFrameRect:(NSRect)rect toScreen:(NSScreen*)screen -{ - /* Allow window sizes larger than the screen */ - NSRect suggested = [super constrainFrameRect: rect toScreen: screen]; - const CGFloat difference = rect.size.height - suggested.size.height; - suggested.origin.y -= difference; - suggested.size.height += difference; - return suggested; -} - -- (BOOL)closeButtonPressed -{ - PyObject* result; - PyGILState_STATE gstate; - gstate = PyGILState_Ensure(); - result = PyObject_CallMethod(manager, "close", ""); - if(result) - Py_DECREF(result); - else - PyErr_Print(); - PyGILState_Release(gstate); - return YES; -} - -- (void)close -{ - [super close]; - --FigureWindowCount; - if (!FigureWindowCount) [NSApp stop: self]; - /* This is needed for show(), which should exit from [NSApp run] - * after all windows are closed. - */ -} - -- (void)dealloc -{ - PyGILState_STATE gstate; - gstate = PyGILState_Ensure(); - Py_DECREF(manager); - PyGILState_Release(gstate); - /* The reference count of the view that was added as a subview to the - * content view of this window was increased during the call to addSubview, - * and is decreased during the call to [super dealloc]. - */ - [super dealloc]; -} -@end - -@implementation ToolWindow -- (ToolWindow*)initWithContentRect:(NSRect)rect master:(NSWindow*)window -{ - [self initWithContentRect: rect - styleMask: NSTitledWindowMask - | NSClosableWindowMask - | NSResizableWindowMask - | NSMiniaturizableWindowMask - backing: NSBackingStoreBuffered - defer: YES]; - [self setTitle: @"Subplot Configuration Tool"]; - [[NSNotificationCenter defaultCenter] addObserver: self - selector: @selector(masterCloses:) - name: NSWindowWillCloseNotification - object: window]; - return self; -} - -- (void)masterCloses:(NSNotification*)notification -{ - [self close]; -} - -- (void)close -{ - [[NSNotificationCenter defaultCenter] removeObserver: self]; - [super close]; -} -@end - -@implementation View -- (BOOL)isFlipped -{ - return NO; -} - -- (View*)initWithFrame:(NSRect)rect -{ - self = [super initWithFrame: rect]; - rubberband = NSZeroRect; - inside = false; - tracking = 0; - device_scale = 1; - return self; -} - -- (void)dealloc -{ - FigureCanvas* fc = (FigureCanvas*)canvas; - if (fc) fc->view = NULL; - [self removeTrackingRect: tracking]; - [super dealloc]; -} - -- (void)setCanvas: (PyObject*)newCanvas -{ - canvas = newCanvas; -} - -static void _buffer_release(void* info, const void* data, size_t size) { - PyBuffer_Release((Py_buffer *)info); -} - -static int _copy_agg_buffer(CGContextRef cr, PyObject *renderer) -{ - Py_buffer buffer; - - if (PyObject_GetBuffer(renderer, &buffer, PyBUF_CONTIG_RO) == -1) { - PyErr_Print(); - return 1; - } - - if (buffer.ndim != 3 || buffer.shape[2] != 4) { - PyBuffer_Release(&buffer); - return 1; - } - - const Py_ssize_t nrows = buffer.shape[0]; - const Py_ssize_t ncols = buffer.shape[1]; - const size_t bytesPerComponent = 1; - const size_t bitsPerComponent = 8 * bytesPerComponent; - const size_t nComponents = 4; /* red, green, blue, alpha */ - const size_t bitsPerPixel = bitsPerComponent * nComponents; - const size_t bytesPerRow = nComponents * bytesPerComponent * ncols; - - CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); - if (!colorspace) { - PyBuffer_Release(&buffer); - return 1; - } - - CGDataProviderRef provider = CGDataProviderCreateWithData(&buffer, - buffer.buf, - buffer.len, - _buffer_release); - if (!provider) { - PyBuffer_Release(&buffer); - CGColorSpaceRelease(colorspace); - return 1; - } - - CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault | kCGImageAlphaLast; - CGImageRef bitmap = CGImageCreate(ncols, - nrows, - bitsPerComponent, - bitsPerPixel, - bytesPerRow, - colorspace, - bitmapInfo, - provider, - NULL, - false, - kCGRenderingIntentDefault); - CGColorSpaceRelease(colorspace); - CGDataProviderRelease(provider); - - if (!bitmap) { - PyBuffer_Release(&buffer); - return 1; - } - - CGFloat deviceScale = _get_device_scale(cr); - CGContextSaveGState(cr); - CGContextDrawImage(cr, CGRectMake(0, 0, ncols/deviceScale, nrows/deviceScale), bitmap); - CGImageRelease(bitmap); - CGContextRestoreGState(cr); - - return 0; -} - --(void)drawRect:(NSRect)rect -{ - PyObject* renderer = NULL; - PyObject* renderer_buffer = NULL; - - PyGILState_STATE gstate = PyGILState_Ensure(); - - CGContextRef cr = [[NSGraphicsContext currentContext] graphicsPort]; - - double new_device_scale = _get_device_scale(cr); - - if (device_scale != new_device_scale) { - device_scale = new_device_scale; - if (!PyObject_CallMethod(canvas, "_set_device_scale", "d", device_scale, NULL)) { - PyErr_Print(); - goto exit; - } - } - - renderer = PyObject_CallMethod(canvas, "_draw", "", NULL); - if (!renderer) - { - PyErr_Print(); - goto exit; - } - - renderer_buffer = PyObject_GetAttrString(renderer, "_renderer"); - if (!renderer_buffer) { - PyErr_Print(); - goto exit; - } - - if (_copy_agg_buffer(cr, renderer_buffer)) { - printf("copy_agg_buffer failed\n"); - goto exit; - } - - - if (!NSIsEmptyRect(rubberband)) { - NSFrameRect(rubberband); - } - - exit: - Py_XDECREF(renderer_buffer); - Py_XDECREF(renderer); - - PyGILState_Release(gstate); -} - -- (void)windowDidResize: (NSNotification*)notification -{ - int width, height; - Window* window = [notification object]; - NSSize size = [[window contentView] frame].size; - NSRect rect = [self frame]; - - size.height -= rect.origin.y; - width = size.width; - height = size.height; - - [self setFrameSize: size]; - - PyGILState_STATE gstate = PyGILState_Ensure(); - PyObject* result = PyObject_CallMethod( - canvas, "resize", "ii", width, height); - if(result) - Py_DECREF(result); - else - PyErr_Print(); - PyGILState_Release(gstate); - if (tracking) [self removeTrackingRect: tracking]; - tracking = [self addTrackingRect: [self bounds] - owner: self - userData: nil - assumeInside: NO]; - [self setNeedsDisplay: YES]; -} - -- (void)windowWillClose:(NSNotification*)notification -{ - PyGILState_STATE gstate; - PyObject* result; - - gstate = PyGILState_Ensure(); - result = PyObject_CallMethod(canvas, "close_event", ""); - if(result) - Py_DECREF(result); - else - PyErr_Print(); - PyGILState_Release(gstate); -} - -- (BOOL)windowShouldClose:(NSNotification*)notification -{ - NSWindow* window = [self window]; - NSEvent* event = [NSEvent otherEventWithType: NSApplicationDefined - location: NSZeroPoint - modifierFlags: 0 - timestamp: 0.0 - windowNumber: 0 - context: nil - subtype: WINDOW_CLOSING - data1: 0 - data2: 0]; - [NSApp postEvent: event atStart: true]; - if ([window respondsToSelector: @selector(closeButtonPressed)]) - { BOOL closed = [((Window*) window) closeButtonPressed]; - /* If closed, the window has already been closed via the manager. */ - if (closed) return NO; - } - return YES; -} - -- (void)mouseEntered:(NSEvent *)event -{ - PyGILState_STATE gstate; - PyObject* result; - NSWindow* window = [self window]; - if ([window isKeyWindow]==false) return; - - gstate = PyGILState_Ensure(); - result = PyObject_CallMethod(canvas, "enter_notify_event", ""); - if(result) - Py_DECREF(result); - else - PyErr_Print(); - PyGILState_Release(gstate); - - [window setAcceptsMouseMovedEvents: YES]; - inside = true; -} - -- (void)mouseExited:(NSEvent *)event -{ - PyGILState_STATE gstate; - PyObject* result; - NSWindow* window = [self window]; - if ([window isKeyWindow]==false) return; - - if (inside==false) return; - gstate = PyGILState_Ensure(); - result = PyObject_CallMethod(canvas, "leave_notify_event", ""); - if(result) - Py_DECREF(result); - else - PyErr_Print(); - PyGILState_Release(gstate); - - [[self window] setAcceptsMouseMovedEvents: NO]; - inside = false; -} - -- (void)mouseDown:(NSEvent *)event -{ - int x, y; - int num; - int dblclick = 0; - PyObject* result; - PyGILState_STATE gstate; - NSPoint location = [event locationInWindow]; - location = [self convertPoint: location fromView: nil]; - x = location.x * device_scale; - y = location.y * device_scale; - switch ([event type]) - { case NSLeftMouseDown: - { unsigned int modifier = [event modifierFlags]; - if (modifier & NSControlKeyMask) - /* emulate a right-button click */ - num = 3; - else if (modifier & NSAlternateKeyMask) - /* emulate a middle-button click */ - num = 2; - else - { - num = 1; - if ([NSCursor currentCursor]==[NSCursor openHandCursor]) - [[NSCursor closedHandCursor] set]; - } - break; - } - case NSOtherMouseDown: num = 2; break; - case NSRightMouseDown: num = 3; break; - default: return; /* Unknown mouse event */ - } - if ([event clickCount] == 2) { - dblclick = 1; - } - gstate = PyGILState_Ensure(); - result = PyObject_CallMethod(canvas, "button_press_event", "iiii", x, y, num, dblclick); - if(result) - Py_DECREF(result); - else - PyErr_Print(); - - PyGILState_Release(gstate); -} - -- (void)mouseUp:(NSEvent *)event -{ - int num; - int x, y; - PyObject* result; - PyGILState_STATE gstate; - NSPoint location = [event locationInWindow]; - location = [self convertPoint: location fromView: nil]; - x = location.x * device_scale; - y = location.y * device_scale; - switch ([event type]) - { case NSLeftMouseUp: - num = 1; - if ([NSCursor currentCursor]==[NSCursor closedHandCursor]) - [[NSCursor openHandCursor] set]; - break; - case NSOtherMouseUp: num = 2; break; - case NSRightMouseUp: num = 3; break; - default: return; /* Unknown mouse event */ - } - gstate = PyGILState_Ensure(); - result = PyObject_CallMethod(canvas, "button_release_event", "iii", x, y, num); - if(result) - Py_DECREF(result); - else - PyErr_Print(); - - PyGILState_Release(gstate); -} - -- (void)mouseMoved:(NSEvent *)event -{ - int x, y; - NSPoint location = [event locationInWindow]; - location = [self convertPoint: location fromView: nil]; - x = location.x * device_scale; - y = location.y * device_scale; - PyGILState_STATE gstate = PyGILState_Ensure(); - PyObject* result = PyObject_CallMethod(canvas, "motion_notify_event", "ii", x, y); - if(result) - Py_DECREF(result); - else - PyErr_Print(); - - PyGILState_Release(gstate); -} - -- (void)mouseDragged:(NSEvent *)event -{ - int x, y; - NSPoint location = [event locationInWindow]; - location = [self convertPoint: location fromView: nil]; - x = location.x * device_scale; - y = location.y * device_scale; - PyGILState_STATE gstate = PyGILState_Ensure(); - PyObject* result = PyObject_CallMethod(canvas, "motion_notify_event", "ii", x, y); - if(result) - Py_DECREF(result); - else - PyErr_Print(); - - PyGILState_Release(gstate); -} - -- (void)rightMouseDown:(NSEvent *)event -{ - int x, y; - int num = 3; - int dblclick = 0; - PyObject* result; - PyGILState_STATE gstate; - NSPoint location = [event locationInWindow]; - location = [self convertPoint: location fromView: nil]; - x = location.x * device_scale; - y = location.y * device_scale; - gstate = PyGILState_Ensure(); - if ([event clickCount] == 2) { - dblclick = 1; - } - result = PyObject_CallMethod(canvas, "button_press_event", "iiii", x, y, num, dblclick); - if(result) - Py_DECREF(result); - else - PyErr_Print(); - - PyGILState_Release(gstate); -} - -- (void)rightMouseUp:(NSEvent *)event -{ - int x, y; - int num = 3; - PyObject* result; - PyGILState_STATE gstate; - NSPoint location = [event locationInWindow]; - location = [self convertPoint: location fromView: nil]; - x = location.x * device_scale; - y = location.y * device_scale; - gstate = PyGILState_Ensure(); - result = PyObject_CallMethod(canvas, "button_release_event", "iii", x, y, num); - if(result) - Py_DECREF(result); - else - PyErr_Print(); - - PyGILState_Release(gstate); -} - -- (void)rightMouseDragged:(NSEvent *)event -{ - int x, y; - NSPoint location = [event locationInWindow]; - location = [self convertPoint: location fromView: nil]; - x = location.x * device_scale; - y = location.y * device_scale; - PyGILState_STATE gstate = PyGILState_Ensure(); - PyObject* result = PyObject_CallMethod(canvas, "motion_notify_event", "ii", x, y); - if(result) - Py_DECREF(result); - else - PyErr_Print(); - - PyGILState_Release(gstate); -} - -- (void)otherMouseDown:(NSEvent *)event -{ - int x, y; - int num = 2; - int dblclick = 0; - PyObject* result; - PyGILState_STATE gstate; - NSPoint location = [event locationInWindow]; - location = [self convertPoint: location fromView: nil]; - x = location.x * device_scale; - y = location.y * device_scale; - gstate = PyGILState_Ensure(); - if ([event clickCount] == 2) { - dblclick = 1; - } - result = PyObject_CallMethod(canvas, "button_press_event", "iiii", x, y, num, dblclick); - if(result) - Py_DECREF(result); - else - PyErr_Print(); - - PyGILState_Release(gstate); -} - -- (void)otherMouseUp:(NSEvent *)event -{ - int x, y; - int num = 2; - PyObject* result; - PyGILState_STATE gstate; - NSPoint location = [event locationInWindow]; - location = [self convertPoint: location fromView: nil]; - x = location.x * device_scale; - y = location.y * device_scale; - gstate = PyGILState_Ensure(); - result = PyObject_CallMethod(canvas, "button_release_event", "iii", x, y, num); - if(result) - Py_DECREF(result); - else - PyErr_Print(); - - PyGILState_Release(gstate); -} - -- (void)otherMouseDragged:(NSEvent *)event -{ - int x, y; - NSPoint location = [event locationInWindow]; - location = [self convertPoint: location fromView: nil]; - x = location.x * device_scale; - y = location.y * device_scale; - PyGILState_STATE gstate = PyGILState_Ensure(); - PyObject* result = PyObject_CallMethod(canvas, "motion_notify_event", "ii", x, y); - if(result) - Py_DECREF(result); - else - PyErr_Print(); - - PyGILState_Release(gstate); -} - -- (void)setRubberband:(NSRect)rect -{ - if (!NSIsEmptyRect(rubberband)) [self setNeedsDisplayInRect: rubberband]; - rubberband = rect; - [self setNeedsDisplayInRect: rubberband]; -} - -- (void)removeRubberband -{ - if (NSIsEmptyRect(rubberband)) return; - [self setNeedsDisplayInRect: rubberband]; - rubberband = NSZeroRect; -} - - - -- (const char*)convertKeyEvent:(NSEvent*)event -{ - NSDictionary* specialkeymappings = [NSDictionary dictionaryWithObjectsAndKeys: - @"left", [NSNumber numberWithUnsignedLong:NSLeftArrowFunctionKey], - @"right", [NSNumber numberWithUnsignedLong:NSRightArrowFunctionKey], - @"up", [NSNumber numberWithUnsignedLong:NSUpArrowFunctionKey], - @"down", [NSNumber numberWithUnsignedLong:NSDownArrowFunctionKey], - @"f1", [NSNumber numberWithUnsignedLong:NSF1FunctionKey], - @"f2", [NSNumber numberWithUnsignedLong:NSF2FunctionKey], - @"f3", [NSNumber numberWithUnsignedLong:NSF3FunctionKey], - @"f4", [NSNumber numberWithUnsignedLong:NSF4FunctionKey], - @"f5", [NSNumber numberWithUnsignedLong:NSF5FunctionKey], - @"f6", [NSNumber numberWithUnsignedLong:NSF6FunctionKey], - @"f7", [NSNumber numberWithUnsignedLong:NSF7FunctionKey], - @"f8", [NSNumber numberWithUnsignedLong:NSF8FunctionKey], - @"f9", [NSNumber numberWithUnsignedLong:NSF9FunctionKey], - @"f10", [NSNumber numberWithUnsignedLong:NSF10FunctionKey], - @"f11", [NSNumber numberWithUnsignedLong:NSF11FunctionKey], - @"f12", [NSNumber numberWithUnsignedLong:NSF12FunctionKey], - @"f13", [NSNumber numberWithUnsignedLong:NSF13FunctionKey], - @"f14", [NSNumber numberWithUnsignedLong:NSF14FunctionKey], - @"f15", [NSNumber numberWithUnsignedLong:NSF15FunctionKey], - @"f16", [NSNumber numberWithUnsignedLong:NSF16FunctionKey], - @"f17", [NSNumber numberWithUnsignedLong:NSF17FunctionKey], - @"f18", [NSNumber numberWithUnsignedLong:NSF18FunctionKey], - @"f19", [NSNumber numberWithUnsignedLong:NSF19FunctionKey], - @"scroll_lock", [NSNumber numberWithUnsignedLong:NSScrollLockFunctionKey], - @"break", [NSNumber numberWithUnsignedLong:NSBreakFunctionKey], - @"insert", [NSNumber numberWithUnsignedLong:NSInsertFunctionKey], - @"delete", [NSNumber numberWithUnsignedLong:NSDeleteFunctionKey], - @"home", [NSNumber numberWithUnsignedLong:NSHomeFunctionKey], - @"end", [NSNumber numberWithUnsignedLong:NSEndFunctionKey], - @"pagedown", [NSNumber numberWithUnsignedLong:NSPageDownFunctionKey], - @"pageup", [NSNumber numberWithUnsignedLong:NSPageUpFunctionKey], - @"backspace", [NSNumber numberWithUnsignedLong:NSDeleteCharacter], - @"enter", [NSNumber numberWithUnsignedLong:NSEnterCharacter], - @"tab", [NSNumber numberWithUnsignedLong:NSTabCharacter], - @"enter", [NSNumber numberWithUnsignedLong:NSCarriageReturnCharacter], - @"backtab", [NSNumber numberWithUnsignedLong:NSBackTabCharacter], - @"escape", [NSNumber numberWithUnsignedLong:27], - nil - ]; - - NSMutableString* returnkey = [NSMutableString string]; - if ([event modifierFlags] & NSControlKeyMask) - [returnkey appendString:@"ctrl+" ]; - if ([event modifierFlags] & NSAlternateKeyMask) - [returnkey appendString:@"alt+" ]; - if ([event modifierFlags] & NSCommandKeyMask) - [returnkey appendString:@"cmd+" ]; - - unichar uc = [[event charactersIgnoringModifiers] characterAtIndex:0]; - NSString* specialchar = [specialkeymappings objectForKey:[NSNumber numberWithUnsignedLong:uc]]; - if (specialchar){ - if ([event modifierFlags] & NSShiftKeyMask) - [returnkey appendString:@"shift+" ]; - [returnkey appendString:specialchar]; - } - else - [returnkey appendString:[event charactersIgnoringModifiers]]; - - return [returnkey UTF8String]; -} - -- (void)keyDown:(NSEvent*)event -{ - PyObject* result; - const char* s = [self convertKeyEvent: event]; - PyGILState_STATE gstate = PyGILState_Ensure(); - if (s==NULL) - { - result = PyObject_CallMethod(canvas, "key_press_event", "O", Py_None); - } - else - { - result = PyObject_CallMethod(canvas, "key_press_event", "s", s); - } - if(result) - Py_DECREF(result); - else - PyErr_Print(); - - PyGILState_Release(gstate); -} - -- (void)keyUp:(NSEvent*)event -{ - PyObject* result; - const char* s = [self convertKeyEvent: event]; - PyGILState_STATE gstate = PyGILState_Ensure(); - if (s==NULL) - { - result = PyObject_CallMethod(canvas, "key_release_event", "O", Py_None); - } - else - { - result = PyObject_CallMethod(canvas, "key_release_event", "s", s); - } - if(result) - Py_DECREF(result); - else - PyErr_Print(); - - PyGILState_Release(gstate); -} - -- (void)scrollWheel:(NSEvent*)event -{ - int step; - float d = [event deltaY]; - if (d > 0) step = 1; - else if (d < 0) step = -1; - else return; - NSPoint location = [event locationInWindow]; - NSPoint point = [self convertPoint: location fromView: nil]; - int x = (int)round(point.x * device_scale); - int y = (int)round(point.y * device_scale - 1); - - PyObject* result; - PyGILState_STATE gstate = PyGILState_Ensure(); - result = PyObject_CallMethod(canvas, "scroll_event", "iii", x, y, step); - if(result) - Py_DECREF(result); - else - PyErr_Print(); - - PyGILState_Release(gstate); -} - -- (BOOL)acceptsFirstResponder -{ - return YES; -} - -/* This is all wrong. Address of pointer is being passed instead of pointer, keynames don't - match up with what the front-end and does the front-end even handle modifier keys by themselves? - -- (void)flagsChanged:(NSEvent*)event -{ - const char *s = NULL; - if (([event modifierFlags] & NSControlKeyMask) == NSControlKeyMask) - s = "control"; - else if (([event modifierFlags] & NSShiftKeyMask) == NSShiftKeyMask) - s = "shift"; - else if (([event modifierFlags] & NSAlternateKeyMask) == NSAlternateKeyMask) - s = "alt"; - else return; - PyGILState_STATE gstate = PyGILState_Ensure(); - PyObject* result = PyObject_CallMethod(canvas, "key_press_event", "s", &s); - if(result) - Py_DECREF(result); - else - PyErr_Print(); - - PyGILState_Release(gstate); -} - */ -@end - -@implementation ScrollableButton -- (void)setScrollWheelUpAction:(SEL)action -{ - scrollWheelUpAction = action; -} - -- (void)setScrollWheelDownAction:(SEL)action -{ - scrollWheelDownAction = action; -} - -- (void)scrollWheel:(NSEvent*)event -{ - float d = [event deltaY]; - Window* target = [self target]; - if (d > 0) - [NSApp sendAction: scrollWheelUpAction to: target from: self]; - else if (d < 0) - [NSApp sendAction: scrollWheelDownAction to: target from: self]; -} -@end - -@implementation MenuItem -+ (MenuItem*)menuItemWithTitle: (NSString*)title -{ - MenuItem* item = [[MenuItem alloc] initWithTitle: title - action: nil - keyEquivalent: @""]; - item->index = -1; - return [item autorelease]; -} - -+ (MenuItem*)menuItemForAxis: (int)i -{ - NSString* title = [NSString stringWithFormat: @"Axis %d", i+1]; - MenuItem* item = [[MenuItem alloc] initWithTitle: title - action: @selector(toggle:) - keyEquivalent: @""]; - [item setTarget: item]; - [item setState: NSOnState]; - item->index = i; - return [item autorelease]; -} - -+ (MenuItem*)menuItemSelectAll -{ - MenuItem* item = [[MenuItem alloc] initWithTitle: @"Select All" - action: @selector(selectAll:) - keyEquivalent: @""]; - [item setTarget: item]; - item->index = -1; - return [item autorelease]; -} - -+ (MenuItem*)menuItemInvertAll -{ - MenuItem* item = [[MenuItem alloc] initWithTitle: @"Invert All" - action: @selector(invertAll:) - keyEquivalent: @""]; - [item setTarget: item]; - item->index = -1; - return [item autorelease]; -} - -- (void)toggle:(id)sender -{ - if ([self state]) [self setState: NSOffState]; - else [self setState: NSOnState]; -} - -- (void)selectAll:(id)sender -{ - NSMenu* menu = [sender menu]; - if(!menu) return; /* Weird */ - NSArray* items = [menu itemArray]; - NSEnumerator* enumerator = [items objectEnumerator]; - MenuItem* item; - while ((item = [enumerator nextObject])) - { - if (item->index >= 0) [item setState: NSOnState]; - } -} - -- (void)invertAll:(id)sender -{ - NSMenu* menu = [sender menu]; - if(!menu) return; /* Weird */ - NSArray* items = [menu itemArray]; - NSEnumerator* enumerator = [items objectEnumerator]; - MenuItem* item; - while ((item = [enumerator nextObject])) - { - if (item->index < 0) continue; - if ([item state]==NSOffState) [item setState: NSOnState]; - else [item setState: NSOffState]; - } -} - -- (int)index -{ - return self->index; -} -@end - -static PyObject* -show(PyObject* self) -{ - [NSApp activateIgnoringOtherApps: YES]; - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSArray *windowsArray = [NSApp windows]; - NSEnumerator *enumerator = [windowsArray objectEnumerator]; - NSWindow *window; - while ((window = [enumerator nextObject])) { - [window orderFront:nil]; - } - [pool release]; - Py_BEGIN_ALLOW_THREADS - [NSApp run]; - Py_END_ALLOW_THREADS - Py_RETURN_NONE; -} - -typedef struct { - PyObject_HEAD - CFRunLoopTimerRef timer; -} Timer; - -static PyObject* -Timer_new(PyTypeObject* type, PyObject *args, PyObject *kwds) -{ - Timer* self = (Timer*)type->tp_alloc(type, 0); - if (!self) return NULL; - self->timer = NULL; - return (PyObject*) self; -} - -static PyObject* -Timer_repr(Timer* self) -{ -#if PY3K - return PyUnicode_FromFormat("Timer object %p wrapping CFRunLoopTimerRef %p", - (void*) self, (void*)(self->timer)); -#else - return PyString_FromFormat("Timer object %p wrapping CFRunLoopTimerRef %p", - (void*) self, (void*)(self->timer)); -#endif -} - -static char Timer_doc[] = -"A Timer object wraps a CFRunLoopTimerRef and can add it to the event loop.\n"; - -static void timer_callback(CFRunLoopTimerRef timer, void* info) -{ - PyObject* method = info; - PyGILState_STATE gstate = PyGILState_Ensure(); - PyObject* result = PyObject_CallFunction(method, NULL); - if (result) { - Py_DECREF(result); - } else { - PyErr_Print(); - } - PyGILState_Release(gstate); -} - -static void context_cleanup(const void* info) -{ - Py_DECREF((PyObject*)info); -} - -static PyObject* -Timer__timer_start(Timer* self, PyObject* args) -{ - CFRunLoopRef runloop; - CFRunLoopTimerRef timer; - CFRunLoopTimerContext context; - double milliseconds; - CFTimeInterval interval; - PyObject* attribute; - PyObject* failure; - runloop = CFRunLoopGetCurrent(); - if (!runloop) { - PyErr_SetString(PyExc_RuntimeError, "Failed to obtain run loop"); - return NULL; - } - attribute = PyObject_GetAttrString((PyObject*)self, "_interval"); - if (attribute==NULL) - { - PyErr_SetString(PyExc_AttributeError, "Timer has no attribute '_interval'"); - return NULL; - } - milliseconds = PyFloat_AsDouble(attribute); - failure = PyErr_Occurred(); - Py_DECREF(attribute); - if (failure) return NULL; - attribute = PyObject_GetAttrString((PyObject*)self, "_single"); - if (attribute==NULL) - { - PyErr_SetString(PyExc_AttributeError, "Timer has no attribute '_single'"); - return NULL; - } - switch (PyObject_IsTrue(attribute)) { - case 1: - interval = 0; - break; - case 0: - interval = milliseconds / 1000.0; - break; - case -1: - default: - PyErr_SetString(PyExc_ValueError, "Cannot interpret _single attribute as True of False"); - return NULL; - } - Py_DECREF(attribute); - attribute = PyObject_GetAttrString((PyObject*)self, "_on_timer"); - if (attribute==NULL) - { - PyErr_SetString(PyExc_AttributeError, "Timer has no attribute '_on_timer'"); - return NULL; - } - if (!PyMethod_Check(attribute)) { - PyErr_SetString(PyExc_RuntimeError, "_on_timer should be a Python method"); - return NULL; - } - context.version = 0; - context.retain = NULL; - context.release = context_cleanup; - context.copyDescription = NULL; - context.info = attribute; - timer = CFRunLoopTimerCreate(kCFAllocatorDefault, - 0, - interval, - 0, - 0, - timer_callback, - &context); - if (!timer) { - Py_DECREF(attribute); - PyErr_SetString(PyExc_RuntimeError, "Failed to create timer"); - return NULL; - } - if (self->timer) { - CFRunLoopTimerInvalidate(self->timer); - CFRelease(self->timer); - } - CFRunLoopAddTimer(runloop, timer, kCFRunLoopCommonModes); - /* Don't release the timer here, since the run loop may be destroyed and - * the timer lost before we have a chance to decrease the reference count - * of the attribute */ - self->timer = timer; - Py_RETURN_NONE; -} - -static PyObject* -Timer__timer_stop(Timer* self) -{ - if (self->timer) { - CFRunLoopTimerInvalidate(self->timer); - CFRelease(self->timer); - self->timer = NULL; - } - Py_RETURN_NONE; -} - -static void -Timer_dealloc(Timer* self) -{ - Timer__timer_stop(self); - Py_TYPE(self)->tp_free((PyObject*)self); -} - -static PyMethodDef Timer_methods[] = { - {"_timer_start", - (PyCFunction)Timer__timer_start, - METH_VARARGS, - "Initialize and start the timer." - }, - {"_timer_stop", - (PyCFunction)Timer__timer_stop, - METH_NOARGS, - "Stop the timer." - }, - {NULL} /* Sentinel */ -}; - -static PyTypeObject TimerType = { - PyVarObject_HEAD_INIT(NULL, 0) - "_macosx.Timer", /*tp_name*/ - sizeof(Timer), /*tp_basicsize*/ - 0, /*tp_itemsize*/ - (destructor)Timer_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - (reprfunc)Timer_repr, /*tp_repr*/ - 0, /*tp_as_number*/ - 0, /*tp_as_sequence*/ - 0, /*tp_as_mapping*/ - 0, /*tp_hash */ - 0, /*tp_call*/ - 0, /*tp_str*/ - 0, /*tp_getattro*/ - 0, /*tp_setattro*/ - 0, /*tp_as_buffer*/ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ - Timer_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - Timer_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - Timer_new, /* tp_new */ -}; - -static bool verify_framework(void) -{ -#ifdef COMPILING_FOR_10_6 - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSRunningApplication* app = [NSRunningApplication currentApplication]; - NSApplicationActivationPolicy activationPolicy = [app activationPolicy]; - [pool release]; - switch (activationPolicy) { - case NSApplicationActivationPolicyRegular: - case NSApplicationActivationPolicyAccessory: - return true; - case NSApplicationActivationPolicyProhibited: - break; - } -#else - ProcessSerialNumber psn; - if (CGMainDisplayID()!=0 - && GetCurrentProcess(&psn)==noErr - && SetFrontProcess(&psn)==noErr) return true; -#endif - PyErr_SetString(PyExc_RuntimeError, - "Python is not installed as a framework. The Mac OS X backend will " - "not be able to function correctly if Python is not installed as a " - "framework. See the Python documentation for more information on " - "installing Python as a framework on Mac OS X. Please either reinstall " - "Python as a framework, or try one of the other backends. If you are " - "using (Ana)Conda please install python.app and replace the use of 'python' " - "with 'pythonw'. See 'Working with Matplotlib on OSX' " - "in the Matplotlib FAQ for more information."); - return false; -} - -static struct PyMethodDef methods[] = { - {"show", - (PyCFunction)show, - METH_NOARGS, - "Show all the figures and enter the main loop.\nThis function does not return until all Matplotlib windows are closed,\nand is normally not needed in interactive sessions." - }, - {"choose_save_file", - (PyCFunction)choose_save_file, - METH_VARARGS, - "Closes the window." - }, - {"set_cursor", - (PyCFunction)set_cursor, - METH_VARARGS, - "Sets the active cursor." - }, - {NULL, NULL, 0, NULL}/* sentinel */ -}; - -#if PY3K - -static struct PyModuleDef moduledef = { - PyModuleDef_HEAD_INIT, - "_macosx", - "Mac OS X native backend", - -1, - methods, - NULL, - NULL, - NULL, - NULL -}; - -PyObject* PyInit__macosx(void) - -#else - -void init_macosx(void) -#endif -{ - PyObject *module; - - if (PyType_Ready(&FigureCanvasType) < 0 - || PyType_Ready(&FigureManagerType) < 0 - || PyType_Ready(&NavigationToolbarType) < 0 - || PyType_Ready(&NavigationToolbar2Type) < 0 - || PyType_Ready(&TimerType) < 0) -#if PY3K - return NULL; -#else - return; -#endif - - NSApp = [NSApplication sharedApplication]; - - if (!verify_framework()) -#if PY3K - return NULL; -#else - return; -#endif - -#if PY3K - module = PyModule_Create(&moduledef); - if (module==NULL) return NULL; -#else - module = Py_InitModule4("_macosx", - methods, - "Mac OS X native backend", - NULL, - PYTHON_API_VERSION); -#endif - - Py_INCREF(&FigureCanvasType); - Py_INCREF(&FigureManagerType); - Py_INCREF(&NavigationToolbarType); - Py_INCREF(&NavigationToolbar2Type); - Py_INCREF(&TimerType); - PyModule_AddObject(module, "FigureCanvas", (PyObject*) &FigureCanvasType); - PyModule_AddObject(module, "FigureManager", (PyObject*) &FigureManagerType); - PyModule_AddObject(module, "NavigationToolbar", (PyObject*) &NavigationToolbarType); - PyModule_AddObject(module, "NavigationToolbar2", (PyObject*) &NavigationToolbar2Type); - PyModule_AddObject(module, "Timer", (PyObject*) &TimerType); - - PyOS_InputHook = wait_for_stdin; - - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - WindowServerConnectionManager* connectionManager = [WindowServerConnectionManager sharedManager]; - NSWorkspace* workspace = [NSWorkspace sharedWorkspace]; - NSNotificationCenter* notificationCenter = [workspace notificationCenter]; - [notificationCenter addObserver: connectionManager - selector: @selector(launch:) - name: NSWorkspaceDidLaunchApplicationNotification - object: nil]; - [pool release]; -#if PY3K - return module; -#endif -} diff --git a/contrib/python/matplotlib/py2/src/_path.h b/contrib/python/matplotlib/py2/src/_path.h deleted file mode 100644 index 76f1894c4a..0000000000 --- a/contrib/python/matplotlib/py2/src/_path.h +++ /dev/null @@ -1,1316 +0,0 @@ -/* -*- mode: c++; c-basic-offset: 4 -*- */ - -#ifndef __PATH_H__ -#define __PATH_H__ - -#include <limits> -#include <math.h> -#include <vector> -#include <cmath> -#include <algorithm> - -#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_curves()); - 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 (bool)result[0]; -} - -template <class PathIterator, class PointArray, class ResultArray> -void points_on_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_stroke<curve_t> stroke_t; - - size_t i; - for (i = 0; i < points.size(); ++i) { - result[i] = false; - } - - transformed_path_t trans_path(path, trans); - no_nans_t nan_removed_path(trans_path, true, path.has_curves()); - 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); -} - -template <class PathIterator> -inline bool point_on_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_on_path(points, r, path, trans, result); - - return (bool)result[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_curves()); - - 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 be Nx2"); - } - - 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, - e_offset_position offset_position, - 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); - if (offset_position == OFFSET_POSITION_DATA) { - trans = agg::trans_affine_translation(xo, yo) * trans; - } else { - 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_curves()); - 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: - - http://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 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) -{ - double den = ((y4 - y3) * (x2 - x1)) - ((x4 - x3) * (y2 - y1)); - if (den == 0.0) { - return false; - } - - double n1 = ((x4 - x3) * (y1 - y3)) - ((y4 - y3) * (x1 - x3)); - double n2 = ((x2 - x1) * (y1 - y3)) - ((y2 - y1) * (x1 - x3)); - - double u1 = n1 / den; - double u2 = n2 / den; - - return (u1 >= 0.0 && u1 <= 1.0 && u2 >= 0.0 && 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_curves()); - no_nans_t n2(p2, true, p2.has_curves()); - - 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) { - c2.rewind(0); - c2.vertex(&x21, &y21); - while (c2.vertex(&x22, &y22) != agg::path_cmd_stop) { - 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_curves()); - 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_curves()); - clipped_t clipped(nan_removed, do_clip && !path.has_curves(), 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_curves()); - clipped_t clipped(nan_removed, do_clip && !path.has_curves(), 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; -} - -char *__append_to_string(char *p, char **buffer, size_t *buffersize, - const char *content) -{ - for (const char *i = content; *i; ++i) { - if (p < *buffer) { - /* This is just an internal error */ - return NULL; - } - if ((size_t)(p - *buffer) >= *buffersize) { - ptrdiff_t diff = p - *buffer; - *buffersize *= 2; - *buffer = (char *)realloc(*buffer, *buffersize); - if (*buffer == NULL) { - return NULL; - } - p = *buffer + diff; - } - - *p++ = *i; - } - - return p; -} - - -char *__add_number(double val, const char *format, int precision, - char **buffer, char *p, size_t *buffersize) -{ - char *result; - -#if PY_VERSION_HEX >= 0x02070000 - char *str; - str = PyOS_double_to_string(val, format[0], precision, 0, NULL); -#else - char str[64]; - PyOS_ascii_formatd(str, 64, format, val); -#endif - - // Delete trailing zeros and decimal point - char *q = str; - for (; *q != 0; ++q) { - // Find the end of the string - } - - --q; - for (; q >= str && *q == '0'; --q) { - // Rewind through all the zeros - } - - // If the end is a decimal qoint, delete that too - if (q >= str && *q == '.') { - --q; - } - - // Truncate the string - ++q; - *q = 0; - -#if PY_VERSION_HEX >= 0x02070000 - if ((result = __append_to_string(p, buffer, buffersize, str)) == NULL) { - PyMem_Free(str); - return NULL; - } - PyMem_Free(str); -#else - if ((result = __append_to_string(p, buffer, buffersize, str)) == NULL) { - return NULL; - } -#endif - - return result; -} - - -template <class PathIterator> -int __convert_to_string(PathIterator &path, - int precision, - char **codes, - bool postfix, - char **buffer, - size_t *buffersize) -{ -#if PY_VERSION_HEX >= 0x02070000 - const char *format = "f"; -#else - char format[64]; - snprintf(format, 64, "%s.%df", "%", precision); -#endif - - char *p = *buffer; - double x[3]; - double y[3]; - double last_x = 0.0; - double last_y = 0.0; - - const int sizes[] = { 1, 1, 2, 3 }; - int size = 0; - unsigned code; - - while ((code = path.vertex(&x[0], &y[0])) != agg::path_cmd_stop) { - if (code == 0x4f) { - if ((p = __append_to_string(p, buffer, buffersize, codes[4])) == NULL) return 1; - } else if (code < 5) { - size = sizes[code - 1]; - - for (int i = 1; i < size; ++i) { - unsigned subcode = path.vertex(&x[i], &y[i]); - if (subcode != code) { - return 2; - } - } - - /* 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) { - if ((p = __append_to_string(p, buffer, buffersize, codes[code - 1])) == NULL) return 1; - if ((p = __append_to_string(p, buffer, buffersize, " ")) == NULL) return 1; - } - - for (int i = 0; i < size; ++i) { - if ((p = __add_number(x[i], format, precision, buffer, p, buffersize)) == NULL) return 1; - if ((p = __append_to_string(p, buffer, buffersize, " ")) == NULL) return 1; - if ((p = __add_number(y[i], format, precision, buffer, p, buffersize)) == NULL) return 1; - if ((p = __append_to_string(p, buffer, buffersize, " ")) == NULL) return 1; - } - - if (postfix) { - if ((p = __append_to_string(p, buffer, buffersize, codes[code - 1])) == NULL) return 1; - } - - last_x = x[size - 1]; - last_y = y[size - 1]; - } else { - // Unknown code value - return 2; - } - - if ((p = __append_to_string(p, buffer, buffersize, "\n")) == NULL) return 1; - } - - *buffersize = p - *buffer; - - return 0; -} - -template <class PathIterator> -int 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, - char **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_curves()); - clipped_t clipped(nan_removed, do_clip && !path.has_curves(), clip_rect); - simplify_t simplified(clipped, simplify, path.simplify_threshold()); - - *buffersize = path.total_vertices() * (precision + 5) * 4; - if (*buffersize == 0) { - return 0; - } - - if (sketch_params.scale != 0.0) { - *buffersize *= 10.0; - } - - *buffer = (char *)malloc(*buffersize); - if (*buffer == NULL) { - return 1; - } - - if (sketch_params.scale == 0.0) { - return __convert_to_string(simplified, precision, codes, postfix, buffer, buffersize); - } 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, buffersize); - } - -} - -template<class T> -struct _is_sorted -{ - bool operator()(PyArrayObject *array) - { - npy_intp size; - npy_intp i; - T last_value; - T current_value; - - size = PyArray_DIM(array, 0); - - // std::isnan is only in C++11, which we don't yet require, - // so we use the "self == self" trick - for (i = 0; i < size; ++i) { - last_value = *((T *)PyArray_GETPTR1(array, i)); - if (last_value == last_value) { - break; - } - } - - if (i == size) { - // The whole array is non-finite - return false; - } - - for (; i < size; ++i) { - current_value = *((T *)PyArray_GETPTR1(array, i)); - if (current_value == current_value) { - if (current_value < last_value) { - return false; - } - last_value = current_value; - } - } - - return true; - } -}; - - -template<class T> -struct _is_sorted_int -{ - bool operator()(PyArrayObject *array) - { - npy_intp size; - npy_intp i; - T last_value; - T current_value; - - size = PyArray_DIM(array, 0); - - last_value = *((T *)PyArray_GETPTR1(array, 0)); - - for (i = 1; i < size; ++i) { - current_value = *((T *)PyArray_GETPTR1(array, i)); - if (current_value < last_value) { - return false; - } - last_value = current_value; - } - - return true; - } -}; - - -#endif diff --git a/contrib/python/matplotlib/py2/src/_path_wrapper.cpp b/contrib/python/matplotlib/py2/src/_path_wrapper.cpp deleted file mode 100644 index 08a595e7c4..0000000000 --- a/contrib/python/matplotlib/py2/src/_path_wrapper.cpp +++ /dev/null @@ -1,900 +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)"; - -static PyObject *Py_point_in_path(PyObject *self, PyObject *args, PyObject *kwds) -{ - 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)"; - -static PyObject *Py_points_in_path(PyObject *self, PyObject *args, PyObject *kwds) -{ - 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_point_on_path__doc__ = "point_on_path(x, y, radius, path, trans)"; - -static PyObject *Py_point_on_path(PyObject *self, PyObject *args, PyObject *kwds) -{ - double x, y, r; - py::PathIterator path; - agg::trans_affine trans; - bool result; - - if (!PyArg_ParseTuple(args, - "dddO&O&:point_on_path", - &x, - &y, - &r, - &convert_path, - &path, - &convert_trans_affine, - &trans)) { - return NULL; - } - - CALL_CPP("point_on_path", (result = point_on_path(x, y, r, path, trans))); - - if (result) { - Py_RETURN_TRUE; - } else { - Py_RETURN_FALSE; - } -} - -const char *Py_points_on_path__doc__ = "points_on_path(points, radius, path, trans)"; - -static PyObject *Py_points_on_path(PyObject *self, PyObject *args, PyObject *kwds) -{ - numpy::array_view<const double, 2> points; - double r; - py::PathIterator path; - agg::trans_affine trans; - - if (!PyArg_ParseTuple(args, - "O&dO&O&:points_on_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_on_path", (points_on_path(points, r, path, trans, results))); - - return results.pyobj(); -} - -const char *Py_get_path_extents__doc__ = "get_path_extents(path, trans)"; - -static PyObject *Py_get_path_extents(PyObject *self, PyObject *args, PyObject *kwds) -{ - py::PathIterator path; - agg::trans_affine trans; - - if (!PyArg_ParseTuple( - args, "O&O&:get_path_extents", &convert_path, &path, &convert_trans_affine, &trans)) { - return NULL; - } - - extent_limits e; - - CALL_CPP("get_path_extents", (reset_limits(e))); - CALL_CPP("get_path_extents", (update_path_extents(path, 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; - - return extents.pyobj(); -} - -const char *Py_update_path_extents__doc__ = - "update_path_extents(path, trans, rect, minpos, ignore)"; - -static PyObject *Py_update_path_extents(PyObject *self, PyObject *args, PyObject *kwds) -{ - 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("; - -static PyObject *Py_get_path_collection_extents(PyObject *self, PyObject *args, PyObject *kwds) -{ - agg::trans_affine master_transform; - PyObject *pathsobj; - 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&OO&O&O&:get_path_collection_extents", - &convert_trans_affine, - &master_transform, - &pathsobj, - &convert_transforms, - &transforms, - &convert_points, - &offsets, - &convert_trans_affine, - &offset_trans)) { - return NULL; - } - - try - { - py::PathGenerator paths(pathsobj); - - CALL_CPP("get_path_collection_extents", - (get_path_collection_extents( - master_transform, paths, transforms, offsets, offset_trans, e))); - } - catch (const py::exception &) - { - return NULL; - } - - 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; - - return extents.pyobj(); -} - -const char *Py_point_in_path_collection__doc__ = - "point_in_path_collection(x, y, radius, master_transform, paths, transforms, offsets, " - "offset_trans, filled, offset_position)"; - -static PyObject *Py_point_in_path_collection(PyObject *self, PyObject *args, PyObject *kwds) -{ - double x, y, radius; - agg::trans_affine master_transform; - PyObject *pathsobj; - numpy::array_view<const double, 3> transforms; - numpy::array_view<const double, 2> offsets; - agg::trans_affine offset_trans; - int filled; - e_offset_position offset_position; - std::vector<int> result; - - if (!PyArg_ParseTuple(args, - "dddO&OO&O&O&iO&:point_in_path_collection", - &x, - &y, - &radius, - &convert_trans_affine, - &master_transform, - &pathsobj, - &convert_transforms, - &transforms, - &convert_points, - &offsets, - &convert_trans_affine, - &offset_trans, - &filled, - &convert_offset_position, - &offset_position)) { - return NULL; - } - - try - { - py::PathGenerator paths(pathsobj); - - CALL_CPP("point_in_path_collection", - (point_in_path_collection(x, - y, - radius, - master_transform, - paths, - transforms, - offsets, - offset_trans, - filled, - offset_position, - result))); - } - catch (const py::exception &) - { - return NULL; - } - - 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)"; - -static PyObject *Py_path_in_path(PyObject *self, PyObject *args, PyObject *kwds) -{ - 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)"; - -static PyObject *Py_clip_path_to_rect(PyObject *self, PyObject *args, PyObject *kwds) -{ - py::PathIterator path; - agg::rect_d rect; - int inside; - std::vector<Polygon> result; - - if (!PyArg_ParseTuple(args, - "O&O&i:clip_path_to_rect", - &convert_path, - &path, - &convert_rect, - &rect, - &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)"; - -static PyObject *Py_affine_transform(PyObject *self, PyObject *args, PyObject *kwds) -{ - PyObject *vertices_obj; - agg::trans_affine trans; - - if (!PyArg_ParseTuple(args, - "OO&:affine_transform", - &vertices_obj, - &convert_trans_affine, - &trans)) { - return NULL; - } - - try { - numpy::array_view<double, 2> vertices(vertices_obj); - 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(); - } catch (py::exception &) { - PyErr_Clear(); - try { - numpy::array_view<double, 1> vertices(vertices_obj); - 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(); - } catch (py::exception &) { - return NULL; - } - } -} - -const char *Py_count_bboxes_overlapping_bbox__doc__ = "count_bboxes_overlapping_bbox(bbox, bboxes)"; - -static PyObject *Py_count_bboxes_overlapping_bbox(PyObject *self, PyObject *args, PyObject *kwds) -{ - 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)"; - -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)"; - -static PyObject *Py_path_intersects_rectangle(PyObject *self, PyObject *args, PyObject *kwds) -{ - py::PathIterator path; - double rect_x1, rect_y1, rect_x2, rect_y2; - int filled = 0; - const char *names[] = { "path", "rect_x1", "rect_y1", "rect_x2", "rect_y2", "filled", NULL }; - bool result; - - if (!PyArg_ParseTupleAndKeywords(args, - kwds, - "O&dddd|i:path_intersects_rectangle", - (char **)names, - &convert_path, - &path, - &rect_x1, - &rect_y1, - &rect_x2, - &rect_y2, - &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)"; - -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)"; - -static PyObject *Py_cleanup_path(PyObject *self, PyObject *args, PyObject *kwds) -{ - py::PathIterator path; - agg::trans_affine trans; - int remove_nans; - agg::rect_d clip_rect; - e_snap_mode snap_mode; - double stroke_width; - PyObject *simplifyobj; - bool simplify = false; - int return_curves; - SketchParams sketch; - - if (!PyArg_ParseTuple(args, - "O&O&iO&O&dOiO&:cleanup_path", - &convert_path, - &path, - &convert_trans_affine, - &trans, - &remove_nans, - &convert_rect, - &clip_rect, - &convert_snap, - &snap_mode, - &stroke_width, - &simplifyobj, - &return_curves, - &convert_sketch_params, - &sketch)) { - return NULL; - } - - if (simplifyobj == Py_None) { - simplify = path.should_simplify(); - } else if (PyObject_IsTrue(simplifyobj)) { - simplify = true; - } - - 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)"; - -static PyObject *Py_convert_to_string(PyObject *self, PyObject *args, PyObject *kwds) -{ - py::PathIterator path; - agg::trans_affine trans; - agg::rect_d cliprect; - PyObject *simplifyobj; - bool simplify = false; - SketchParams sketch; - int precision; - PyObject *codesobj; - char *codes[5]; - int postfix; - char *buffer = NULL; - size_t buffersize; - PyObject *result; - int status; - - if (!PyArg_ParseTuple(args, - "O&O&O&OO&iOi:convert_to_string", - &convert_path, - &path, - &convert_trans_affine, - &trans, - &convert_rect, - &cliprect, - &simplifyobj, - &convert_sketch_params, - &sketch, - &precision, - &codesobj, - &postfix)) { - return NULL; - } - - if (simplifyobj == Py_None) { - simplify = path.should_simplify(); - } else if (PyObject_IsTrue(simplifyobj)) { - simplify = true; - } - - if (!PySequence_Check(codesobj)) { - return NULL; - } - if (PySequence_Size(codesobj) != 5) { - PyErr_SetString( - PyExc_ValueError, - "codes must be a 5-length sequence of byte strings"); - return NULL; - } - for (int i = 0; i < 5; ++i) { - PyObject *item = PySequence_GetItem(codesobj, i); - if (item == NULL) { - return NULL; - } - codes[i] = PyBytes_AsString(item); - if (codes[i] == NULL) { - return NULL; - } - } - - CALL_CPP("convert_to_string", - (status = convert_to_string( - path, trans, cliprect, simplify, sketch, - precision, codes, (bool)postfix, &buffer, - &buffersize))); - - if (status) { - free(buffer); - if (status == 1) { - PyErr_SetString(PyExc_MemoryError, "Memory error"); - } else if (status == 2) { - PyErr_SetString(PyExc_ValueError, "Malformed path codes"); - } - return NULL; - } - - if (buffersize == 0) { - result = PyBytes_FromString(""); - } else { - result = PyBytes_FromStringAndSize(buffer, buffersize); - } - - free(buffer); - - return result; -} - - -const char *Py_is_sorted__doc__ = "is_sorted(array)\n\n" - "Returns True if 1-D array is monotonically increasing, ignoring NaNs\n"; - -static PyObject *Py_is_sorted(PyObject *self, PyObject *obj) -{ - npy_intp size; - bool result; - - PyArrayObject *array = (PyArrayObject *)PyArray_FromAny( - obj, NULL, 1, 1, 0, NULL); - - if (array == NULL) { - return NULL; - } - - size = PyArray_DIM(array, 0); - - if (size < 2) { - Py_DECREF(array); - Py_RETURN_TRUE; - } - - /* Handle just the most common types here, otherwise coerce to - double */ - switch(PyArray_TYPE(array)) { - case NPY_INT: - { - _is_sorted_int<npy_int> is_sorted; - result = is_sorted(array); - } - break; - - case NPY_LONG: - { - _is_sorted_int<npy_long> is_sorted; - result = is_sorted(array); - } - break; - - case NPY_LONGLONG: - { - _is_sorted_int<npy_longlong> is_sorted; - result = is_sorted(array); - } - break; - - case NPY_FLOAT: - { - _is_sorted<npy_float> is_sorted; - result = is_sorted(array); - } - break; - - case NPY_DOUBLE: - { - _is_sorted<npy_double> is_sorted; - result = is_sorted(array); - } - break; - - default: - { - Py_DECREF(array); - array = (PyArrayObject *)PyArray_FromObject(obj, NPY_DOUBLE, 1, 1); - - if (array == NULL) { - return NULL; - } - - _is_sorted<npy_double> is_sorted; - result = is_sorted(array); - } - } - - Py_DECREF(array); - - if (result) { - Py_RETURN_TRUE; - } else { - Py_RETURN_FALSE; - } -} - - -extern "C" { - - 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__}, - {"point_on_path", (PyCFunction)Py_point_on_path, METH_VARARGS, Py_point_on_path__doc__}, - {"points_on_path", (PyCFunction)Py_points_on_path, METH_VARARGS, Py_points_on_path__doc__}, - {"get_path_extents", (PyCFunction)Py_get_path_extents, METH_VARARGS, Py_get_path_extents__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", (PyCFunction)Py_is_sorted, METH_O, Py_is_sorted__doc__}, - {NULL} - }; - -#if PY3K - static struct PyModuleDef moduledef = { - PyModuleDef_HEAD_INIT, - "_path", - NULL, - 0, - module_functions, - NULL, - NULL, - NULL, - NULL - }; - -#define INITERROR return NULL - PyMODINIT_FUNC PyInit__path(void) -#else -#define INITERROR return - PyMODINIT_FUNC init_path(void) -#endif - { - PyObject *m; -#if PY3K - m = PyModule_Create(&moduledef); -#else - m = Py_InitModule3("_path", module_functions, NULL); -#endif - - if (m == NULL) { - INITERROR; - } - - import_array(); - -#if PY3K - return m; -#endif - } -} diff --git a/contrib/python/matplotlib/py2/src/_png.cpp b/contrib/python/matplotlib/py2/src/_png.cpp deleted file mode 100644 index ea7bf32efe..0000000000 --- a/contrib/python/matplotlib/py2/src/_png.cpp +++ /dev/null @@ -1,793 +0,0 @@ -/* -*- mode: c++; c-basic-offset: 4 -*- */ - -/* For linux, png.h must be imported before Python.h because - png.h needs to be the one to define setjmp. - Undefining _POSIX_C_SOURCE and _XOPEN_SOURCE stops a couple - of harmless warnings. -*/ -#define PY_SSIZE_T_CLEAN - -extern "C" { -# include <png.h> -# ifdef _POSIX_C_SOURCE -# undef _POSIX_C_SOURCE -# endif -# ifndef _AIX -# ifdef _XOPEN_SOURCE -# undef _XOPEN_SOURCE -# endif -# endif -} - -#include "numpy_cpp.h" -#include "mplutils.h" -#include "file_compat.h" - -# include <vector> -# include "Python.h" - - -// As reported in [3082058] build _png.so on aix -#ifdef _AIX -#undef jmpbuf -#endif - -struct buffer_t { - PyObject *str; - size_t cursor; - size_t size; -}; - - -static void write_png_data_buffer(png_structp png_ptr, png_bytep data, png_size_t length) -{ - buffer_t *buff = (buffer_t *)png_get_io_ptr(png_ptr); - if (buff->cursor + length < buff->size) { - memcpy(PyBytes_AS_STRING(buff->str) + buff->cursor, data, length); - buff->cursor += length; - } -} - -static void flush_png_data_buffer(png_structp png_ptr) -{ - -} - -static void write_png_data(png_structp png_ptr, png_bytep data, png_size_t length) -{ - PyObject *py_file_obj = (PyObject *)png_get_io_ptr(png_ptr); - PyObject *write_method = PyObject_GetAttrString(py_file_obj, "write"); - PyObject *result = NULL; - if (write_method) { -#if PY3K - result = PyObject_CallFunction(write_method, (char *)"y#", data, length); -#else - result = PyObject_CallFunction(write_method, (char *)"s#", data, length); -#endif - } - Py_XDECREF(write_method); - Py_XDECREF(result); -} - -static void flush_png_data(png_structp png_ptr) -{ - PyObject *py_file_obj = (PyObject *)png_get_io_ptr(png_ptr); - PyObject *flush_method = PyObject_GetAttrString(py_file_obj, "flush"); - PyObject *result = NULL; - if (flush_method) { - result = PyObject_CallFunction(flush_method, (char *)""); - } - Py_XDECREF(flush_method); - Py_XDECREF(result); -} - -const char *Py_write_png__doc__ = - "write_png(buffer, file, dpi=0, compression=6, filter=auto, metadata=None)\n" - "\n" - "Parameters\n" - "----------\n" - "buffer : numpy array of image data\n" - " Must be an MxNxD array of dtype uint8.\n" - " - if D is 1, the image is greyscale\n" - " - if D is 3, the image is RGB\n" - " - if D is 4, the image is RGBA\n" - "\n" - "file : str path, file-like object or None\n" - " - If a str, must be a file path\n" - " - If a file-like object, must write bytes\n" - " - If None, a byte string containing the PNG data will be returned\n" - "\n" - "dpi : float\n" - " The dpi to store in the file metadata.\n" - "\n" - "compression : int\n" - " The level of lossless zlib compression to apply. 0 indicates no\n" - " compression. Values 1-9 indicate low/fast through high/slow\n" - " compression. Default is 6.\n" - "\n" - "filter : int\n" - " Filter to apply. Must be one of the constants: PNG_FILTER_NONE,\n" - " PNG_FILTER_SUB, PNG_FILTER_UP, PNG_FILTER_AVG, PNG_FILTER_PAETH.\n" - " See the PNG standard for more information.\n" - " If not provided, libpng will try to automatically determine the\n" - " best filter on a line-by-line basis.\n" - "\n" - "metadata : dictionary\n" - " The keyword-text pairs that are stored as comments in the image.\n" - " Keys must be shorter than 79 chars. The only supported encoding\n" - " for both keywords and values is Latin-1 (ISO 8859-1).\n" - " Examples given in the PNG Specification are:\n" - " - Title: Short (one line) title or caption for image\n" - " - Author: Name of image's creator\n" - " - Description: Description of image (possibly long)\n" - " - Copyright: Copyright notice\n" - " - Creation Time: Time of original image creation\n" - " (usually RFC 1123 format, see below)\n" - " - Software: Software used to create the image\n" - " - Disclaimer: Legal disclaimer\n" - " - Warning: Warning of nature of content\n" - " - Source: Device used to create the image\n" - " - Comment: Miscellaneous comment; conversion\n" - " from other image format\n" - "\n" - "Returns\n" - "-------\n" - "buffer : bytes or None\n" - " Byte string containing the PNG content if None was passed in for\n" - " file, otherwise None is returned.\n"; - -// this code is heavily adapted from -// https://www.object-craft.com.au/projects/paint/ which licensed under the -// (BSD compatible) LICENSE_PAINT which is included in this distribution. -static PyObject *Py_write_png(PyObject *self, PyObject *args, PyObject *kwds) -{ - numpy::array_view<unsigned char, 3> buffer; - PyObject *filein; - PyObject *metadata = NULL; - PyObject *meta_key, *meta_val; - png_text *text; - Py_ssize_t pos = 0; - int meta_pos = 0; - Py_ssize_t meta_size; - double dpi = 0; - int compression = 6; - int filter = -1; - const char *names[] = { "buffer", "file", "dpi", "compression", "filter", "metadata", NULL }; - - // We don't need strict contiguity, just for each row to be - // contiguous, and libpng has special handling for getting RGB out - // of RGBA, ARGB or BGR. But the simplest thing to do is to - // enforce contiguity using array_view::converter_contiguous. - if (!PyArg_ParseTupleAndKeywords(args, - kwds, - "O&O|diiO:write_png", - (char **)names, - &buffer.converter_contiguous, - &buffer, - &filein, - &dpi, - &compression, - &filter, - &metadata)) { - return NULL; - } - - png_uint_32 width = (png_uint_32)buffer.dim(1); - png_uint_32 height = (png_uint_32)buffer.dim(0); - int channels = buffer.dim(2); - std::vector<png_bytep> row_pointers(height); - for (png_uint_32 row = 0; row < (png_uint_32)height; ++row) { - row_pointers[row] = (png_bytep)&buffer(row, 0, 0); - } - - FILE *fp = NULL; - mpl_off_t offset = 0; - bool close_file = false; - bool close_dup_file = false; - PyObject *py_file = NULL; - - png_structp png_ptr = NULL; - png_infop info_ptr = NULL; - struct png_color_8_struct sig_bit; - int png_color_type; - buffer_t buff; - buff.str = NULL; - - switch (channels) { - case 1: - png_color_type = PNG_COLOR_TYPE_GRAY; - break; - case 3: - png_color_type = PNG_COLOR_TYPE_RGB; - break; - case 4: - png_color_type = PNG_COLOR_TYPE_RGB_ALPHA; - break; - default: - PyErr_SetString(PyExc_ValueError, - "Buffer must be an NxMxD array with D in 1, 3, 4 " - "(grayscale, RGB, RGBA)"); - goto exit; - } - - if (compression < 0 || compression > 9) { - PyErr_Format(PyExc_ValueError, - "compression must be in range 0-9, got %d", compression); - goto exit; - } - - if (PyBytes_Check(filein) || PyUnicode_Check(filein)) { - if ((py_file = mpl_PyFile_OpenFile(filein, (char *)"wb")) == NULL) { - goto exit; - } - close_file = true; - } else { - py_file = filein; - } - - if (filein == Py_None) { - buff.size = width * height * 4 + 1024; - buff.str = PyBytes_FromStringAndSize(NULL, buff.size); - if (buff.str == NULL) { - goto exit; - } - buff.cursor = 0; - } else { - #if PY3K - if (close_file) { - #else - if (close_file || PyFile_Check(py_file)) { - #endif - fp = mpl_PyFile_Dup(py_file, (char *)"wb", &offset); - } - - if (fp) { - close_dup_file = true; - } else { - PyErr_Clear(); - PyObject *write_method = PyObject_GetAttrString(py_file, "write"); - if (!(write_method && PyCallable_Check(write_method))) { - Py_XDECREF(write_method); - PyErr_SetString(PyExc_TypeError, - "Object does not appear to be a 8-bit string path or " - "a Python file-like object"); - goto exit; - } - Py_XDECREF(write_method); - } - } - - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (png_ptr == NULL) { - PyErr_SetString(PyExc_RuntimeError, "Could not create write struct"); - goto exit; - } - - png_set_compression_level(png_ptr, compression); - if (filter >= 0) { - png_set_filter(png_ptr, 0, filter); - } - - info_ptr = png_create_info_struct(png_ptr); - if (info_ptr == NULL) { - PyErr_SetString(PyExc_RuntimeError, "Could not create info struct"); - goto exit; - } - - if (setjmp(png_jmpbuf(png_ptr))) { - PyErr_SetString(PyExc_RuntimeError, "libpng signaled error"); - goto exit; - } - - if (buff.str) { - png_set_write_fn(png_ptr, (void *)&buff, &write_png_data_buffer, &flush_png_data_buffer); - } else if (fp) { - png_init_io(png_ptr, fp); - } else { - png_set_write_fn(png_ptr, (void *)py_file, &write_png_data, &flush_png_data); - } - png_set_IHDR(png_ptr, - info_ptr, - width, - height, - 8, - png_color_type, - PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_BASE, - PNG_FILTER_TYPE_BASE); - - // Save the dpi of the image in the file - if (dpi > 0.0) { - png_uint_32 dots_per_meter = (png_uint_32)(dpi / (2.54 / 100.0)); - png_set_pHYs(png_ptr, info_ptr, dots_per_meter, dots_per_meter, PNG_RESOLUTION_METER); - } - -#ifdef PNG_TEXT_SUPPORTED - // Save the metadata - if (metadata != NULL) { - meta_size = PyDict_Size(metadata); - text = new png_text[meta_size]; - - while (PyDict_Next(metadata, &pos, &meta_key, &meta_val)) { - text[meta_pos].compression = PNG_TEXT_COMPRESSION_NONE; -#if PY3K - if (PyUnicode_Check(meta_key)) { - PyObject *temp_key = PyUnicode_AsEncodedString(meta_key, "latin_1", "strict"); - if (temp_key != NULL) { - text[meta_pos].key = PyBytes_AsString(temp_key); - } - } else if (PyBytes_Check(meta_key)) { - text[meta_pos].key = PyBytes_AsString(meta_key); - } else { - char invalid_key[79]; - sprintf(invalid_key,"INVALID KEY %d", meta_pos); - text[meta_pos].key = invalid_key; - } - if (PyUnicode_Check(meta_val)) { - PyObject *temp_val = PyUnicode_AsEncodedString(meta_val, "latin_1", "strict"); - if (temp_val != NULL) { - text[meta_pos].text = PyBytes_AsString(temp_val); - } - } else if (PyBytes_Check(meta_val)) { - text[meta_pos].text = PyBytes_AsString(meta_val); - } else { - text[meta_pos].text = (char *)"Invalid value in metadata"; - } -#else - text[meta_pos].key = PyString_AsString(meta_key); - text[meta_pos].text = PyString_AsString(meta_val); -#endif -#ifdef PNG_iTXt_SUPPORTED - text[meta_pos].lang = NULL; -#endif - meta_pos++; - } - png_set_text(png_ptr, info_ptr, text, meta_size); - delete[] text; - } -#endif - - sig_bit.alpha = 0; - switch (png_color_type) { - case PNG_COLOR_TYPE_GRAY: - sig_bit.gray = 8; - sig_bit.red = 0; - sig_bit.green = 0; - sig_bit.blue = 0; - break; - case PNG_COLOR_TYPE_RGB_ALPHA: - sig_bit.alpha = 8; - // fall through - case PNG_COLOR_TYPE_RGB: - sig_bit.gray = 0; - sig_bit.red = 8; - sig_bit.green = 8; - sig_bit.blue = 8; - break; - default: - PyErr_SetString(PyExc_RuntimeError, "internal error, bad png_color_type"); - goto exit; - } - png_set_sBIT(png_ptr, info_ptr, &sig_bit); - - png_write_info(png_ptr, info_ptr); - png_write_image(png_ptr, &row_pointers[0]); - png_write_end(png_ptr, info_ptr); - -exit: - - if (png_ptr && info_ptr) { - png_destroy_write_struct(&png_ptr, &info_ptr); - } - - if (close_dup_file) { - mpl_PyFile_DupClose(py_file, fp, offset); - } - - if (close_file) { - mpl_PyFile_CloseFile(py_file); - Py_DECREF(py_file); - } - - if (PyErr_Occurred()) { - Py_XDECREF(buff.str); - return NULL; - } else { - if (buff.str) { - _PyBytes_Resize(&buff.str, buff.cursor); - return buff.str; - } - Py_RETURN_NONE; - } -} - -static void _read_png_data(PyObject *py_file_obj, png_bytep data, png_size_t length) -{ - PyObject *read_method = PyObject_GetAttrString(py_file_obj, "read"); - PyObject *result = NULL; - char *buffer; - Py_ssize_t bufflen; - if (read_method) { - result = PyObject_CallFunction(read_method, (char *)"i", length); - if (result) { - if (PyBytes_AsStringAndSize(result, &buffer, &bufflen) == 0) { - if (bufflen == (Py_ssize_t)length) { - memcpy(data, buffer, length); - } else { - PyErr_SetString(PyExc_IOError, "read past end of file"); - } - } else { - PyErr_SetString(PyExc_IOError, "failed to copy buffer"); - } - } else { - PyErr_SetString(PyExc_IOError, "failed to read file"); - } - - - } - Py_XDECREF(read_method); - Py_XDECREF(result); -} - -static void read_png_data(png_structp png_ptr, png_bytep data, png_size_t length) -{ - PyObject *py_file_obj = (PyObject *)png_get_io_ptr(png_ptr); - _read_png_data(py_file_obj, data, length); - if (PyErr_Occurred()) { - png_error(png_ptr, "failed to read file"); - } - -} - -static PyObject *_read_png(PyObject *filein, bool float_result) -{ - png_byte header[8]; // 8 is the maximum size that can be checked - FILE *fp = NULL; - mpl_off_t offset = 0; - bool close_file = false; - bool close_dup_file = false; - PyObject *py_file = NULL; - png_structp png_ptr = NULL; - png_infop info_ptr = NULL; - int num_dims; - std::vector<png_bytep> row_pointers; - png_uint_32 width = 0; - png_uint_32 height = 0; - int bit_depth; - PyObject *result = NULL; - - // TODO: Remove direct calls to Numpy API here - - if (PyBytes_Check(filein) || PyUnicode_Check(filein)) { - if ((py_file = mpl_PyFile_OpenFile(filein, (char *)"rb")) == NULL) { - goto exit; - } - close_file = true; - } else { - py_file = filein; - } - - #if PY3K - if (close_file) { - #else - if (close_file || PyFile_Check(py_file)) { - #endif - fp = mpl_PyFile_Dup(py_file, (char *)"rb", &offset); - } - - if (fp) { - close_dup_file = true; - if (fread(header, 1, 8, fp) != 8) { - PyErr_SetString(PyExc_IOError, "error reading PNG header"); - goto exit; - } - } else { - PyErr_Clear(); - - PyObject *read_method = PyObject_GetAttrString(py_file, "read"); - if (!(read_method && PyCallable_Check(read_method))) { - Py_XDECREF(read_method); - PyErr_SetString(PyExc_TypeError, - "Object does not appear to be a 8-bit string path or " - "a Python file-like object"); - goto exit; - } - Py_XDECREF(read_method); - _read_png_data(py_file, header, 8); - if (PyErr_Occurred()) { - goto exit; - } - } - - if (png_sig_cmp(header, 0, 8)) { - PyErr_SetString(PyExc_ValueError, "invalid PNG header"); - goto exit; - } - - /* initialize stuff */ - png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - - if (!png_ptr) { - PyErr_SetString(PyExc_RuntimeError, "png_create_read_struct failed"); - goto exit; - } - - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { - PyErr_SetString(PyExc_RuntimeError, "png_create_info_struct failed"); - goto exit; - } - - if (setjmp(png_jmpbuf(png_ptr))) { - if (!PyErr_Occurred()) { - PyErr_SetString(PyExc_RuntimeError, "error setting jump"); - } - goto exit; - } - - if (fp) { - png_init_io(png_ptr, fp); - } else { - png_set_read_fn(png_ptr, (void *)py_file, &read_png_data); - } - png_set_sig_bytes(png_ptr, 8); - png_read_info(png_ptr, info_ptr); - - width = png_get_image_width(png_ptr, info_ptr); - height = png_get_image_height(png_ptr, info_ptr); - - bit_depth = png_get_bit_depth(png_ptr, info_ptr); - - // Unpack 1, 2, and 4-bit images - if (bit_depth < 8) { - png_set_packing(png_ptr); - } - - // If sig bits are set, shift data - png_color_8p sig_bit; - if ((png_get_color_type(png_ptr, info_ptr) != PNG_COLOR_TYPE_PALETTE) && - png_get_sBIT(png_ptr, info_ptr, &sig_bit)) { - png_set_shift(png_ptr, sig_bit); - } - -#if NPY_BYTE_ORDER == NPY_LITTLE_ENDIAN - // Convert big endian to little - if (bit_depth == 16) { - png_set_swap(png_ptr); - } -#endif - - // Convert palletes to full RGB - if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_PALETTE) { - png_set_palette_to_rgb(png_ptr); - bit_depth = 8; - } - - // If there's an alpha channel convert gray to RGB - if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_GRAY_ALPHA) { - png_set_gray_to_rgb(png_ptr); - } - - png_set_interlace_handling(png_ptr); - png_read_update_info(png_ptr, info_ptr); - - row_pointers.resize(height); - for (png_uint_32 row = 0; row < height; row++) { - row_pointers[row] = new png_byte[png_get_rowbytes(png_ptr, info_ptr)]; - } - - png_read_image(png_ptr, &row_pointers[0]); - - npy_intp dimensions[3]; - dimensions[0] = height; // numrows - dimensions[1] = width; // numcols - if (png_get_color_type(png_ptr, info_ptr) & PNG_COLOR_MASK_ALPHA) { - dimensions[2] = 4; // RGBA images - } else if (png_get_color_type(png_ptr, info_ptr) & PNG_COLOR_MASK_COLOR) { - dimensions[2] = 3; // RGB images - } else { - dimensions[2] = 1; // Greyscale images - } - - if (float_result) { - double max_value = (1 << bit_depth) - 1; - - numpy::array_view<float, 3> A(dimensions); - - for (png_uint_32 y = 0; y < height; y++) { - png_byte *row = row_pointers[y]; - for (png_uint_32 x = 0; x < width; x++) { - if (bit_depth == 16) { - png_uint_16 *ptr = &reinterpret_cast<png_uint_16 *>(row)[x * dimensions[2]]; - for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++) { - A(y, x, p) = (float)(ptr[p]) / max_value; - } - } else { - png_byte *ptr = &(row[x * dimensions[2]]); - for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++) { - A(y, x, p) = (float)(ptr[p]) / max_value; - } - } - } - } - - result = A.pyobj(); - } else if (bit_depth == 16) { - numpy::array_view<png_uint_16, 3> A(dimensions); - - for (png_uint_32 y = 0; y < height; y++) { - png_byte *row = row_pointers[y]; - for (png_uint_32 x = 0; x < width; x++) { - png_uint_16 *ptr = &reinterpret_cast<png_uint_16 *>(row)[x * dimensions[2]]; - for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++) { - A(y, x, p) = ptr[p]; - } - } - } - - result = A.pyobj(); - } else if (bit_depth == 8) { - numpy::array_view<png_byte, 3> A(dimensions); - - for (png_uint_32 y = 0; y < height; y++) { - png_byte *row = row_pointers[y]; - for (png_uint_32 x = 0; x < width; x++) { - png_byte *ptr = &(row[x * dimensions[2]]); - for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++) { - A(y, x, p) = ptr[p]; - } - } - } - - result = A.pyobj(); - } else { - PyErr_SetString(PyExc_RuntimeError, "image has unknown bit depth"); - goto exit; - } - - // free the png memory - png_read_end(png_ptr, info_ptr); - - // For gray, return an x by y array, not an x by y by 1 - num_dims = (png_get_color_type(png_ptr, info_ptr) & PNG_COLOR_MASK_COLOR) ? 3 : 2; - - if (num_dims == 2) { - PyArray_Dims dims = {dimensions, 2}; - PyObject *reshaped = PyArray_Newshape((PyArrayObject *)result, &dims, NPY_CORDER); - Py_DECREF(result); - result = reshaped; - } - -exit: - if (png_ptr && info_ptr) { -#ifndef png_infopp_NULL - png_destroy_read_struct(&png_ptr, &info_ptr, NULL); -#else - png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); -#endif - } - - if (close_dup_file) { - mpl_PyFile_DupClose(py_file, fp, offset); - } - - if (close_file) { - mpl_PyFile_CloseFile(py_file); - Py_DECREF(py_file); - } - - for (png_uint_32 row = 0; row < height; row++) { - delete[] row_pointers[row]; - } - - if (PyErr_Occurred()) { - Py_XDECREF(result); - return NULL; - } else { - return result; - } -} - -const char *Py_read_png_float__doc__ = - "read_png_float(file)\n" - "\n" - "Read in a PNG file, converting values to floating-point doubles\n" - "in the range (0, 1)\n" - "\n" - "Parameters\n" - "----------\n" - "file : str path or file-like object\n"; - -static PyObject *Py_read_png_float(PyObject *self, PyObject *args, PyObject *kwds) -{ - return _read_png(args, true); -} - -const char *Py_read_png_int__doc__ = - "read_png_int(file)\n" - "\n" - "Read in a PNG file with original integer values.\n" - "\n" - "Parameters\n" - "----------\n" - "file : str path or file-like object\n"; - -static PyObject *Py_read_png_int(PyObject *self, PyObject *args, PyObject *kwds) -{ - return _read_png(args, false); -} - -const char *Py_read_png__doc__ = - "read_png(file)\n" - "\n" - "Read in a PNG file, converting values to floating-point doubles\n" - "in the range (0, 1)\n" - "\n" - "Alias for read_png_float()\n" - "\n" - "Parameters\n" - "----------\n" - "file : str path or file-like object\n"; - -static PyMethodDef module_methods[] = { - {"write_png", (PyCFunction)Py_write_png, METH_VARARGS|METH_KEYWORDS, Py_write_png__doc__}, - {"read_png", (PyCFunction)Py_read_png_float, METH_O, Py_read_png__doc__}, - {"read_png_float", (PyCFunction)Py_read_png_float, METH_O, Py_read_png_float__doc__}, - {"read_png_int", (PyCFunction)Py_read_png_int, METH_O, Py_read_png_int__doc__}, - {NULL} -}; - -extern "C" { - -#if PY3K - static struct PyModuleDef moduledef = { - PyModuleDef_HEAD_INIT, - "_png", - NULL, - 0, - module_methods, - NULL, - NULL, - NULL, - NULL - }; - -#define INITERROR return NULL - - PyMODINIT_FUNC PyInit__png(void) - -#else -#define INITERROR return - - PyMODINIT_FUNC init_png(void) -#endif - - { - PyObject *m; - -#if PY3K - m = PyModule_Create(&moduledef); -#else - m = Py_InitModule3("_png", module_methods, NULL); -#endif - - if (m == NULL) { - INITERROR; - } - - import_array(); - - if (PyModule_AddIntConstant(m, "PNG_FILTER_NONE", PNG_FILTER_NONE) || - PyModule_AddIntConstant(m, "PNG_FILTER_SUB", PNG_FILTER_SUB) || - PyModule_AddIntConstant(m, "PNG_FILTER_UP", PNG_FILTER_UP) || - PyModule_AddIntConstant(m, "PNG_FILTER_AVG", PNG_FILTER_AVG) || - PyModule_AddIntConstant(m, "PNG_FILTER_PAETH", PNG_FILTER_PAETH)) { - INITERROR; - } - - -#if PY3K - return m; -#endif - } -} diff --git a/contrib/python/matplotlib/py2/src/_tkagg.cpp b/contrib/python/matplotlib/py2/src/_tkagg.cpp deleted file mode 100644 index 106f1398b3..0000000000 --- a/contrib/python/matplotlib/py2/src/_tkagg.cpp +++ /dev/null @@ -1,475 +0,0 @@ -/* -*- mode: c++; c-basic-offset: 4 -*- */ - -/* - * This code is derived from The Python Imaging Library and is covered - * by the PIL license. - * - * See LICENSE/LICENSE.PIL for details. - * - */ -#define PY_SSIZE_T_CLEAN -#include <Python.h> -#include <cstdlib> -#include <cstdio> -#include <sstream> - -#include <agg_basics.h> // agg:int8u - -// Include our own excerpts from the Tcl / Tk headers -#include "_tkmini.h" - -#if defined(_MSC_VER) -# define IMG_FORMAT "%d %d %Iu" -#else -# define IMG_FORMAT "%d %d %zu" -#endif -#define BBOX_FORMAT "%f %f %f %f" - -typedef struct -{ - PyObject_HEAD - Tcl_Interp *interp; -} TkappObject; - -// Global vars for Tcl / Tk functions. We load these symbols from the tkinter -// extension module or loaded Tcl / Tk libraries at run-time. -static Tcl_CreateCommand_t TCL_CREATE_COMMAND; -static Tcl_AppendResult_t TCL_APPEND_RESULT; -static Tk_MainWindow_t TK_MAIN_WINDOW; -static Tk_FindPhoto_t TK_FIND_PHOTO; -static Tk_PhotoPutBlock_NoComposite_t TK_PHOTO_PUT_BLOCK_NO_COMPOSITE; -static Tk_PhotoBlank_t TK_PHOTO_BLANK; - -static int PyAggImagePhoto(ClientData clientdata, Tcl_Interp *interp, int - argc, char **argv) -{ - Tk_PhotoHandle photo; - Tk_PhotoImageBlock block; - - // vars for blitting - - size_t pdata; - int wdata, hdata, bbox_parse; - float x1, x2, y1, y2; - bool has_bbox; - agg::int8u *destbuffer, *buffer; - int destx, desty, destwidth, destheight, deststride; - - long mode; - long nval; - if (TK_MAIN_WINDOW(interp) == NULL) { - // Will throw a _tkinter.TclError with "this isn't a Tk application" - return TCL_ERROR; - } - - if (argc != 5) { - TCL_APPEND_RESULT(interp, "usage: ", argv[0], " destPhoto srcImage", (char *)NULL); - return TCL_ERROR; - } - - /* get Tcl PhotoImage handle */ - photo = TK_FIND_PHOTO(interp, argv[1]); - if (photo == NULL) { - TCL_APPEND_RESULT(interp, "destination photo must exist", (char *)NULL); - return TCL_ERROR; - } - /* get buffer from str which is "height width ptr" */ - if (sscanf(argv[2], IMG_FORMAT, &hdata, &wdata, &pdata) != 3) { - TCL_APPEND_RESULT(interp, - "error reading data, expected height width ptr", - (char *)NULL); - return TCL_ERROR; - } - buffer = (agg::int8u*)pdata; - - /* get array mode (0=mono, 1=rgb, 2=rgba) */ - mode = atol(argv[3]); - if ((mode != 0) && (mode != 1) && (mode != 2)) { - TCL_APPEND_RESULT(interp, "illegal image mode", (char *)NULL); - return TCL_ERROR; - } - - /* check for bbox/blitting */ - bbox_parse = sscanf(argv[4], BBOX_FORMAT, &x1, &x2, &y1, &y2); - if (bbox_parse == 4) { - has_bbox = true; - } - else if ((bbox_parse == 1) && (x1 == 0)){ - has_bbox = false; - } else { - TCL_APPEND_RESULT(interp, "illegal bbox", (char *)NULL); - return TCL_ERROR; - } - - if (has_bbox) { - int srcstride = wdata * 4; - destx = (int)x1; - desty = (int)(hdata - y2); - destwidth = (int)(x2 - x1); - destheight = (int)(y2 - y1); - deststride = 4 * destwidth; - - destbuffer = new agg::int8u[deststride * destheight]; - if (destbuffer == NULL) { - TCL_APPEND_RESULT(interp, "could not allocate memory", (char *)NULL); - return TCL_ERROR; - } - - for (int i = 0; i < destheight; ++i) { - memcpy(destbuffer + (deststride * i), - &buffer[(i + desty) * srcstride + (destx * 4)], - deststride); - } - } else { - destbuffer = NULL; - destx = desty = destwidth = destheight = deststride = 0; - } - - /* setup tkblock */ - block.pixelSize = 1; - if (mode == 0) { - block.offset[0] = block.offset[1] = block.offset[2] = 0; - nval = 1; - } else { - block.offset[0] = 0; - block.offset[1] = 1; - block.offset[2] = 2; - if (mode == 1) { - block.offset[3] = 0; - block.pixelSize = 3; - nval = 3; - } else { - block.offset[3] = 3; - block.pixelSize = 4; - nval = 4; - } - } - - if (has_bbox) { - block.width = destwidth; - block.height = destheight; - block.pitch = deststride; - block.pixelPtr = destbuffer; - - TK_PHOTO_PUT_BLOCK_NO_COMPOSITE(photo, &block, destx, desty, - destwidth, destheight); - delete[] destbuffer; - - } else { - block.width = wdata; - block.height = hdata; - block.pitch = (int)block.width * nval; - block.pixelPtr = buffer; - - /* Clear current contents */ - TK_PHOTO_BLANK(photo); - /* Copy opaque block to photo image, and leave the rest to TK */ - TK_PHOTO_PUT_BLOCK_NO_COMPOSITE(photo, &block, 0, 0, block.width, - block.height); - } - - return TCL_OK; -} - -static PyObject *_tkinit(PyObject *self, PyObject *args) -{ - Tcl_Interp *interp; - TkappObject *app; - - PyObject *arg; - int is_interp; - if (!PyArg_ParseTuple(args, "Oi", &arg, &is_interp)) { - return NULL; - } - - if (is_interp) { - interp = (Tcl_Interp *)PyLong_AsVoidPtr(arg); - } else { - /* Do it the hard way. This will break if the TkappObject - layout changes */ - app = (TkappObject *)arg; - interp = app->interp; - } - - /* This will bomb if interp is invalid... */ - - TCL_CREATE_COMMAND(interp, - "PyAggImagePhoto", - (Tcl_CmdProc *)PyAggImagePhoto, - (ClientData)0, - (Tcl_CmdDeleteProc *)NULL); - - Py_INCREF(Py_None); - return Py_None; -} - -static PyMethodDef functions[] = { - /* Tkinter interface stuff */ - { "tkinit", (PyCFunction)_tkinit, 1 }, - { NULL, NULL } /* sentinel */ -}; - -// Functions to fill global TCL / Tk function pointers by dynamic loading -#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) - -/* - * On Windows, we can't load the tkinter module to get the TCL or 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 and Tk - * function names. - */ -#include <windows.h> -#define PSAPI_VERSION 1 -#include <psapi.h> -// Must be linked with 'psapi' library - -FARPROC _dfunc(HMODULE lib_handle, const char *func_name) -{ - // Load function `func_name` from `lib_handle`. - // Set Python exception if we can't find `func_name` in `lib_handle`. - // Returns function pointer or NULL if not present. - - char message[100]; - - FARPROC func = GetProcAddress(lib_handle, func_name); - if (func == NULL) { - sprintf(message, "Cannot load function %s", func_name); - PyErr_SetString(PyExc_RuntimeError, message); - } - return func; -} - -int get_tcl(HMODULE hMod) -{ - // Try to fill TCL global vars with function pointers. Return 0 for no - // functions found, 1 for all functions found, -1 for some but not all - // functions found. - TCL_CREATE_COMMAND = (Tcl_CreateCommand_t) - GetProcAddress(hMod, "Tcl_CreateCommand"); - if (TCL_CREATE_COMMAND == NULL) { // Maybe not TCL module - return 0; - } - TCL_APPEND_RESULT = (Tcl_AppendResult_t) _dfunc(hMod, - "Tcl_AppendResult"); - return (TCL_APPEND_RESULT == NULL) ? -1 : 1; -} - -int get_tk(HMODULE hMod) -{ - // Try to fill Tk global vars with function pointers. Return 0 for no - // functions found, 1 for all functions found, -1 for some but not all - // functions found. - TK_MAIN_WINDOW = (Tk_MainWindow_t) - GetProcAddress(hMod, "Tk_MainWindow"); - if (TK_MAIN_WINDOW == NULL) { // Maybe not Tk module - return 0; - } - return ( // -1 if any remaining symbols are NULL - ((TK_FIND_PHOTO = (Tk_FindPhoto_t) - _dfunc(hMod, "Tk_FindPhoto")) == NULL) || - ((TK_PHOTO_PUT_BLOCK_NO_COMPOSITE = (Tk_PhotoPutBlock_NoComposite_t) - _dfunc(hMod, "Tk_PhotoPutBlock_NoComposite")) == NULL) || - ((TK_PHOTO_BLANK = (Tk_PhotoBlank_t) - _dfunc(hMod, "Tk_PhotoBlank")) == NULL)) - ? -1 : 1; -} - -int load_tkinter_funcs(void) -{ - // Load TCL and Tk functions by searching all modules in current process. - // Return 0 for success, non-zero for failure. - - HMODULE hMods[1024]; - HANDLE hProcess; - DWORD cbNeeded; - unsigned int i; - int found_tcl = 0; - int found_tk = 0; - - // Returns pseudo-handle that does not need to be closed - hProcess = GetCurrentProcess(); - - // Iterate through modules in this process looking for TCL / Tk names - if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) { - for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) { - if (!found_tcl) { - found_tcl = get_tcl(hMods[i]); - if (found_tcl == -1) { - return 1; - } - } - if (!found_tk) { - found_tk = get_tk(hMods[i]); - if (found_tk == -1) { - return 1; - } - } - if (found_tcl && found_tk) { - return 0; - } - } - } - - if (found_tcl == 0) { - PyErr_SetString(PyExc_RuntimeError, "Could not find TCL routines"); - } else { - PyErr_SetString(PyExc_RuntimeError, "Could not find Tk routines"); - } - return 1; -} - -#else // not Windows - -/* - * On Unix, we can get the TCL and Tk synbols from the tkinter module, because - * tkinter uses these symbols, and the symbols are therefore visible in the - * tkinter dynamic library (module). - */ -#if PY_MAJOR_VERSION >= 3 -#define TKINTER_PKG "tkinter" -#define TKINTER_MOD "_tkinter" -// From module __file__ attribute to char *string for dlopen. -char *fname2char(PyObject *fname) -{ - PyObject* bytes; - bytes = PyUnicode_EncodeFSDefault(fname); - if (bytes == NULL) { - return NULL; - } - return PyBytes_AsString(bytes); -} -#else -#define TKINTER_PKG "Tkinter" -#define TKINTER_MOD "tkinter" -// From module __file__ attribute to char *string for dlopen -#define fname2char(s) (PyString_AsString(s)) -#endif - -#include <dlfcn.h> - -void *_dfunc(void *lib_handle, const char *func_name) -{ - // Load function `func_name` from `lib_handle`. - // Set Python exception if we can't find `func_name` in `lib_handle`. - // Returns function pointer or NULL if not present. - - void* func; - // Reset errors. - dlerror(); - func = dlsym(lib_handle, func_name); - if (func == NULL) { - const char *error = dlerror(); - PyErr_SetString(PyExc_RuntimeError, error); - } - return func; -} - -int _func_loader(void *lib) -{ - // Fill global function pointers from dynamic lib. - // Return 1 if any pointer is NULL, 0 otherwise. - return ( - ((TCL_CREATE_COMMAND = (Tcl_CreateCommand_t) - _dfunc(lib, "Tcl_CreateCommand")) == NULL) || - ((TCL_APPEND_RESULT = (Tcl_AppendResult_t) - _dfunc(lib, "Tcl_AppendResult")) == NULL) || - ((TK_MAIN_WINDOW = (Tk_MainWindow_t) - _dfunc(lib, "Tk_MainWindow")) == NULL) || - ((TK_FIND_PHOTO = (Tk_FindPhoto_t) - _dfunc(lib, "Tk_FindPhoto")) == NULL) || - ((TK_PHOTO_PUT_BLOCK_NO_COMPOSITE = (Tk_PhotoPutBlock_NoComposite_t) - _dfunc(lib, "Tk_PhotoPutBlock_NoComposite")) == NULL) || - ((TK_PHOTO_BLANK = (Tk_PhotoBlank_t) - _dfunc(lib, "Tk_PhotoBlank")) == NULL)); -} - -int load_tkinter_funcs(void) -{ - // Load tkinter global funcs from tkinter compiled module. - // Return 0 for success, non-zero for failure. - int ret = -1; - void *main_program, *tkinter_lib; - char *tkinter_libname; - PyObject *pModule = NULL, *pSubmodule = NULL, *pString = NULL; - - // Try loading from the main program namespace first - main_program = dlopen(NULL, RTLD_LAZY); - if (_func_loader(main_program) == 0) { - return 0; - } - // Clear exception triggered when we didn't find symbols above. - PyErr_Clear(); - - // Now try finding the tkinter compiled module - pModule = PyImport_ImportModule(TKINTER_PKG); - if (pModule == NULL) { - goto exit; - } - pSubmodule = PyObject_GetAttrString(pModule, TKINTER_MOD); - if (pSubmodule == NULL) { - goto exit; - } - pString = PyObject_GetAttrString(pSubmodule, "__file__"); - if (pString == NULL) { - goto exit; - } - tkinter_libname = fname2char(pString); - if (tkinter_libname == NULL) { - goto exit; - } - tkinter_lib = dlopen(tkinter_libname, RTLD_LAZY); - if (tkinter_lib == NULL) { - /* Perhaps it is a cffi module, like in PyPy? */ - pString = PyObject_GetAttrString(pSubmodule, "tklib_cffi"); - if (pString == NULL) { - goto fail; - } - pString = PyObject_GetAttrString(pString, "__file__"); - if (pString == NULL) { - goto fail; - } - tkinter_libname = fname2char(pString); - if (tkinter_libname == NULL) { - goto fail; - } - tkinter_lib = dlopen(tkinter_libname, RTLD_LAZY); - } - if (tkinter_lib == NULL) { - goto fail; - } - ret = _func_loader(tkinter_lib); - // dlclose probably safe because tkinter has been imported. - dlclose(tkinter_lib); - goto exit; -fail: - PyErr_SetString(PyExc_RuntimeError, - "Cannot dlopen tkinter module file"); -exit: - Py_XDECREF(pModule); - Py_XDECREF(pSubmodule); - Py_XDECREF(pString); - return ret; -} -#endif // end not Windows - -#if PY_MAJOR_VERSION >= 3 -static PyModuleDef _tkagg_module = { PyModuleDef_HEAD_INIT, "_tkagg", "", -1, functions, - NULL, NULL, NULL, NULL }; - -PyMODINIT_FUNC PyInit__tkagg(void) -{ - PyObject *m; - - m = PyModule_Create(&_tkagg_module); - - return (load_tkinter_funcs() == 0) ? m : NULL; -} -#else -PyMODINIT_FUNC init_tkagg(void) -{ - Py_InitModule("_tkagg", functions); - - load_tkinter_funcs(); -} -#endif diff --git a/contrib/python/matplotlib/py2/src/_tkmini.h b/contrib/python/matplotlib/py2/src/_tkmini.h deleted file mode 100644 index 9b730b6c8c..0000000000 --- a/contrib/python/matplotlib/py2/src/_tkmini.h +++ /dev/null @@ -1,128 +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 - -/* Tcl header excerpts */ -#define TCL_OK 0 -#define TCL_ERROR 1 - -/* - * Users of versions of Tcl >= 8.6 encouraged to tread Tcl_Interp as an opaque - * pointer. The following definition results when TCL_NO_DEPRECATED defined. - */ -typedef struct Tcl_Interp Tcl_Interp; - -typedef struct Tcl_Command_ *Tcl_Command; -typedef void *ClientData; - -typedef int (Tcl_CmdProc) (ClientData clientData, Tcl_Interp - *interp, int argc, const char *argv[]); -typedef void (Tcl_CmdDeleteProc) (ClientData clientData); - -/* Typedefs derived from function signatures in Tcl header */ -/* Tcl_CreateCommand */ -typedef Tcl_Command (*Tcl_CreateCommand_t)(Tcl_Interp *interp, - const char *cmdName, Tcl_CmdProc *proc, - ClientData clientData, - Tcl_CmdDeleteProc *deleteProc); -/* Tcl_AppendResult */ -typedef void (*Tcl_AppendResult_t) (Tcl_Interp *interp, ...); - -/* Tk header excerpts */ -typedef struct Tk_Window_ *Tk_Window; - -typedef void *Tk_PhotoHandle; - -typedef struct Tk_PhotoImageBlock -{ - unsigned char *pixelPtr; - int width; - int height; - int pitch; - int pixelSize; - int offset[4]; -} Tk_PhotoImageBlock; - -/* Typedefs derived from function signatures in Tk header */ -/* Tk_MainWindow */ -typedef Tk_Window (*Tk_MainWindow_t) (Tcl_Interp *interp); -typedef Tk_PhotoHandle (*Tk_FindPhoto_t) (Tcl_Interp *interp, const char - *imageName); -/* Tk_PhotoPutBLock_NoComposite typedef */ -typedef void (*Tk_PhotoPutBlock_NoComposite_t) (Tk_PhotoHandle handle, - Tk_PhotoImageBlock *blockPtr, int x, int y, - int width, int height); -/* Tk_PhotoBlank */ -typedef void (*Tk_PhotoBlank_t) (Tk_PhotoHandle handle); - -/* - * end block for C++ - */ - -#ifdef __cplusplus -} -#endif diff --git a/contrib/python/matplotlib/py2/src/_ttconv.cpp b/contrib/python/matplotlib/py2/src/_ttconv.cpp deleted file mode 100644 index e18c8a53ca..0000000000 --- a/contrib/python/matplotlib/py2/src/_ttconv.cpp +++ /dev/null @@ -1,307 +0,0 @@ -/* -*- mode: c++; c-basic-offset: 4 -*- */ - -/* - _ttconv.c - - Python wrapper for TrueType conversion library in ../ttconv. - */ -#define PY_SSIZE_T_CLEAN -#include "mplutils.h" - -#include <Python.h> -#include "ttconv/pprdrv.h" -#include "py_exceptions.h" -#include <vector> -#include <cassert> - -/** - * An implementation of TTStreamWriter that writes to a Python - * file-like object. - */ -class PythonFileWriter : public TTStreamWriter -{ - PyObject *_write_method; - - public: - PythonFileWriter() - { - _write_method = NULL; - } - - ~PythonFileWriter() - { - Py_XDECREF(_write_method); - } - - void set(PyObject *write_method) - { - Py_XDECREF(_write_method); - _write_method = write_method; - Py_XINCREF(_write_method); - } - - virtual void write(const char *a) - { - PyObject *result = NULL; - if (_write_method) { - PyObject *decoded = NULL; - decoded = PyUnicode_DecodeLatin1(a, strlen(a), ""); - if (decoded == NULL) { - throw py::exception(); - } - result = PyObject_CallFunction(_write_method, (char *)"O", decoded); - Py_DECREF(decoded); - if (!result) { - throw py::exception(); - } - Py_DECREF(result); - } - } -}; - -int fileobject_to_PythonFileWriter(PyObject *object, void *address) -{ - PythonFileWriter *file_writer = (PythonFileWriter *)address; - - PyObject *write_method = PyObject_GetAttrString(object, "write"); - if (write_method == NULL || !PyCallable_Check(write_method)) { - PyErr_SetString(PyExc_TypeError, "Expected a file-like object with a write method."); - return 0; - } - - file_writer->set(write_method); - Py_DECREF(write_method); - - return 1; -} - -int pyiterable_to_vector_int(PyObject *object, void *address) -{ - std::vector<int> *result = (std::vector<int> *)address; - - PyObject *iterator = PyObject_GetIter(object); - if (!iterator) { - return 0; - } - - PyObject *item; - while ((item = PyIter_Next(iterator))) { -#if PY3K - long value = PyLong_AsLong(item); -#else - long value = PyInt_AsLong(item); -#endif - Py_DECREF(item); - if (value == -1 && PyErr_Occurred()) { - return 0; - } - result->push_back((int)value); - } - - Py_DECREF(iterator); - - return 1; -} - -static PyObject *convert_ttf_to_ps(PyObject *self, PyObject *args, PyObject *kwds) -{ - const char *filename; - PythonFileWriter output; - int fonttype; - std::vector<int> glyph_ids; - - static const char *kwlist[] = { "filename", "output", "fonttype", "glyph_ids", NULL }; - if (!PyArg_ParseTupleAndKeywords(args, - kwds, -#if PY_MAJOR_VERSION == 3 - "yO&i|O&:convert_ttf_to_ps", -#else - "sO&i|O&:convert_ttf_to_ps", -#endif - (char **)kwlist, - &filename, - fileobject_to_PythonFileWriter, - &output, - &fonttype, - pyiterable_to_vector_int, - &glyph_ids)) { - return NULL; - } - - if (fonttype != 3 && fonttype != 42) { - PyErr_SetString(PyExc_ValueError, - "fonttype must be either 3 (raw Postscript) or 42 " - "(embedded Truetype)"); - return NULL; - } - - try - { - insert_ttfont(filename, output, (font_type_enum)fonttype, glyph_ids); - } - catch (TTException &e) - { - PyErr_SetString(PyExc_RuntimeError, e.getMessage()); - return NULL; - } - catch (const py::exception &) - { - return NULL; - } - catch (...) - { - PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception"); - return NULL; - } - - Py_INCREF(Py_None); - return Py_None; -} - -class PythonDictionaryCallback : public TTDictionaryCallback -{ - PyObject *_dict; - - public: - PythonDictionaryCallback(PyObject *dict) - { - _dict = dict; - } - - virtual void add_pair(const char *a, const char *b) - { - assert(a != NULL); - assert(b != NULL); - PyObject *value = PyBytes_FromString(b); - if (!value) { - throw py::exception(); - } - if (PyDict_SetItemString(_dict, a, value)) { - Py_DECREF(value); - throw py::exception(); - } - Py_DECREF(value); - } -}; - -static PyObject *py_get_pdf_charprocs(PyObject *self, PyObject *args, PyObject *kwds) -{ - const char *filename; - std::vector<int> glyph_ids; - PyObject *result; - - static const char *kwlist[] = { "filename", "glyph_ids", NULL }; - if (!PyArg_ParseTupleAndKeywords(args, - kwds, -#if PY_MAJOR_VERSION == 3 - "y|O&:get_pdf_charprocs", -#else - "s|O&:get_pdf_charprocs", -#endif - (char **)kwlist, - &filename, - pyiterable_to_vector_int, - &glyph_ids)) { - return NULL; - } - - result = PyDict_New(); - if (!result) { - return NULL; - } - - PythonDictionaryCallback dict(result); - - try - { - ::get_pdf_charprocs(filename, glyph_ids, dict); - } - catch (TTException &e) - { - Py_DECREF(result); - PyErr_SetString(PyExc_RuntimeError, e.getMessage()); - return NULL; - } - catch (const py::exception &) - { - Py_DECREF(result); - return NULL; - } - catch (...) - { - Py_DECREF(result); - PyErr_SetString(PyExc_RuntimeError, "Unknown C++ exception"); - return NULL; - } - - return result; -} - -static PyMethodDef ttconv_methods[] = -{ - { - "convert_ttf_to_ps", (PyCFunction)convert_ttf_to_ps, METH_VARARGS | METH_KEYWORDS, - "convert_ttf_to_ps(filename, output, fonttype, glyph_ids)\n" - "\n" - "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.\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." - }, - { - "get_pdf_charprocs", (PyCFunction)py_get_pdf_charprocs, METH_VARARGS | METH_KEYWORDS, - "get_pdf_charprocs(filename, glyph_ids)\n" - "\n" - "Given a Truetype font file, returns a dictionary containing the PDF Type 3\n" - "representation of its paths. Useful for subsetting a Truetype font inside\n" - "of a PDF file.\n" - "\n" - "filename is the path to a TTF font file.\n" - "glyph_ids is a list of the numeric glyph ids to include.\n" - "The return value is a dictionary where the keys are glyph names and\n" - "the values are the stream content needed to render that glyph. This\n" - "is useful to generate the CharProcs dictionary in a PDF Type 3 font.\n" - }, - {0, 0, 0, 0} /* Sentinel */ -}; - -static const char *module_docstring = - "Module to handle converting and subsetting TrueType " - "fonts to Postscript Type 3, Postscript Type 42 and " - "Pdf Type 3 fonts."; - -#if PY3K -static PyModuleDef ttconv_module = { - PyModuleDef_HEAD_INIT, - "ttconv", - module_docstring, - -1, - ttconv_methods, - NULL, NULL, NULL, NULL -}; - -PyMODINIT_FUNC -PyInit_ttconv(void) -{ - PyObject* m; - - m = PyModule_Create(&ttconv_module); - - return m; -} -#else -PyMODINIT_FUNC -initttconv(void) -{ - Py_InitModule3("ttconv", ttconv_methods, module_docstring); -} -#endif diff --git a/contrib/python/matplotlib/py2/src/_windowing.cpp b/contrib/python/matplotlib/py2/src/_windowing.cpp deleted file mode 100644 index 7a20baa0a3..0000000000 --- a/contrib/python/matplotlib/py2/src/_windowing.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "Python.h" -#include <windows.h> - -static PyObject * -_GetForegroundWindow(PyObject *module, PyObject *args) -{ - HWND handle = GetForegroundWindow(); - if (!PyArg_ParseTuple(args, ":GetForegroundWindow")) - { - return NULL; - } - return PyLong_FromSize_t((size_t)handle); -} - -static PyObject * -_SetForegroundWindow(PyObject *module, PyObject *args) -{ - HWND handle; - if (!PyArg_ParseTuple(args, "n:SetForegroundWindow", &handle)) - { - return NULL; - } - if (!SetForegroundWindow(handle)) - { - return PyErr_Format(PyExc_RuntimeError, - "Error setting window"); - } - Py_INCREF(Py_None); - return Py_None; -} - -static PyMethodDef _windowing_methods[] = -{ - {"GetForegroundWindow", _GetForegroundWindow, METH_VARARGS}, - {"SetForegroundWindow", _SetForegroundWindow, METH_VARARGS}, - {NULL, NULL} -}; - -#if PY_MAJOR_VERSION >= 3 - -static struct PyModuleDef moduledef = { - PyModuleDef_HEAD_INIT, - "_windowing", - "", - -1, - _windowing_methods, - NULL, - NULL, - NULL, - NULL -}; - -PyMODINIT_FUNC PyInit__windowing(void) -{ - PyObject *module = PyModule_Create(&moduledef); - return module; -} - -#else -PyMODINIT_FUNC init_windowing() -{ - Py_InitModule("_windowing", _windowing_methods); -} -#endif diff --git a/contrib/python/matplotlib/py2/src/agg_workaround.h b/contrib/python/matplotlib/py2/src/agg_workaround.h deleted file mode 100644 index bfadf39284..0000000000 --- a/contrib/python/matplotlib/py2/src/agg_workaround.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef __AGG_WORKAROUND_H__ -#define __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/py2/src/array.h b/contrib/python/matplotlib/py2/src/array.h deleted file mode 100644 index 8056366a1c..0000000000 --- a/contrib/python/matplotlib/py2/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 _SCALAR_H_ -#define _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/py2/src/file_compat.h b/contrib/python/matplotlib/py2/src/file_compat.h deleted file mode 100644 index 114279fb1a..0000000000 --- a/contrib/python/matplotlib/py2/src/file_compat.h +++ /dev/null @@ -1,240 +0,0 @@ -#ifndef __FILE_COMPAT_H__ -#define __FILE_COMPAT_H__ -#define PY_SSIZE_T_CLEAN -#include <Python.h> -#include <stdio.h> -#include "numpy/npy_common.h" -#include "numpy/ndarrayobject.h" -#include "mplutils.h" - -#ifdef __cplusplus -extern "C" { -#endif -#if defined(_MSC_VER) && defined(_WIN64) && (_MSC_VER > 1400) - #include <io.h> - #define mpl_fseek _fseeki64 - #define mpl_ftell _ftelli64 - #define mpl_lseek _lseeki64 - #define mpl_off_t npy_int64 - - #if NPY_SIZEOF_INT == 8 - #define MPL_OFF_T_PYFMT "i" - #elif NPY_SIZEOF_LONG == 8 - #define MPL_OFF_T_PYFMT "l" - #elif NPY_SIZEOF_LONGLONG == 8 - #define MPL_OFF_T_PYFMT "L" - #else - #error Unsupported size for type off_t - #endif -#else - #define mpl_fseek fseek - #define mpl_ftell ftell - #define mpl_lseek lseek - #define mpl_off_t off_t - - #if NPY_SIZEOF_INT == NPY_SIZEOF_SHORT - #define MPL_OFF_T_PYFMT "h" - #elif NPY_SIZEOF_INT == NPY_SIZEOF_INT - #define MPL_OFF_T_PYFMT "i" - #elif NPY_SIZEOF_INT == NPY_SIZEOF_LONG - #define MPL_OFF_T_PYFMT "l" - #elif NPY_SIZEOF_INT == NPY_SIZEOF_LONGLONG - #define MPL_OFF_T_PYFMT "L" - #else - #error Unsupported size for type off_t - #endif -#endif - -/* - * PyFile_* compatibility - */ -#if PY3K | defined(PYPY_VERSION) - -/* - * Get a FILE* handle to the file represented by the Python object - */ -static NPY_INLINE FILE *mpl_PyFile_Dup(PyObject *file, char *mode, mpl_off_t *orig_pos) -{ - int fd, fd2; - PyObject *ret, *os; - mpl_off_t pos; - FILE *handle; - - if (mode[0] != 'r') { - /* Flush first to ensure things end up in the file in the correct order */ - ret = PyObject_CallMethod(file, (char *)"flush", (char *)""); - if (ret == NULL) { - return NULL; - } - Py_DECREF(ret); - } - - fd = PyObject_AsFileDescriptor(file); - if (fd == -1) { - return NULL; - } - - /* The handle needs to be dup'd because we have to call fclose - at the end */ - os = PyImport_ImportModule("os"); - if (os == NULL) { - return NULL; - } - ret = PyObject_CallMethod(os, (char *)"dup", (char *)"i", fd); - Py_DECREF(os); - if (ret == NULL) { - return NULL; - } - fd2 = PyNumber_AsSsize_t(ret, NULL); - Py_DECREF(ret); - -/* Convert to FILE* handle */ -#ifdef _WIN32 - handle = _fdopen(fd2, mode); -#else - handle = fdopen(fd2, mode); -#endif - if (handle == NULL) { - PyErr_SetString(PyExc_IOError, "Getting a FILE* from a Python file object failed"); - } - - /* Record the original raw file handle position */ - *orig_pos = mpl_ftell(handle); - if (*orig_pos == -1) { - // handle is a stream, so we don't have to worry about this - return handle; - } - - /* Seek raw handle to the Python-side position */ - ret = PyObject_CallMethod(file, (char *)"tell", (char *)""); - if (ret == NULL) { - fclose(handle); - return NULL; - } - pos = PyNumber_AsSsize_t(ret, PyExc_OverflowError); - Py_DECREF(ret); - if (PyErr_Occurred()) { - fclose(handle); - return NULL; - } - if (mpl_fseek(handle, pos, SEEK_SET) == -1) { - PyErr_SetString(PyExc_IOError, "seeking file failed"); - return NULL; - } - return handle; -} - -/* - * Close the dup-ed file handle, and seek the Python one to the current position - */ -static NPY_INLINE int mpl_PyFile_DupClose(PyObject *file, FILE *handle, mpl_off_t orig_pos) -{ - PyObject *exc_type = NULL, *exc_value = NULL, *exc_tb = NULL; - PyErr_Fetch(&exc_type, &exc_value, &exc_tb); - - int fd; - PyObject *ret; - mpl_off_t position; - - position = mpl_ftell(handle); - - /* Close the FILE* handle */ - fclose(handle); - - /* Restore original file handle position, in order to not confuse - Python-side data structures. Note that this would fail if an exception - is currently set, which can happen as this function is called in cleanup - code, so we need to carefully fetch and restore the exception state. */ - fd = PyObject_AsFileDescriptor(file); - if (fd == -1) { - goto fail; - } - if (mpl_lseek(fd, orig_pos, SEEK_SET) != -1) { - if (position == -1) { - PyErr_SetString(PyExc_IOError, "obtaining file position failed"); - goto fail; - } - - /* Seek Python-side handle to the FILE* handle position */ - ret = PyObject_CallMethod(file, (char *)"seek", (char *)(MPL_OFF_T_PYFMT "i"), position, 0); - if (ret == NULL) { - goto fail; - } - Py_DECREF(ret); - } - PyErr_Restore(exc_type, exc_value, exc_tb); - return 0; -fail: - Py_XDECREF(exc_type); - Py_XDECREF(exc_value); - Py_XDECREF(exc_tb); - return -1; -} - -static NPY_INLINE int mpl_PyFile_Check(PyObject *file) -{ - int fd; - fd = PyObject_AsFileDescriptor(file); - if (fd == -1) { - PyErr_Clear(); - return 0; - } - return 1; -} - -#else - -static NPY_INLINE FILE *mpl_PyFile_Dup(PyObject *file, const char *mode, mpl_off_t *orig_pos) -{ - return PyFile_AsFile(file); -} - -static NPY_INLINE int mpl_PyFile_DupClose(PyObject *file, FILE *handle, mpl_off_t orig_pos) -{ - // deliberately nothing - return 0; -} - -static NPY_INLINE int mpl_PyFile_Check(PyObject *file) -{ - return PyFile_Check(file); -} - -#endif - -static NPY_INLINE PyObject *mpl_PyFile_OpenFile(PyObject *filename, const char *mode) -{ - PyObject *open; - open = PyDict_GetItemString(PyEval_GetBuiltins(), "open"); - if (open == NULL) { - return NULL; - } - return PyObject_CallFunction(open, (char *)"Os", filename, mode); -} - -static NPY_INLINE int mpl_PyFile_CloseFile(PyObject *file) -{ - PyObject *type, *value, *tb; - PyErr_Fetch(&type, &value, &tb); - - PyObject *ret; - - ret = PyObject_CallMethod(file, (char *)"close", NULL); - if (ret == NULL) { - goto fail; - } - Py_DECREF(ret); - PyErr_Restore(type, value, tb); - return 0; -fail: - Py_XDECREF(type); - Py_XDECREF(value); - Py_XDECREF(tb); - return -1; -} - -#ifdef __cplusplus -} -#endif - -#endif /* ifndef __FILE_COMPAT_H__ */ diff --git a/contrib/python/matplotlib/py2/src/ft2font.cpp b/contrib/python/matplotlib/py2/src/ft2font.cpp deleted file mode 100644 index 7245ca332a..0000000000 --- a/contrib/python/matplotlib/py2/src/ft2font.cpp +++ /dev/null @@ -1,808 +0,0 @@ -/* -*- mode: c++; c-basic-offset: 4 -*- */ - -#define NO_IMPORT_ARRAY - -#include <algorithm> -#include <stdexcept> -#include <string> - -#include "ft2font.h" -#include "mplutils.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://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; - -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 = CLAMP(x, 0, image_width); - FT_Int y1 = CLAMP(y, 0, image_height); - FT_Int x2 = CLAMP(x + char_width, 0, image_width); - FT_Int y2 = CLAMP(y + char_height, 0, image_height); - - FT_Int x_start = MAX(0, -x); - FT_Int y_offset = y1 - 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; -} - -inline double conv(long v) -{ - return double(v) / 64.0; -} - -int FT2Font::get_path_count() -{ - // get the glyph as a path, a list of (COMMAND, *args) as described in matplotlib.path - // this code is from agg's decompose_ft_outline with minor modifications - - if (!face->glyph) { - throw std::runtime_error("No glyph loaded"); - } - - FT_Outline &outline = face->glyph->outline; - - FT_Vector v_last; - FT_Vector v_control; - FT_Vector v_start; - - FT_Vector *point; - FT_Vector *limit; - unsigned char *tags; - - int n; // index of contour in outline - int first; // index of first point in contour - char tag; // current point's state - int count; - - count = 0; - first = 0; - for (n = 0; n < outline.n_contours; n++) { - int last; // index of last point in contour - bool starts_with_last; - - last = outline.contours[n]; - limit = outline.points + last; - - v_start = outline.points[first]; - v_last = outline.points[last]; - - v_control = v_start; - - point = outline.points + first; - tags = outline.tags + first; - tag = FT_CURVE_TAG(tags[0]); - - // A contour cannot start with a cubic control point! - if (tag == FT_CURVE_TAG_CUBIC) { - throw std::runtime_error("A contour cannot start with a cubic control point"); - } else if (tag == FT_CURVE_TAG_CONIC) { - starts_with_last = true; - } else { - starts_with_last = false; - } - - count++; - - while (point < limit) { - if (!starts_with_last) { - point++; - tags++; - } - starts_with_last = false; - - tag = FT_CURVE_TAG(tags[0]); - switch (tag) { - case FT_CURVE_TAG_ON: // emit a single line_to - { - count++; - continue; - } - - case FT_CURVE_TAG_CONIC: // consume conic arcs - { - Count_Do_Conic: - if (point < limit) { - point++; - tags++; - tag = FT_CURVE_TAG(tags[0]); - - if (tag == FT_CURVE_TAG_ON) { - count += 2; - continue; - } - - if (tag != FT_CURVE_TAG_CONIC) { - throw std::runtime_error("Invalid font"); - } - - count += 2; - - goto Count_Do_Conic; - } - - count += 2; - - goto Count_Close; - } - - default: // FT_CURVE_TAG_CUBIC - { - if (point + 1 > limit || FT_CURVE_TAG(tags[1]) != FT_CURVE_TAG_CUBIC) { - throw std::runtime_error("Invalid font"); - } - - point += 2; - tags += 2; - - if (point <= limit) { - count += 3; - continue; - } - - count += 3; - - goto Count_Close; - } - } - } - - Count_Close: - count++; - first = last + 1; - } - - return count; -} - -void FT2Font::get_path(double *outpoints, unsigned char *outcodes) -{ - FT_Outline &outline = face->glyph->outline; - bool flip_y = false; // todo, pass me as kwarg - - FT_Vector v_last; - FT_Vector v_control; - FT_Vector v_start; - - FT_Vector *point; - FT_Vector *limit; - unsigned char *tags; - - int n; // index of contour in outline - int first; // index of first point in contour - char tag; // current point's state - - first = 0; - for (n = 0; n < outline.n_contours; n++) { - int last; // index of last point in contour - bool starts_with_last; - - last = outline.contours[n]; - limit = outline.points + last; - - v_start = outline.points[first]; - v_last = outline.points[last]; - - v_control = v_start; - - point = outline.points + first; - tags = outline.tags + first; - tag = FT_CURVE_TAG(tags[0]); - - double x, y; - if (tag != FT_CURVE_TAG_ON) { - x = conv(v_last.x); - y = flip_y ? -conv(v_last.y) : conv(v_last.y); - starts_with_last = true; - } else { - x = conv(v_start.x); - y = flip_y ? -conv(v_start.y) : conv(v_start.y); - starts_with_last = false; - } - - *(outpoints++) = x; - *(outpoints++) = y; - *(outcodes++) = MOVETO; - - while (point < limit) { - if (!starts_with_last) { - point++; - tags++; - } - starts_with_last = false; - - tag = FT_CURVE_TAG(tags[0]); - switch (tag) { - case FT_CURVE_TAG_ON: // emit a single line_to - { - double x = conv(point->x); - double y = flip_y ? -conv(point->y) : conv(point->y); - *(outpoints++) = x; - *(outpoints++) = y; - *(outcodes++) = LINETO; - continue; - } - - case FT_CURVE_TAG_CONIC: // consume conic arcs - { - v_control.x = point->x; - v_control.y = point->y; - - Do_Conic: - if (point < limit) { - FT_Vector vec; - FT_Vector v_middle; - - point++; - tags++; - tag = FT_CURVE_TAG(tags[0]); - - vec.x = point->x; - vec.y = point->y; - - if (tag == FT_CURVE_TAG_ON) { - double xctl = conv(v_control.x); - double yctl = flip_y ? -conv(v_control.y) : conv(v_control.y); - double xto = conv(vec.x); - double yto = flip_y ? -conv(vec.y) : conv(vec.y); - *(outpoints++) = xctl; - *(outpoints++) = yctl; - *(outpoints++) = xto; - *(outpoints++) = yto; - *(outcodes++) = CURVE3; - *(outcodes++) = CURVE3; - continue; - } - - v_middle.x = (v_control.x + vec.x) / 2; - v_middle.y = (v_control.y + vec.y) / 2; - - double xctl = conv(v_control.x); - double yctl = flip_y ? -conv(v_control.y) : conv(v_control.y); - double xto = conv(v_middle.x); - double yto = flip_y ? -conv(v_middle.y) : conv(v_middle.y); - *(outpoints++) = xctl; - *(outpoints++) = yctl; - *(outpoints++) = xto; - *(outpoints++) = yto; - *(outcodes++) = CURVE3; - *(outcodes++) = CURVE3; - - v_control = vec; - goto Do_Conic; - } - double xctl = conv(v_control.x); - double yctl = flip_y ? -conv(v_control.y) : conv(v_control.y); - double xto = conv(v_start.x); - double yto = flip_y ? -conv(v_start.y) : conv(v_start.y); - - *(outpoints++) = xctl; - *(outpoints++) = yctl; - *(outpoints++) = xto; - *(outpoints++) = yto; - *(outcodes++) = CURVE3; - *(outcodes++) = CURVE3; - - goto Close; - } - - default: // FT_CURVE_TAG_CUBIC - { - FT_Vector vec1, vec2; - - vec1.x = point[0].x; - vec1.y = point[0].y; - vec2.x = point[1].x; - vec2.y = point[1].y; - - point += 2; - tags += 2; - - if (point <= limit) { - FT_Vector vec; - - vec.x = point->x; - vec.y = point->y; - - double xctl1 = conv(vec1.x); - double yctl1 = flip_y ? -conv(vec1.y) : conv(vec1.y); - double xctl2 = conv(vec2.x); - double yctl2 = flip_y ? -conv(vec2.y) : conv(vec2.y); - double xto = conv(vec.x); - double yto = flip_y ? -conv(vec.y) : conv(vec.y); - - (*outpoints++) = xctl1; - (*outpoints++) = yctl1; - (*outpoints++) = xctl2; - (*outpoints++) = yctl2; - (*outpoints++) = xto; - (*outpoints++) = yto; - (*outcodes++) = CURVE4; - (*outcodes++) = CURVE4; - (*outcodes++) = CURVE4; - continue; - } - - double xctl1 = conv(vec1.x); - double yctl1 = flip_y ? -conv(vec1.y) : conv(vec1.y); - double xctl2 = conv(vec2.x); - double yctl2 = flip_y ? -conv(vec2.y) : conv(vec2.y); - double xto = conv(v_start.x); - double yto = flip_y ? -conv(v_start.y) : conv(v_start.y); - (*outpoints++) = xctl1; - (*outpoints++) = yctl1; - (*outpoints++) = xctl2; - (*outpoints++) = yctl2; - (*outpoints++) = xto; - (*outpoints++) = yto; - (*outcodes++) = CURVE4; - (*outcodes++) = CURVE4; - (*outcodes++) = CURVE4; - - goto Close; - } - } - } - - Close: - (*outpoints++) = 0.0; - (*outpoints++) = 0.0; - (*outcodes++) = ENDPOLY; - first = last + 1; - } -} - -FT2Font::FT2Font(FT_Open_Args &open_args, long hinting_factor_) : image(), face(NULL) -{ - clear(); - - int error = FT_Open_Face(_ft2Library, &open_args, 0, &face); - - if (error == FT_Err_Unknown_File_Format) { - throw std::runtime_error("Can not load face. Unknown file format."); - } else if (error == FT_Err_Cannot_Open_Resource) { - throw std::runtime_error("Can not load face. Can not open resource."); - } else if (error == FT_Err_Invalid_File_Format) { - throw std::runtime_error("Can not load face. Invalid file format."); - } else if (error) { - throw std::runtime_error("Can not load face."); - } - - // 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 std::runtime_error("Could not set the fontsize"); - } - - 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); -} - -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() -{ - angle = 0.0; - - pen.x = 0; - pen.y = 0; - - for (size_t i = 0; i < glyphs.size(); i++) { - FT_Done_Glyph(glyphs[i]); - } - - glyphs.clear(); -} - -void FT2Font::set_size(double ptsize, double dpi) -{ - int error = FT_Set_Char_Size( - face, (long)(ptsize * 64), 0, (unsigned int)(dpi * hinting_factor), (unsigned int)dpi); - FT_Matrix transform = { 65536 / hinting_factor, 0, 0, 65536 }; - FT_Set_Transform(face, &transform, 0); - - if (error) { - throw std::runtime_error("Could not set the fontsize"); - } -} - -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_Set_Charmap(face, charmap)) { - throw std::runtime_error("Could not set the charmap"); - } -} - -void FT2Font::select_charmap(unsigned long i) -{ - if (FT_Select_Charmap(face, (FT_Encoding)i)) { - throw std::runtime_error("Could not set the charmap"); - } -} - -int FT2Font::get_kerning(FT_UInt left, FT_UInt right, FT_UInt mode) -{ - if (!FT_HAS_KERNING(face)) { - return 0; - } - FT_Vector delta; - - if (!FT_Get_Kerning(face, left, right, mode, &delta)) { - return (int)(delta.x) / (hinting_factor << 6); - } else { - return 0; - } -} - -void FT2Font::set_text( - size_t N, uint32_t *codepoints, double angle, FT_Int32 flags, std::vector<double> &xys) -{ - angle = angle / 360.0 * 2 * M_PI; - - // this computes width and height in subpixels so we have to divide by 64 - matrix.xx = (FT_Fixed)(cos(angle) * 0x10000L); - matrix.xy = (FT_Fixed)(-sin(angle) * 0x10000L); - matrix.yx = (FT_Fixed)(sin(angle) * 0x10000L); - matrix.yy = (FT_Fixed)(cos(angle) * 0x10000L); - - FT_Bool use_kerning = FT_HAS_KERNING(face); - FT_UInt previous = 0; - - clear(); - - bbox.xMin = bbox.yMin = 32000; - bbox.xMax = bbox.yMax = -32000; - - for (unsigned int n = 0; n < N; n++) { - std::string thischar("?"); - FT_UInt glyph_index; - FT_BBox glyph_bbox; - FT_Pos last_advance; - - glyph_index = FT_Get_Char_Index(face, codepoints[n]); - - // retrieve kerning distance and move pen position - if (use_kerning && previous && glyph_index) { - FT_Vector delta; - FT_Get_Kerning(face, previous, glyph_index, FT_KERNING_DEFAULT, &delta); - pen.x += (delta.x << 10) / (hinting_factor << 16); - } - error = FT_Load_Glyph(face, glyph_index, flags); - if (error) { - throw std::runtime_error("could not load glyph"); - } - // ignore errors, jump to next glyph - - // extract glyph image and store it in our table - - FT_Glyph thisGlyph; - error = FT_Get_Glyph(face->glyph, &thisGlyph); - - if (error) { - throw std::runtime_error("could not get glyph"); - } - // ignore errors, jump to next glyph - - last_advance = 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; - glyphs.push_back(thisGlyph); - } - - 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) -{ - int error = FT_Load_Char(face, (unsigned long)charcode, flags); - - if (error) { - throw std::runtime_error("Could not load charcode"); - } - - FT_Glyph thisGlyph; - error = FT_Get_Glyph(face->glyph, &thisGlyph); - - if (error) { - throw std::runtime_error("Could not get glyph"); - } - - glyphs.push_back(thisGlyph); -} - -void FT2Font::load_glyph(FT_UInt glyph_index, FT_Int32 flags) -{ - int error = FT_Load_Glyph(face, glyph_index, flags); - - if (error) { - throw std::runtime_error("Could not load glyph"); - } - - FT_Glyph thisGlyph; - error = FT_Get_Glyph(face->glyph, &thisGlyph); - - if (error) { - throw std::runtime_error("Could not load glyph"); - } - - glyphs.push_back(thisGlyph); -} - -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) -{ - size_t width = (bbox.xMax - bbox.xMin) / 64 + 2; - size_t height = (bbox.yMax - bbox.yMin) / 64 + 2; - - image.resize(width, height); - - for (size_t n = 0; n < glyphs.size(); n++) { - error = FT_Glyph_To_Bitmap( - &glyphs[n], antialiased ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO, 0, 1); - if (error) { - throw std::runtime_error("Could not convert glyph to bitmap"); - } - - 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 / 64.)); - FT_Int y = (FT_Int)((bbox.yMax / 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++) { - - error = FT_Glyph_To_Bitmap( - &glyphs[n], antialiased ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO, 0, 1); - if (error) { - throw std::runtime_error("Could not convert glyph to bitmap"); - } - - 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 / 64.); - FT_Int y = (FT_Int)(bbox.yMax / 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"); - } - - 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 std::runtime_error("Could not convert glyph to bitmap"); - } - - 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) -{ - 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_Get_Glyph_Name(face, glyph_number, buffer, 128)) { - throw std::runtime_error("Could not get glyph names."); - } - } -} - -long FT2Font::get_name_index(char *name) -{ - return FT_Get_Name_Index(face, (FT_String *)name); -} diff --git a/contrib/python/matplotlib/py2/src/ft2font.h b/contrib/python/matplotlib/py2/src/ft2font.h deleted file mode 100644 index 072428ceed..0000000000 --- a/contrib/python/matplotlib/py2/src/ft2font.h +++ /dev/null @@ -1,139 +0,0 @@ -/* -*- mode: c++; c-basic-offset: 4 -*- */ - -/* A python interface to FreeType */ -#ifndef _FT2FONT_H -#define _FT2FONT_H -#include <vector> -#include <stdint.h> - -extern "C" { -#include <ft2build.h> -#include FT_FREETYPE_H -#include FT_GLYPH_H -#include FT_SFNT_NAMES_H -#include FT_TYPE1_TABLES_H -#include FT_TRUETYPE_TABLES_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 write_bitmap(FILE *fp) const; - 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); - 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); - void load_char(long charcode, FT_Int32 flags); - 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); - long get_name_index(char *name); - int get_path_count(); - void get_path(double *outpoints, unsigned char *outcodes); - - FT_Face &get_face() - { - return face; - } - FT2Image &get_image() - { - return image; - } - FT_Glyph &get_last_glyph() - { - return glyphs.back(); - } - size_t get_last_glyph_index() - { - return glyphs.size() - 1; - } - size_t get_num_glyphs() - { - return glyphs.size(); - } - long get_hinting_factor() - { - return hinting_factor; - } - - private: - FT2Image image; - FT_Face face; - FT_Matrix matrix; /* transformation matrix */ - FT_Vector pen; /* untransformed origin */ - FT_Error error; - std::vector<FT_Glyph> glyphs; - std::vector<FT_Vector> pos; - FT_BBox bbox; - FT_Pos advance; - double angle; - double ptsize; - double dpi; - long hinting_factor; - - void set_scalable_attributes(); - - // prevent copying - FT2Font(const FT2Font &); - FT2Font &operator=(const FT2Font &); -}; - -#endif diff --git a/contrib/python/matplotlib/py2/src/ft2font_wrapper.cpp b/contrib/python/matplotlib/py2/src/ft2font_wrapper.cpp deleted file mode 100644 index d0e516ad02..0000000000 --- a/contrib/python/matplotlib/py2/src/ft2font_wrapper.cpp +++ /dev/null @@ -1,1808 +0,0 @@ -#include "mplutils.h" -#include "ft2font.h" -#include "file_compat.h" -#include "py_exceptions.h" -#include "numpy_cpp.h" - -// From Python -#include <structmember.h> - -#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 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(x0, y0, x1, y1)\n" - "\n" - "Draw a rect to the image.\n" - "\n"; - -static PyObject *PyFT2Image_draw_rect(PyFT2Image *self, PyObject *args, PyObject *kwds) -{ - 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(x0, y0, x1, y1)\n" - "\n" - "Draw a filled rect to the image.\n" - "\n"; - -static PyObject *PyFT2Image_draw_rect_filled(PyFT2Image *self, PyObject *args, PyObject *kwds) -{ - 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; -} - -const char *PyFT2Image_as_str__doc__ = - "s = image.as_str()\n" - "\n" - "Return the image buffer as a string\n" - "\n"; - -static PyObject *PyFT2Image_as_str(PyFT2Image *self, PyObject *args, PyObject *kwds) -{ - // TODO: Use a buffer to avoid the copy - return PyBytes_FromStringAndSize((const char *)self->x->get_buffer(), - self->x->get_width() * self->x->get_height()); -} - -const char *PyFT2Image_as_rgba_str__doc__ = - "s = image.as_rgba_str()\n" - "\n" - "Return the image buffer as a RGBA string\n" - "\n"; - -static PyObject *PyFT2Image_as_rgba_str(PyFT2Image *self, PyObject *args, PyObject *kwds) -{ - npy_intp dims[] = {(npy_intp)self->x->get_height(), (npy_intp)self->x->get_width(), 4 }; - numpy::array_view<unsigned char, 3> result(dims); - - unsigned char *src = self->x->get_buffer(); - unsigned char *end = src + (self->x->get_width() * self->x->get_height()); - unsigned char *dst = result.data(); - - while (src != end) { - *dst++ = 0; - *dst++ = 0; - *dst++ = 0; - *dst++ = *src++; - } - - return result.pyobj(); -} - -const char *PyFT2Image_as_array__doc__ = - "x = image.as_array()\n" - "\n" - "Return the image buffer as a width x height numpy array of ubyte \n" - "\n"; - -static PyObject *PyFT2Image_as_array(PyFT2Image *self, PyObject *args, PyObject *kwds) -{ - npy_intp dims[] = {(npy_intp)self->x->get_height(), (npy_intp)self->x->get_width() }; - return PyArray_SimpleNewFromData(2, dims, NPY_UBYTE, self->x->get_buffer()); -} - -static PyObject *PyFT2Image_get_width(PyFT2Image *self, PyObject *args, PyObject *kwds) -{ - return PyLong_FromLong(self->x->get_width()); -} - -static PyObject *PyFT2Image_get_height(PyFT2Image *self, PyObject *args, PyObject *kwds) -{ - return PyLong_FromLong(self->x->get_height()); -} - -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 PyFT2ImageType; - -static PyTypeObject *PyFT2Image_init_type(PyObject *m, PyTypeObject *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__}, - {"as_str", (PyCFunction)PyFT2Image_as_str, METH_NOARGS, PyFT2Image_as_str__doc__}, - {"as_rgba_str", (PyCFunction)PyFT2Image_as_rgba_str, METH_NOARGS, PyFT2Image_as_rgba_str__doc__}, - {"as_array", (PyCFunction)PyFT2Image_as_array, METH_NOARGS, PyFT2Image_as_array__doc__}, - {"get_width", (PyCFunction)PyFT2Image_get_width, METH_NOARGS, NULL}, - {"get_height", (PyCFunction)PyFT2Image_get_height, METH_NOARGS, NULL}, - {NULL} - }; - - static PyBufferProcs buffer_procs; - memset(&buffer_procs, 0, sizeof(PyBufferProcs)); - buffer_procs.bf_getbuffer = (getbufferproc)PyFT2Image_get_buffer; - - memset(type, 0, sizeof(PyTypeObject)); - type->tp_name = "matplotlib.ft2font.FT2Image"; - type->tp_basicsize = sizeof(PyFT2Image); - type->tp_dealloc = (destructor)PyFT2Image_dealloc; - type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_NEWBUFFER; - type->tp_methods = methods; - type->tp_new = PyFT2Image_new; - type->tp_init = (initproc)PyFT2Image_init; - type->tp_as_buffer = &buffer_procs; - - if (PyType_Ready(type) < 0) { - return NULL; - } - - if (PyModule_AddObject(m, "FT2Image", (PyObject *)type)) { - return NULL; - } - - return type; -} - -/********************************************************************** - * 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_new(const FT_Face &face, const FT_Glyph &glyph, size_t ind, long hinting_factor) -{ - PyGlyph *self; - self = (PyGlyph *)PyGlyphType.tp_alloc(&PyGlyphType, 0); - - self->glyphInd = ind; - - 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(PyObject *m, PyTypeObject *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} - }; - - memset(type, 0, sizeof(PyTypeObject)); - type->tp_name = "matplotlib.ft2font.Glyph"; - type->tp_basicsize = sizeof(PyGlyph); - type->tp_dealloc = (destructor)PyGlyph_dealloc; - type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; - type->tp_members = members; - type->tp_getset = getset; - - if (PyType_Ready(type) < 0) { - return NULL; - } - - /* Don't need to add to module, since you can't create glyphs - directly from Python */ - - return type; -} - -/********************************************************************** - * FT2Font - * */ - -typedef struct -{ - PyObject_HEAD - FT2Font *x; - PyObject *fname; - PyObject *py_file; - FILE *fp; - int close_file; - mpl_off_t offset; - FT_StreamRec stream; - FT_Byte *mem; - size_t mem_size; - Py_ssize_t shape[2]; - Py_ssize_t strides[2]; - Py_ssize_t suboffsets[2]; -} PyFT2Font; - -static unsigned long read_from_file_callback(FT_Stream stream, - unsigned long offset, - unsigned char *buffer, - unsigned long count) -{ - - PyFT2Font *def = (PyFT2Font *)stream->descriptor.pointer; - - if (fseek(def->fp, offset, SEEK_SET) == -1) { - return 0; - } - - if (count > 0) { - return fread(buffer, 1, count, def->fp); - } - - return 0; -} - -static void close_file_callback(FT_Stream stream) -{ - PyFT2Font *def = (PyFT2Font *)stream->descriptor.pointer; - - if (mpl_PyFile_DupClose(def->py_file, def->fp, def->offset)) { - throw std::runtime_error("Couldn't close file"); - } - - if (def->close_file) { - mpl_PyFile_CloseFile(def->py_file); - } - - Py_DECREF(def->py_file); - def->py_file = NULL; -} - -static int convert_open_args(PyFT2Font *self, PyObject *py_file_arg, FT_Open_Args *open_args) -{ - PyObject *py_file = NULL; - int close_file = 0; - FILE *fp; - PyObject *data = NULL; - char *data_ptr; - Py_ssize_t data_len; - long file_size; - FT_Byte *new_memory; - mpl_off_t offset = 0; - - int result = 0; - - memset((void *)open_args, 0, sizeof(FT_Open_Args)); - - if (PyBytes_Check(py_file_arg) || PyUnicode_Check(py_file_arg)) { - if ((py_file = mpl_PyFile_OpenFile(py_file_arg, (char *)"rb")) == NULL) { - goto exit; - } - close_file = 1; - } else { - Py_INCREF(py_file_arg); - py_file = py_file_arg; - } - - if ((fp = mpl_PyFile_Dup(py_file, (char *)"rb", &offset))) { - Py_INCREF(py_file); - self->py_file = py_file; - self->close_file = close_file; - self->fp = fp; - self->offset = offset; - fseek(fp, 0, SEEK_END); - file_size = ftell(fp); - fseek(fp, 0, SEEK_SET); - - self->stream.base = NULL; - self->stream.size = (unsigned long)file_size; - self->stream.pos = 0; - self->stream.descriptor.pointer = self; - self->stream.read = &read_from_file_callback; - self->stream.close = &close_file_callback; - - open_args->flags = FT_OPEN_STREAM; - open_args->stream = &self->stream; - } else { - if (PyObject_HasAttrString(py_file_arg, "read") && - (data = PyObject_CallMethod(py_file_arg, (char *)"read", (char *)""))) { - if (PyBytes_AsStringAndSize(data, &data_ptr, &data_len)) { - goto exit; - } - - if (self->mem) { - free(self->mem); - } - self->mem = (FT_Byte *)malloc((self->mem_size + data_len) * sizeof(FT_Byte)); - if (self->mem == NULL) { - goto exit; - } - new_memory = self->mem + self->mem_size; - self->mem_size += data_len; - - memcpy(new_memory, data_ptr, data_len); - open_args->flags = FT_OPEN_MEMORY; - open_args->memory_base = new_memory; - open_args->memory_size = data_len; - open_args->stream = NULL; - } else { - PyErr_SetString(PyExc_TypeError, - "First argument must be a path or file object reading bytes"); - goto exit; - } - } - - result = 1; - -exit: - - Py_XDECREF(py_file); - Py_XDECREF(data); - - return result; -} - -static PyTypeObject PyFT2FontType; - -static PyObject *PyFT2Font_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyFT2Font *self; - self = (PyFT2Font *)type->tp_alloc(type, 0); - self->x = NULL; - self->fname = NULL; - self->py_file = NULL; - self->fp = NULL; - self->close_file = 0; - self->offset = 0; - memset(&self->stream, 0, sizeof(FT_StreamRec)); - self->mem = 0; - self->mem_size = 0; - return (PyObject *)self; -} - -const char *PyFT2Font_init__doc__ = - "FT2Font(ttffile)\n" - "\n" - "Create a new FT2Font object\n" - "The following global font attributes are defined:\n" - " num_faces number of faces in file\n" - " face_flags face flags (int type); see the ft2font constants\n" - " style_flags style flags (int type); see the ft2font constants\n" - " num_glyphs number of glyphs in the face\n" - " family_name face family name\n" - " style_name face style name\n" - " num_fixed_sizes number of bitmap in the face\n" - " scalable face is scalable\n" - "\n" - "The following are available, if scalable is true:\n" - " bbox face global bounding box (xmin, ymin, xmax, ymax)\n" - " units_per_EM number of font units covered by the EM\n" - " ascender ascender in 26.6 units\n" - " descender descender in 26.6 units\n" - " height height in 26.6 units; used to compute a default\n" - " line spacing (baseline-to-baseline distance)\n" - " max_advance_width maximum horizontal cursor advance for all glyphs\n" - " max_advance_height same for vertical layout\n" - " underline_position vertical position of the underline bar\n" - " underline_thickness vertical thickness of the underline\n" - " postscript_name PostScript name of the font\n"; - -static void PyFT2Font_fail(PyFT2Font *self) -{ - free(self->mem); - self->mem = NULL; - Py_XDECREF(self->py_file); - self->py_file = NULL; -} - -static int PyFT2Font_init(PyFT2Font *self, PyObject *args, PyObject *kwds) -{ - PyObject *fname; - FT_Open_Args open_args; - long hinting_factor = 8; - const char *names[] = { "filename", "hinting_factor", NULL }; - - if (!PyArg_ParseTupleAndKeywords( - args, kwds, "O|l:FT2Font", (char **)names, &fname, &hinting_factor)) { - return -1; - } - - if (!convert_open_args(self, fname, &open_args)) { - return -1; - } - - CALL_CPP_FULL( - "FT2Font", (self->x = new FT2Font(open_args, hinting_factor)), PyFT2Font_fail(self), -1); - - Py_INCREF(fname); - self->fname = fname; - - return 0; -} - -static void PyFT2Font_dealloc(PyFT2Font *self) -{ - delete self->x; - free(self->mem); - Py_XDECREF(self->py_file); - Py_XDECREF(self->fname); - Py_TYPE(self)->tp_free((PyObject *)self); -} - -const char *PyFT2Font_clear__doc__ = - "clear()\n" - "\n" - "Clear all the glyphs, reset for a new set_text"; - -static PyObject *PyFT2Font_clear(PyFT2Font *self, PyObject *args, PyObject *kwds) -{ - CALL_CPP("clear", (self->x->clear())); - - Py_RETURN_NONE; -} - -const char *PyFT2Font_set_size__doc__ = - "set_size(ptsize, dpi)\n" - "\n" - "Set the point size and dpi of the text.\n"; - -static PyObject *PyFT2Font_set_size(PyFT2Font *self, PyObject *args, PyObject *kwds) -{ - 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(i)\n" - "\n" - "Make the i-th charmap current\n"; - -static PyObject *PyFT2Font_set_charmap(PyFT2Font *self, PyObject *args, PyObject *kwds) -{ - 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(i)\n" - "\n" - "select charmap i where i is one of the FT_Encoding number\n"; - -static PyObject *PyFT2Font_select_charmap(PyFT2Font *self, PyObject *args, PyObject *kwds) -{ - 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__ = - "dx = get_kerning(left, right, mode)\n" - "\n" - "Get the kerning between left char and right glyph indices\n" - "mode is a kerning mode constant\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, PyObject *kwds) -{ - FT_UInt left, right, mode; - int result; - - if (!PyArg_ParseTuple(args, "III:get_kerning", &left, &right, &mode)) { - return NULL; - } - - CALL_CPP("get_kerning", (result = self->x->get_kerning(left, right, mode))); - - return PyLong_FromLong(result); -} - -const char *PyFT2Font_set_text__doc__ = - "set_text(s, angle)\n" - "\n" - "Set the text string and angle.\n" - "You must call this before draw_glyphs_to_bitmap\n" - "A sequence of x,y positions is returned"; - -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_SIZE(textobj); - codepoints.resize(size); - Py_UNICODE *unistr = PyUnicode_AsUnicode(textobj); - for (size_t i = 0; i < size; ++i) { - codepoints[i] = unistr[i]; - } - } else if (PyBytes_Check(textobj)) { - size = PyBytes_Size(textobj); - codepoints.resize(size); - char *bytestr = PyBytes_AsString(textobj); - for (size_t i = 0; i < size; ++i) { - codepoints[i] = bytestr[i]; - } - } else { - PyErr_SetString(PyExc_TypeError, "String must be unicode or bytes"); - 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()\n" - "\n" - "Return the number of loaded glyphs\n"; - -static PyObject *PyFT2Font_get_num_glyphs(PyFT2Font *self, PyObject *args, PyObject *kwds) -{ - return PyLong_FromLong(self->x->get_num_glyphs()); -} - -const char *PyFT2Font_load_char__doc__ = - "load_char(charcode, flags=LOAD_FORCE_AUTOHINT)\n" - "\n" - "Load character with charcode in current fontfile and set glyph.\n" - "The flags argument can be a bitwise-or of the LOAD_XXX constants.\n" - "Return value is a Glyph object, with attributes\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; - 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; - } - - CALL_CPP("load_char", (self->x->load_char(charcode, flags))); - - return PyGlyph_new(self->x->get_face(), - self->x->get_last_glyph(), - self->x->get_last_glyph_index(), - self->x->get_hinting_factor()); -} - -const char *PyFT2Font_load_glyph__doc__ = - "load_glyph(glyphindex, flags=LOAD_FORCE_AUTOHINT)\n" - "\n" - "Load character with glyphindex in current fontfile and set glyph.\n" - "The flags argument can be a bitwise-or of the LOAD_XXX constants.\n" - "Return value is a Glyph object, with attributes\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; - 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; - } - - CALL_CPP("load_glyph", (self->x->load_glyph(glyph_index, flags))); - - return PyGlyph_new(self->x->get_face(), - self->x->get_last_glyph(), - self->x->get_last_glyph_index(), - self->x->get_hinting_factor()); -} - -const char *PyFT2Font_get_width_height__doc__ = - "w, h = get_width_height()\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, PyObject *kwds) -{ - 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__ = - "x, y = get_bitmap_offset()\n" - "\n" - "Get the 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, PyObject *kwds) -{ - 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__ = - "d = get_descent()\n" - "\n" - "Get the descent of the current string set by set_text in 26.6 subpixels.\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, PyObject *kwds) -{ - 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()\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) -{ - int antialiased = 1; - const char *names[] = { "antialiased", NULL }; - - if (!PyArg_ParseTupleAndKeywords( - args, kwds, "|i:draw_glyphs_to_bitmap", (char **)names, &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()\n" - "\n" - "Get the xy locations of the current glyphs\n"; - -static PyObject *PyFT2Font_get_xys(PyFT2Font *self, PyObject *args, PyObject *kwds) -{ - int antialiased = 1; - std::vector<double> xys; - const char *names[] = { "antialiased", NULL }; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:get_xys", (char **)names, &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(bitmap, x, y, glyph)\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 intended for people who\n" - "want to render individual glyphs at precise locations, eg, a\n" - "a glyph returned by load_char\n"; - -static PyObject *PyFT2Font_draw_glyph_to_bitmap(PyFT2Font *self, PyObject *args, PyObject *kwds) -{ - PyFT2Image *image; - double xd, yd; - PyGlyph *glyph; - int antialiased = 1; - const char *names[] = { "image", "x", "y", "glyph", "antialiased", NULL }; - - if (!PyArg_ParseTupleAndKeywords(args, - kwds, - "O!ddO!|i:draw_glyph_to_bitmap", - (char **)names, - &PyFT2ImageType, - &image, - &xd, - &yd, - &PyGlyphType, - &glyph, - &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(index)\n" - "\n" - "Retrieves the ASCII name of a given glyph in a face.\n"; - -static PyObject *PyFT2Font_get_glyph_name(PyFT2Font *self, PyObject *args, PyObject *kwds) -{ - unsigned int glyph_number; - char buffer[128]; - - 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))); - - return PyUnicode_FromString(buffer); -} - -const char *PyFT2Font_get_charmap__doc__ = - "get_charmap()\n" - "\n" - "Returns a dictionary 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 *kwds) -{ - PyObject *charmap; - - charmap = PyDict_New(); - if (charmap == NULL) { - return NULL; - } - - FT_UInt index; - FT_ULong code = FT_Get_First_Char(self->x->get_face(), &index); - while (index != 0) { - PyObject *key; - PyObject *val; - - key = PyLong_FromLong(code); - if (key == NULL) { - Py_DECREF(charmap); - return NULL; - } - - val = PyLong_FromLong(index); - if (val == NULL) { - Py_DECREF(key); - Py_DECREF(charmap); - return NULL; - } - - if (PyDict_SetItem(charmap, key, val)) { - Py_DECREF(key); - Py_DECREF(val); - Py_DECREF(charmap); - return NULL; - } - - Py_DECREF(key); - Py_DECREF(val); - - code = FT_Get_Next_Char(self->x->get_face(), code, &index); - } - - return charmap; -} - - -const char *PyFT2Font_get_char_index__doc__ = - "get_char_index()\n" - "\n" - "Given a character code, returns a glyph index.\n"; - -static PyObject *PyFT2Font_get_char_index(PyFT2Font *self, PyObject *args, PyObject *kwds) -{ - FT_UInt index; - FT_ULong ccode; - - if (!PyArg_ParseTuple(args, "k:get_char_index", &ccode)) { - return NULL; - } - - index = FT_Get_Char_Index(self->x->get_face(), ccode); - - return PyLong_FromLong(index); -} - - -const char *PyFT2Font_get_sfnt__doc__ = - "get_sfnt(name)\n" - "\n" - "Get all values from the SFNT names table. Result is a dictionary whose" - "key is the platform-ID, ISO-encoding-scheme, language-code, and" - "description.\n"; - -static PyObject *PyFT2Font_get_sfnt(PyFT2Font *self, PyObject *args, PyObject *kwds) -{ - 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(name)\n" - "\n" - "Returns 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, PyObject *kwds) -{ - char *glyphname; - long name_index; - - if (!PyArg_ParseTuple(args, "es:get_name_index", "ascii", &glyphname)) { - return NULL; - } - - CALL_CPP("get_name_index", name_index = self->x->get_name_index(glyphname)); - - PyMem_Free(glyphname); - - return PyLong_FromLong(name_index); -} - -const char *PyFT2Font_get_ps_font_info__doc__ = - "get_ps_font_info()\n" - "\n" - "Return the information in the PS Font Info structure.\n"; - -static PyObject *PyFT2Font_get_ps_font_info(PyFT2Font *self, PyObject *args, PyObject *kwds) -{ - 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(name)\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, PyObject *kwds) -{ - char *tagname; - - if (!PyArg_ParseTuple(args, "es:get_sfnt_table", "ascii", &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; - } - } - - PyMem_Free(tagname); - - 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: { -#if PY3K - 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}"; -#else - 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:s#, s:(kkkk)," - "s:s#, s:H, s:H, s:H}"; -#endif - 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: { - #if PY3K - 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}"; - #else - char pclt_dict[] = - "{s:(h,H), s:k, s:H, s:H, s:H, s:H, s:H, s:H, s:s#, s:s#, s:b, " - "s:b, s:b}"; - #endif - 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()\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, PyObject *kwds) -{ - int count; - - CALL_CPP("get_path", (count = self->x->get_path_count())); - - npy_intp vertices_dims[2] = { count, 2 }; - numpy::array_view<double, 2> vertices(vertices_dims); - - npy_intp codes_dims[1] = { count }; - numpy::array_view<unsigned char, 1> codes(codes_dims); - - self->x->get_path(vertices.data(), codes.data()); - - return Py_BuildValue("NN", vertices.pyobj(), codes.pyobj()); -} - -const char *PyFT2Font_get_image__doc__ = - "get_image()\n" - "\n" - "Returns the underlying image buffer for this font object.\n"; - -static PyObject *PyFT2Font_get_image(PyFT2Font *self, PyObject *args, PyObject *kwds) -{ - 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->fname) { - Py_INCREF(self->fname); - return self->fname; - } - - Py_RETURN_NONE; -} - -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(PyObject *m, PyTypeObject *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_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_path__doc__}, - {NULL} - }; - - static PyBufferProcs buffer_procs; - memset(&buffer_procs, 0, sizeof(PyBufferProcs)); - buffer_procs.bf_getbuffer = (getbufferproc)PyFT2Font_get_buffer; - - memset(type, 0, sizeof(PyTypeObject)); - type->tp_name = "matplotlib.ft2font.FT2Font"; - type->tp_doc = PyFT2Font_init__doc__; - type->tp_basicsize = sizeof(PyFT2Font); - type->tp_dealloc = (destructor)PyFT2Font_dealloc; - type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_NEWBUFFER; - type->tp_methods = methods; - type->tp_getset = getset; - type->tp_new = PyFT2Font_new; - type->tp_init = (initproc)PyFT2Font_init; - type->tp_as_buffer = &buffer_procs; - - if (PyType_Ready(type) < 0) { - return NULL; - } - - if (PyModule_AddObject(m, "FT2Font", (PyObject *)type)) { - return NULL; - } - - return type; -} - -extern "C" { - -#if PY3K -static struct PyModuleDef moduledef = { - PyModuleDef_HEAD_INIT, - "ft2font", - NULL, - 0, - NULL, - NULL, - NULL, - NULL, - NULL -}; - -#define INITERROR return NULL - -PyMODINIT_FUNC PyInit_ft2font(void) - -#else -#define INITERROR return - -PyMODINIT_FUNC initft2font(void) -#endif - -{ - PyObject *m; - -#if PY3K - m = PyModule_Create(&moduledef); -#else - m = Py_InitModule3("ft2font", NULL, NULL); -#endif - - if (m == NULL) { - INITERROR; - } - - if (!PyFT2Image_init_type(m, &PyFT2ImageType)) { - INITERROR; - } - - if (!PyGlyph_init_type(m, &PyGlyphType)) { - INITERROR; - } - - if (!PyFT2Font_init_type(m, &PyFT2FontType)) { - INITERROR; - } - - PyObject *d = PyModule_GetDict(m); - - if (add_dict_int(d, "SCALABLE", FT_FACE_FLAG_SCALABLE) || - add_dict_int(d, "FIXED_SIZES", FT_FACE_FLAG_FIXED_SIZES) || - add_dict_int(d, "FIXED_WIDTH", FT_FACE_FLAG_FIXED_WIDTH) || - add_dict_int(d, "SFNT", FT_FACE_FLAG_SFNT) || - add_dict_int(d, "HORIZONTAL", FT_FACE_FLAG_HORIZONTAL) || - add_dict_int(d, "VERTICAL", FT_FACE_FLAG_VERTICAL) || - add_dict_int(d, "KERNING", FT_FACE_FLAG_KERNING) || - add_dict_int(d, "FAST_GLYPHS", FT_FACE_FLAG_FAST_GLYPHS) || - add_dict_int(d, "MULTIPLE_MASTERS", FT_FACE_FLAG_MULTIPLE_MASTERS) || - add_dict_int(d, "GLYPH_NAMES", FT_FACE_FLAG_GLYPH_NAMES) || - add_dict_int(d, "EXTERNAL_STREAM", FT_FACE_FLAG_EXTERNAL_STREAM) || - add_dict_int(d, "ITALIC", FT_STYLE_FLAG_ITALIC) || - add_dict_int(d, "BOLD", FT_STYLE_FLAG_BOLD) || - add_dict_int(d, "KERNING_DEFAULT", FT_KERNING_DEFAULT) || - add_dict_int(d, "KERNING_UNFITTED", FT_KERNING_UNFITTED) || - add_dict_int(d, "KERNING_UNSCALED", FT_KERNING_UNSCALED) || - add_dict_int(d, "LOAD_DEFAULT", FT_LOAD_DEFAULT) || - add_dict_int(d, "LOAD_NO_SCALE", FT_LOAD_NO_SCALE) || - add_dict_int(d, "LOAD_NO_HINTING", FT_LOAD_NO_HINTING) || - add_dict_int(d, "LOAD_RENDER", FT_LOAD_RENDER) || - add_dict_int(d, "LOAD_NO_BITMAP", FT_LOAD_NO_BITMAP) || - add_dict_int(d, "LOAD_VERTICAL_LAYOUT", FT_LOAD_VERTICAL_LAYOUT) || - add_dict_int(d, "LOAD_FORCE_AUTOHINT", FT_LOAD_FORCE_AUTOHINT) || - add_dict_int(d, "LOAD_CROP_BITMAP", FT_LOAD_CROP_BITMAP) || - add_dict_int(d, "LOAD_PEDANTIC", FT_LOAD_PEDANTIC) || - add_dict_int(d, "LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH", FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH) || - add_dict_int(d, "LOAD_NO_RECURSE", FT_LOAD_NO_RECURSE) || - add_dict_int(d, "LOAD_IGNORE_TRANSFORM", FT_LOAD_IGNORE_TRANSFORM) || - add_dict_int(d, "LOAD_MONOCHROME", FT_LOAD_MONOCHROME) || - add_dict_int(d, "LOAD_LINEAR_DESIGN", FT_LOAD_LINEAR_DESIGN) || - add_dict_int(d, "LOAD_NO_AUTOHINT", (unsigned long)FT_LOAD_NO_AUTOHINT) || - add_dict_int(d, "LOAD_TARGET_NORMAL", (unsigned long)FT_LOAD_TARGET_NORMAL) || - add_dict_int(d, "LOAD_TARGET_LIGHT", (unsigned long)FT_LOAD_TARGET_LIGHT) || - add_dict_int(d, "LOAD_TARGET_MONO", (unsigned long)FT_LOAD_TARGET_MONO) || - add_dict_int(d, "LOAD_TARGET_LCD", (unsigned long)FT_LOAD_TARGET_LCD) || - add_dict_int(d, "LOAD_TARGET_LCD_V", (unsigned long)FT_LOAD_TARGET_LCD_V)) { - INITERROR; - } - - // initialize library - int error = FT_Init_FreeType(&_ft2Library); - - if (error) { - PyErr_SetString(PyExc_RuntimeError, "Could not initialize the freetype2 library"); - INITERROR; - } - - { - FT_Int major, minor, patch; - char version_string[64]; - - FT_Library_Version(_ft2Library, &major, &minor, &patch); - sprintf(version_string, "%d.%d.%d", major, minor, patch); - if (PyModule_AddStringConstant(m, "__freetype_version__", version_string)) { - INITERROR; - } - } - - if (PyModule_AddStringConstant(m, "__freetype_build_type__", STRINGIFY(FREETYPE_BUILD_TYPE))) { - INITERROR; - } - - import_array(); - -#if PY3K - return m; -#endif -} - -} // extern "C" diff --git a/contrib/python/matplotlib/py2/src/mplutils.cpp b/contrib/python/matplotlib/py2/src/mplutils.cpp deleted file mode 100644 index bc09db52aa..0000000000 --- a/contrib/python/matplotlib/py2/src/mplutils.cpp +++ /dev/null @@ -1,21 +0,0 @@ -/* -*- mode: c++; c-basic-offset: 4 -*- */ - -#include "mplutils.h" - -int add_dict_int(PyObject *dict, const char *key, long val) -{ - PyObject *valobj; - valobj = PyLong_FromLong(val); - if (valobj == NULL) { - return 1; - } - - if (PyDict_SetItemString(dict, (char *)key, valobj)) { - Py_DECREF(valobj); - return 1; - } - - Py_DECREF(valobj); - - return 0; -} diff --git a/contrib/python/matplotlib/py2/src/mplutils.h b/contrib/python/matplotlib/py2/src/mplutils.h deleted file mode 100644 index 4b59e08bbd..0000000000 --- a/contrib/python/matplotlib/py2/src/mplutils.h +++ /dev/null @@ -1,73 +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 - -#if defined(_MSC_VER) && _MSC_VER <= 1600 -typedef unsigned __int8 uint8_t; -#else -#include <stdint.h> -#endif - -#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> - -#if PY_MAJOR_VERSION >= 3 -#define PY3K 1 -#define Py_TPFLAGS_HAVE_NEWBUFFER 0 -#else -#define PY3K 0 -#endif - -#undef CLAMP -#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) - -#undef MAX -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) - -inline double mpl_round(double v) -{ - return (double)(int)(v + ((v >= 0.0) ? 0.5 : -0.5)); -} - -enum { - STOP = 0, - MOVETO = 1, - LINETO = 2, - CURVE3 = 3, - CURVE4 = 4, - ENDPOLY = 0x4f -}; - -const size_t NUM_VERTICES[] = { 1, 1, 1, 2, 3, 1 }; - -extern "C" int add_dict_int(PyObject *dict, const char *key, long val); - -#if defined(_MSC_VER) && (_MSC_VER < 1800) -namespace std { - inline bool isfinite(double num) { return _finite(num); } -} -#endif - -#endif diff --git a/contrib/python/matplotlib/py2/src/numpy_cpp.h b/contrib/python/matplotlib/py2/src/numpy_cpp.h deleted file mode 100644 index 75f773ee58..0000000000 --- a/contrib/python/matplotlib/py2/src/numpy_cpp.h +++ /dev/null @@ -1,569 +0,0 @@ -/* -*- mode: c++; c-basic-offset: 4 -*- */ - -#ifndef _NUMPY_CPP_H_ -#define _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(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; - } - - int 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 0; - } - - 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 1; - } - } - if (PyArray_NDIM(tmp) != ND) { - PyErr_Format(PyExc_ValueError, - "Expected %d-dimensional array, got %d", - ND, - PyArray_NDIM(tmp)); - Py_DECREF(tmp); - return 0; - } - - /* 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 = (char *)PyArray_BYTES(tmp); - } - - return 1; - } - - 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/py2/src/path_cleanup.cpp b/contrib/python/matplotlib/py2/src/path_cleanup.cpp deleted file mode 100644 index f9f2213b3d..0000000000 --- a/contrib/python/matplotlib/py2/src/path_cleanup.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* -*- mode: c++; c-basic-offset: 4 -*- */ - -#include <Python.h> -#define NO_IMPORT_ARRAY -#include "numpy/arrayobject.h" - -#include "py_converters.h" - -#include "py_adaptors.h" -#include "agg_conv_transform.h" -#include "path_converters.h" - -class PathCleanupIterator -{ - 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 Sketch<simplify_t> sketch_t; - - py::PathIterator m_path_iter; - agg::trans_affine m_transform; - transformed_path_t m_transformed; - nan_removal_t m_nan_removed; - clipped_t m_clipped; - snapped_t m_snapped; - simplify_t m_simplify; - sketch_t m_sketch; - - public: - PathCleanupIterator(PyObject *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, - double sketch_scale, - double sketch_length, - double sketch_randomness) - : m_transform(trans), - m_transformed(m_path_iter, m_transform), - m_nan_removed(m_transformed, remove_nans, m_path_iter.has_curves()), - m_clipped(m_nan_removed, do_clip && !m_path_iter.has_curves(), rect), - m_snapped(m_clipped, snap_mode, m_path_iter.total_vertices(), stroke_width), - m_simplify(m_snapped, - do_simplify && m_path_iter.should_simplify(), - m_path_iter.simplify_threshold()), - m_sketch(m_simplify, sketch_scale, sketch_length, sketch_randomness) - { - convert_path(path, &m_path_iter); - - Py_INCREF(path); - m_path_iter.rewind(0); - } - - unsigned vertex(double *x, double *y) - { - return m_simplify.vertex(x, y); - } -}; - -extern "C" { -void *get_path_iterator(PyObject *path, - PyObject *trans, - int remove_nans, - int do_clip, - double rect[4], - e_snap_mode snap_mode, - double stroke_width, - int do_simplify, - double sketch_scale, - double sketch_length, - double sketch_randomness) -{ - agg::trans_affine agg_trans; - if (!convert_trans_affine(trans, &agg_trans)) { - return NULL; - } - agg::rect_base<double> clip_rect(rect[0], rect[1], rect[2], rect[3]); - - PathCleanupIterator *pipeline = new PathCleanupIterator(path, - agg_trans, - remove_nans != 0, - do_clip != 0, - clip_rect, - snap_mode, - stroke_width, - do_simplify != 0, - sketch_scale, - sketch_length, - sketch_randomness); - - return (void *)pipeline; -} - -unsigned get_vertex(void *pipeline, double *x, double *y) -{ - PathCleanupIterator *pipeline_iter = (PathCleanupIterator *)pipeline; - - unsigned code = pipeline_iter->vertex(x, y); - return code; -} - -void free_path_iterator(void *pipeline) -{ - PathCleanupIterator *pipeline_iter = (PathCleanupIterator *)pipeline; - - delete pipeline_iter; -} -} diff --git a/contrib/python/matplotlib/py2/src/path_cleanup.h b/contrib/python/matplotlib/py2/src/path_cleanup.h deleted file mode 100644 index b481395aa5..0000000000 --- a/contrib/python/matplotlib/py2/src/path_cleanup.h +++ /dev/null @@ -1,27 +0,0 @@ -/* -*- mode: c++; c-basic-offset: 4 -*- */ - -#ifndef PATH_CLEANUP_H -#define PATH_CLEANUP_H - -#include <Python.h> - -enum e_snap_mode { - SNAP_AUTO, - SNAP_FALSE, - SNAP_TRUE -}; - -void *get_path_iterator(PyObject *path, - PyObject *trans, - int remove_nans, - int do_clip, - double rect[4], - enum e_snap_mode snap_mode, - double stroke_width, - int do_simplify); - -unsigned get_vertex(void *pipeline, double *x, double *y); - -void free_path_iterator(void *pipeline); - -#endif /* PATH_CLEANUP_H */ diff --git a/contrib/python/matplotlib/py2/src/path_converters.h b/contrib/python/matplotlib/py2/src/path_converters.h deleted file mode 100644 index db40c18d5a..0000000000 --- a/contrib/python/matplotlib/py2/src/path_converters.h +++ /dev/null @@ -1,1011 +0,0 @@ -/* -*- mode: c++; c-basic-offset: 4 -*- */ - -#ifndef __PATH_CONVERTERS_H__ -#define __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 can not 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_curves; - - public: - /* has_curves should be true if the path contains bezier curve - segments, as this requires a slower algorithm to remove the - NaNs. When in doubt, set to true. - */ - PathNanRemover(VertexSource &source, bool remove_nans, bool has_curves) - : m_source(&source), m_remove_nans(remove_nans), m_has_curves(has_curves) - { - // empty - } - - 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_curves) { - /* This is the slow method for when there might be curves. */ - 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); - if (code == agg::path_cmd_stop || - code == (agg::path_cmd_end_poly | agg::path_flags_close)) { - return code; - } - - if (needs_move_to) { - queue_push(agg::path_cmd_move_to, *x, *y); - } - - size_t num_extra_points = num_extra_points_map[code & 0xF]; - bool has_nan = (!(std::isfinite(*x) && std::isfinite(*y))); - queue_push(code, *x, *y); - - /* Note: this test can not 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); - has_nan = has_nan || !(std::isfinite(*x) && std::isfinite(*y)); - queue_push(code, *x, *y); - } - - if (!has_nan) { - break; - } - - 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_curves - { - /* This is the fast path for when we know we have no curves */ - code = m_source->vertex(x, y); - - if (code == agg::path_cmd_stop || - code == (agg::path_cmd_end_poly | agg::path_flags_close)) { - 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)) { - return code; - } - } while (!(std::isfinite(*x) && std::isfinite(*y))); - return agg::path_cmd_move_to; - } - - 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; - - 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_moveto(true), - m_has_init(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_moveto(true), - m_has_init(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_moveto = true; - m_source->rewind(path_id); - } - - int draw_clipped_line(double x0, double y0, double x1, double y1) - { - 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 - 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); - - m_moveto = false; - return 1; - } - - return 0; - } - - unsigned vertex(double *x, double *y) - { - unsigned code; - bool emit_moveto = false; - - if (m_do_clipping) { - /* 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) { - draw_clipped_line(m_lastX, m_lastY, m_initX, m_initY); - } - queue_push( - agg::path_cmd_end_poly | agg::path_flags_close, - m_lastX, m_lastY); - goto exit_loop; - - 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; - // 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_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; - } else { - // If not doing any clipping, just pass along the vertices - // verbatim - return m_source->vertex(x, y); - } - } -}; - -/************************************************************ - 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 = (int)mpl_round(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); - } - - 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(); - double d_M_PI = 3.14159265358979323846; - m_p += pow(m_randomness, d_rand * 2.0 - 1.0); - double r = sin(m_p / (m_length / (d_M_PI * 2.0))) * m_scale; - 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); - *x += r * num / len; - *y += r * -den / len; - } - } 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; -}; - -#endif // __PATH_CONVERTERS_H__ diff --git a/contrib/python/matplotlib/py2/src/py_adaptors.h b/contrib/python/matplotlib/py2/src/py_adaptors.h deleted file mode 100644 index 3d0dbdab45..0000000000 --- a/contrib/python/matplotlib/py2/src/py_adaptors.h +++ /dev/null @@ -1,251 +0,0 @@ -/* -*- mode: c++; c-basic-offset: 4 -*- */ - -#ifndef __PY_ADAPTORS_H__ -#define __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_curves() 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(PyObject *obj) : m_paths(NULL), m_npaths(0) - { - if (!set(obj)) { - throw py::exception(); - } - } - - ~PathGenerator() - { - Py_XDECREF(m_paths); - } - - int set(PyObject *obj) - { - if (!PySequence_Check(obj)) { - return 0; - } - - 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)) { - throw py::exception(); - } - Py_DECREF(item); - return path; - } -}; -} - -#endif diff --git a/contrib/python/matplotlib/py2/src/py_converters.cpp b/contrib/python/matplotlib/py2/src/py_converters.cpp deleted file mode 100644 index 2d5d415a2c..0000000000 --- a/contrib/python/matplotlib/py2/src/py_converters.cpp +++ /dev/null @@ -1,619 +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 bytes or unicode", 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, (char *)name, NULL); - if (value == NULL) { - if (!PyObject_HasAttrString(obj, (char *)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, (char *)name); - if (value == NULL) { - if (!PyObject_HasAttrString(obj, (char *)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; - - *val = PyObject_IsTrue(obj); - - 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 { - try - { - numpy::array_view<const double, 2> rect_arr(rectobj); - - if (rect_arr.dim(0) != 2 || rect_arr.dim(1) != 2) { - PyErr_SetString(PyExc_ValueError, "Invalid bounding box"); - return 0; - } - - rect->x1 = rect_arr(0, 0); - rect->y1 = rect_arr(0, 1); - rect->x2 = rect_arr(1, 0); - rect->y2 = rect_arr(1, 1); - } - catch (py::exception &) - { - PyErr_Clear(); - - try - { - numpy::array_view<const double, 1> rect_arr(rectobj); - - if (rect_arr.dim(0) != 4) { - PyErr_SetString(PyExc_ValueError, "Invalid bounding box"); - return 0; - } - - rect->x1 = rect_arr(0); - rect->y1 = rect_arr(1); - rect->x2 = rect_arr(2); - rect->y2 = rect_arr(3); - } - catch (py::exception &) - { - return 0; - } - } - } - - return 1; -} - -int convert_rgba(PyObject *rgbaobj, void *rgbap) -{ - agg::rgba *rgba = (agg::rgba *)rgbap; - - if (rgbaobj == NULL || rgbaobj == Py_None) { - rgba->r = 0.0; - rgba->g = 0.0; - rgba->b = 0.0; - rgba->a = 0.0; - } else { - rgba->a = 1.0; - if (!PyArg_ParseTuple( - rgbaobj, "ddd|d:rgba", &(rgba->r), &(rgba->g), &(rgba->b), &(rgba->a))) { - return 0; - } - } - - return 1; -} - -int convert_dashes(PyObject *dashobj, void *dashesp) -{ - Dashes *dashes = (Dashes *)dashesp; - - if (dashobj == NULL && dashobj == Py_None) { - return 1; - } - - PyObject *dash_offset_obj = NULL; - double dash_offset = 0.0; - PyObject *dashes_seq = NULL; - Py_ssize_t nentries; - - if (!PyArg_ParseTuple(dashobj, "OO:dashes", &dash_offset_obj, &dashes_seq)) { - return 0; - } - - if (dash_offset_obj != Py_None) { - dash_offset = PyFloat_AsDouble(dash_offset_obj); - if (PyErr_Occurred()) { - return 0; - } - } - - if (dashes_seq == Py_None) { - return 1; - } - - if (!PySequence_Check(dashes_seq)) { - PyErr_SetString(PyExc_TypeError, "Invalid dashes sequence"); - return 0; - } - - nentries = PySequence_Size(dashes_seq); - if (nentries % 2 != 0) { - PyErr_Format(PyExc_ValueError, "dashes sequence must have an even number of elements"); - return 0; - } - - for (Py_ssize_t i = 0; i < nentries; ++i) { - PyObject *item; - double length; - double skip; - - item = PySequence_GetItem(dashes_seq, i); - 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); - 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; - } - - try - { - numpy::array_view<const double, 2> matrix(obj); - - if (matrix.dim(0) == 3 && matrix.dim(1) == 3) { - trans->sx = matrix(0, 0); - trans->shx = matrix(0, 1); - trans->tx = matrix(0, 2); - - trans->shy = matrix(1, 0); - trans->sy = matrix(1, 1); - trans->ty = matrix(1, 2); - - return 1; - } - } - catch (py::exception &) - { - return 0; - } - - 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; - } - should_simplify = PyObject_IsTrue(should_simplify_obj); - - 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_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 if (PyObject_IsTrue(obj)) { - *snap = SNAP_TRUE; - } else { - *snap = SNAP_FALSE; - } - - 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_offset_position(PyObject *obj, void *offsetp) -{ - e_offset_position *offset = (e_offset_position *)offsetp; - const char *names[] = {"data", NULL}; - int values[] = {OFFSET_POSITION_DATA}; - int result = (int)OFFSET_POSITION_FIGURE; - - if (!convert_string_enum(obj, "offset_position", names, values, &result)) { - PyErr_Clear(); - } - - *offset = (e_offset_position)result; - - 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; - } - - points->set(obj); - - if (points->size() == 0) { - return 1; - } - - if (points->dim(1) != 2) { - PyErr_Format(PyExc_ValueError, - "Points must be Nx2 array, got %" NPY_INTP_FMT "x%" NPY_INTP_FMT, - points->dim(0), points->dim(1)); - 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; - } - - trans->set(obj); - - if (trans->size() == 0) { - return 1; - } - - if (trans->dim(1) != 3 || trans->dim(2) != 3) { - PyErr_Format(PyExc_ValueError, - "Transforms must be Nx3x3 array, got %" NPY_INTP_FMT "x%" NPY_INTP_FMT "x%" NPY_INTP_FMT, - trans->dim(0), trans->dim(1), trans->dim(2)); - 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; - } - - bbox->set(obj); - - if (bbox->size() == 0) { - return 1; - } - - if (bbox->dim(1) != 2 || bbox->dim(2) != 2) { - PyErr_Format(PyExc_ValueError, - "Bbox array must be Nx2x2 array, got %" NPY_INTP_FMT "x%" NPY_INTP_FMT "x%" NPY_INTP_FMT, - bbox->dim(0), bbox->dim(1), bbox->dim(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; - } - - colors->set(obj); - - if (colors->size() == 0) { - return 1; - } - - if (colors->dim(1) != 4) { - PyErr_Format(PyExc_ValueError, - "Colors array must be Nx4 array, got %" NPY_INTP_FMT "x%" NPY_INTP_FMT, - colors->dim(0), colors->dim(1)); - return 0; - } - - return 1; -} -} diff --git a/contrib/python/matplotlib/py2/src/py_converters.h b/contrib/python/matplotlib/py2/src/py_converters.h deleted file mode 100644 index 02d84affe8..0000000000 --- a/contrib/python/matplotlib/py2/src/py_converters.h +++ /dev/null @@ -1,49 +0,0 @@ -/* -*- mode: c++; c-basic-offset: 4 -*- */ - -#ifndef __PY_CONVERTERS_H__ -#define __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 "numpy_cpp.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_clippath(PyObject *clippath_tuple, void *clippathp); -int convert_snap(PyObject *obj, void *snapp); -int convert_offset_position(PyObject *obj, void *offsetp); -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/py2/src/py_exceptions.h b/contrib/python/matplotlib/py2/src/py_exceptions.h deleted file mode 100644 index 1ee2d51903..0000000000 --- a/contrib/python/matplotlib/py2/src/py_exceptions.h +++ /dev/null @@ -1,72 +0,0 @@ -/* -*- mode: c++; c-basic-offset: 4 -*- */ - -#ifndef __PY_EXCEPTIONS_H__ -#define __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, NULL) - -#define CALL_CPP(name, a) CALL_CPP_FULL(name, a, , NULL) - -#define CALL_CPP_INIT(name, a) CALL_CPP_FULL(name, a, , -1) - -#endif diff --git a/contrib/python/matplotlib/py2/src/qhull_wrap.c b/contrib/python/matplotlib/py2/src/qhull_wrap.c deleted file mode 100644 index 836a16c555..0000000000 --- a/contrib/python/matplotlib/py2/src/qhull_wrap.c +++ /dev/null @@ -1,378 +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/noprefix.h" -#include "qhull_ra.h" -#include <stdio.h> - - -#if PY_MAJOR_VERSION >= 3 -#define PY3K 1 -#else -#define PY3K 0 -#endif - -#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 qhT qhData; -static qhT* qh = &qhData; - -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(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, const int* tri_indices, - int indices[3]) -{ - facetT *neighbor, **neighborp; - FOREACHneighbor_(facet) - *indices++ = (neighbor->upperdelaunay ? -1 : tri_indices[neighbor->id]); -} - -/* Return 1 if the specified points arrays contain at least 3 unique points, - * or 0 otherwise. */ -static int -at_least_3_unique_points(int 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 0; - - 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 1; - } - } - } - - /* Run out of points before 3 unique points found. */ - return 0; -} - -/* Delaunay implementation methyod. If hide_qhull_errors is 1 then qhull error - * messages are discarded; if it is 0 then they are written to stderr. */ -static PyObject* -delaunay_impl(int npoints, const double* x, const double* y, - int hide_qhull_errors) -{ - coordT* points = NULL; - facetT* facet; - int i, ntri, max_facet_id; - FILE* error_file = NULL; /* qhull expects a FILE* to write errors to. */ - int exitcode; /* Value returned from qh_new_qhull(). */ - int* tri_indices = NULL; /* Maps qhull facet id to triangle index. */ - int indices[3]; - int curlong, totlong; /* Memory remaining after qh_memfreeshort. */ - PyObject* tuple; /* Return tuple (triangles, neighbors). */ - const int ndim = 2; - npy_intp dims[2]; - PyArrayObject* triangles = NULL; - PyArrayObject* neighbors = NULL; - int* triangles_ptr; - int* neighbors_ptr; - double x_mean = 0.0; - double y_mean = 0.0; - - QHULL_LIB_CHECK - - /* Allocate points. */ - points = (coordT*)malloc(npoints*ndim*sizeof(coordT)); - if (points == NULL) { - PyErr_SetString(PyExc_MemoryError, - "Could not allocate points array in qhull.delaunay"); - goto error_before_qhull; - } - - /* 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. */ - 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) { - PyErr_SetString(PyExc_RuntimeError, - "Could not open devnull in qhull.delaunay"); - goto error_before_qhull; - } - } - else { - /* qhull errors written to stderr. */ - error_file = stderr; - } - - /* Perform Delaunay triangulation. */ - exitcode = qh_new_qhull(qh, ndim, npoints, points, False, - "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." : ""); - goto error; - } - - /* 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. */ - tri_indices = (int*)malloc((max_facet_id+1)*sizeof(int)); - if (tri_indices == NULL) { - PyErr_SetString(PyExc_MemoryError, - "Could not allocate triangle map in qhull.delaunay"); - goto error; - } - - /* Allocate python arrays to return. */ - dims[0] = ntri; - dims[1] = 3; - triangles = (PyArrayObject*)PyArray_SimpleNew(ndim, dims, NPY_INT); - if (triangles == NULL) { - PyErr_SetString(PyExc_MemoryError, - "Could not allocate triangles array in qhull.delaunay"); - goto error; - } - - neighbors = (PyArrayObject*)PyArray_SimpleNew(ndim, dims, NPY_INT); - if (neighbors == NULL) { - PyErr_SetString(PyExc_MemoryError, - "Could not allocate neighbors array in qhull.delaunay"); - goto error; - } - - triangles_ptr = (int*)PyArray_DATA(triangles); - neighbors_ptr = (int*)PyArray_DATA(neighbors); - - /* Determine triangles array and set tri_indices array. */ - i = 0; - FORALLfacets { - if (!facet->upperdelaunay) { - tri_indices[facet->id] = i++; - get_facet_vertices(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) { - 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]; - } - } - - /* Clean up. */ - qh_freeqhull(qh, !qh_ALL); - qh_memfreeshort(qh, &curlong, &totlong); - if (curlong || totlong) - PyErr_WarnEx(PyExc_RuntimeWarning, - "Qhull could not free all allocated memory", 1); - if (hide_qhull_errors) - fclose(error_file); - free(tri_indices); - free(points); - - tuple = PyTuple_New(2); - PyTuple_SetItem(tuple, 0, (PyObject*)triangles); - PyTuple_SetItem(tuple, 1, (PyObject*)neighbors); - return tuple; - -error: - /* Clean up. */ - Py_XDECREF(triangles); - Py_XDECREF(neighbors); - qh_freeqhull(qh, !qh_ALL); - qh_memfreeshort(qh, &curlong, &totlong); - /* Don't bother checking curlong and totlong as raising error anyway. */ - if (hide_qhull_errors) - fclose(error_file); - free(tri_indices); - -error_before_qhull: - free(points); - - return NULL; -} - -/* Process python arguments and call Delaunay implementation method. */ -static PyObject* -delaunay(PyObject *self, PyObject *args) -{ - PyObject* xarg; - PyObject* yarg; - PyArrayObject* xarray; - PyArrayObject* yarray; - PyObject* ret; - int npoints; - const double* x; - const double* y; - - if (!PyArg_ParseTuple(args, "OO", &xarg, &yarg)) { - PyErr_SetString(PyExc_ValueError, "expecting x and y arrays"); - return NULL; - } - - xarray = (PyArrayObject*)PyArray_ContiguousFromObject(xarg, NPY_DOUBLE, - 1, 1); - yarray = (PyArrayObject*)PyArray_ContiguousFromObject(yarg, NPY_DOUBLE, - 1, 1); - if (xarray == 0 || yarray == 0 || - PyArray_DIM(xarray,0) != PyArray_DIM(yarray, 0)) { - Py_XDECREF(xarray); - Py_XDECREF(yarray); - PyErr_SetString(PyExc_ValueError, - "x and y must be 1D arrays of the same length"); - return NULL; - } - - npoints = PyArray_DIM(xarray, 0); - - if (npoints < 3) { - Py_XDECREF(xarray); - Py_XDECREF(yarray); - PyErr_SetString(PyExc_ValueError, - "x and y arrays must have a length of at least 3"); - return NULL; - } - - x = (const double*)PyArray_DATA(xarray); - y = (const double*)PyArray_DATA(yarray); - - if (!at_least_3_unique_points(npoints, x, y)) { - Py_XDECREF(xarray); - Py_XDECREF(yarray); - PyErr_SetString(PyExc_ValueError, - "x and y arrays must consist of at least 3 unique points"); - return NULL; - } - - ret = delaunay_impl(npoints, x, y, Py_VerboseFlag == 0); - - Py_XDECREF(xarray); - Py_XDECREF(yarray); - return ret; -} - -/* Return qhull version string for assistance in debugging. */ -static PyObject* -version(void) -{ - return PyBytes_FromString(qh_version); -} - -static PyMethodDef qhull_methods[] = { - {"delaunay", (PyCFunction)delaunay, METH_VARARGS, ""}, - {"version", (PyCFunction)version, METH_NOARGS, ""}, - {NULL, NULL, 0, NULL} -}; - -#if PY3K -static struct PyModuleDef qhull_module = { - PyModuleDef_HEAD_INIT, - "qhull", - "Computing Delaunay triangulations.\n", - -1, - qhull_methods, - NULL, NULL, NULL, NULL -}; - -#define ERROR_RETURN return NULL - -PyMODINIT_FUNC -PyInit__qhull(void) -#else -#define ERROR_RETURN return - -PyMODINIT_FUNC -init_qhull(void) -#endif -{ - PyObject* m; - - #if PY3K - m = PyModule_Create(&qhull_module); - #else - m = Py_InitModule3("_qhull", qhull_methods, - "Computing Delaunay triangulations.\n"); - #endif - - if (m == NULL) { - ERROR_RETURN; - } - - import_array(); - - #if PY3K - return m; - #endif -} diff --git a/contrib/python/matplotlib/py2/src/ya.make b/contrib/python/matplotlib/py2/src/ya.make deleted file mode 100644 index 486bc04e49..0000000000 --- a/contrib/python/matplotlib/py2/src/ya.make +++ /dev/null @@ -1,68 +0,0 @@ -PY2_LIBRARY() - -VERSION(2.2.5) - -LICENSE(PSF-2.0) - -NO_COMPILER_WARNINGS() - -PEERDIR( - ADDINCL contrib/libs/freetype - ADDINCL contrib/libs/libpng - ADDINCL contrib/python/numpy - contrib/libs/qhull - contrib/python/matplotlib/py2/extern/agg24-svn - contrib/python/matplotlib/py2/extern/ttconv -) - -ADDINCL( - contrib/libs/qhull/libqhull_r - contrib/python/matplotlib/py2 - contrib/python/matplotlib/py2/extern - contrib/python/matplotlib/py2/extern/agg24-svn/include -) - -CFLAGS( - -D_MULTIARRAYMODULE - -DFREETYPE_BUILD_TYPE=local - -DNPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION - -DMPL_DEVNULL=/dev/null -) - -IF (OS_WINDOWS) - LDFLAGS( - Psapi.lib - ) -ENDIF() - -PY_REGISTER( - matplotlib._contour - matplotlib._image # peerdir agg24-svn - matplotlib._path # peerdir agg24-svn - matplotlib._png - matplotlib._qhull # peerdir libqhull - matplotlib.backends._backend_agg # peerdir agg24-svn - matplotlib.backends._tkagg - matplotlib.ft2font - matplotlib.ttconv # peerdir ttconv -) - -SRCS( - _backend_agg.cpp - _backend_agg_wrapper.cpp - _contour.cpp - _contour_wrapper.cpp - _image.cpp - _image_wrapper.cpp - _path_wrapper.cpp - _png.cpp - _tkagg.cpp - _ttconv.cpp - ft2font.cpp - ft2font_wrapper.cpp - mplutils.cpp - py_converters.cpp - qhull_wrap.c -) - -END() |