Revision: 3993
          http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3993&view=rev
Author:   mdboom
Date:     2007-10-24 10:11:00 -0700 (Wed, 24 Oct 2007)

Log Message:
-----------
Forgot to svn add these files in last commit.

Added Paths:
-----------
    branches/transforms/src/_path.cpp
    branches/transforms/src/agg_py_transforms.h

Added: branches/transforms/src/_path.cpp
===================================================================
--- branches/transforms/src/_path.cpp                           (rev 0)
+++ branches/transforms/src/_path.cpp   2007-10-24 17:11:00 UTC (rev 3993)
@@ -0,0 +1,384 @@
+#include "agg_py_path_iterator.h"
+#include "agg_py_transforms.h"
+
+#include "CXX/Extensions.hxx"
+
+#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"
+
+// the extension module
+class _path_module : public Py::ExtensionModule<_path_module>
+{
+public:
+  _path_module()
+    : Py::ExtensionModule<_path_module>( "_path" )
+  {
+    add_varargs_method("point_in_path", &_path_module::point_in_path,
+                      "point_in_path(x, y, path, trans)");
+    add_varargs_method("point_on_path", &_path_module::point_on_path,
+                      "point_on_path(x, y, r, path, trans)");
+    add_varargs_method("get_path_extents", &_path_module::get_path_extents,
+                      "get_path_extents(path, trans)");
+    add_varargs_method("get_path_collection_extents", 
&_path_module::get_path_collection_extents,
+                      "get_path_collection_extents(trans, paths, transforms, 
offsets, offsetTrans)");
+    add_varargs_method("point_in_path_collection", 
&_path_module::point_in_path_collection,
+                      "point_in_path_collection(x, y, r, trans, paths, 
transforms, offsets, offsetTrans, filled)");
+
+    initialize("Helper functions for paths");
+  }
+
+  virtual ~_path_module() {}
+
+private:
+
+  Py::Object point_in_path(const Py::Tuple& args);
+  Py::Object point_on_path(const Py::Tuple& args);
+  Py::Object get_path_extents(const Py::Tuple& args);
+  Py::Object get_path_collection_extents(const Py::Tuple& args);
+  Py::Object point_in_path_collection(const Py::Tuple& args);
+};
+
+//
+// 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, [EMAIL PROTECTED]
+//
+// 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 T>
+bool point_in_path_impl(double tx, double ty, T& path) {
+  int yflag0, yflag1, inside_flag;
+  double vtx0, vty0, vtx1, vty1, sx, sy;
+  double x, y;
+
+  path.rewind(0);
+  unsigned code = path.vertex(&x, &y);
+  if (code == agg::path_cmd_stop)
+    return false;
+
+  while (true) {
+    sx = vtx0 = x;
+    sy = vty0 = y;
+
+    // get test bit for above/below X axis
+    yflag0 = (vty0 >= ty);
+
+    vtx1 = x;
+    vty1 = x;
+
+    inside_flag = 0;
+    while (true) {
+      code = path.vertex(&x, &y);
+
+      // The following cases denote the beginning on a new subpath
+      if ((code & agg::path_cmd_end_poly) == agg::path_cmd_end_poly) {
+       x = sx; y = sy;
+      } else if (code == agg::path_cmd_move_to)
+       break;
+      
+      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 != 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 ) {
+         inside_flag ^= 1;
+       }
+      }
+
+      // Move to the next pair of vertices, retaining info as possible.
+      yflag0 = yflag1;
+      vtx0 = vtx1;
+      vty0 = vty1;
+       
+      vtx1 = x;
+      vty1 = y;
+
+      if (code == agg::path_cmd_stop || 
+         (code & agg::path_cmd_end_poly) == agg::path_cmd_end_poly)
+       break;
+    }
+
+    if (inside_flag != 0)
+      return true;
+
+    if (code == agg::path_cmd_stop)
+      return false;
+  }
+
+  return false;
+}
+
+bool point_in_path(double x, double y, PathIterator& path, agg::trans_affine& 
trans) {
+  typedef agg::conv_transform<PathIterator> transformed_path_t;
+  typedef agg::conv_curve<transformed_path_t> curve_t;
+  
+  transformed_path_t trans_path(path, trans);
+  curve_t curved_path(trans_path);
+  return point_in_path_impl(x, y, curved_path);
+}
+
+bool point_on_path(double x, double y, double r, PathIterator& path, 
agg::trans_affine& trans) {
+  typedef agg::conv_transform<PathIterator> transformed_path_t;
+  typedef agg::conv_curve<transformed_path_t> curve_t;
+  typedef agg::conv_stroke<curve_t> stroke_t;
+
+  transformed_path_t trans_path(path, trans);
+  curve_t curved_path(trans_path);
+  stroke_t stroked_path(curved_path);
+  stroked_path.width(r * 2.0);
+  return point_in_path_impl(x, y, stroked_path);
+}
+
+Py::Object _path_module::point_in_path(const Py::Tuple& args) {
+  args.verify_length(4);
+  
+  double x = Py::Float(args[0]);
+  double y = Py::Float(args[1]);
+  PathIterator path(args[2]);
+  agg::trans_affine trans = py_to_agg_transformation_matrix(args[3]);
+
+  if (::point_in_path(x, y, path, trans))
+    return Py::Int(1);
+  return Py::Int(0);
+}
+
+Py::Object _path_module::point_on_path(const Py::Tuple& args) {
+  args.verify_length(5);
+  
+  double x = Py::Float(args[0]);
+  double y = Py::Float(args[1]);
+  double r = Py::Float(args[2]);
+  PathIterator path(args[3]);
+  agg::trans_affine trans = py_to_agg_transformation_matrix(args[4]);
+
+  if (::point_on_path(x, y, r, path, trans))
+    return Py::Int(1);
+  return Py::Int(0);
+}
+
+void get_path_extents(PathIterator& path, agg::trans_affine& trans, 
+                     double* x0, double* y0, double* x1, double* y1) {
+  typedef agg::conv_transform<PathIterator> transformed_path_t;
+  typedef agg::conv_curve<transformed_path_t> curve_t;
+  double x, y;
+  unsigned code;
+
+  transformed_path_t tpath(path, trans);
+  curve_t curved_path(tpath);
+
+  curved_path.rewind(0);
+
+  while ((code = curved_path.vertex(&x, &y)) != agg::path_cmd_stop) {
+    if ((code & agg::path_cmd_end_poly) == agg::path_cmd_end_poly)
+      continue;
+    if (x < *x0) *x0 = x;
+    if (y < *y0) *y0 = y;
+    if (x > *x1) *x1 = x;
+    if (y > *y1) *y1 = y;
+  }
+}
+
+Py::Object _path_module::get_path_extents(const Py::Tuple& args) {
+  args.verify_length(2);
+  
+  PathIterator path(args[0]);
+  agg::trans_affine trans = py_to_agg_transformation_matrix(args[1]);
+
+  double x0 =  std::numeric_limits<double>::infinity();
+  double y0 =  std::numeric_limits<double>::infinity();
+  double x1 = -std::numeric_limits<double>::infinity();
+  double y1 = -std::numeric_limits<double>::infinity();
+
+  ::get_path_extents(path, trans, &x0, &y0, &x1, &y1);
+
+  Py::Tuple result(4);
+  result[0] = Py::Float(x0);
+  result[1] = Py::Float(y0);
+  result[2] = Py::Float(x1);
+  result[3] = Py::Float(y1);
+  return result;
+}
+
+Py::Object _path_module::get_path_collection_extents(const Py::Tuple& args) {
+  args.verify_length(5);
+
+  //segments, trans, clipbox, colors, linewidths, antialiaseds
+  agg::trans_affine      master_transform = 
py_to_agg_transformation_matrix(args[0]);
+  Py::SeqBase<Py::Object> paths                   = args[1];
+  Py::SeqBase<Py::Object> transforms_obj   = args[2];
+  Py::Object              offsets_obj      = args[3];
+  agg::trans_affine       offset_trans     = 
py_to_agg_transformation_matrix(args[4], false);
+
+  PyArrayObject* offsets = NULL;
+  double x0, y0, x1, y1;
+
+  try {
+    offsets = (PyArrayObject*)PyArray_FromObject(offsets_obj.ptr(), 
PyArray_DOUBLE, 2, 2);
+    if (!offsets || offsets->dimensions[1] != 2)
+      throw Py::ValueError("Offsets array must be Nx2");
+
+    size_t Npaths      = paths.length();
+    size_t Noffsets    = offsets->dimensions[0];
+    size_t N          = std::max(Npaths, Noffsets);
+    size_t Ntransforms = std::min(transforms_obj.length(), N);
+    size_t i;
+
+    // Convert all of the transforms up front
+    typedef std::vector<agg::trans_affine> transforms_t;
+    transforms_t transforms;
+    transforms.reserve(Ntransforms);
+    for (i = 0; i < Ntransforms; ++i) {
+      agg::trans_affine trans = py_to_agg_transformation_matrix
+       (transforms_obj[i], false);
+      trans *= master_transform;
+      transforms.push_back(trans);
+    }
+    
+    // The offset each of those and collect the mins/maxs
+    x0 = std::numeric_limits<double>::infinity();
+    y0 = std::numeric_limits<double>::infinity();
+    x1 = -std::numeric_limits<double>::infinity();
+    y1 = -std::numeric_limits<double>::infinity();
+    for (i = 0; i < N; ++i) {
+      PathIterator path(paths[i % Npaths]);
+      
+      double xo                = *(double*)PyArray_GETPTR2(offsets, i % 
Noffsets, 0);
+      double yo                = *(double*)PyArray_GETPTR2(offsets, i % 
Noffsets, 1);
+      offset_trans.transform(&xo, &yo);
+      agg::trans_affine_translation transOffset(xo, yo);
+      agg::trans_affine trans = transforms[i % Ntransforms];
+      trans *= transOffset;
+
+      ::get_path_extents(path, trans, &x0, &y0, &x1, &y1);
+    }
+  } catch (...) {
+    Py_XDECREF(offsets);
+    throw;
+  }
+
+  Py_XDECREF(offsets);
+
+  Py::Tuple result(4);
+  result[0] = Py::Float(x0);
+  result[1] = Py::Float(y0);
+  result[2] = Py::Float(x1);
+  result[3] = Py::Float(y1);
+  return result;
+}
+
+Py::Object _path_module::point_in_path_collection(const Py::Tuple& args) {
+  args.verify_length(9);
+
+  //segments, trans, clipbox, colors, linewidths, antialiaseds
+  double                 x                = Py::Float(args[0]);
+  double                 y                = Py::Float(args[1]);
+  double                  radius           = Py::Float(args[2]);
+  agg::trans_affine      master_transform = 
py_to_agg_transformation_matrix(args[3]);
+  Py::SeqBase<Py::Object> paths                   = args[4];
+  Py::SeqBase<Py::Object> transforms_obj   = args[5];
+  Py::SeqBase<Py::Object> offsets_obj      = args[6];
+  agg::trans_affine       offset_trans     = 
py_to_agg_transformation_matrix(args[7]);
+  bool                    filled           = Py::Int(args[8]);
+  
+  PyArrayObject* offsets = 
(PyArrayObject*)PyArray_FromObject(offsets_obj.ptr(), PyArray_DOUBLE, 2, 2);
+  if (!offsets || offsets->dimensions[1] != 2)
+    throw Py::ValueError("Offsets array must be Nx2");
+
+  size_t Npaths             = paths.length();
+  size_t Noffsets    = offsets->dimensions[0];
+  size_t N          = std::max(Npaths, Noffsets);
+  size_t Ntransforms = std::min(transforms_obj.length(), N);
+  size_t i;
+
+  // Convert all of the transforms up front
+  typedef std::vector<agg::trans_affine> transforms_t;
+  transforms_t transforms;
+  transforms.reserve(Ntransforms);
+  for (i = 0; i < Ntransforms; ++i) {
+    agg::trans_affine trans = py_to_agg_transformation_matrix
+      (transforms_obj[i], false);
+    trans *= master_transform;
+    transforms.push_back(trans);
+  }
+
+  Py::List result;
+
+  for (i = 0; i < N; ++i) {
+    PathIterator path(paths[i % Npaths]);
+    
+    double xo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 0);
+    double yo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 1);
+    offset_trans.transform(&xo, &yo);
+    agg::trans_affine_translation transOffset(xo, yo);
+    agg::trans_affine trans = transforms[i % Ntransforms];
+    trans *= transOffset;
+
+    if (filled) {
+      if (::point_in_path(x, y, path, trans))
+       result.append(Py::Int((int)i));
+    } else {
+      if (::point_on_path(x, y, radius, path, trans))
+       result.append(Py::Int((int)i));
+    }
+  }
+
+  return result;
+}
+
+extern "C"
+DL_EXPORT(void)
+  init_path(void)
+{
+  import_array();
+  
+  static _path_module* _path = NULL;
+  _path = new _path_module;
+};

Added: branches/transforms/src/agg_py_transforms.h
===================================================================
--- branches/transforms/src/agg_py_transforms.h                         (rev 0)
+++ branches/transforms/src/agg_py_transforms.h 2007-10-24 17:11:00 UTC (rev 
3993)
@@ -0,0 +1,58 @@
+#ifndef __AGG_PY_TRANSFORMS_H__
+#define __AGG_PY_TRANSFORMS_H__
+
+#define PY_ARRAY_TYPES_PREFIX NumPy
+#include "numpy/arrayobject.h"
+
+#include "CXX/Objects.hxx"
+#include "agg_trans_affine.h"
+
+
+/** A helper function to convert from a Numpy affine transformation matrix
+ *  to an agg::trans_affine.
+ */
+agg::trans_affine py_to_agg_transformation_matrix(const Py::Object& obj, bool 
errors = true) {
+  PyArrayObject* matrix = NULL;
+  
+  try {
+    if (obj.ptr() == Py_None)
+      throw std::exception();
+    matrix = (PyArrayObject*) PyArray_FromObject(obj.ptr(), PyArray_DOUBLE, 2, 
2);
+    if (!matrix)
+      throw std::exception();
+    if (matrix->nd == 2 || matrix->dimensions[0] == 3 || matrix->dimensions[1] 
== 3) {
+      size_t stride0 = matrix->strides[0];
+      size_t stride1 = matrix->strides[1];
+      char* row0 = matrix->data;
+      char* row1 = row0 + stride0;
+      
+      double a = *(double*)(row0);
+      row0 += stride1;
+      double c = *(double*)(row0);
+      row0 += stride1;
+      double e = *(double*)(row0);
+      
+      double b = *(double*)(row1);
+      row1 += stride1;
+      double d = *(double*)(row1);
+      row1 += stride1;
+      double f = *(double*)(row1);
+      
+      Py_XDECREF(matrix);
+      
+      return agg::trans_affine(a, b, c, d, e, f);
+    }
+
+    throw std::exception();
+  } catch (...) {
+    if (errors) {
+      Py_XDECREF(matrix);
+      throw Py::TypeError("Invalid affine transformation matrix");
+    }
+  }
+
+  Py_XDECREF(matrix);
+  return agg::trans_affine();
+}
+
+#endif // __AGG_PY_TRANSFORMS_H__


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/
_______________________________________________
Matplotlib-checkins mailing list
Matplotlib-checkins@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins

Reply via email to