yade-dev team mailing list archive
-
yade-dev team
-
Mailing list archive
-
Message #01335
[svn] r1814 - in trunk: . lib lib/py lib/py/pygts-0.3.1
Author: eudoxos
Date: 2009-06-25 00:06:24 +0200 (Thu, 25 Jun 2009)
New Revision: 1814
Added:
trunk/lib/py/pygts-0.3.1/
trunk/lib/py/pygts-0.3.1/__init__.py
trunk/lib/py/pygts-0.3.1/cleanup.c
trunk/lib/py/pygts-0.3.1/cleanup.h
trunk/lib/py/pygts-0.3.1/edge.c
trunk/lib/py/pygts-0.3.1/edge.h
trunk/lib/py/pygts-0.3.1/face.c
trunk/lib/py/pygts-0.3.1/face.h
trunk/lib/py/pygts-0.3.1/object.c
trunk/lib/py/pygts-0.3.1/object.h
trunk/lib/py/pygts-0.3.1/point.c
trunk/lib/py/pygts-0.3.1/point.h
trunk/lib/py/pygts-0.3.1/pygts.c
trunk/lib/py/pygts-0.3.1/pygts.h
trunk/lib/py/pygts-0.3.1/pygts.py
trunk/lib/py/pygts-0.3.1/segment.c
trunk/lib/py/pygts-0.3.1/segment.h
trunk/lib/py/pygts-0.3.1/surface.c
trunk/lib/py/pygts-0.3.1/surface.h
trunk/lib/py/pygts-0.3.1/triangle.c
trunk/lib/py/pygts-0.3.1/triangle.h
trunk/lib/py/pygts-0.3.1/vertex.c
trunk/lib/py/pygts-0.3.1/vertex.h
Modified:
trunk/SConstruct
trunk/lib/SConscript
trunk/lib/py/README
Log:
1. Add checks for GTS (optional)
2. Add pyGTS to our tree (built only if needed), since no packages are available.
Modified: trunk/SConstruct
===================================================================
--- trunk/SConstruct 2009-06-24 17:04:39 UTC (rev 1813)
+++ trunk/SConstruct 2009-06-24 22:06:24 UTC (rev 1814)
@@ -129,7 +129,7 @@
ListVariable('exclude','Yade components that will not be built','none',names=['qt3','gui','extra','common','dem','fem','lattice','mass-spring','realtime-rigidbody','snow']),
EnumVariable('arcs','Whether to generate or use branch probabilities','',['','gen','use'],{'no':'','0':'','false':''},1),
# OK, dummy prevents bug in scons: if one selects all, it says all in scons.config, but without quotes, which generates error.
- ListVariable('features','Optional features that are turned on','python,log4cxx,openGL',names=['openGL','python','log4cxx','binfmt','CGAL','dummy']),
+ ListVariable('features','Optional features that are turned on','python,log4cxx,openGL',names=['openGL','python','log4cxx','binfmt','CGAL','dummy','GTS']),
('jobs','Number of jobs to run at the same time (same as -j, but saved)',4,None,int),
('extraModules', 'Extra directories with their own SConscript files (must be in-tree) (whitespace separated)',None,None,Split),
('buildPrefix','Where to create build-[version][variant] directory for intermediary files','..'),
@@ -321,6 +321,11 @@
ok=conf.CheckLibWithHeader('glut','GL/glut.h','c','glutGetModifiers();',autoadd=1)
if not ok: featureNotOK('openGL')
env.Append(CPPDEFINES='YADE_OPENGL')
+ if 'GTS' in env['features']:
+ env.ParseConfig('pkg-config glib-2.0 --cflags --libs');
+ ok=conf.CheckLibWithHeader('gts','gts.h','c','gts_object_class();',autoadd=1)
+ if not ok: featureNotOK('GTS')
+ env.Append(CPPDEFINES='YADE_GTS')
if 'qt3' not in env['exclude']:
if 'openGL' not in env['features']:
print "\nQt3 interface can only be used if openGL is enabled.\nEither add openGL to 'features' or add qt3 to 'exclude'."
Modified: trunk/lib/SConscript
===================================================================
--- trunk/lib/SConscript 2009-06-24 17:04:39 UTC (rev 1813)
+++ trunk/lib/SConscript 2009-06-24 22:06:24 UTC (rev 1814)
@@ -73,8 +73,13 @@
LIBS=env['LIBS']+['glut','$QGLVIEWER_LIB']),
])
+if 'GTS' in env['features']:
+ env.Install('$PREFIX/lib/yade$SUFFIX/py/gts',[
+ env.SharedLibrary('_gts',['py/pygts-0.3.1/cleanup.c','py/pygts-0.3.1/edge.c','py/pygts-0.3.1/face.c','py/pygts-0.3.1/object.c','py/pygts-0.3.1/point.c','py/pygts-0.3.1/pygts.c','py/pygts-0.3.1/segment.c','py/pygts-0.3.1/surface.c','py/pygts-0.3.1/triangle.c','py/pygts-0.3.1/vertex.c'],SHLIBPREFIX='',CPPDEFINES=env['CPPDEFINES']+['PYGTS_HAS_NUMPY']),
+ env.File('py/pygts-0.3.1/__init__.py'),
+ env.File('py/pygts-0.3.1/pygts.py')
+ ])
-
env.Install('$PREFIX/lib/yade$SUFFIX/lib',[
env.SharedLibrary('yade-base',
Modified: trunk/lib/py/README
===================================================================
--- trunk/lib/py/README 2009-06-24 17:04:39 UTC (rev 1813)
+++ trunk/lib/py/README 2009-06-24 22:06:24 UTC (rev 1814)
@@ -2,3 +2,10 @@
homepage: http://partiallydisassembled.net/euclid.html
latest SVN version: http://pyeuclid.googlecode.com/svn/trunk/euclid.py
documentation: http://partiallydisassembled.net/euclid/
+
+pygts-0.3.1:
+ homepage: http://pygts.sourceforge.net/
+ documentation: http://pygts.svn.sourceforge.net/viewvc/pygts/doc/gts.html
+ license: GNU GPL v2
+ note: the local version is only the 'gts' directory of the source archive (doc, examples, test ommited). Distutils are not used for building either.
+
Added: trunk/lib/py/pygts-0.3.1/__init__.py
===================================================================
--- trunk/lib/py/pygts-0.3.1/__init__.py 2009-06-24 17:04:39 UTC (rev 1813)
+++ trunk/lib/py/pygts-0.3.1/__init__.py 2009-06-24 22:06:24 UTC (rev 1814)
@@ -0,0 +1,104 @@
+# pygts - python package for the manipulation of triangulated surfaces
+#
+# Copyright (C) 2009 Thomas J. Duck
+# All rights reserved.
+#
+# Thomas J. Duck <tom.duck@xxxxxx>
+# Department of Physics and Atmospheric Science,
+# Dalhousie University, Halifax, Nova Scotia, Canada, B3H 3J5
+#
+# NOTICE
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+"""A package for constructing and manipulating triangulated surfaces.
+
+PyGTS is a python binding for the GNU Triangulated Surface (GTS)
+Library, which may be used to build, manipulate, and perform
+computations on triangulated surfaces.
+
+The following geometric primitives are provided:
+
+ Point - a point in 3D space
+ Vertex - a Point in 3D space that may be used to define a Segment
+ Segment - a line defined by two Vertex end-points
+ Edge - a Segment that may be used to define the edge of a Triangle
+ Triangle - a triangle defined by three Edges
+ Face - a Triangle that may be used to define a face on a Surface
+ Surface - a surface composed of Faces
+
+A tetrahedron is assembled from these primitives as follows. First,
+create Vertices for each of the tetrahedron's points:
+
+ import gts
+
+ v1 = gts.Vertex(1,1,1)
+ v2 = gts.Vertex(-1,-1,1)
+ v3 = gts.Vertex(-1,1,-1)
+ v4 = gts.Vertex(1,-1,-1)
+
+Next, connect the four vertices to create six unique Edges:
+
+ e1 = gts.Edge(v1,v2)
+ e2 = gts.Edge(v2,v3)
+ e3 = gts.Edge(v3,v1)
+ e4 = gts.Edge(v1,v4)
+ e5 = gts.Edge(v4,v2)
+ e6 = gts.Edge(v4,v3)
+
+The four triangular faces are composed using three edges each:
+
+ f1 = gts.Face(e1,e2,e3)
+ f2 = gts.Face(e1,e4,e5)
+ f3 = gts.Face(e2,e5,e6)
+ f4 = gts.Face(e3,e4,e6)
+
+Finally, the surface is assembled from the faces:
+
+ s = gts.Surface()
+ for face in [f1,f2,f3,f4]:
+ s.add(face)
+
+Some care must be taken in the orientation of the faces. In the above
+example, the surface normals are pointing inward, and so the surface
+technically defines a void, rather than a solid. To create a
+tetrahedron with surface normals pointing outward, use the following
+instead:
+
+ f1.revert()
+ s = Surface()
+ for face in [f1,f2,f3,f4]:
+ if not face.is_compatible(s):
+ face.revert()
+ s.add(face)
+
+Once the Surface is constructed, there are many different operations that
+can be performed. For example, the volume can be calculated using:
+
+ s.volume()
+
+The difference between two Surfaces s1 and s2 is given by:
+
+ s3 = s2.difference(s1)
+
+Etc.
+
+It is also possible to read in GTS data files and plot surfaces to
+the screen. See the example programs packaged with PyGTS for
+more information.
+"""
+
+from pygts import *
Added: trunk/lib/py/pygts-0.3.1/cleanup.c
===================================================================
--- trunk/lib/py/pygts-0.3.1/cleanup.c 2009-06-24 17:04:39 UTC (rev 1813)
+++ trunk/lib/py/pygts-0.3.1/cleanup.c 2009-06-24 22:06:24 UTC (rev 1814)
@@ -0,0 +1,491 @@
+/* pygts - python package for the manipulation of triangulated surfaces
+ *
+ * Copyright (C) 1999 St�ane Popinet
+ * Copyright (C) 2009 Thomas J. Duck
+ * All rights reserved.
+ *
+ * Thomas J. Duck <tom.duck@xxxxxx>
+ * Department of Physics and Atmospheric Science,
+ * Dalhousie University, Halifax, Nova Scotia, Canada, B3H 3J5
+ *
+ * NOTICE
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+/*
+ * Below are functions for cleaning up duplicated edges and faces on
+ * a surface. This file contains modified functions from the GTS
+ * distribution.
+ */
+
+#include "pygts.h"
+
+
+/**
+ * Original documentation from GTS's vertex.c:
+ *
+ * gts_vertices_merge:
+ * @vertices: a list of #GtsVertex.
+ * @epsilon: half the size of the bounding box to consider for each vertex.
+ * @check: function called for each pair of vertices about to be merged
+ * or %NULL.
+ *
+ * For each vertex v in @vertices look if there are any vertex of
+ * @vertices contained in a box centered on v of size 2*@epsilon. If
+ * there are and if @check is not %NULL and returns %TRUE, replace
+ * them with v (using gts_vertex_replace()), destroy them and remove
+ * them from list. This is done efficiently using Kd-Trees.
+ *
+ * Returns: the updated list of vertices.
+ */
+/* This function is modified from the original in GTS in order to avoid
+ * deallocating any objects referenced by the live-objects table. The
+ * approach is similar to what is used for replace() in vertex.c.
+ */
+GList*
+pygts_vertices_merge(GList* vertices, gdouble epsilon,
+ gboolean (* check) (GtsVertex *, GtsVertex *))
+{
+ GPtrArray *array;
+ GList *i, *next;
+ GNode *kdtree;
+ GtsVertex *v;
+ GtsBBox *bbox;
+ GSList *selected, *j;
+ GtsVertex *sv;
+ PygtsObject *obj;
+ PygtsVertex *vertex=NULL;
+ GSList *parents=NULL, *ii,*cur;
+
+ g_return_val_if_fail(vertices != NULL, 0);
+
+ array = g_ptr_array_new();
+ i = vertices;
+ while (i) {
+ g_ptr_array_add(array, i->data);
+ i = g_list_next(i);
+ }
+ kdtree = gts_kdtree_new(array, NULL);
+ g_ptr_array_free(array, TRUE);
+
+ i = vertices;
+ while(i) {
+ v = i->data;
+ if (!GTS_OBJECT(v)->reserved) { /* Do something only if v is active */
+
+ /* build bounding box */
+ bbox = gts_bbox_new(gts_bbox_class(), v,
+ GTS_POINT(v)->x - epsilon,
+ GTS_POINT(v)->y - epsilon,
+ GTS_POINT(v)->z - epsilon,
+ GTS_POINT(v)->x + epsilon,
+ GTS_POINT(v)->y + epsilon,
+ GTS_POINT(v)->z + epsilon);
+
+ /* select vertices which are inside bbox using kdtree */
+ j = selected = gts_kdtree_range(kdtree, bbox, NULL);
+ while(j) {
+ sv = j->data;
+ if( sv!=v && !GTS_OBJECT(sv)->reserved && (!check||(*check)(sv, v)) ) {
+ /* sv is not v and is active */
+ if( (obj = g_hash_table_lookup(obj_table,GTS_OBJECT(sv))) !=NULL ) {
+ vertex = PYGTS_VERTEX(obj);
+ /* Detach and save any parent segments */
+ ii = sv->segments;
+ while(ii!=NULL) {
+ cur = ii;
+ ii = g_slist_next(ii);
+ if(PYGTS_IS_PARENT_SEGMENT(cur->data)) {
+ sv->segments = g_slist_remove_link(sv->segments, cur);
+ parents = g_slist_prepend(parents,cur->data);
+ g_slist_free_1(cur);
+ }
+ }
+ }
+
+ gts_vertex_replace(sv, v);
+ GTS_OBJECT(sv)->reserved = sv; /* mark sv as inactive */
+
+ /* Reattach the parent segments */
+ if( vertex != NULL ) {
+ ii = parents;
+ while(ii!=NULL) {
+ sv->segments = g_slist_prepend(sv->segments, ii->data);
+ ii = g_slist_next(ii);
+ }
+ g_slist_free(parents);
+ parents = NULL;
+ }
+ vertex = NULL;
+ }
+ j = g_slist_next(j);
+ }
+ g_slist_free(selected);
+ gts_object_destroy(GTS_OBJECT(bbox));
+ }
+ i = g_list_next(i);
+ }
+ gts_kdtree_destroy(kdtree);
+
+
+ /* destroy inactive vertices and removes them from list */
+
+ /* we want to control vertex destruction */
+ gts_allow_floating_vertices = TRUE;
+
+ i = vertices;
+ while (i) {
+ v = i->data;
+ next = g_list_next(i);
+ if(GTS_OBJECT(v)->reserved) { /* v is inactive */
+ if( g_hash_table_lookup(obj_table,GTS_OBJECT(v))==NULL ) {
+ gts_object_destroy(GTS_OBJECT(v));
+ }
+ else {
+ GTS_OBJECT(v)->reserved = 0;
+ }
+ vertices = g_list_remove_link(vertices, i);
+ g_list_free_1(i);
+ }
+ i = next;
+ }
+ gts_allow_floating_vertices = FALSE;
+
+ return vertices;
+}
+
+
+static void
+build_list(gpointer data, GSList ** list)
+{
+ *list = g_slist_prepend(*list, data);
+}
+
+
+static void
+build_list1(gpointer data, GList ** list)
+{
+ *list = g_list_prepend(*list, data);
+}
+
+
+void
+pygts_vertex_cleanup(GtsSurface *s, gdouble threshold)
+{
+ GList * vertices = NULL;
+
+ /* merge vertices which are close enough */
+ /* build list of vertices */
+ gts_surface_foreach_vertex(s, (GtsFunc) build_list1, &vertices);
+
+ /* merge vertices: we MUST update the variable vertices because this function
+ modifies the list (i.e. removes the merged vertices). */
+ vertices = pygts_vertices_merge(vertices, threshold, NULL);
+
+ /* free the list */
+ g_list_free(vertices);
+}
+
+
+void
+pygts_edge_cleanup(GtsSurface *s)
+{
+ GSList *edges = NULL;
+ GSList *i, *ii, *cur, *parents=NULL;
+ PygtsEdge *edge;
+ GtsEdge *e, *duplicate;
+
+ g_return_if_fail(s != NULL);
+
+ /* build list of edges */
+ gts_surface_foreach_edge(s, (GtsFunc)build_list, &edges);
+
+ /* remove degenerate and duplicate edges.
+ Note: we could use gts_edges_merge() to remove the duplicates and then
+ remove the degenerate edges but it is more efficient to do everything
+ at once (and it's more pedagogical too ...) */
+
+ /* We want to control manually the destruction of edges */
+ gts_allow_floating_edges = TRUE;
+
+ i = edges;
+ while(i) {
+ e = i->data;
+ if(GTS_SEGMENT(e)->v1 == GTS_SEGMENT(e)->v2) {
+ /* edge is degenerate */
+ if( !g_hash_table_lookup(obj_table,GTS_OBJECT(e)) ) {
+ /* destroy e */
+ gts_object_destroy(GTS_OBJECT(e));
+ }
+ }
+ else {
+ if((duplicate = gts_edge_is_duplicate(e))) {
+
+ /* Detach and save any parent triangles */
+ if( (edge = PYGTS_EDGE(g_hash_table_lookup(obj_table,GTS_OBJECT(e))))
+ !=NULL ) {
+ ii = e->triangles;
+ while(ii!=NULL) {
+ cur = ii;
+ ii = g_slist_next(ii);
+ if(PYGTS_IS_PARENT_TRIANGLE(cur->data)) {
+ e->triangles = g_slist_remove_link(e->triangles, cur);
+ parents = g_slist_prepend(parents,cur->data);
+ g_slist_free_1(cur);
+ }
+ }
+ }
+
+ /* replace e with its duplicate */
+ gts_edge_replace(e, duplicate);
+
+ /* Reattach the parent segments */
+ if( edge != NULL ) {
+ ii = parents;
+ while(ii!=NULL) {
+ e->triangles = g_slist_prepend(e->triangles, ii->data);
+ ii = g_slist_next(ii);
+ }
+ g_slist_free(parents);
+ parents = NULL;
+ }
+
+ if( !g_hash_table_lookup(obj_table,GTS_OBJECT(e)) ) {
+ /* destroy e */
+ gts_object_destroy(GTS_OBJECT (e));
+ }
+ }
+ }
+ i = g_slist_next(i);
+ }
+
+ /* don't forget to reset to default */
+ gts_allow_floating_edges = FALSE;
+
+ /* free list of edges */
+ g_slist_free (edges);
+}
+
+
+void
+pygts_face_cleanup(GtsSurface * s)
+{
+ GSList *triangles = NULL;
+ GSList * i;
+
+ g_return_if_fail(s != NULL);
+
+ /* build list of triangles */
+ gts_surface_foreach_face(s, (GtsFunc) build_list, &triangles);
+
+ /* remove duplicate and degenerate triangles */
+ i = triangles;
+ while(i) {
+ GtsTriangle * t = i->data;
+ if (!gts_triangle_is_ok(t)) {
+ /* destroy t, its edges (if not used by any other triangle)
+ and its corners (if not used by any other edge) */
+ if( g_hash_table_lookup(obj_table,GTS_OBJECT(t))==NULL ) {
+ gts_object_destroy(GTS_OBJECT(t));
+ }
+ else {
+ gts_surface_remove_face(PYGTS_SURFACE_AS_GTS_SURFACE(s),GTS_FACE(t));
+ }
+ }
+ i = g_slist_next(i);
+ }
+
+ /* free list of triangles */
+ g_slist_free(triangles);
+}
+
+
+/* old main program (below) - retained as an example of how to use the
+ * functions above.
+ */
+
+/* cleanup - using a given threshold merge vertices which are too close.
+ Eliminate degenerate and duplicate edges.
+ Eliminate duplicate triangles . */
+/* static int */
+/* main (int argc, char * argv[]) */
+/* { */
+/* GtsSurface * s, * m; */
+/* GList * vertices = NULL; */
+/* gboolean verbose = FALSE, sever = FALSE, boundary = FALSE; */
+/* gdouble threshold; */
+/* int c = 0; */
+/* GtsFile * fp; */
+/* gboolean (* check) (GtsVertex *, GtsVertex *) = NULL; */
+
+/* if (!setlocale (LC_ALL, "POSIX")) */
+/* g_warning ("cannot set locale to POSIX"); */
+
+/* s = gts_surface_new (gts_surface_class (), */
+/* gts_face_class (), */
+/* gts_edge_class (), */
+/* gts_vertex_class ()); */
+
+/* /\* parse options using getopt *\/ */
+/* while (c != EOF) { */
+/* #ifdef HAVE_GETOPT_LONG */
+/* static struct option long_options[] = { */
+/* {"2D", no_argument, NULL, 'c'}, */
+/* {"boundary", no_argument, NULL, 'b'}, */
+/* {"merge", required_argument, NULL, 'm'}, */
+/* {"sever", no_argument, NULL, 's'}, */
+/* {"help", no_argument, NULL, 'h'}, */
+/* {"verbose", no_argument, NULL, 'v'}, */
+/* { NULL } */
+/* }; */
+/* int option_index = 0; */
+/* switch ((c = getopt_long (argc, argv, "hvsm:bc", */
+/* long_options, &option_index))) { */
+/* #else /\* not HAVE_GETOPT_LONG *\/ */
+/* switch ((c = getopt (argc, argv, "hvsm:bc"))) { */
+/* #endif /\* not HAVE_GETOPT_LONG *\/ */
+/* case 'c': /\* 2D *\/ */
+/* check = check_boundaries; */
+/* break; */
+/* case 'b': /\* boundary *\/ */
+/* boundary = TRUE; */
+/* break; */
+/* case 's': /\* sever *\/ */
+/* sever = TRUE; */
+/* break; */
+/* case 'm': { /\* merge *\/ */
+/* FILE * fptr = fopen (optarg, "rt"); */
+/* GtsFile * fp; */
+
+/* if (fptr == NULL) { */
+/* fprintf (stderr, "cleanup: cannot open file `%s' for merging\n", */
+/* optarg); */
+/* return 1; /\* failure *\/ */
+/* } */
+/* m = gts_surface_new (gts_surface_class (), */
+/* gts_face_class (), */
+/* gts_edge_class (), */
+/* s->vertex_class); */
+/* fp = gts_file_new (fptr); */
+/* if (gts_surface_read (m, fp)) { */
+/* fprintf (stderr, "cleanup: file `%s' is not a valid GTS file\n", */
+/* optarg); */
+/* fprintf (stderr, "%s:%d:%d: %s\n", */
+/* optarg, fp->line, fp->pos, fp->error); */
+/* return 1; /\* failure *\/ */
+/* } */
+/* gts_file_destroy (fp); */
+/* fclose (fptr); */
+/* gts_surface_merge (s, m); */
+/* gts_object_destroy (GTS_OBJECT (m)); */
+/* break; */
+/* } */
+/* case 'v': /\* verbose *\/ */
+/* verbose = TRUE; */
+/* break; */
+/* case 'h': /\* help *\/ */
+/* fprintf (stderr, */
+/* "Usage: cleanup [OPTION] THRESHOLD < FILE\n" */
+/* "Merge vertices of the GTS surface FILE if they are closer than THRESHOLD,\n" */
+/* "eliminate degenerate, duplicate edges and duplicate triangles.\n" */
+/* "\n" */
+/* " -c --2D 2D boundary merging\n" */
+/* " -b --boundary only consider boundary vertices for merging\n" */
+/* " -s --sever sever \"contact\" vertices\n" */
+/* " -m FILE --merge merge surface FILE\n" */
+/* " -v --verbose print statistics about the surface\n" */
+/* " -h --help display this help and exit\n" */
+/* "\n" */
+/* "Report bugs to %s\n", */
+/* GTS_MAINTAINER); */
+/* return 0; /\* success *\/ */
+/* break; */
+/* case '?': /\* wrong options *\/ */
+/* fprintf (stderr, "Try `cleanup --help' for more information.\n"); */
+/* return 1; /\* failure *\/ */
+/* } */
+/* } */
+
+/* if (optind >= argc) { /\* missing threshold *\/ */
+/* fprintf (stderr, */
+/* "cleanup: missing THRESHOLD\n" */
+/* "Try `cleanup --help' for more information.\n"); */
+/* return 1; /\* failure *\/ */
+/* } */
+
+/* threshold = atof (argv[optind]); */
+
+/* if (threshold < 0.0) { /\* threshold must be positive *\/ */
+/* fprintf (stderr, */
+/* "cleanup: THRESHOLD must be >= 0.0\n" */
+/* "Try `cleanup --help' for more information.\n"); */
+/* return 1; /\* failure *\/ */
+/* } */
+
+/* /\* read surface in *\/ */
+/* m = gts_surface_new (gts_surface_class (), */
+/* gts_face_class (), */
+/* gts_edge_class (), */
+/* s->vertex_class); */
+/* fp = gts_file_new (stdin); */
+/* if (gts_surface_read (m, fp)) { */
+/* fputs ("cleanup: file on standard input is not a valid GTS file\n", */
+/* stderr); */
+/* fprintf (stderr, "stdin:%d:%d: %s\n", fp->line, fp->pos, fp->error); */
+/* return 1; /\* failure *\/ */
+/* } */
+/* gts_surface_merge (s, m); */
+/* gts_object_destroy (GTS_OBJECT (m)); */
+
+/* /\* if verbose on print stats *\/ */
+/* if (verbose) */
+/* gts_surface_print_stats (s, stderr); */
+
+/* /\* merge vertices which are close enough *\/ */
+/* /\* build list of vertices *\/ */
+/* gts_surface_foreach_vertex (s, boundary ? (GtsFunc) build_list2 : (GtsFunc) build_list1, */
+/* &vertices); */
+/* /\* merge vertices: we MUST update the variable vertices because this function */
+/* modifies the list (i.e. removes the merged vertices). *\/ */
+/* vertices = gts_vertices_merge (vertices, threshold, check); */
+
+/* /\* free the list *\/ */
+/* g_list_free (vertices); */
+
+/* /\* eliminate degenerate and duplicate edges *\/ */
+/* edge_cleanup (s); */
+/* /\* eliminate duplicate triangles *\/ */
+/* triangle_cleanup (s); */
+
+/* if (sever) */
+/* gts_surface_foreach_vertex (s, (GtsFunc) vertex_cleanup, NULL); */
+
+/* /\* if verbose on print stats *\/ */
+/* if (verbose) { */
+/* GtsBBox * bb = gts_bbox_surface (gts_bbox_class (), s); */
+/* gts_surface_print_stats (s, stderr); */
+/* fprintf (stderr, "# Bounding box: [%g,%g,%g] [%g,%g,%g]\n", */
+/* bb->x1, bb->y1, bb->z1, */
+/* bb->x2, bb->y2, bb->z2); */
+/* } */
+
+/* /\* write surface *\/ */
+/* gts_surface_write (s, stdout); */
+
+/* return 0; /\* success *\/ */
+/* } */
Added: trunk/lib/py/pygts-0.3.1/cleanup.h
===================================================================
--- trunk/lib/py/pygts-0.3.1/cleanup.h 2009-06-24 17:04:39 UTC (rev 1813)
+++ trunk/lib/py/pygts-0.3.1/cleanup.h 2009-06-24 22:06:24 UTC (rev 1814)
@@ -0,0 +1,44 @@
+/* pygts - python package for the manipulation of triangulated surfaces
+ *
+ * Copyright (C) 2009 Thomas J. Duck
+ * All rights reserved.
+ *
+ * Thomas J. Duck <tom.duck@xxxxxx>
+ * Department of Physics and Atmospheric Science,
+ * Dalhousie University, Halifax, Nova Scotia, Canada, B3H 3J5
+ *
+ * NOTICE
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+/*
+ * Below are functions for cleaning up duplicated edges and faces on
+ * a surface. This file was adapted from the example file of the same
+ * name in the GTS distribution.
+ */
+
+#ifndef __PYGTS_CLEANUP_H__
+#define __PYGTS_CLEANUP_H__
+
+GList* pygts_vertices_merge(GList* vertices, gdouble epsilon,
+ gboolean (* check) (GtsVertex *, GtsVertex *));
+void pygts_vertex_cleanup(GtsSurface *s, gdouble threhold);
+void pygts_edge_cleanup(GtsSurface * s);
+void pygts_face_cleanup(GtsSurface * s);
+
+#endif /* __PYGTS_CLEANUP_H__ */
Added: trunk/lib/py/pygts-0.3.1/edge.c
===================================================================
--- trunk/lib/py/pygts-0.3.1/edge.c 2009-06-24 17:04:39 UTC (rev 1813)
+++ trunk/lib/py/pygts-0.3.1/edge.c 2009-06-24 22:06:24 UTC (rev 1814)
@@ -0,0 +1,639 @@
+/* pygts - python package for the manipulation of triangulated surfaces
+ *
+ * Copyright (C) 2009 Thomas J. Duck
+ * All rights reserved.
+ *
+ * Thomas J. Duck <tom.duck@xxxxxx>
+ * Department of Physics and Atmospheric Science,
+ * Dalhousie University, Halifax, Nova Scotia, Canada, B3H 3J5
+ *
+ * NOTICE
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "pygts.h"
+
+
+#if PYGTS_DEBUG
+ #define SELF_CHECK if(!pygts_edge_check((PyObject*)self)) { \
+ PyErr_SetString(PyExc_RuntimeError, \
+ "problem with self object (internal error)"); \
+ return NULL; \
+ }
+#else
+ #define SELF_CHECK
+#endif
+
+
+/*-------------------------------------------------------------------------*/
+/* Methods exported to python */
+
+static PyObject*
+is_ok(PygtsEdge *self, PyObject *args)
+{
+ if(pygts_edge_is_ok(self)) {
+ Py_INCREF(Py_True);
+ return Py_True;
+ }
+ else {
+ Py_INCREF(Py_False);
+ return Py_False;
+ }
+}
+
+
+static PyObject*
+is_unattached(PygtsEdge *self, PyObject *args)
+{
+ guint n;
+
+ SELF_CHECK
+
+ /* Check for attachments other than to the gtsobj_parent */
+ n = g_slist_length(PYGTS_EDGE_AS_GTS_EDGE(self)->triangles);
+ if( n > 1 ) {
+ Py_INCREF(Py_False);
+ return Py_False;
+ }
+ else if( n == 1 ){
+ Py_INCREF(Py_True);
+ return Py_True;
+ }
+ else {
+ PyErr_SetString(PyExc_RuntimeError,"Edge lost parent (internal error)");
+ return NULL;
+ }
+}
+
+
+/* replace() works, but can break Triangles and so is disabled */
+
+/* static PyObject* */
+/* replace(PygtsEdge *self, PyObject *args) */
+/* { */
+/* PyObject *e2_; */
+/* PygtsEdge *e2; */
+/* GSList *parents=NULL, *i, *cur; */
+
+/* #if PYGTS_DEBUG */
+/* if(!pygts_edge_check((PyObject*)self)) { */
+/* PyErr_SetString(PyExc_TypeError, */
+/* "problem with self object (internal error)"); */
+/* return NULL; */
+/* } */
+/* #endif */
+
+/* /\* Parse the args *\/ */
+/* if(! PyArg_ParseTuple(args, "O", &e2_) ) { */
+/* return NULL; */
+/* } */
+
+/* /\* Convert to PygtsObjects *\/ */
+/* if(!pygts_edge_check(e2_)) { */
+/* PyErr_SetString(PyExc_TypeError,"expected an Edge"); */
+/* return NULL; */
+/* } */
+/* e2 = PYGTS_EDGE(e2_); */
+
+/* if(PYGTS_OBJECT(self)->gtsobj!=PYGTS_OBJECT(e2)->gtsobj) { */
+/* /\* (Ignore self-replacement) *\/ */
+
+/* /\* Detach and save any parent triangles *\/ */
+/* i = GTS_EDGE(PYGTS_OBJECT(self)->gtsobj)->triangles; */
+/* while(i!=NULL) { */
+/* cur = i; */
+/* i = i->next; */
+/* if(PYGTS_IS_PARENT_TRIANGLE(cur->data)) { */
+/* GTS_EDGE(PYGTS_OBJECT(self)->gtsobj)->triangles = */
+/* g_slist_remove_link(GTS_EDGE(PYGTS_OBJECT(self)->gtsobj)->triangles, */
+/* cur); */
+/* parents = g_slist_prepend(parents,cur->data); */
+/* g_slist_free_1(cur); */
+/* } */
+/* } */
+
+/* /\* Perform the replace operation *\/ */
+/* gts_edge_replace(GTS_EDGE(PYGTS_OBJECT(self)->gtsobj), */
+/* GTS_EDGE(PYGTS_OBJECT(e2)->gtsobj)); */
+
+/* /\* Reattach the parent segments *\/ */
+/* i = parents; */
+/* while(i!=NULL) { */
+/* GTS_EDGE(PYGTS_OBJECT(self)->gtsobj)->triangles = */
+/* g_slist_prepend(GTS_EDGE(PYGTS_OBJECT(self)->gtsobj)->triangles, */
+/* i->data); */
+/* i = i->next; */
+/* } */
+/* g_slist_free(parents); */
+/* } */
+
+/* #if PYGTS_DEBUG */
+/* if(!pygts_edge_check((PyObject*)self)) { */
+/* PyErr_SetString(PyExc_TypeError, */
+/* "problem with self object (internal error)"); */
+/* return NULL; */
+/* } */
+/* #endif */
+
+/* Py_INCREF(Py_None); */
+/* return Py_None; */
+/* } */
+
+
+static PyObject*
+face_number(PygtsEdge *self, PyObject *args)
+{
+ PyObject *s_;
+ GtsSurface *s;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &s_) ) {
+ return NULL;
+ }
+
+ /* Convert to PygtsObjects */
+ if(!pygts_surface_check(s_)) {
+ PyErr_SetString(PyExc_TypeError,"expected a Surface");
+ return NULL;
+ }
+ s = PYGTS_SURFACE_AS_GTS_SURFACE(s_);
+
+ return Py_BuildValue("i",
+ gts_edge_face_number(PYGTS_EDGE_AS_GTS_EDGE(self),s));
+}
+
+
+static PyObject*
+belongs_to_tetrahedron(PygtsEdge *self, PyObject *args)
+{
+ SELF_CHECK
+
+ if(gts_edge_belongs_to_tetrahedron(PYGTS_EDGE_AS_GTS_EDGE(self))) {
+ Py_INCREF(Py_True);
+ return Py_True;
+ }
+ else {
+ Py_INCREF(Py_False);
+ return Py_False;
+ }
+}
+
+
+static PyObject*
+is_boundary(PygtsEdge *self, PyObject *args)
+{
+ PyObject *s_;
+ GtsSurface *s;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &s_) ) {
+ return NULL;
+ }
+
+ /* Convert to PygtsObjects */
+ if(!pygts_surface_check(s_)) {
+ PyErr_SetString(PyExc_TypeError,"expected a Surface");
+ return NULL;
+ }
+ s = PYGTS_SURFACE_AS_GTS_SURFACE(s_);
+
+ /* Make the call and return */
+ if(gts_edge_is_boundary(PYGTS_EDGE_AS_GTS_EDGE(self),s)!=NULL) {
+ Py_INCREF(Py_True);
+ return Py_True;
+ }
+ else {
+ Py_INCREF(Py_False);
+ return Py_False;
+ }
+}
+
+
+static PyObject*
+contacts(PygtsEdge *self, PyObject *args)
+{
+ SELF_CHECK
+
+ return Py_BuildValue("i",
+ gts_edge_is_contact(PYGTS_EDGE_AS_GTS_EDGE(self)));
+}
+
+
+/* Methods table */
+static PyMethodDef methods[] = {
+ {"is_ok", (PyCFunction)is_ok,
+ METH_NOARGS,
+ "True if this Edge e is not degenerate or duplicate.\n"
+ "False otherwise. Degeneracy implies e.v1.id == e.v2.id.\n"
+ "\n"
+ "Signature: e.is_ok()\n"
+ },
+
+ {"is_unattached", (PyCFunction)is_unattached,
+ METH_NOARGS,
+ "True if this Edge e is not part of any Triangle.\n"
+ "\n"
+ "Signature: e.is_unattached()\n"
+ },
+
+/* Edge replace() method works but results in Triangles that are "not ok";
+ * i.e., they have edges that don't connect. We don't want that problem
+ * and so the method has been disabled.
+ */
+/*
+ {"replace", (PyCFunction)replace,
+ METH_VARARGS,
+ "Replaces this Edge e1 with Edge e2 in all Triangles that have e1.\n"
+ "Edge e1 itself is left unchanged.\n"
+ "\n"
+ "Signature: e1.replace(e2).\n"
+ },
+*/
+
+ {"face_number", (PyCFunction)face_number,
+ METH_VARARGS,
+ "Returns number of faces using this Edge e on Surface s.\n"
+ "\n"
+ "Signature: e.face_number(s)\n"
+ },
+
+ {"is_boundary", (PyCFunction)is_boundary,
+ METH_VARARGS,
+ "Returns True if this Edge e is a boundary on Surface s.\n"
+ "Otherwise False.\n"
+ "\n"
+ "Signature: e.is_boundary(s)\n"
+ },
+
+ {"belongs_to_tetrahedron", (PyCFunction)belongs_to_tetrahedron,
+ METH_NOARGS,
+ "Returns True if this Edge e belongs to a tetrahedron.\n"
+ "Otherwise False.\n"
+ "\n"
+ "Signature: e.belongs_to_tetrahedron()\n"
+ },
+
+ {"contacts", (PyCFunction)contacts,
+ METH_NOARGS,
+ "Returns number of sets of connected triangles share this Edge e\n"
+ "as a contact Edge.\n"
+ "\n"
+ "Signature: e.contacts()\n"
+ },
+
+ {NULL} /* Sentinel */
+};
+
+
+/*-------------------------------------------------------------------------*/
+/* Python type methods */
+
+static GtsObject* parent(GtsEdge *e1);
+
+static PyObject *
+new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ PyObject *o;
+ PygtsObject *obj;
+ GtsEdge *tmp;
+ GtsObject *edge=NULL;
+ PyObject *v1_,*v2_;
+ PygtsVertex *v1,*v2;
+ guint alloc_gtsobj = TRUE;
+ guint N;
+
+ /* Parse the args */
+ if(kwds) {
+ o = PyDict_GetItemString(kwds,"alloc_gtsobj");
+ if(o==Py_False) {
+ alloc_gtsobj = FALSE;
+ }
+ if(o!=NULL) {
+ PyDict_DelItemString(kwds, "alloc_gtsobj");
+ }
+ }
+ if(kwds) {
+ Py_INCREF(Py_False);
+ PyDict_SetItemString(kwds,"alloc_gtsobj", Py_False);
+ }
+
+ /* Allocate the gtsobj (if needed) */
+ if( alloc_gtsobj ) {
+
+ /* Parse the args */
+ if( (N = PyTuple_Size(args)) < 2 ) {
+ PyErr_SetString(PyExc_TypeError,"expected two Vertices");
+ return NULL;
+ }
+ v1_ = PyTuple_GET_ITEM(args,0);
+ v2_ = PyTuple_GET_ITEM(args,1);
+
+ /* Convert to PygtsObjects */
+ if(!pygts_vertex_check(v1_)) {
+ PyErr_SetString(PyExc_TypeError,"expected two Vertices");
+ return NULL;
+ }
+ if(!pygts_vertex_check(v2_)) {
+ PyErr_SetString(PyExc_TypeError,"expected two Vertices");
+ return NULL;
+ }
+ v1 = PYGTS_VERTEX(v1_);
+ v2 = PYGTS_VERTEX(v2_);
+
+ /* Error check */
+ if(PYGTS_OBJECT(v1)->gtsobj == PYGTS_OBJECT(v2)->gtsobj) {
+ PyErr_SetString(PyExc_ValueError,"Vertices given are the same");
+ return NULL;
+ }
+
+ /* Create the GtsEdge */
+ edge = GTS_OBJECT(gts_edge_new(gts_edge_class(),
+ GTS_VERTEX(v1->gtsobj),
+ GTS_VERTEX(v2->gtsobj)));
+ if( edge == NULL ) {
+ PyErr_SetString(PyExc_MemoryError, "could not create Edge");
+ return NULL;
+ }
+
+ /* Check for duplicate */
+ tmp = gts_edge_is_duplicate(GTS_EDGE(edge));
+ if( tmp != NULL ) {
+ gts_object_destroy(edge);
+ edge = GTS_OBJECT(tmp);
+ }
+
+ /* If corresponding PyObject found in object table, we are done */
+ if( (obj=g_hash_table_lookup(obj_table,edge)) != NULL ) {
+ Py_INCREF(obj);
+ return (PyObject*)obj;
+ }
+ }
+
+ /* Chain up */
+ obj = PYGTS_OBJECT(PygtsSegmentType.tp_new(type,args,kwds));
+
+ if( alloc_gtsobj ) {
+ obj->gtsobj = edge;
+
+ /* Create a parent GtsTriangle */
+ if( (obj->gtsobj_parent = parent(GTS_EDGE(obj->gtsobj))) == NULL ) {
+ gts_object_destroy(obj->gtsobj);
+ obj->gtsobj = NULL;
+ return NULL;
+ }
+
+ pygts_object_register(PYGTS_OBJECT(obj));
+ }
+
+ return (PyObject*)obj;
+}
+
+
+static int
+init(PygtsEdge *self, PyObject *args, PyObject *kwds)
+{
+ gint ret;
+
+ /* Chain up */
+ if( (ret=PygtsSegmentType.tp_init((PyObject*)self,args,kwds)) != 0 ){
+ return ret;
+ }
+
+ return 0;
+}
+
+
+/* Methods table */
+PyTypeObject PygtsEdgeType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "gts.Edge", /* tp_name */
+ sizeof(PygtsEdge), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* 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 */
+ "Edge object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 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)init, /* tp_init */
+ 0, /* tp_alloc */
+ (newfunc)new /* tp_new */
+};
+
+
+/*-------------------------------------------------------------------------*/
+/* Pygts functions */
+
+gboolean
+pygts_edge_check(PyObject* o)
+{
+ if(! PyObject_TypeCheck(o, &PygtsEdgeType)) {
+ return FALSE;
+ }
+ else {
+#if PYGTS_DEBUG
+ return pygts_edge_is_ok(PYGTS_EDGE(o));
+#else
+ return TRUE;
+#endif
+ }
+}
+
+gboolean
+pygts_edge_is_ok(PygtsEdge *e)
+{
+ GSList *parent;
+ PygtsObject *obj;
+
+ obj = PYGTS_OBJECT(e);
+
+ if(!pygts_segment_is_ok(PYGTS_SEGMENT(e))) return FALSE;
+
+ /* Check for a valid parent */
+ g_return_val_if_fail(obj->gtsobj_parent!=NULL,FALSE);
+ g_return_val_if_fail(PYGTS_IS_PARENT_TRIANGLE(obj->gtsobj_parent),FALSE);
+ parent = g_slist_find(GTS_EDGE(obj->gtsobj)->triangles,
+ obj->gtsobj_parent);
+ g_return_val_if_fail(parent!=NULL,FALSE);
+
+ return TRUE;
+}
+
+
+static GtsObject*
+parent(GtsEdge *e1) {
+ GtsVertex *v1,*v2,*v3;
+ GtsPoint *p1,*p2;
+ GtsEdge *e2, *e3;
+ GtsTriangle *p;
+
+ /* Create a third vertex for the triangle */
+ v1 = GTS_SEGMENT(e1)->v1;
+ v2 = GTS_SEGMENT(e1)->v2;
+ p1 = GTS_POINT(v1);
+ p2 = GTS_POINT(v2);
+ v3 = gts_vertex_new(pygts_parent_vertex_class(),
+ p1->x+p2->x,p1->y+p2->y,p1->z+p2->z);
+ if( v3 == NULL ) {
+ PyErr_SetString(PyExc_MemoryError, "could not create Vertex");
+ return NULL;
+ }
+
+ /* Create another two edges */
+ if( (e2 = gts_edge_new(pygts_parent_edge_class(),v2,v3)) == NULL ) {
+ PyErr_SetString(PyExc_MemoryError, "could not create Edge");
+ return NULL;
+ }
+ if( (e3 = gts_edge_new(pygts_parent_edge_class(),v3,v1)) == NULL ) {
+ PyErr_SetString(PyExc_MemoryError, "could not create Edge");
+ gts_object_destroy(GTS_OBJECT(e2));
+ return NULL;
+ }
+
+ /* Create and return the parent */
+ if( (p = gts_triangle_new(pygts_parent_triangle_class(),e1,e2,e3))
+ == NULL ) {
+ gts_object_destroy(GTS_OBJECT(e2));
+ gts_object_destroy(GTS_OBJECT(e3));
+ PyErr_SetString(PyExc_MemoryError, "could not create Triangle");
+ return NULL;
+ }
+
+ return GTS_OBJECT(p);
+}
+
+
+PygtsEdge *
+pygts_edge_new(GtsEdge *e)
+{
+ PyObject *args, *kwds;
+ PygtsObject *edge;
+
+ /* Check for Edge in the object table */
+ if( (edge = PYGTS_OBJECT(g_hash_table_lookup(obj_table,GTS_OBJECT(e))))
+ !=NULL ) {
+ Py_INCREF(edge);
+ return PYGTS_EDGE(edge);
+ }
+
+ /* Build a new Edge */
+ args = Py_BuildValue("OO",Py_None,Py_None);
+ kwds = Py_BuildValue("{s:O}","alloc_gtsobj",Py_False);
+ edge = PYGTS_EDGE(PygtsEdgeType.tp_new(&PygtsEdgeType, args, kwds));
+ Py_DECREF(args);
+ Py_DECREF(kwds);
+ if( edge == NULL ) {
+ PyErr_SetString(PyExc_MemoryError,"could not create Edge");
+ return NULL;
+ }
+ edge->gtsobj = GTS_OBJECT(e);
+
+ /* Attach the parent */
+ if( (edge->gtsobj_parent = parent(e)) == NULL ) {
+ Py_DECREF(edge);
+ return NULL;
+ }
+
+ /* Register and return */
+ pygts_object_register(edge);
+ return PYGTS_EDGE(edge);
+}
+
+
+GtsTriangleClass*
+pygts_parent_triangle_class(void)
+{
+ static GtsTriangleClass *klass = NULL;
+ GtsObjectClass *super = NULL;
+
+ if (klass == NULL) {
+
+ super = GTS_OBJECT_CLASS(gts_triangle_class());
+
+ GtsObjectClassInfo pygts_parent_triangle_info = {
+ "PygtsParentTriangle",
+ sizeof(PygtsParentTriangle),
+ sizeof(GtsTriangleClass),
+ (GtsObjectClassInitFunc)(super->info.class_init_func),
+ (GtsObjectInitFunc)(super->info.object_init_func),
+ (GtsArgSetFunc) NULL,
+ (GtsArgGetFunc) NULL
+ };
+ klass = gts_object_class_new(gts_object_class(),
+ &pygts_parent_triangle_info);
+ }
+
+ return klass;
+}
+
+
+GtsEdgeClass*
+pygts_parent_edge_class(void)
+{
+ static GtsEdgeClass *klass = NULL;
+ GtsObjectClass *super = NULL;
+
+ if (klass == NULL) {
+
+ super = GTS_OBJECT_CLASS(pygts_parent_segment_class());
+
+ GtsObjectClassInfo pygts_parent_edge_info = {
+ "PygtsParentEdge",
+ sizeof(PygtsParentEdge),
+ sizeof(GtsEdgeClass),
+ (GtsObjectClassInitFunc)(super->info.class_init_func),
+ (GtsObjectInitFunc)(super->info.object_init_func),
+ (GtsArgSetFunc) NULL,
+ (GtsArgGetFunc) NULL
+ };
+ klass = gts_object_class_new(gts_object_class(),
+ &pygts_parent_edge_info);
+ }
+
+ return klass;
+}
Added: trunk/lib/py/pygts-0.3.1/edge.h
===================================================================
--- trunk/lib/py/pygts-0.3.1/edge.h 2009-06-24 17:04:39 UTC (rev 1813)
+++ trunk/lib/py/pygts-0.3.1/edge.h 2009-06-24 22:06:24 UTC (rev 1814)
@@ -0,0 +1,78 @@
+/* pygts - python package for the manipulation of triangulated surfaces
+ *
+ * Copyright (C) 2009 Thomas J. Duck
+ * All rights reserved.
+ *
+ * Thomas J. Duck <tom.duck@xxxxxx>
+ * Department of Physics and Atmospheric Science,
+ * Dalhousie University, Halifax, Nova Scotia, Canada, B3H 3J5
+ *
+ * NOTICE
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PYGTS_EDGE_H__
+#define __PYGTS_EDGE_H__
+
+typedef struct _PygtsObject PygtsEdge;
+
+#define PYGTS_EDGE(obj) ((PygtsEdge*)obj)
+
+#define PYGTS_EDGE_AS_GTS_EDGE(o) (GTS_EDGE(PYGTS_OBJECT(o)->gtsobj))
+
+extern PyTypeObject PygtsEdgeType;
+
+gboolean pygts_edge_check(PyObject* o);
+gboolean pygts_edge_is_ok(PygtsEdge *e);
+
+PygtsEdge* pygts_edge_new(GtsEdge *e);
+
+
+/*-------------------------------------------------------------------------*/
+/* Parent GTS triangle for GTS edges */
+
+/* Define a GtsTriangle subclass that can be readily identified as the parent
+ * of an encapsulated GtsEdge. The pygts_parent_triangle_class() function
+ * is defined at the bottom, and is what ultimately allows the distinction
+ * to be made. This capability is used for edge replacement operations.
+ */
+typedef struct _GtsTriangle PygtsParentTriangle;
+
+#define PYGTS_PARENT_TRIANGLE(obj) GTS_OBJECT_CAST(obj,\
+ GtsTriangle,\
+ pygts_parent_triangle_class())
+
+#define PYGTS_IS_PARENT_TRIANGLE(obj)(gts_object_is_from_class(obj,\
+ pygts_parent_triangle_class()))
+
+GtsTriangleClass* pygts_parent_triangle_class(void);
+
+
+/* GTS edges in parent triangles */
+
+typedef struct _GtsEdge PygtsParentEdge;
+
+#define PYGTS_PARENT_EDGE(obj) GTS_OBJECT_CAST(obj,\
+ GtsEdge,\
+ pygts_parent_edge_class())
+
+#define PYGTS_IS_PARENT_EDGE(obj)(gts_object_is_from_class(obj,\
+ pygts_parent_edge_class()))
+
+GtsEdgeClass* pygts_parent_edge_class(void);
+
+#endif /* __PYGTS_EDGE_H__ */
Added: trunk/lib/py/pygts-0.3.1/face.c
===================================================================
--- trunk/lib/py/pygts-0.3.1/face.c 2009-06-24 17:04:39 UTC (rev 1813)
+++ trunk/lib/py/pygts-0.3.1/face.c 2009-06-24 22:06:24 UTC (rev 1814)
@@ -0,0 +1,646 @@
+/* pygts - python package for the manipulation of triangulated surfaces
+ *
+ * Copyright (C) 2009 Thomas J. Duck
+ * All rights reserved.
+ *
+ * Thomas J. Duck <tom.duck@xxxxxx>
+ * Department of Physics and Atmospheric Science,
+ * Dalhousie University, Halifax, Nova Scotia, Canada, B3H 3J5
+ *
+ * NOTICE
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "pygts.h"
+
+
+#if PYGTS_DEBUG
+ #define SELF_CHECK if(!pygts_face_check((PyObject*)self)) { \
+ PyErr_SetString(PyExc_RuntimeError, \
+ "problem with self object (internal error)"); \
+ return NULL; \
+ }
+#else
+ #define SELF_CHECK
+#endif
+
+
+/*-------------------------------------------------------------------------*/
+/* Methods exported to python */
+
+static PyObject*
+is_ok(PygtsFace *self, PyObject *args)
+{
+ if(pygts_face_is_ok(self)) {
+ Py_INCREF(Py_True);
+ return Py_True;
+ }
+ else {
+ Py_INCREF(Py_False);
+ return Py_False;
+ }
+}
+
+
+static PyObject*
+is_unattached(PygtsFace *self, PyObject *args)
+{
+ guint n;
+
+ /* Check for attachments other than to the gtsobj_parent */
+ n = g_slist_length(PYGTS_FACE_AS_GTS_FACE(self)->surfaces);
+ if( n > 1 ) {
+ Py_INCREF(Py_False);
+ return Py_False;
+ }
+ else if( n == 1 ){
+ Py_INCREF(Py_True);
+ return Py_True;
+ }
+ else {
+ PyErr_SetString(PyExc_RuntimeError, "Face lost parent (internal error)");
+ return NULL;
+ }
+}
+
+
+static PyObject*
+neighbor_number(PygtsFace *self, PyObject *args)
+{
+ PyObject *s_=NULL;
+ PygtsSurface *s=NULL;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &s_) )
+ return NULL;
+
+ /* Convert to PygtsObjects */
+ if( pygts_surface_check(s_) ) {
+ s = PYGTS_SURFACE(s_);
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError, "expected a Surface");
+ return NULL;
+ }
+
+ return Py_BuildValue("i",
+ gts_face_neighbor_number(PYGTS_FACE_AS_GTS_FACE(self),
+ PYGTS_SURFACE_AS_GTS_SURFACE(s)));
+}
+
+
+static PyObject*
+neighbors(PygtsFace *self, PyObject *args)
+{
+ PyObject *s_=NULL;
+ PygtsSurface *s=NULL;
+ guint i,N;
+ PyObject *tuple;
+ GSList *faces,*f;
+ PygtsFace *face;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &s_) )
+ return NULL;
+
+ /* Convert to PygtsObjects */
+ if( pygts_surface_check(s_) ) {
+ s = PYGTS_SURFACE(s_);
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError, "expected a Surface");
+ return NULL;
+ }
+
+ N = gts_face_neighbor_number(PYGTS_FACE_AS_GTS_FACE(self),
+ PYGTS_SURFACE_AS_GTS_SURFACE(s));
+
+ if( (tuple=PyTuple_New(N)) == NULL) {
+ PyErr_SetString(PyExc_MemoryError, "Could not create tuple");
+ return NULL;
+ }
+
+ /* Get the neighbors */
+ faces = gts_face_neighbors(PYGTS_FACE_AS_GTS_FACE(self),
+ PYGTS_SURFACE_AS_GTS_SURFACE(s));
+ f = faces;
+
+ for(i=0;i<N;i++) {
+ if( (face = pygts_face_new(GTS_FACE(f->data))) == NULL ) {
+ Py_DECREF(tuple);
+ return NULL;
+ }
+ PyTuple_SET_ITEM(tuple, i, (PyObject*)face);
+ f = g_slist_next(f);
+ }
+
+ return (PyObject*)tuple;
+}
+
+
+static PyObject*
+is_compatible(PygtsFace *self, PyObject *args)
+{
+ PyObject *o1_=NULL;
+ GtsEdge *e=NULL;
+ PygtsTriangle *t=NULL;
+ PygtsSurface *s=NULL;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &o1_) )
+ return NULL;
+
+ /* Convert to PygtsObjects */
+ if( pygts_triangle_check(o1_) ) {
+ t = PYGTS_TRIANGLE(o1_);
+ }
+ else {
+ if( pygts_surface_check(o1_) ) {
+ s = PYGTS_SURFACE(o1_);
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError, "expected a Triangle or Surface");
+ return NULL;
+ }
+ }
+
+ if(t!=NULL) {
+ if( (e = gts_triangles_common_edge(PYGTS_TRIANGLE_AS_GTS_TRIANGLE(self),
+ PYGTS_TRIANGLE_AS_GTS_TRIANGLE(t)))
+ == NULL ) {
+ PyErr_SetString(PyExc_RuntimeError, "Faces do not share common edge");
+ return NULL;
+ }
+ if(gts_triangles_are_compatible(PYGTS_TRIANGLE_AS_GTS_TRIANGLE(self),
+ PYGTS_TRIANGLE_AS_GTS_TRIANGLE(t),
+ e)==TRUE) {
+
+ Py_INCREF(Py_True);
+ return Py_True;
+ }
+ }
+ else {
+ if(gts_face_is_compatible(PYGTS_FACE_AS_GTS_FACE(self),
+ PYGTS_SURFACE_AS_GTS_SURFACE(s))==TRUE) {
+ Py_INCREF(Py_True);
+ return Py_True;
+ }
+ }
+ Py_INCREF(Py_False);
+ return Py_False;
+}
+
+
+static PyObject*
+is_on(PygtsFace *self, PyObject *args)
+{
+ PyObject *s_=NULL;
+ PygtsSurface *s=NULL;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &s_) )
+ return NULL;
+
+ /* Convert to PygtsObjects */
+ if( pygts_surface_check(s_) ) {
+ s = PYGTS_SURFACE(s_);
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError, "expected a Surface");
+ return NULL;
+ }
+
+ if( gts_face_has_parent_surface(PYGTS_FACE_AS_GTS_FACE(self),
+ PYGTS_SURFACE_AS_GTS_SURFACE(s)) ) {
+ Py_INCREF(Py_True);
+ return Py_True;
+ }
+ else {
+ Py_INCREF(Py_False);
+ return Py_False;
+ }
+}
+
+
+/* Methods table */
+static PyMethodDef methods[] = {
+ {"is_ok", (PyCFunction)is_ok,
+ METH_NOARGS,
+ "True if this Face f is non-degenerate and non-duplicate.\n"
+ "False otherwise.\n"
+ "\n"
+ "Signature: f.is_ok()\n"
+ },
+
+ {"is_unattached", (PyCFunction)is_unattached,
+ METH_NOARGS,
+ "True if this Face f is not part of any Surface.\n"
+ "\n"
+ "Signature: f.is_unattached().\n"
+ },
+
+ {"neighbor_number", (PyCFunction)neighbor_number,
+ METH_VARARGS,
+ "Returns the number of neighbors of Face f belonging to Surface s.\n"
+ "\n"
+ "Signature: f.neighbor_number(s).\n"
+ },
+
+ {"neighbors", (PyCFunction)neighbors,
+ METH_VARARGS,
+ "Returns a tuple of neighbors of this Face f belonging to Surface s.\n"
+ "\n"
+ "Signature: f.neighbors(s).\n"
+ },
+
+ {"is_compatible", (PyCFunction)is_compatible,
+ METH_VARARGS,
+ "True if Face f is compatible with all neighbors in Surface s.\n"
+ "False otherwise.\n"
+ "\n"
+ "Signature: f.is_compatible(s).\n"
+ },
+
+ {"is_on", (PyCFunction)is_on,
+ METH_VARARGS,
+ "True if this Face f is on Surface s. False otherwise.\n"
+ "\n"
+ "Signature: f.is_on(s).\n"
+ },
+
+ {NULL} /* Sentinel */
+};
+
+
+/*-------------------------------------------------------------------------*/
+/* Python type methods */
+
+
+static GtsObject * parent(GtsFace *face);
+
+static PyObject *
+new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ PyObject *o;
+ PygtsObject *obj;
+ guint alloc_gtsobj = TRUE;
+ PyObject *o1_,*o2_,*o3_;
+ GtsVertex *v1=NULL, *v2=NULL, *v3=NULL;
+ GtsEdge *e1=NULL,*e2=NULL,*e3=NULL,*e;
+ GtsSegment *s1,*s2,*s3;
+ gboolean flag=FALSE; /* Flag when the args are gts.Point objects */
+ GtsFace *f;
+ GtsTriangle *t;
+ guint N;
+
+ /* Parse the args */
+ if(kwds) {
+ o = PyDict_GetItemString(kwds,"alloc_gtsobj");
+ if(o==Py_False) {
+ alloc_gtsobj = FALSE;
+ }
+ if(o!=NULL) {
+ PyDict_DelItemString(kwds, "alloc_gtsobj");
+ }
+ }
+ if(kwds) {
+ Py_INCREF(Py_False);
+ PyDict_SetItemString(kwds,"alloc_gtsobj", Py_False);
+ }
+
+ /* Allocate the gtsobj (if needed) */
+ if( alloc_gtsobj ) {
+
+ /* Parse the args */
+ if( (N = PyTuple_Size(args)) < 3 ) {
+ PyErr_SetString(PyExc_TypeError,"expected three Edges or three Vertices");
+ return NULL;
+ }
+ o1_ = PyTuple_GET_ITEM(args,0);
+ o2_ = PyTuple_GET_ITEM(args,1);
+ o3_ = PyTuple_GET_ITEM(args,2);
+
+ /* Convert to PygtsObjects */
+ if( pygts_edge_check(o1_) ) {
+ e1 = PYGTS_EDGE_AS_GTS_EDGE(o1_);
+ }
+ else {
+ if( pygts_vertex_check(o1_) ) {
+ v1 = PYGTS_VERTEX_AS_GTS_VERTEX(o1_);
+ flag = TRUE;
+ }
+ }
+
+ if( pygts_edge_check(o2_) ) {
+ e2 = PYGTS_EDGE_AS_GTS_EDGE(o2_);
+ }
+ else {
+ if( pygts_vertex_check(o2_) ) {
+ v2 = PYGTS_VERTEX_AS_GTS_VERTEX(o2_);
+ flag = TRUE;
+ }
+ }
+
+ if( pygts_edge_check(o3_) ) {
+ e3 = PYGTS_EDGE_AS_GTS_EDGE(o3_);
+ }
+ else {
+ if(pygts_vertex_check(o3_)) {
+ v3 = PYGTS_VERTEX_AS_GTS_VERTEX(o3_);
+ flag = TRUE;
+ }
+ }
+
+ /* Check for three edges or three vertices */
+ if( !((e1!=NULL && e2!=NULL && e3!=NULL) ||
+ (v1!=NULL && v2!=NULL && v3!=NULL)) ) {
+ PyErr_SetString(PyExc_TypeError,
+ "three Edge or three Vertex objects expected");
+ return NULL;
+ }
+
+ if(flag) {
+
+ /* Create gts edges */
+ if( (e1 = gts_edge_new(gts_edge_class(),v1,v2)) == NULL ) {
+ PyErr_SetString(PyExc_MemoryError, "could not create Edge");
+ return NULL;
+ }
+ if( (e2 = gts_edge_new(gts_edge_class(),v2,v3)) == NULL ) {
+ PyErr_SetString(PyExc_MemoryError, "could not create Edge");
+ gts_object_destroy(GTS_OBJECT(e1));
+ return NULL;
+ }
+ if( (e3 = gts_edge_new(gts_edge_class(),v3,v1)) == NULL ) {
+ PyErr_SetString(PyExc_MemoryError, "could not create Edge");
+ gts_object_destroy(GTS_OBJECT(e1));
+ gts_object_destroy(GTS_OBJECT(e2));
+ return NULL;
+ }
+
+ /* Check for duplicates */
+ if( (e = gts_edge_is_duplicate(e1)) != NULL ) {
+ gts_object_destroy(GTS_OBJECT(e1));
+ e1 = e;
+ }
+ if( (e = gts_edge_is_duplicate(e2)) != NULL ) {
+ gts_object_destroy(GTS_OBJECT(e2));
+ e2 = e;
+ }
+ if( (e = gts_edge_is_duplicate(e3)) != NULL ) {
+ gts_object_destroy(GTS_OBJECT(e3));
+ e3 = e;
+ }
+ }
+
+ /* Check that edges connect */
+ s1 = GTS_SEGMENT(e1);
+ s2 = GTS_SEGMENT(e2);
+ s3 = GTS_SEGMENT(e3);
+ if( !((s1->v1==s3->v2 && s1->v2==s2->v1 && s2->v2==s3->v1) ||
+ (s1->v1==s3->v2 && s1->v2==s2->v2 && s2->v1==s3->v1) ||
+ (s1->v1==s3->v1 && s1->v2==s2->v1 && s2->v2==s3->v2) ||
+ (s1->v2==s3->v2 && s1->v1==s2->v1 && s2->v2==s3->v1) ||
+ (s1->v1==s3->v1 && s1->v2==s2->v2 && s2->v1==s3->v2) ||
+ (s1->v2==s3->v2 && s1->v1==s2->v2 && s2->v1==s3->v1) ||
+ (s1->v2==s3->v1 && s1->v1==s2->v1 && s2->v2==s3->v2) ||
+ (s1->v2==s3->v1 && s1->v1==s2->v2 && s2->v1==s3->v2)) ) {
+ PyErr_SetString(PyExc_RuntimeError, "Edges in face must connect");
+ if(!g_hash_table_lookup(obj_table,GTS_OBJECT(e1))) {
+ gts_object_destroy(GTS_OBJECT(e1));
+ }
+ if(!g_hash_table_lookup(obj_table,GTS_OBJECT(e1))) {
+ gts_object_destroy(GTS_OBJECT(e2));
+ }
+ if(!g_hash_table_lookup(obj_table,GTS_OBJECT(e1))) {
+ gts_object_destroy(GTS_OBJECT(e3));
+ }
+ return NULL;
+ }
+
+ /* Create the GtsFace */
+ if( (f = gts_face_new(gts_face_class(),e1,e2,e3)) == NULL ) {
+ PyErr_SetString(PyExc_MemoryError, "could not create Face");
+ if(!g_hash_table_lookup(obj_table,GTS_OBJECT(e1))) {
+ gts_object_destroy(GTS_OBJECT(e1));
+ }
+ if(!g_hash_table_lookup(obj_table,GTS_OBJECT(e1))) {
+ gts_object_destroy(GTS_OBJECT(e2));
+ }
+ if(!g_hash_table_lookup(obj_table,GTS_OBJECT(e1))) {
+ gts_object_destroy(GTS_OBJECT(e3));
+ }
+ return NULL;
+ }
+
+ /* Check for duplicate */
+ t = gts_triangle_is_duplicate(GTS_TRIANGLE(f));
+ if( t != NULL ) {
+ gts_object_destroy(GTS_OBJECT(f));
+ if(!GTS_IS_FACE(t)) {
+ PyErr_SetString(PyExc_TypeError, "expected a Face (internal error)");
+ }
+ f = GTS_FACE(t);
+ }
+
+ /* If corresponding PyObject found in object table, we are done */
+ if( (obj=g_hash_table_lookup(obj_table,GTS_OBJECT(f))) != NULL ) {
+ Py_INCREF(obj);
+ return (PyObject*)obj;
+ }
+ }
+
+ /* Chain up */
+ obj = PYGTS_OBJECT(PygtsTriangleType.tp_new(type,args,kwds));
+
+ if( alloc_gtsobj ) {
+
+ obj->gtsobj = GTS_OBJECT(f);
+
+ /* Create the parent GtsSurface */
+ if( (obj->gtsobj_parent = parent(GTS_FACE(obj->gtsobj))) == NULL ) {
+ gts_object_destroy(obj->gtsobj);
+ obj->gtsobj = NULL;
+ return NULL;
+ }
+
+ pygts_object_register(PYGTS_OBJECT(obj));
+ }
+
+ return (PyObject*)obj;
+}
+
+
+static int
+init(PygtsFace *self, PyObject *args, PyObject *kwds)
+{
+ gint ret;
+
+ /* Chain up */
+ if( (ret=PygtsTriangleType.tp_init((PyObject*)self,args,kwds)) != 0 ){
+ return ret;
+ }
+
+ return 0;
+}
+
+
+/* Methods table */
+PyTypeObject PygtsFaceType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "gts.Face", /* tp_name */
+ sizeof(PygtsFace), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* 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 */
+ "Face object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 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)init, /* tp_init */
+ 0, /* tp_alloc */
+ (newfunc)new /* tp_new */
+};
+
+
+/*-------------------------------------------------------------------------*/
+/* Pygts functions */
+
+gboolean
+pygts_face_check(PyObject* o)
+{
+ if(! PyObject_TypeCheck(o, &PygtsFaceType)) {
+ return FALSE;
+ }
+ else {
+#if PYGTS_DEBUG
+ return pygts_face_is_ok(PYGTS_FACE(o));
+#else
+ return TRUE;
+#endif
+ }
+}
+
+
+gboolean
+pygts_face_is_ok(PygtsFace *f)
+{
+ GSList *parent;
+ PygtsObject *obj;
+
+ obj = PYGTS_OBJECT(f);
+
+ if(!pygts_triangle_is_ok(PYGTS_TRIANGLE(f))) return FALSE;
+
+ /* Check for a valid parent */
+ g_return_val_if_fail(obj->gtsobj_parent!=NULL,FALSE);
+ g_return_val_if_fail(GTS_IS_SURFACE(obj->gtsobj_parent),FALSE);
+ parent = g_slist_find(GTS_FACE(obj->gtsobj)->surfaces,
+ obj->gtsobj_parent);
+ g_return_val_if_fail(parent!=NULL,FALSE);
+
+ return TRUE;
+}
+
+
+static GtsObject *
+parent(GtsFace *face) {
+ GtsSurface *p;
+
+ p = gts_surface_new(gts_surface_class(), gts_face_class(),
+ gts_edge_class(), gts_vertex_class());
+
+ if( p == NULL ) {
+ PyErr_SetString(PyExc_MemoryError, "could not create parent");
+ return NULL;
+ }
+ gts_surface_add_face(p,face);
+
+ return GTS_OBJECT(p);
+}
+
+
+PygtsFace *
+pygts_face_new(GtsFace *f)
+{
+ PyObject *args, *kwds;
+ PygtsObject *face;
+
+ /* Check for Face in the object table */
+ if( (face=PYGTS_OBJECT(g_hash_table_lookup(obj_table,GTS_OBJECT(f))))
+ != NULL ) {
+ Py_INCREF(face);
+ return PYGTS_FACE(face);
+ }
+
+ /* Build a new Face */
+ args = Py_BuildValue("OOO",Py_None,Py_None,Py_None);
+ kwds = Py_BuildValue("{s:O}","alloc_gtsobj",Py_False);
+ face = PYGTS_OBJECT(PygtsFaceType.tp_new(&PygtsFaceType, args, kwds));
+ Py_DECREF(args);
+ Py_DECREF(kwds);
+ if( face == NULL ) {
+ PyErr_SetString(PyExc_MemoryError, "could not create Face");
+ return NULL;
+ }
+ face->gtsobj = GTS_OBJECT(f);
+
+ /* Attach the parent */
+ if( (face->gtsobj_parent = parent(f)) == NULL ) {
+ Py_DECREF(face);
+ return NULL;
+ }
+
+ /* Register and return */
+ pygts_object_register(face);
+ return PYGTS_FACE(face);
+}
Added: trunk/lib/py/pygts-0.3.1/face.h
===================================================================
--- trunk/lib/py/pygts-0.3.1/face.h 2009-06-24 17:04:39 UTC (rev 1813)
+++ trunk/lib/py/pygts-0.3.1/face.h 2009-06-24 22:06:24 UTC (rev 1814)
@@ -0,0 +1,48 @@
+/* pygts - python package for the manipulation of triangulated surfaces
+ *
+ * Copyright (C) 2009 Thomas J. Duck
+ * All rights reserved.
+ *
+ * Thomas J. Duck <tom.duck@xxxxxx>
+ * Department of Physics and Atmospheric Science,
+ * Dalhousie University, Halifax, Nova Scotia, Canada, B3H 3J5
+ *
+ * NOTICE
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PYGTS_FACE_H__
+#define __PYGTS_FACE_H__
+
+#ifndef gts_face_is_unattached
+#define gts_face_is_unattached(f) ((f)->surfaces == NULL ? TRUE : FALSE)
+#endif
+
+typedef struct _PygtsObject PygtsFace;
+
+#define PYGTS_FACE(obj) ((PygtsFace*)obj)
+
+#define PYGTS_FACE_AS_GTS_FACE(o) (GTS_FACE(PYGTS_OBJECT(o)->gtsobj))
+
+extern PyTypeObject PygtsFaceType;
+
+gboolean pygts_face_check(PyObject* o);
+gboolean pygts_face_is_ok(PygtsFace *f);
+
+PygtsFace* pygts_face_new(GtsFace *f);
+
+#endif /* __PYGTS_FACE_H__ */
Added: trunk/lib/py/pygts-0.3.1/object.c
===================================================================
--- trunk/lib/py/pygts-0.3.1/object.c 2009-06-24 17:04:39 UTC (rev 1813)
+++ trunk/lib/py/pygts-0.3.1/object.c 2009-06-24 22:06:24 UTC (rev 1814)
@@ -0,0 +1,245 @@
+/* pygts - python package for the manipulation of triangulated surfaces
+ *
+ * Copyright (C) 2009 Thomas J. Duck
+ * All rights reserved.
+ *
+ * Thomas J. Duck <tom.duck@xxxxxx>
+ * Department of Physics and Atmospheric Science,
+ * Dalhousie University, Halifax, Nova Scotia, Canada, B3H 3J5
+ *
+ * NOTICE
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "pygts.h"
+
+
+/*-------------------------------------------------------------------------*/
+/* Methods exported to python */
+
+static PyObject*
+is_unattached(PygtsObject *self, PyObject *args, PyObject *kwds)
+{
+ /* Objects are unattached by default */
+ Py_INCREF(Py_False);
+ return Py_False;
+}
+
+
+/* Methods table */
+static PyMethodDef methods[] = {
+ {"is_unattached", (PyCFunction)is_unattached,
+ METH_NOARGS,
+ "True if this Object o is not attached to another Object.\n"
+ "Otherwise False.\n"
+ "\n"
+ "Trace: o.is_unattached().\n"
+ },
+
+ {NULL} /* Sentinel */
+};
+
+
+/*-------------------------------------------------------------------------*/
+/* Attributes exported to python */
+
+static PyObject *
+id(PygtsObject *self, void *closure)
+{
+ if( self->gtsobj == NULL) {
+ PyErr_SetString(PyExc_RuntimeError, "GTS object does not exist!");
+ return NULL;
+ }
+ /* Use the pointer of the gtsobj */
+ return Py_BuildValue("i",(long)(self->gtsobj));
+}
+
+
+/* Methods table */
+static PyGetSetDef getset[] = {
+ {"id", (getter)id, NULL, "GTS object id", NULL},
+ {NULL} /* Sentinel */
+};
+
+
+/*-------------------------------------------------------------------------*/
+/* Python type methods */
+
+static void
+dealloc(PygtsObject* self)
+{
+ /* De-register entry from the object table */
+ pygts_object_deregister(self);
+
+ if(self->gtsobj_parent!=NULL) {
+ /* Free the parent; GTS will free the child unless it is attached
+ * to something else.
+ */
+ gts_object_destroy(self->gtsobj_parent);
+ self->gtsobj_parent=NULL;
+ }
+ else {
+ /* We have the only reference, and so it is safe to destroy the gtsobj
+ * (unless it was never created in the first place).
+ */
+ if(self->gtsobj!=NULL) {
+ gts_object_destroy(self->gtsobj);
+ self->gtsobj=NULL;
+ }
+ }
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+
+static PyObject *
+new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ PygtsObject *self;
+
+ /* Chain up object allocation */
+ self = PYGTS_OBJECT(type->tp_alloc(type, 0));
+ if( self == NULL ) return NULL;
+
+ /* Object initialization */
+ self->gtsobj = NULL;
+ self->gtsobj_parent = NULL;
+
+ return (PyObject *)self;
+}
+
+
+static int
+init(PygtsObject *self, PyObject *args, PyObject *kwds)
+{
+ if( self->gtsobj == NULL ) {
+ PyErr_SetString(PyExc_RuntimeError, "Cannot create abstract Object");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int
+compare(PygtsObject *o1, PygtsObject *o2)
+{
+ if(o1->gtsobj==o2->gtsobj) {
+ return 0;
+ }
+ else {
+ return -1;
+ }
+}
+
+
+/* Methods table */
+PyTypeObject PygtsObjectType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "gts.Object" , /* tp_name */
+ sizeof(PygtsObject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ (cmpfunc)compare, /* tp_compare */
+ 0, /* 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 */
+ "Base object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ methods, /* tp_methods */
+ 0, /* tp_members */
+ getset, /* tp_getset */
+ 0, /* tp_base: attached in pygts.c */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)init, /* tp_init */
+ 0, /* tp_alloc */
+ (newfunc)new /* tp_new */
+};
+
+
+/*-------------------------------------------------------------------------*/
+/* Pygts functions */
+
+gboolean
+pygts_object_check(PyObject* o)
+{
+ if(! PyObject_TypeCheck(o, &PygtsObjectType)) {
+ return FALSE;
+ }
+ else {
+#if PYGTS_DEBUG
+ return pygts_object_is_ok(PYGTS_OBJECT(o));
+#else
+ return TRUE;
+#endif
+ }
+}
+
+
+gboolean
+pygts_object_is_ok(PygtsObject *o)
+{
+ g_return_val_if_fail(o->gtsobj!=NULL,FALSE);
+ g_return_val_if_fail(g_hash_table_lookup(obj_table,o->gtsobj)!=NULL,FALSE);
+ return TRUE;
+}
+
+
+/*-------------------------------------------------------------------------*/
+/* Object table functions */
+
+GHashTable *obj_table; /* GtsObject key, associated PyObject value */
+
+void
+pygts_object_register(PygtsObject *o)
+{
+ if( g_hash_table_lookup(obj_table,o->gtsobj) == NULL ) {
+ g_hash_table_insert(obj_table,o->gtsobj,o);
+ }
+}
+
+
+void
+pygts_object_deregister(PygtsObject *o)
+{
+ if(o->gtsobj!=NULL) {
+ if(g_hash_table_lookup(obj_table,o->gtsobj)==o) {
+ g_hash_table_remove(obj_table,o->gtsobj);
+ }
+ }
+}
+
Added: trunk/lib/py/pygts-0.3.1/object.h
===================================================================
--- trunk/lib/py/pygts-0.3.1/object.h 2009-06-24 17:04:39 UTC (rev 1813)
+++ trunk/lib/py/pygts-0.3.1/object.h 2009-06-24 22:06:24 UTC (rev 1814)
@@ -0,0 +1,53 @@
+/* pygts - python package for the manipulation of triangulated surfaces
+ *
+ * Copyright (C) 2009 Thomas J. Duck
+ * All rights reserved.
+ *
+ * Thomas J. Duck <tom.duck@xxxxxx>
+ * Department of Physics and Atmospheric Science,
+ * Dalhousie University, Halifax, Nova Scotia, Canada, B3H 3J5
+ *
+ * NOTICE
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PYGTS_OBJECT_H__
+#define __PYGTS_OBJECT_H__
+
+
+typedef struct _PygtsObject PygtsObject;
+typedef struct _PygtsMethods PygtsMethods;
+
+#define PYGTS_OBJECT(obj) ((PygtsObject*)obj)
+
+struct _PygtsObject {
+ PyObject_HEAD
+ GtsObject *gtsobj; /* Encapsulated GtsObject */
+ GtsObject *gtsobj_parent; /* A parent object to ensure persistence */
+};
+
+extern PyTypeObject PygtsObjectType;
+extern PygtsMethods PygtsObjectMethods;
+
+gboolean pygts_object_check(PyObject* o);
+gboolean pygts_object_is_ok(PygtsObject *o);
+
+extern GHashTable *obj_table; /* GtsObject key, associated PyObject value */
+void pygts_object_register(PygtsObject *o);
+void pygts_object_deregister(PygtsObject *o);
+
+#endif /* __PYGTS_OBJECT_H__ */
Added: trunk/lib/py/pygts-0.3.1/point.c
===================================================================
--- trunk/lib/py/pygts-0.3.1/point.c 2009-06-24 17:04:39 UTC (rev 1813)
+++ trunk/lib/py/pygts-0.3.1/point.c 2009-06-24 22:06:24 UTC (rev 1814)
@@ -0,0 +1,1227 @@
+/* pygts - python point for the manipulation of triangulated surfaces
+ *
+ * Copyright (C) 2009 Thomas J. Duck
+ * All rights reserved.
+ *
+ * Thomas J. Duck <tom.duck@xxxxxx>
+ * Department of Physics and Atmospheric Science,
+ * Dalhousie University, Halifax, Nova Scotia, Canada, B3H 3J5
+ *
+ * NOTICE
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "pygts.h"
+
+
+#if PYGTS_DEBUG
+ #define SELF_CHECK if(!pygts_point_check((PyObject*)self)) { \
+ PyErr_SetString(PyExc_RuntimeError, \
+ "problem with self object (internal error)"); \
+ return NULL; \
+ }
+#else
+ #define SELF_CHECK
+#endif
+
+
+/*-------------------------------------------------------------------------*/
+/* Methods exported to python */
+
+static PyObject*
+is_ok(PygtsPoint *self, PyObject *args)
+{
+ if(pygts_point_is_ok(self)) {
+ Py_INCREF(Py_True);
+ return Py_True;
+ }
+ else {
+ Py_INCREF(Py_False);
+ return Py_False;
+ }
+}
+
+
+static PyObject*
+set(PygtsPoint *self, PyObject *args)
+{
+ gdouble x=0,y=0,z=0;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "|ddd", &x,&y,&z)) {
+ return NULL;
+ }
+
+ gts_point_set(PYGTS_POINT_AS_GTS_POINT(self),x,y,z);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+static PyObject*
+coords(PygtsPoint *self, PyObject *args)
+{
+ SELF_CHECK
+
+ return Py_BuildValue("ddd",PYGTS_POINT_AS_GTS_POINT(self)->x,
+ PYGTS_POINT_AS_GTS_POINT(self)->y,
+ PYGTS_POINT_AS_GTS_POINT(self)->z);
+}
+
+
+static PyObject*
+is_in_rectangle(PygtsPoint* self, PyObject *args)
+{
+ PyObject *o1_,*o2_;
+ PygtsPoint *p1, *p2;
+ gboolean flag = FALSE;
+ gdouble x,y;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "OO", &o1_, &o2_) ) {
+ return NULL;
+ }
+
+ /* Convert to PygtsObjects */
+ if(!(pygts_point_check(o1_) && pygts_point_check(o2_))) {
+ PyErr_SetString(PyExc_TypeError,"expected two Points");
+ return NULL;
+ }
+
+ p1 = PYGTS_POINT(o1_);
+ p2 = PYGTS_POINT(o2_);
+
+ /* Test if point *may* be on rectangle perimeter */
+ x = PYGTS_POINT_AS_GTS_POINT(self)->x;
+ y = PYGTS_POINT_AS_GTS_POINT(self)->y;
+ if( PYGTS_POINT_AS_GTS_POINT(p1)->x == x ||
+ PYGTS_POINT_AS_GTS_POINT(p1)->y == y ||
+ PYGTS_POINT_AS_GTS_POINT(p2)->x == x ||
+ PYGTS_POINT_AS_GTS_POINT(p2)->y == y ) {
+ flag = TRUE;
+ }
+
+ if( gts_point_is_in_rectangle(PYGTS_POINT_AS_GTS_POINT(self),
+ PYGTS_POINT_AS_GTS_POINT(p1),
+ PYGTS_POINT_AS_GTS_POINT(p2)) ) {
+ if(flag) {
+ return Py_BuildValue("i",0);
+ }
+ else {
+ return Py_BuildValue("i",1);
+ }
+ }
+ else {
+ if( flag &&
+ gts_point_is_in_rectangle(PYGTS_POINT_AS_GTS_POINT(self),
+ PYGTS_POINT_AS_GTS_POINT(p2),
+ PYGTS_POINT_AS_GTS_POINT(p1))) {
+ return Py_BuildValue("i",0);
+ }
+ else {
+ return Py_BuildValue("i",-1);
+ }
+ }
+}
+
+
+static PyObject*
+distance(PygtsPoint* self, PyObject *args)
+{
+ PyObject *o_;
+ PygtsPoint *p=NULL;
+ PygtsSegment *s=NULL;
+ PygtsTriangle *t=NULL;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &o_) ) {
+ return NULL;
+ }
+
+ /* Convert to PygtsObjects */
+ if(pygts_point_check(o_)) {
+ p = PYGTS_POINT(o_);
+ }
+ else {
+ if(pygts_segment_check(o_)) {
+ s = PYGTS_SEGMENT(o_);
+ }
+ else {
+ if(pygts_triangle_check(o_)) {
+ t = PYGTS_TRIANGLE(o_);
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError,
+ "expected a Point, Segment or Triangle");
+ return NULL;
+ }
+ }
+ }
+
+ if(p!=NULL) {
+ return Py_BuildValue("d",
+ gts_point_distance(PYGTS_POINT_AS_GTS_POINT(self),
+ PYGTS_POINT_AS_GTS_POINT(p)));
+ }
+ else {
+ if(s!=NULL) {
+ return Py_BuildValue("d",
+ gts_point_segment_distance(PYGTS_POINT_AS_GTS_POINT(self),
+ PYGTS_SEGMENT_AS_GTS_SEGMENT(s) )
+ );
+ }
+ else {
+ return Py_BuildValue("d",
+ gts_point_triangle_distance(PYGTS_POINT_AS_GTS_POINT(self),
+ PYGTS_TRIANGLE_AS_GTS_TRIANGLE(t) )
+ );
+ }
+ }
+}
+
+
+static PyObject*
+distance2(PygtsPoint* self, PyObject *args)
+{
+ PyObject *o_;
+ PygtsPoint *p=NULL;
+ PygtsSegment *s=NULL;
+ PygtsTriangle *t=NULL;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &o_) ) {
+ return NULL;
+ }
+
+ /* Convert to PygtsObjects */
+ if(pygts_point_check(o_)) {
+ p = PYGTS_POINT(o_);
+ }
+ else {
+ if(pygts_segment_check(o_)) {
+ s = PYGTS_SEGMENT(o_);
+ }
+ else {
+ if(pygts_triangle_check(o_)) {
+ t = PYGTS_TRIANGLE(o_);
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError,
+ "expected a Point, Segment or Triangle");
+ return NULL;
+ }
+ }
+ }
+
+ if(p!=NULL) {
+ return Py_BuildValue("d",
+ gts_point_distance2(PYGTS_POINT_AS_GTS_POINT(self),
+ PYGTS_POINT_AS_GTS_POINT(p)));
+ }
+ else {
+ if(s!=NULL) {
+ return Py_BuildValue("d",
+ gts_point_segment_distance2(PYGTS_POINT_AS_GTS_POINT(self),
+ PYGTS_SEGMENT_AS_GTS_SEGMENT(s) )
+ );
+ }
+ else {
+ return Py_BuildValue("d",
+ gts_point_triangle_distance2(PYGTS_POINT_AS_GTS_POINT(self),
+ PYGTS_TRIANGLE_AS_GTS_TRIANGLE(t) )
+ );
+ }
+ }
+}
+
+
+static PyObject*
+orientation_3d(PygtsPoint* self, PyObject *args)
+{
+ PyObject *p1_,*p2_,*p3_;
+ PygtsPoint *p1,*p2,*p3;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "OOO", &p1_, &p2_, &p3_) ) {
+ return NULL;
+ }
+
+ /* Convert to PygtsObjects */
+ if(!pygts_point_check(p1_)) {
+ PyErr_SetString(PyExc_TypeError,"expected three Points");
+ return NULL;
+ }
+ if(!pygts_point_check(p2_)) {
+ PyErr_SetString(PyExc_TypeError,"expected three Points");
+ return NULL;
+ }
+ if(!pygts_point_check(p3_)) {
+ PyErr_SetString(PyExc_TypeError,"expected three Points");
+ return NULL;
+ }
+ p1 = PYGTS_POINT(p1_);
+ p2 = PYGTS_POINT(p2_);
+ p3 = PYGTS_POINT(p3_);
+
+ return Py_BuildValue("d",
+ gts_point_orientation_3d(PYGTS_POINT_AS_GTS_POINT(p1),
+ PYGTS_POINT_AS_GTS_POINT(p2),
+ PYGTS_POINT_AS_GTS_POINT(p3),
+ PYGTS_POINT_AS_GTS_POINT(self)));
+}
+
+
+static PyObject*
+orientation_3d_sos(PygtsPoint* self, PyObject *args)
+{
+ PyObject *p1_,*p2_,*p3_;
+ PygtsPoint *p1,*p2,*p3;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "OOO", &p1_, &p2_, &p3_) ) {
+ return NULL;
+ }
+
+ /* Convert to PygtsObjects */
+ if(!pygts_point_check(p1_)) {
+ PyErr_SetString(PyExc_TypeError,"expected three Points");
+ return NULL;
+ }
+ if(!pygts_point_check(p2_)) {
+ PyErr_SetString(PyExc_TypeError,"expected three Points");
+ return NULL;
+ }
+ if(!pygts_point_check(p3_)) {
+ PyErr_SetString(PyExc_TypeError,"expected three Points");
+ return NULL;
+ }
+ p1 = PYGTS_POINT(p1_);
+ p2 = PYGTS_POINT(p2_);
+ p3 = PYGTS_POINT(p3_);
+
+ return Py_BuildValue("i",gts_point_orientation_3d_sos(
+ PYGTS_POINT_AS_GTS_POINT(p1),
+ PYGTS_POINT_AS_GTS_POINT(p2),
+ PYGTS_POINT_AS_GTS_POINT(p3),
+ PYGTS_POINT_AS_GTS_POINT(self)));
+}
+
+
+static PyObject*
+is_in_circle(PygtsPoint* self, PyObject *args)
+{
+ PyObject *o1_=NULL,*o2_=NULL,*o3_=NULL;
+ PygtsPoint *p1=NULL, *p2=NULL, *p3=NULL;
+ PygtsTriangle *t=NULL;
+ gdouble result;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O|OO", &o1_, &o2_, &o3_) ) {
+ return NULL;
+ }
+ if( (o2_==NULL && o3_!=NULL) || (o2_!=NULL && o3_==NULL) ) {
+ PyErr_SetString(PyExc_TypeError,"expected three Points or one Triangle");
+ return NULL;
+ }
+
+ /* Convert to PygtsObjects */
+ if(o2_==NULL && o3_==NULL) {
+ if(!pygts_triangle_check(o1_)) {
+ PyErr_SetString(PyExc_TypeError,"expected three Points or one Triangle");
+ return NULL;
+ }
+ t = PYGTS_TRIANGLE(o1_);
+ }
+ else {
+ if(!pygts_point_check(o1_)) {
+ PyErr_SetString(PyExc_TypeError,"expected three Points or one Triangle");
+ return NULL;
+ }
+ if(!pygts_point_check(o2_)) {
+ PyErr_SetString(PyExc_TypeError,"expected three Points or one Triangle");
+ return NULL;
+ }
+ if(!pygts_point_check(o3_)) {
+ PyErr_SetString(PyExc_TypeError,"expected three Points or one Triangle");
+ return NULL;
+ }
+ p1 = PYGTS_POINT(o1_);
+ p2 = PYGTS_POINT(o2_);
+ p3 = PYGTS_POINT(o3_);
+ }
+
+
+ if(t!=NULL){
+ result=gts_point_in_triangle_circle(PYGTS_POINT_AS_GTS_POINT(self),
+ PYGTS_TRIANGLE_AS_GTS_TRIANGLE(t));
+ }
+ else {
+ result = gts_point_in_circle(PYGTS_POINT_AS_GTS_POINT(self),
+ PYGTS_POINT_AS_GTS_POINT(p1),
+ PYGTS_POINT_AS_GTS_POINT(p2),
+ PYGTS_POINT_AS_GTS_POINT(p3));
+ }
+ if(result>0) return Py_BuildValue("i",1);
+ if(result==0) return Py_BuildValue("i",0);
+ return Py_BuildValue("i",-1);
+}
+
+
+static PyObject*
+is_in(PygtsPoint* self, PyObject *args)
+{
+ PyObject *t_;
+ PygtsTriangle *t;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &t_) ) {
+ return NULL;
+ }
+
+ /* Convert to PygtsObjects */
+ if(!pygts_triangle_check(t_)) {
+ PyErr_SetString(PyExc_TypeError,"expected a Triangle");
+ return NULL;
+ }
+ t = PYGTS_TRIANGLE(t_);
+
+ return Py_BuildValue("i",
+ gts_point_is_in_triangle(PYGTS_POINT_AS_GTS_POINT(self),
+ PYGTS_TRIANGLE_AS_GTS_TRIANGLE(t)));
+}
+
+
+static PyObject*
+is_inside(PygtsPoint* self, PyObject *args)
+{
+ PyObject *s_;
+ PygtsSurface *s;
+ GNode *tree;
+ gboolean is_open=FALSE, ret;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &s_) ) {
+ return NULL;
+ }
+
+ /* Convert to PygtsObjects */
+ if(!pygts_surface_check(s_)) {
+ PyErr_SetString(PyExc_TypeError,"expected a Surface");
+ return NULL;
+ }
+ s = PYGTS_SURFACE(s_);
+
+ /* Error check */
+ if(!gts_surface_is_closed(PYGTS_SURFACE_AS_GTS_SURFACE(s))) {
+ PyErr_SetString(PyExc_RuntimeError,"Surface is not closed");
+ return NULL;
+ }
+
+ /* Determing is_open parameter; note the meaning is different from the
+ * error check above.
+ */
+ if( gts_surface_volume(PYGTS_SURFACE_AS_GTS_SURFACE(s))<0. ) {
+ is_open = TRUE;
+ }
+
+ /* Construct the tree */
+ if((tree=gts_bb_tree_surface(PYGTS_SURFACE_AS_GTS_SURFACE(s))) == NULL) {
+ PyErr_SetString(PyExc_MemoryError,"could not create GTree");
+ return NULL;
+ }
+
+ /* Make the call */
+ ret = gts_point_is_inside_surface(PYGTS_POINT_AS_GTS_POINT(self), tree,
+ is_open);
+
+ g_node_destroy(tree);
+
+ if(ret) {
+ Py_INCREF(Py_True);
+ return Py_True;
+ }
+ else {
+ Py_INCREF(Py_False);
+ return Py_False;
+ }
+}
+
+
+static PyObject*
+closest(PygtsPoint* self, PyObject *args)
+{
+ PyObject *o1_,*o2_;
+ PygtsPoint *p=NULL;
+ PygtsSegment *s=NULL;
+ PygtsTriangle *t=NULL;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "OO", &o1_, &o2_) ) {
+ return NULL;
+ }
+
+ /* Convert to PygtsObjects */
+ if(pygts_segment_check(o1_)) {
+ s = PYGTS_SEGMENT(o1_);
+ }
+ else {
+ if(pygts_triangle_check(o1_)) {
+ t = PYGTS_TRIANGLE(o1_);
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError,
+ "expected a Segment or Triangle, and a Point");
+ return NULL;
+ }
+ }
+ if(pygts_point_check(o2_)) {
+ p = PYGTS_POINT(o2_);
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError,
+ "expected a Segment or Triangle, and a Point");
+ return NULL;
+ }
+
+ if(s!=NULL) {
+ gts_point_segment_closest(PYGTS_POINT_AS_GTS_POINT(p),
+ PYGTS_SEGMENT_AS_GTS_SEGMENT(s),
+ PYGTS_POINT_AS_GTS_POINT(self));
+ }
+ else {
+ gts_point_triangle_closest(PYGTS_POINT_AS_GTS_POINT(p),
+ PYGTS_TRIANGLE_AS_GTS_TRIANGLE(t),
+ PYGTS_POINT_AS_GTS_POINT(self));
+ }
+
+ Py_INCREF(self);
+ return (PyObject*)self;
+}
+
+
+/* Helper for rotate() */
+gint
+pygts_point_rotate(GtsPoint* p, gdouble dx, gdouble dy, gdouble dz, gdouble a)
+{
+ GtsMatrix *m;
+ GtsVector v;
+
+ v[0] = dx; v[1] = dy; v[2] = dz;
+ if( (m = gts_matrix_rotate(NULL,v,a)) == NULL ) {
+ PyErr_SetString(PyExc_MemoryError,"could not create matrix");
+ return -1;
+ }
+ gts_point_transform(p,m);
+ gts_matrix_destroy(m);
+
+ return 0;
+}
+
+
+static PyObject*
+rotate(PygtsPoint* self, PyObject *args, PyObject *keywds)
+{
+ static char *kwlist[] = {"dx", "dy", "dz", "a", NULL};
+ gdouble dx=0,dy=0,dz=0,a=0;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTupleAndKeywords(args, keywds,"|dddd", kwlist,
+ &dx, &dy, &dz, &a) ) {
+ return NULL;
+ }
+
+ if(pygts_point_rotate(PYGTS_POINT_AS_GTS_POINT(self),dx,dy,dz,a)==-1)
+ return NULL;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+/* Helper for scale() */
+gint
+pygts_point_scale(GtsPoint* p, gdouble dx, gdouble dy, gdouble dz)
+{
+ GtsMatrix *m;
+ GtsVector v;
+
+ v[0] = dx; v[1] = dy; v[2] = dz;
+ if( (m = gts_matrix_scale(NULL,v)) == NULL ) {
+ PyErr_SetString(PyExc_MemoryError,"could not create matrix");
+ return -1;
+ }
+ gts_point_transform(p,m);
+ gts_matrix_destroy(m);
+
+ return 0;
+}
+
+
+static PyObject*
+scale(PygtsPoint* self, PyObject *args, PyObject *keywds)
+{
+ static char *kwlist[] = {"dx", "dy", "dz", NULL};
+ gdouble dx=1,dy=1,dz=1;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTupleAndKeywords(args, keywds,"|ddd", kwlist,
+ &dx, &dy, &dz) ) {
+ return NULL;
+ }
+
+ if(pygts_point_scale(PYGTS_POINT_AS_GTS_POINT(self),dx,dy,dz)==-1)
+ return NULL;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+/* Helper for translate() */
+gint
+pygts_point_translate(GtsPoint* p, gdouble dx, gdouble dy, gdouble dz)
+{
+ GtsMatrix *m;
+ GtsVector v;
+
+ v[0] = dx; v[1] = dy; v[2] = dz;
+ if( (m = gts_matrix_translate(NULL,v)) == NULL ) {
+ PyErr_SetString(PyExc_MemoryError,"could not create matrix");
+ return -1;
+ }
+ gts_point_transform(p,m);
+ gts_matrix_destroy(m);
+
+ return 0;
+}
+
+
+static PyObject*
+translate(PygtsPoint* self, PyObject *args, PyObject *keywds)
+{
+ static char *kwlist[] = {"dx", "dy", "dz", NULL};
+ gdouble dx=0,dy=0,dz=0;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTupleAndKeywords(args, keywds,"|ddd", kwlist,
+ &dx, &dy, &dz) ) {
+ return NULL;
+ }
+
+ if(pygts_point_translate(PYGTS_POINT_AS_GTS_POINT(self),dx,dy,dz)==-1)
+ return NULL;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+/* Methods table */
+static PyMethodDef methods[] = {
+
+ {"is_ok", (PyCFunction)is_ok,
+ METH_NOARGS,
+ "True if this Point p is OK. False otherwise.\n"
+ "This method is useful for unit testing and debugging.\n"
+ "\n"
+ "Signature: p.is_ok().\n"
+ },
+
+ {"set", (PyCFunction)set,
+ METH_VARARGS,
+ "Sets x, y, and z coordinates of this Point p.\n"
+ "\n"
+ "Signature: p.set(x,y,z)\n"
+ },
+
+ {"coords", (PyCFunction)coords,
+ METH_VARARGS,
+ "Returns a tuple of the x, y, and z coordinates for this Point p.\n"
+ "\n"
+ "Signature: p.coords(x,y,z)\n"
+ },
+
+ {"is_in_rectangle", (PyCFunction)is_in_rectangle,
+ METH_VARARGS,
+ "True if this Point p is in box with bottom-left and upper-right\n"
+ "Points p1 and p2.\n"
+ "\n"
+ "Signature: p.is_in_rectange(p1,p2)\n"
+ },
+
+ {"distance", (PyCFunction)distance,
+ METH_VARARGS,
+ "Returns Euclidean distance between this Point p and other Point p2,\n"
+ "Segment s, or Triangle t."
+ "\n"
+ "Signature: p.distance(p2), p.distance(s) or p.distance(t)\n"
+ },
+
+ {"distance2", (PyCFunction)distance2,
+ METH_VARARGS,
+ "Returns squared Euclidean distance between Point p and Point p2,\n"
+ "Segment s, or Triangle t.\n"
+ "\n"
+ "Signature: p.distance2(p2), p.distance2(s), or p.distance2(t)\n"
+ },
+
+ {"orientation_3d", (PyCFunction)orientation_3d,
+ METH_VARARGS,
+ "Determines if this Point p is above, below or on plane of 3 Points\n"
+ "p1, p2 and p3.\n"
+ "\n"
+ "Signature: p.orientation_3d(p1,p2,p3)\n"
+ "\n"
+ "Below is defined so that p1, p2 and p3 appear in counterclockwise\n"
+ "order when viewed from above the plane.\n"
+ "\n"
+ "The return value is positive if p4 lies below the plane, negative\n"
+ "if p4 lies above the plane, and zero if the four points are\n"
+ "coplanar. The value is an approximation of six times the signed\n"
+ "volume of the tetrahedron defined by the four points.\n"
+ },
+
+ {"orientation_3d_sos", (PyCFunction)orientation_3d_sos,
+ METH_VARARGS,
+ "Determines if this Point p is above, below or on plane of 3 Points\n"
+ "p1, p2 and p3.\n"
+ "\n"
+ "Signature: p.orientation_3d_sos(p1,p2,p3)\n"
+ "\n"
+ "Below is defined so that p1, p2 and p3 appear in counterclockwise\n"
+ "order when viewed from above the plane.\n"
+ "\n"
+ "The return value is +1 if p4 lies below the plane, and -1 if p4\n"
+ "lies above the plane. Simulation of Simplicity (SoS) is used to\n"
+ "break ties when the orientation is degenerate (i.e. the point lies\n"
+ "on the plane definedby p1, p2 and p3)."
+ },
+
+ {"is_in_circle", (PyCFunction)is_in_circle,
+ METH_VARARGS,
+ "Tests if this Point p is inside or outside circumcircle.\n"
+ "The planar projection (x,y) of Point p is tested against the\n"
+ "circumcircle defined by the planar projection of p1, p2 and p3,\n"
+ "or alternatively the Triangle t\n"
+ "\n"
+ "Signature: p.in_circle(p1,p2,p3) or p.in_circle(t) \n"
+ "\n"
+ "Returns +1 if p lies inside, -1 if p lies outside, and 0 if p lies\n"
+ "on the circle. The Points p1, p2, and p3 must be in\n"
+ "counterclockwise order, or the sign of the result will be reversed.\n"
+ },
+
+ {"is_in", (PyCFunction)is_in,
+ METH_VARARGS,
+ "Tests if this Point p is inside or outside Triangle t.\n"
+ "The planar projection (x,y) of Point p is tested against the\n"
+ "planar projection of Triangle t.\n"
+ "\n"
+ "Signature: p.in_circle(p1,p2,p3) or p.in_circle(t) \n"
+ "\n"
+ "Returns a +1 if p lies inside, -1 if p lies outside, and 0\n"
+ "if p lies on the triangle.\n"
+ },
+
+ {"is_inside", (PyCFunction)is_inside,
+ METH_VARARGS,
+ "True if this Point p is inside or outside Surface s.\n"
+ "False otherwise.\n"
+ "\n"
+ "Signature: p.in_inside(s)\n"
+ },
+
+ {"closest", (PyCFunction)closest,
+ METH_VARARGS,
+ "Set the coordinates of Point p to the Point on Segment s\n"
+ "or Triangle t closest to the Point p2\n"
+ "\n"
+ "Signature: p.closest(s,p2) or p.closest(t,p2)\n"
+ "\n"
+ "Returns the (modified) Point p.\n"
+ },
+
+ {"rotate", (PyCFunction)rotate,
+ METH_VARARGS | METH_KEYWORDS,
+ "Rotates Point p around vector dx,dy,dz by angle a.\n"
+ "The sense of the rotation is given by the right-hand-rule.\n"
+ "\n"
+ "Signature: p.rotate(dx=0,dy=0,dz=0,a=0)\n"
+ },
+
+ {"scale", (PyCFunction)scale,
+ METH_VARARGS | METH_KEYWORDS,
+ "Scales Point p by vector dx,dy,dz.\n"
+ "\n"
+ "Signature: p.scale(dx=1,dy=1,dz=1)\n"
+ },
+
+ {"translate", (PyCFunction)translate,
+ METH_VARARGS | METH_KEYWORDS,
+ "Translates Point p by vector dx,dy,dz.\n"
+ "\n"
+ "Signature: p.translate(dx=0,dy=0,dz=0)\n"
+ },
+
+ {NULL} /* Sentinel */
+};
+
+
+/*-------------------------------------------------------------------------*/
+/* Attributes exported to python */
+
+static PyObject *
+getx(PygtsPoint *self, void *closure)
+{
+ SELF_CHECK
+
+ return Py_BuildValue("d",PYGTS_POINT_AS_GTS_POINT(self)->x);
+}
+
+
+static int
+setx(PygtsPoint *self, PyObject *value, void *closure)
+{
+ if(PyFloat_Check(value)) {
+ PYGTS_POINT_AS_GTS_POINT(self)->x = PyFloat_AsDouble(value);
+ }
+ else if(PyInt_Check(value)) {
+ PYGTS_POINT_AS_GTS_POINT(self)->x = (gdouble)PyInt_AsLong(value);
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError,"expected a float");
+ return -1;
+ }
+ return 0;
+}
+
+
+static PyObject *
+gety(PygtsPoint *self, void *closure)
+{
+ SELF_CHECK
+
+ return Py_BuildValue("d",PYGTS_POINT_AS_GTS_POINT(self)->y);
+}
+
+
+static int
+sety(PygtsPoint *self, PyObject *value, void *closure)
+{
+ if(PyFloat_Check(value)) {
+ PYGTS_POINT_AS_GTS_POINT(self)->y = PyFloat_AsDouble(value);
+ }
+ else if(PyInt_Check(value)) {
+ PYGTS_POINT_AS_GTS_POINT(self)->y = (gdouble)PyInt_AsLong(value);
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError,"expected a float");
+ return -1;
+ }
+ return 0;
+}
+
+
+static PyObject *
+getz(PygtsPoint *self, void *closure)
+{
+ SELF_CHECK
+
+ return Py_BuildValue("d",PYGTS_POINT_AS_GTS_POINT(self)->z);
+}
+
+
+static int
+setz(PygtsPoint *self, PyObject *value, void *closure)
+{
+ if(PyFloat_Check(value)) {
+ PYGTS_POINT_AS_GTS_POINT(self)->z = PyFloat_AsDouble(value);
+ }
+ else if(PyInt_Check(value)) {
+ PYGTS_POINT_AS_GTS_POINT(self)->z = (gdouble)PyInt_AsLong(value);
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError,"expected a float");
+ return -1;
+ }
+ return 0;
+}
+
+
+/* Methods table */
+static PyGetSetDef getset[] = {
+ {"x", (getter)getx, (setter)setx, "x value", NULL},
+ {"y", (getter)gety, (setter)sety, "y value", NULL},
+ {"z", (getter)getz, (setter)setz, "z value", NULL},
+ {NULL} /* Sentinel */
+};
+
+
+/*-------------------------------------------------------------------------*/
+/* Python type methods */
+
+static PyObject *
+new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ PyObject *o;
+ PygtsObject *obj;
+ guint alloc_gtsobj = TRUE;
+
+ /* Parse the args */
+ if(kwds) {
+ o = PyDict_GetItemString(kwds,"alloc_gtsobj");
+ if(o==Py_False) {
+ alloc_gtsobj = FALSE;
+ }
+ if(o!=NULL) {
+ PyDict_DelItemString(kwds, "alloc_gtsobj");
+ }
+ }
+ if(kwds) {
+ Py_INCREF(Py_False);
+ PyDict_SetItemString(kwds,"alloc_gtsobj", Py_False);
+ }
+
+ /* Chain up */
+ obj = PYGTS_OBJECT(PygtsObjectType.tp_new(type,args,kwds));
+
+ /* Allocate the gtsobj (if needed) */
+ if( alloc_gtsobj ) {
+ obj->gtsobj = GTS_OBJECT(gts_point_new(gts_point_class(),0,0,0));
+ if( obj->gtsobj == NULL ) {
+ PyErr_SetString(PyExc_MemoryError, "could not create Point");
+ return NULL;
+ }
+
+ pygts_object_register(obj);
+ }
+
+ return (PyObject*)obj;
+}
+
+
+static int
+init(PygtsPoint *self, PyObject *args, PyObject *kwds)
+{
+ PygtsObject *obj;
+ gdouble x=0,y=0,z=0;
+ guint a;
+ gint ret;
+ static char *kwlist[] = {"x", "y", "z", "alloc_gtsobj", NULL};
+
+ obj = PYGTS_OBJECT(self);
+
+ /* Parse the args */
+ if(! PyArg_ParseTupleAndKeywords(args, kwds, "|dddi", kwlist, &x,&y,&z,&a)) {
+ return -1;
+ }
+
+ /* Initialize */
+ gts_point_set(GTS_POINT(obj->gtsobj),x,y,z);
+
+ /* Chain up */
+ if( (ret=PygtsObjectType.tp_init((PyObject*)self,args,kwds)) != 0 ) {
+ return ret;
+ }
+
+ return 0;
+}
+
+
+static int
+compare(PygtsPoint *p1_, PygtsPoint *p2_)
+{
+ GtsPoint *p1, *p2;
+
+#if PYGTS_DEBUG
+ pygts_point_check((PyObject*)p1_);
+ pygts_point_check((PyObject*)p2_);
+#endif
+
+ p1 = PYGTS_POINT_AS_GTS_POINT(p1_);
+ p2 = PYGTS_POINT_AS_GTS_POINT(p2_);
+
+ return pygts_point_compare(p1,p2);
+}
+
+
+/* Methods table */
+PyTypeObject PygtsPointType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "gts.Point" , /* tp_name */
+ sizeof(PygtsPoint), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ (cmpfunc)compare, /* tp_compare */
+ 0, /* 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 */
+ "Point object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ methods, /* tp_methods */
+ 0, /* tp_members */
+ getset, /* tp_getset */
+ 0, /* tp_base: attached in pygts.c */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)init, /* tp_init */
+ 0, /* tp_alloc */
+ (newfunc)new /* tp_new */
+};
+
+
+/*-------------------------------------------------------------------------*/
+/* Pygts functions */
+
+gboolean
+pygts_point_check(PyObject* o)
+{
+ gboolean check = FALSE;
+ guint i,N;
+ PyObject *obj;
+
+ /* Check for a Point */
+ if( PyObject_TypeCheck(o, &PygtsPointType) ) {
+ check = TRUE;
+ }
+
+ /* Convert list into tuple */
+ if(PyList_Check(o)) {
+ o = PyList_AsTuple(o);
+ }
+ else {
+ Py_INCREF(o);
+ }
+
+ /* Check for a tuple of floats */
+ if( PyTuple_Check(o) ) {
+ if( (N = PyTuple_Size(o)) <= 3 ) {
+ check = TRUE;
+ for(i=0;i<N;i++) {
+ obj = PyTuple_GET_ITEM(o,i);
+ if(!PyFloat_Check(obj) && !PyInt_Check(obj)) {
+ check = FALSE;
+ }
+ }
+ }
+ }
+ Py_DECREF(o);
+
+ if( !check ) {
+ return FALSE;
+ }
+ else {
+#if PYGTS_DEBUG
+ if( PyObject_TypeCheck(o, &PygtsPointType) ) {
+ return pygts_point_is_ok(PYGTS_POINT(o));
+ }
+#endif
+ return TRUE;
+ }
+}
+
+
+gboolean
+pygts_point_is_ok(PygtsPoint *p)
+{
+ return pygts_object_is_ok(PYGTS_OBJECT(p));
+}
+
+
+PygtsPoint *
+pygts_point_new(GtsPoint *p)
+{
+ PyObject *args, *kwds;
+ PygtsObject *point;
+
+ /* Check for Point in the object table */
+ if( (point = PYGTS_OBJECT(g_hash_table_lookup(obj_table,GTS_OBJECT(p))))
+ !=NULL ) {
+ Py_INCREF(point);
+ return PYGTS_POINT(point);
+ }
+
+ /* Build a new Point */
+ args = Py_BuildValue("ddd",0,0,0);
+ kwds = Py_BuildValue("{s:O}","alloc_gtsobj",Py_False);
+ point = PYGTS_POINT(PygtsPointType.tp_new(&PygtsPointType, args, kwds));
+ Py_DECREF(args);
+ Py_DECREF(kwds);
+ if( point == NULL ) {
+ PyErr_SetString(PyExc_MemoryError,"could not create Point");
+ return NULL;
+ }
+ point->gtsobj = GTS_OBJECT(p);
+
+ /* Register and return */
+ pygts_object_register(point);
+ return PYGTS_POINT(point);
+}
+
+
+PygtsPoint *
+pygts_point_from_sequence(PyObject *tuple) {
+ guint i,N;
+ gdouble x=0,y=0,z=0;
+ PyObject *obj;
+ GtsPoint *p;
+ PygtsPoint *point;
+
+ /* Convert list into tuple */
+ if(PyList_Check(tuple)) {
+ tuple = PyList_AsTuple(tuple);
+ }
+ else {
+ Py_INCREF(tuple);
+ }
+ if(!PyTuple_Check(tuple)) {
+ Py_DECREF(tuple);
+ PyErr_SetString(PyExc_TypeError,"expected a list or tuple of vertices");
+ return NULL;
+ }
+
+ /* Get the tuple size */
+ if( (N = PyTuple_Size(tuple)) > 3 ) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "expected a list or tuple of up to three floats");
+ Py_DECREF(tuple);
+ return NULL;
+ }
+
+ /* Get the coordinates */
+ for(i=0;i<N;i++) {
+ obj = PyTuple_GET_ITEM(tuple,i);
+
+ if(!PyFloat_Check(obj) && !PyInt_Check(obj)) {
+ PyErr_SetString(PyExc_TypeError,"expected a list or tuple of floats");
+ Py_DECREF(tuple);
+ return NULL;
+ }
+ if(i==0) {
+ if(PyFloat_Check(obj)) x = PyFloat_AsDouble(obj);
+ else x = (double)PyInt_AsLong(obj);
+ }
+ if(i==1) {
+ if(PyFloat_Check(obj)) y = PyFloat_AsDouble(obj);
+ else y = (double)PyInt_AsLong(obj);
+ }
+ if(i==2) {
+ if(PyFloat_Check(obj)) z = PyFloat_AsDouble(obj);
+ else z = (double)PyInt_AsLong(obj);
+ }
+ }
+ Py_DECREF(tuple);
+
+ /* Create the vertex */
+ if( (p = gts_point_new(gts_point_class(),x,y,z)) == NULL ) {
+ PyErr_SetString(PyExc_MemoryError,"could not create Point");
+ }
+ if( (point = pygts_point_new(p)) == NULL ) {
+ gts_object_destroy(GTS_OBJECT(p));
+ return NULL;
+ }
+
+ return point;
+}
+
+
+int
+pygts_point_compare(GtsPoint* p1,GtsPoint* p2)
+{
+ double r1,r2;
+
+ if( (p1->x==p2->x) && (p1->y==p2->y) && (p1->z==p2->z) ) {
+ return 0;
+ }
+
+ /* Compare distances from origin */
+ r1 = sqrt(pow(p1->x,2) + pow(p1->y,2) + pow(p1->z,2));
+ r2 = sqrt(pow(p2->x,2) + pow(p2->y,2) + pow(p2->z,2));
+ if(r1<r2) return -1;
+ if(r1>r2) return 1;
+
+ /* Compare horizontal distances from origin */
+ r1 = sqrt(pow(p1->x,2) + pow(p1->y,2));
+ r2 = sqrt(pow(p2->x,2) + pow(p2->y,2));
+ if(r1<r2) return -1;
+ if(r1>r2) return 1;
+
+ /* Compare x */
+ r1 = p1->x;
+ r2 = p2->x;
+ if(r1<r2) return -1;
+ if(r1>r2) return 1;
+
+ /* Compare y */
+ r1 = p1->y;
+ r2 = p2->y;
+ if(r1<r2) return -1;
+ if(r1>r2) return 1;
+
+ /* Compare z */
+ r1 = p1->z;
+ r2 = p2->z;
+ if(r1<r2) return -1;
+ return 1;
+}
Added: trunk/lib/py/pygts-0.3.1/point.h
===================================================================
--- trunk/lib/py/pygts-0.3.1/point.h 2009-06-24 17:04:39 UTC (rev 1813)
+++ trunk/lib/py/pygts-0.3.1/point.h 2009-06-24 22:06:24 UTC (rev 1814)
@@ -0,0 +1,51 @@
+/* pygts - python package for the manipulation of triangulated surfaces
+ *
+ * Copyright (C) 2009 Thomas J. Duck
+ * All rights reserved.
+ *
+ * Thomas J. Duck <tom.duck@xxxxxx>
+ * Department of Physics and Atmospheric Science,
+ * Dalhousie University, Halifax, Nova Scotia, Canada, B3H 3J5
+ *
+ * NOTICE
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PYGTS_POINT_H__
+#define __PYGTS_POINT_H__
+
+typedef struct _PygtsObject PygtsPoint;
+
+#define PYGTS_POINT(o) ( PyObject_TypeCheck((PyObject*)o, &PygtsPointType) ? \
+ (PygtsPoint*)o : \
+ pygts_point_from_sequence((PyObject*)o) )
+
+#define PYGTS_POINT_AS_GTS_POINT(o) (GTS_POINT(PYGTS_OBJECT(o)->gtsobj))
+
+extern PyTypeObject PygtsPointType;
+
+gboolean pygts_point_check(PyObject* o);
+gboolean pygts_point_is_ok(PygtsPoint *o);
+
+PygtsPoint* pygts_point_from_sequence(PyObject *tuple);
+int pygts_point_compare(GtsPoint* p1,GtsPoint* p2);
+
+gint pygts_point_rotate(GtsPoint* p,gdouble dx,gdouble dy,gdouble dz,gdouble a);
+gint pygts_point_scale(GtsPoint* p, gdouble dx, gdouble dy, gdouble dz);
+gint pygts_point_translate(GtsPoint* p, gdouble dx, gdouble dy, gdouble dz);
+
+#endif /* __PYGTS_POINT_H__ */
Added: trunk/lib/py/pygts-0.3.1/pygts.c
===================================================================
--- trunk/lib/py/pygts-0.3.1/pygts.c 2009-06-24 17:04:39 UTC (rev 1813)
+++ trunk/lib/py/pygts-0.3.1/pygts.c 2009-06-24 22:06:24 UTC (rev 1814)
@@ -0,0 +1,794 @@
+/* pygts - python package for the manipulation of triangulated surfaces
+ *
+ * Copyright (C) 2009 Thomas J. Duck
+ * All rights reserved.
+ *
+ * Thomas J. Duck <tom.duck@xxxxxx>
+ * Department of Physics and Atmospheric Science,
+ * Dalhousie University, Halifax, Nova Scotia, Canada, B3H 3J5
+ *
+ * NOTICE
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "pygts.h"
+
+#if PYGTS_HAS_NUMPY
+ #include "numpy/arrayobject.h"
+#endif
+
+
+static PyObject*
+merge(PyObject *self, PyObject *args)
+{
+ PyObject *tuple, *obj;
+ guint i,N;
+ GList *vertices=NULL,*v;
+ gdouble epsilon;
+ PygtsVertex *vertex;
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "Od", &tuple, &epsilon) ) {
+ return NULL;
+ }
+ if(PyList_Check(tuple)) {
+ tuple = PyList_AsTuple(tuple);
+ }
+ else {
+ Py_INCREF(tuple);
+ }
+ if(!PyTuple_Check(tuple)) {
+ Py_DECREF(tuple);
+ PyErr_SetString(PyExc_TypeError,"expected a list or tuple of vertices");
+ return NULL;
+ }
+
+ /* Assemble the GList */
+ N = PyTuple_Size(tuple);
+ for(i=N-1;i>0;i--) {
+ obj = PyTuple_GET_ITEM(tuple,i);
+ if(!pygts_vertex_check(obj)) {
+ Py_DECREF(tuple);
+ g_list_free(vertices);
+ PyErr_SetString(PyExc_TypeError,"expected a list or tuple of vertices");
+ return NULL;
+ }
+ vertices = g_list_prepend(vertices,PYGTS_VERTEX_AS_GTS_VERTEX(obj));
+ }
+ Py_DECREF(tuple);
+
+ /* Make the call */
+ vertices = pygts_vertices_merge(vertices,epsilon,NULL);
+
+ /* Assemble the return tuple */
+ N = g_list_length(vertices);
+ if( (tuple=PyTuple_New(N)) == NULL) {
+ PyErr_SetString(PyExc_MemoryError,"could not create tuple");
+ return NULL;
+ }
+ v = vertices;
+ for(i=0;i<N;i++) {
+ if( (vertex = PYGTS_VERTEX(g_hash_table_lookup(obj_table,
+ GTS_OBJECT(v->data))
+ )) ==NULL ) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "could not get object from table (internal error)");
+ g_list_free(vertices);
+ return NULL;
+ }
+ Py_INCREF(vertex);
+ PyTuple_SET_ITEM(tuple,i,(PyObject*)vertex);
+ v = g_list_next(v);
+ }
+
+ g_list_free(vertices);
+
+ return tuple;
+}
+
+
+static PyObject*
+vertices(PyObject *self, PyObject *args)
+{
+ PyObject *tuple, *obj;
+ guint i,N;
+ GSList *segments=NULL,*vertices=NULL,*v;
+ PygtsVertex *vertex;
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &tuple) ) {
+ return NULL;
+ }
+ if(PyList_Check(tuple)) {
+ tuple = PyList_AsTuple(tuple);
+ }
+ else {
+ Py_INCREF(tuple);
+ }
+ if(!PyTuple_Check(tuple)) {
+ Py_DECREF(tuple);
+ PyErr_SetString(PyExc_TypeError,"expected a list or tuple of Segments");
+ return NULL;
+ }
+
+ /* Assemble the GSList */
+ N = PyTuple_Size(tuple);
+ for(i=0;i<N;i++) {
+ obj = PyTuple_GET_ITEM(tuple,N-1-i);
+ if(!pygts_segment_check(obj)) {
+ Py_DECREF(tuple);
+ g_slist_free(segments);
+ PyErr_SetString(PyExc_TypeError,"expected a list or tuple of Segments");
+ return NULL;
+ }
+ segments = g_slist_prepend(segments,PYGTS_SEGMENT_AS_GTS_SEGMENT(obj));
+ }
+ Py_DECREF(tuple);
+
+ /* Make the call */
+ vertices = gts_vertices_from_segments(segments);
+ g_slist_free(segments);
+
+ /* Assemble the return tuple */
+ N = g_slist_length(vertices);
+ if( (tuple=PyTuple_New(N)) == NULL) {
+ PyErr_SetString(PyExc_MemoryError,"could not create tuple");
+ return NULL;
+ }
+ v = vertices;
+ for(i=0;i<N;i++) {
+ if( (vertex = pygts_vertex_new(GTS_VERTEX(v->data))) == NULL ) {
+ Py_DECREF(tuple);
+ g_slist_free(vertices);
+ return NULL;
+ }
+ PyTuple_SET_ITEM(tuple,i,(PyObject*)vertex);
+ v = g_slist_next(v);
+ }
+
+ g_slist_free(vertices);
+
+ return tuple;
+}
+
+
+static PyObject*
+segments(PyObject *self, PyObject *args)
+{
+ PyObject *tuple, *obj;
+ guint i,n,N;
+ GSList *segments=NULL,*vertices=NULL,*s;
+ PygtsSegment *segment;
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &tuple) ) {
+ return NULL;
+ }
+ if(PyList_Check(tuple)) {
+ tuple = PyList_AsTuple(tuple);
+ }
+ else {
+ Py_INCREF(tuple);
+ }
+ if(!PyTuple_Check(tuple)) {
+ Py_DECREF(tuple);
+ PyErr_SetString(PyExc_TypeError,"expected a list or tuple of vertices");
+ return NULL;
+ }
+
+ /* Assemble the GSList */
+ N = PyTuple_Size(tuple);
+ for(i=0;i<N;i++) {
+ obj = PyTuple_GET_ITEM(tuple,i);
+ if(!pygts_vertex_check(obj)) {
+ Py_DECREF(tuple);
+ g_slist_free(vertices);
+ PyErr_SetString(PyExc_TypeError,"expected a list or tuple of vertices");
+ return NULL;
+ }
+ vertices = g_slist_prepend(vertices,PYGTS_VERTEX_AS_GTS_VERTEX(obj));
+ }
+ Py_DECREF(tuple);
+
+ /* Make the call */
+ if( (segments = gts_segments_from_vertices(vertices)) == NULL ) {
+ PyErr_SetString(PyExc_RuntimeError,"could not retrieve segments");
+ return NULL;
+ }
+ g_slist_free(vertices);
+
+ /* Assemble the return tuple */
+ N = g_slist_length(segments);
+ if( (tuple=PyTuple_New(N)) == NULL) {
+ PyErr_SetString(PyExc_MemoryError,"could not create tuple");
+ return NULL;
+ }
+
+ s = segments;
+ n=0;
+ while(s!=NULL) {
+
+ /* Skip any parent segments */
+ if(PYGTS_IS_PARENT_SEGMENT(s->data) || PYGTS_IS_PARENT_EDGE(s->data)) {
+ s = g_slist_next(s);
+ segment = NULL;
+ continue;
+ }
+
+ /* Fill in the tuple */
+ if(GTS_IS_EDGE(s->data)) {
+ segment = PYGTS_SEGMENT(pygts_edge_new(GTS_EDGE(s->data)));
+ }
+ else {
+ segment = pygts_segment_new(GTS_SEGMENT(s->data));
+ }
+ if( segment == NULL ) {
+ Py_DECREF(tuple);
+ g_slist_free(segments);
+ return NULL;
+ }
+ PyTuple_SET_ITEM(tuple,n,(PyObject*)segment);
+ s = g_slist_next(s);
+ n += 1;
+ }
+
+ g_slist_free(segments);
+
+ if(_PyTuple_Resize(&tuple,n)!=0) {
+ Py_DECREF(tuple);
+ return NULL;
+ }
+
+ return tuple;
+}
+
+
+static PyObject*
+triangles(PyObject *self, PyObject *args)
+{
+ PyObject *tuple, *obj;
+ guint i,n,N;
+ GSList *edges=NULL,*triangles=NULL,*t;
+ PygtsTriangle *triangle;
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &tuple) ) {
+ return NULL;
+ }
+ if(PyList_Check(tuple)) {
+ tuple = PyList_AsTuple(tuple);
+ }
+ else {
+ Py_INCREF(tuple);
+ }
+ if(!PyTuple_Check(tuple)) {
+ Py_DECREF(tuple);
+ PyErr_SetString(PyExc_TypeError,"expected a list or tuple of edges");
+ return NULL;
+ }
+
+ /* Assemble the GSList */
+ N = PyTuple_Size(tuple);
+ for(i=0;i<N;i++) {
+ obj = PyTuple_GET_ITEM(tuple,i);
+ if(!pygts_edge_check(obj)) {
+ Py_DECREF(tuple);
+ g_slist_free(edges);
+ PyErr_SetString(PyExc_TypeError,"expected a list or tuple of edges");
+ return NULL;
+ }
+ edges = g_slist_prepend(edges,PYGTS_EDGE_AS_GTS_EDGE(obj));
+ }
+ Py_DECREF(tuple);
+
+ /* Make the call */
+ if( (triangles = gts_triangles_from_edges(edges)) == NULL ) {
+ PyErr_SetString(PyExc_RuntimeError,"could not retrieve triangles");
+ return NULL;
+ }
+ g_slist_free(edges);
+
+ /* Assemble the return tuple */
+ N = g_slist_length(triangles);
+ if( (tuple=PyTuple_New(N)) == NULL) {
+ PyErr_SetString(PyExc_MemoryError,"could not create tuple");
+ return NULL;
+ }
+
+ t = triangles;
+ n=0;
+ while(t!=NULL) {
+
+ /* Skip any parent triangles */
+ if(PYGTS_IS_PARENT_TRIANGLE(t->data)) {
+ t = g_slist_next(t);
+ triangle = NULL;
+ continue;
+ }
+
+ /* Fill in the tuple */
+ if(GTS_IS_FACE(t->data)) {
+ triangle = PYGTS_TRIANGLE(pygts_face_new(GTS_FACE(t->data)));
+ }
+ else {
+ triangle = pygts_triangle_new(GTS_TRIANGLE(t->data));
+ }
+ if( triangle == NULL ) {
+ Py_DECREF(tuple);
+ g_slist_free(triangles);
+ return NULL;
+ }
+ PyTuple_SET_ITEM(tuple,n,(PyObject*)triangle);
+ t = g_slist_next(t);
+ n += 1;
+ }
+
+ g_slist_free(triangles);
+
+ if(_PyTuple_Resize(&tuple,n)!=0) {
+ Py_DECREF(tuple);
+ return NULL;
+ }
+
+ return tuple;
+}
+
+
+static PyObject*
+triangle_enclosing(PyObject *self, PyObject *args)
+{
+ PyObject *tuple, *obj;
+ guint i,N;
+ GSList *points=NULL;
+ GtsTriangle *t;
+ PygtsTriangle *triangle;
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &tuple) ) {
+ return NULL;
+ }
+ if(PyList_Check(tuple)) {
+ tuple = PyList_AsTuple(tuple);
+ }
+ else {
+ Py_INCREF(tuple);
+ }
+ if(!PyTuple_Check(tuple)) {
+ Py_DECREF(tuple);
+ PyErr_SetString(PyExc_TypeError,"expected a list or tuple of points");
+ return NULL;
+ }
+
+ /* Assemble the GSList */
+ N = PyTuple_Size(tuple);
+ for(i=0;i<N;i++) {
+ obj = PyTuple_GET_ITEM(tuple,i);
+ if(!pygts_point_check(obj)) {
+ Py_DECREF(tuple);
+ g_slist_free(points);
+ PyErr_SetString(PyExc_TypeError,"expected a list or tuple of points");
+ return NULL;
+ }
+ points = g_slist_prepend(points,PYGTS_POINT_AS_GTS_POINT(obj));
+ }
+ Py_DECREF(tuple);
+
+ /* Make the call */
+ t = gts_triangle_enclosing(gts_triangle_class(),points,1.0);
+ g_slist_free(points);
+
+ if(t==NULL) {
+ PyErr_SetString(PyExc_RuntimeError,"could not compute triangle");
+ return NULL;
+ }
+
+ if( (triangle = pygts_triangle_new(t)) == NULL ) {
+ return NULL;
+ }
+
+ return (PyObject*)triangle;
+}
+
+
+static PyObject*
+pygts_read(PygtsSurface *self, PyObject *args)
+{
+ PyObject *f_;
+ FILE *f;
+ GtsFile *fp;
+ guint lineno;
+ GtsSurface *s;
+ PygtsSurface *surface;
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &f_) )
+ return NULL;
+
+ /* Convert to PygtsObjects */
+ if(!PyFile_Check(f_)) {
+ PyErr_SetString(PyExc_TypeError,"expected a File");
+ return NULL;
+ }
+ f = PyFile_AsFile(f_);
+
+ if(feof(f)) {
+ PyErr_SetString(PyExc_EOFError,"End of File");
+ return NULL;
+ }
+
+ /* Create a temporary surface to read into */
+ if( (s = gts_surface_new(gts_surface_class(), gts_face_class(),
+ gts_edge_class(), gts_vertex_class())) == NULL ) {
+ PyErr_SetString(PyExc_MemoryError,"could not create Surface");
+ return NULL;
+ }
+
+ /* Read from the file */
+ fp = gts_file_new(f);
+ if( (lineno = gts_surface_read(s,fp)) != 0 ) {
+ PyErr_SetString(PyExc_RuntimeError,fp->error);
+ gts_file_destroy(fp);
+ return NULL;
+ }
+ gts_file_destroy(fp);
+ if( (surface = pygts_surface_new(s)) == NULL ) {
+ gts_object_destroy(GTS_OBJECT(s));
+ return NULL;
+ }
+
+ /* Clean up the surface */
+ pygts_edge_cleanup(PYGTS_SURFACE_AS_GTS_SURFACE(surface));
+ pygts_face_cleanup(PYGTS_SURFACE_AS_GTS_SURFACE(surface));
+
+ return (PyObject*)surface;
+}
+
+
+static PyObject*
+sphere(PyObject *self, PyObject *args)
+{
+ PyObject *kwds;
+ PygtsSurface *surface;
+ guint geodesation_order;
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "i", &geodesation_order) )
+ return NULL;
+
+ /* Chain up object allocation */
+ args = Py_BuildValue("()");
+ kwds = Py_BuildValue("{s:O}","alloc_gtsobj",Py_True);
+ surface = PYGTS_SURFACE(PygtsSurfaceType.tp_new(&PygtsSurfaceType,
+ args, kwds));
+ Py_DECREF(args);
+ Py_DECREF(kwds);
+ if( surface == NULL ) {
+ PyErr_SetString(PyExc_MemoryError, "could not create Surface");
+ return NULL;
+ }
+
+ gts_surface_generate_sphere(PYGTS_SURFACE_AS_GTS_SURFACE(surface),
+ geodesation_order);
+
+ pygts_object_register(PYGTS_OBJECT(surface));
+ return (PyObject*)surface;
+}
+
+
+#if PYGTS_HAS_NUMPY
+
+/* Helper for pygts_iso to fill f with a layer of data from scalar */
+static void isofunc(gdouble **f, GtsCartesianGrid g, guint k, gpointer data)
+{
+ PyArrayObject *scalars = (PyArrayObject *)data;
+ int i, j;
+
+ for (i = 0; i < scalars->dimensions[0]; i++) {
+ for (j = 0; j < scalars->dimensions[1]; j++) {
+ f[i][j] = *(gdouble *)(scalars->data + i*scalars->strides[0] + \
+ j*scalars->strides[1] + k*scalars->strides[2]);
+ }
+ }
+}
+
+#define ISO_CLEANUP \
+ if (scalars) { Py_DECREF(scalars); } \
+ if (extents) { Py_DECREF(extents); }
+
+static PyObject*
+isosurface(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ double isoval[1];
+ PyObject *Oscalars = NULL, *Oextents = NULL;
+ PyArrayObject *scalars = NULL, *extents = NULL;
+ GtsCartesianGrid g;
+ GtsSurface *s;
+ PygtsSurface *surface;
+ char *method = "cubes";
+
+ static char *kwlist[] = {"scalars", "isoval", "method", "extents", NULL};
+
+ if(!PyArg_ParseTupleAndKeywords(args, kwds, "Od|sO", kwlist,
+ &Oscalars, isoval, &method, &Oextents)) {
+ return NULL;
+ }
+
+ if(!(scalars = (PyArrayObject *)
+ PyArray_ContiguousFromObject(Oscalars, PyArray_DOUBLE, 3, 3))) {
+ ISO_CLEANUP;
+ return NULL;
+ }
+
+ if(Oextents &&
+ (!(extents = (PyArrayObject *)
+ PyArray_ContiguousFromObject(Oextents, PyArray_DOUBLE, 1, 1)))) {
+ ISO_CLEANUP;
+ return NULL;
+ }
+
+ if(extents && extents->dimensions[0] < 6) {
+ PyErr_SetString(PyExc_ValueError, "extents must have at least 6 elements");
+ ISO_CLEANUP;
+ return NULL;
+ }
+
+ if(extents) {
+ int s = extents->strides[0];
+ g.x = *(gdouble*)(extents->data + 0*s);
+ g.nx = scalars->dimensions[0];
+ g.dx = (*(gdouble*)(extents->data + 1*s) - \
+ *(gdouble*)(extents->data + 0* s))/(g.nx-1);
+
+ g.y = *(gdouble*)(extents->data + 2*s);
+ g.ny = scalars->dimensions[1];
+ g.dy = (*(gdouble*)(extents->data + 3*s) - \
+ *(gdouble*)(extents->data + 2*s))/(g.ny-1);
+
+ g.z = *(gdouble*)(extents->data + 4*s);
+ g.nz = scalars->dimensions[2];
+ g.dz = (*(gdouble*)(extents->data + 5*s) - \
+ *(gdouble*)(extents->data + 4*s))/(g.nz-1);
+ }
+ else {
+ g.x = -1.0;
+ g.nx = scalars->dimensions[0];
+ g.dx = 2.0/(scalars->dimensions[0]-1);
+ g.y = -1.0;
+ g.ny = scalars->dimensions[1];
+ g.dy = 2.0/(scalars->dimensions[1]-1);
+ g.z = -1.0;
+ g.nz = scalars->dimensions[2];
+ g.dz = 2.0/(scalars->dimensions[2]-1);
+ }
+
+ /* Create the surface */
+ if((s = gts_surface_new(gts_surface_class(), gts_face_class(),
+ gts_edge_class(), gts_vertex_class())) == NULL ) {
+ PyErr_SetString(PyExc_MemoryError,"could not create Surface");
+ return NULL;
+ }
+
+ /* Make the call */
+ switch(method[0]) {
+ case 'c': /* cubes */
+ gts_isosurface_cartesian(s, g, isofunc, scalars, isoval[0]);
+ break;
+ case 't': /* tetra */
+ gts_isosurface_tetra(s, g, isofunc, scalars, isoval[0]);
+ /* *** ATTENTION ***
+ * Isosurface produced is "inside-out", and so we must revert it.
+ * This is a bug in GTS.
+ */
+ gts_surface_foreach_face(s, (GtsFunc)gts_triangle_revert, NULL);
+ /* *** ATTENTION *** */
+ break;
+ case 'b': /* tetra bounded */
+ gts_isosurface_tetra_bounded(s, g, isofunc, scalars, isoval[0]);
+ /* *** ATTENTION ***
+ * Isosurface produced is "inside-out", and so we must revert it.
+ * This is a bug in GTS.
+ */
+ gts_surface_foreach_face(s, (GtsFunc)gts_triangle_revert, NULL);
+ /* *** ATTENTION *** */
+ break;
+ case 'd': /* tetra bcl*/
+ gts_isosurface_tetra_bcl(s, g, isofunc, scalars, isoval[0]);
+ /* *** ATTENTION ***
+ * Isosurface produced is "inside-out", and so we must revert it.
+ * This is a bug in GTS.
+ */
+ gts_surface_foreach_face(s, (GtsFunc)gts_triangle_revert, NULL);
+ /* *** ATTENTION *** */
+ break;
+ default:
+ PyErr_SetString(PyExc_ValueError, "unknown method");
+ ISO_CLEANUP;
+ return NULL;
+ }
+
+ ISO_CLEANUP;
+
+ if( (surface = pygts_surface_new(s)) == NULL ) {
+ gts_object_destroy(GTS_OBJECT(s));
+ return NULL;
+ }
+
+ return (PyObject*)surface;
+}
+
+#endif /* PYGTS_HAS_NUMPY */
+
+
+static PyMethodDef gts_methods[] = {
+
+ {"read", (PyCFunction)pygts_read,
+ METH_VARARGS,
+ "Returns the data read from File f as a Surface.\n"
+ "The File data must be in GTS format (e.g., as written using\n"
+ "Surface.write())\n"
+ "\n"
+ "Signature: read(f)\n"
+ },
+
+ { "sphere", sphere, METH_VARARGS,
+ "Returns a unit sphere generated by recursive subdivision.\n"
+ "First approximation is an isocahedron; each level of refinement\n"
+ "(geodesation_order) increases the number of triangles by a factor\n"
+ "of 4.\n"
+ "\n"
+ "Signature: sphere(geodesation_order)\n"
+ },
+
+#if PYGTS_HAS_NUMPY
+ {"isosurface", (PyCFunction)isosurface,
+ METH_VARARGS|METH_KEYWORDS,
+ "Adds to surface new faces defining the isosurface data[x,y,z] = c\n"
+ "\n"
+ "Signature: isosurface(data, c, ...)\n"
+ "\n"
+ "data is a 3D numpy array.\n"
+ "c is the isovalue defining the surface\n"
+ "\n"
+ "Keyword arguments:\n"
+ "extents= [xmin, xmax, ymin, ymax, zmin, zmax]\n"
+ " A numpy array defining the extent of the data cube.\n"
+ " Default is the cube with corners at (-1,-1,-1) and (1,1,1)\n"
+ " Data is assumed to be regularly sampled in the cube.\n"
+ "method= ['cube'|'tetra'|'dual'|'bounded']\n"
+ " String (only the first character counts) specifying the\n"
+ " method.\n"
+ " cube -- marching cubes (default)\n"
+ " tetra -- marching tetrahedra\n"
+ " dual -- maching tetrahedra producing dual 'body-centred'\n"
+ " faces relative to 'tetra'\n"
+ " bounded -- marching tetrahedra ensuring the surface is\n"
+ " bounded by adding a border of large negative\n"
+ " values around the domain.\n"
+ "\n"
+ "By convention, the normals to the surface are pointing towards\n"
+ "positive values of data[x,y,z] - c.\n"
+ },
+#endif /* PYGTS_HAS_NUMPY */
+
+ { "merge", merge, METH_VARARGS,
+ "Merges list of Vertices that are within a box of side-length\n"
+ "epsilon of each other.\n"
+ "\n"
+ "Signature: merge(list,epsilon)\n"
+ },
+
+ { "vertices", vertices, METH_VARARGS,
+ "Returns tuple of Vertices from a list or tuple of Segments.\n"
+ "\n"
+ "Signature: vertices(list)\n"
+ },
+
+ { "segments", segments, METH_VARARGS,
+ "Returns tuple of Segments from a list or tuple of Vertices.\n"
+ "\n"
+ "Signature: segments(list)\n"
+ },
+
+ { "triangles", triangles, METH_VARARGS,
+ "Returns tuple of Triangles from a list or tuple of Edges.\n"
+ "\n"
+ "Signature: triangles(list)\n"
+ },
+
+ { "triangle_enclosing", triangle_enclosing, METH_VARARGS,
+ "Returns a Triangle that encloses the plane projection of a list\n"
+ "or tuple of Points. The Triangle is equilateral and encloses a\n"
+ "rectangle defined by the maximum and minimum x and y coordinates\n"
+ "of the points.\n"
+ "\n"
+ "Signature: triangles(list)\n"
+ },
+
+
+ {NULL} /* Sentinel */
+};
+
+#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */
+#define PyMODINIT_FUNC void
+#endif
+PyMODINIT_FUNC
+init_gts(void)
+{
+ PyObject* m;
+
+ /* Allocate the object table */
+ if( (obj_table=g_hash_table_new(NULL,NULL)) == NULL ) return;
+
+ /* Set class base types and make ready (i.e., inherit methods) */
+ if (PyType_Ready(&PygtsObjectType) < 0) return;
+
+ PygtsPointType.tp_base = &PygtsObjectType;
+ if (PyType_Ready(&PygtsPointType) < 0) return;
+
+ PygtsVertexType.tp_base = &PygtsPointType;
+ if (PyType_Ready(&PygtsVertexType) < 0) return;
+
+ PygtsSegmentType.tp_base = &PygtsObjectType;
+ if (PyType_Ready(&PygtsSegmentType) < 0) return;
+
+ PygtsEdgeType.tp_base = &PygtsSegmentType;
+ if (PyType_Ready(&PygtsEdgeType) < 0) return;
+
+ PygtsTriangleType.tp_base = &PygtsObjectType;
+ if (PyType_Ready(&PygtsTriangleType) < 0) return;
+
+ PygtsFaceType.tp_base = &PygtsTriangleType;
+ if (PyType_Ready(&PygtsFaceType) < 0) return;
+
+ PygtsSurfaceType.tp_base = &PygtsObjectType;
+ if (PyType_Ready(&PygtsSurfaceType) < 0) return;
+
+
+ /* Initialize the module */
+ m = Py_InitModule3("_gts", gts_methods,"Gnu Triangulated Surface Library");
+ if (m == NULL) return;
+
+#if PYGTS_HAS_NUMPY
+ /* Make sure Surface.iso can work with numpy arrays */
+ import_array()
+#endif
+
+ /* Add new types to python */
+ Py_INCREF(&PygtsObjectType);
+ PyModule_AddObject(m, "Object", (PyObject *)&PygtsObjectType);
+
+ Py_INCREF(&PygtsPointType);
+ PyModule_AddObject(m, "Point", (PyObject *)&PygtsPointType);
+
+ Py_INCREF(&PygtsVertexType);
+ PyModule_AddObject(m, "Vertex", (PyObject *)&PygtsVertexType);
+
+ Py_INCREF(&PygtsSegmentType);
+ PyModule_AddObject(m, "Segment", (PyObject *)&PygtsSegmentType);
+
+ Py_INCREF(&PygtsEdgeType);
+ PyModule_AddObject(m, "Edge", (PyObject *)&PygtsEdgeType);
+
+ Py_INCREF(&PygtsTriangleType);
+ PyModule_AddObject(m, "Triangle", (PyObject *)&PygtsTriangleType);
+
+ Py_INCREF(&PygtsFaceType);
+ PyModule_AddObject(m, "Face", (PyObject *)&PygtsFaceType);
+
+ Py_INCREF(&PygtsSurfaceType);
+ PyModule_AddObject(m, "Surface", (PyObject *)&PygtsSurfaceType);
+}
Added: trunk/lib/py/pygts-0.3.1/pygts.h
===================================================================
--- trunk/lib/py/pygts-0.3.1/pygts.h 2009-06-24 17:04:39 UTC (rev 1813)
+++ trunk/lib/py/pygts-0.3.1/pygts.h 2009-06-24 22:06:24 UTC (rev 1814)
@@ -0,0 +1,59 @@
+/* pygts - python package for the manipulation of triangulated surfaces
+ *
+ * Copyright (C) 2009 Thomas J. Duck
+ * All rights reserved.
+ *
+ * Thomas J. Duck <tom.duck@xxxxxx>
+ * Department of Physics and Atmospheric Science,
+ * Dalhousie University, Halifax, Nova Scotia, Canada, B3H 3J5
+ *
+ * NOTICE
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PYGTS_H__
+#define __PYGTS_H__
+
+#ifndef PYGTS_DEBUG
+#define PYGTS_DEBUG 1
+#endif /* PYGTS_DEBUG */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include <Python.h>
+#include <structmember.h>
+
+/* Defined for arrayobject.h which is only included where needed */
+#define PY_ARRAY_UNIQUE_SYMBOL PYGTS
+
+#include <glib.h>
+#include <gts.h>
+
+#include "object.h"
+#include "point.h"
+#include "vertex.h"
+#include "segment.h"
+#include "edge.h"
+#include "triangle.h"
+#include "face.h"
+#include "surface.h"
+
+#include "cleanup.h"
+
+#endif /* __PYGTS_H__ */
Added: trunk/lib/py/pygts-0.3.1/pygts.py
===================================================================
--- trunk/lib/py/pygts-0.3.1/pygts.py 2009-06-24 17:04:39 UTC (rev 1813)
+++ trunk/lib/py/pygts-0.3.1/pygts.py 2009-06-24 22:06:24 UTC (rev 1814)
@@ -0,0 +1,144 @@
+# pygts - python package for the manipulation of triangulated surfaces
+#
+# Copyright (C) 2009 Thomas J. Duck
+# All rights reserved.
+#
+# Thomas J. Duck <tom.duck@xxxxxx>
+# Department of Physics and Atmospheric Science,
+# Dalhousie University, Halifax, Nova Scotia, Canada, B3H 3J5
+#
+# NOTICE
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+
+from _gts import *
+
+def get_coords_and_face_indices(s,unzip=False):
+ """Returns the coordinates and face indices of Surface s.
+
+ If unzip is True then four tuples are returned. The first three
+ are the x, y, and z coordinates for each Vertex on the Surface.
+ The last is a list of tuples, one for each Face on the Surface,
+ containing 3 indices linking the Face Vertices to the coordinate
+ lists.
+
+ If unzip is False then the coordinates are given in a single list
+ of 3-tuples.
+ """
+ vertices = s.vertices()
+ coords = [v.coords() for v in vertices]
+ face_indices = s.face_indices(vertices)
+
+ if unzip:
+ x,y,z = zip(*coords)
+ return x,y,z,face_indices
+ else:
+ return vertices, coords
+
+
+def cube():
+ """Returns a cube of side length 2 centered at the origin."""
+
+ #
+ # v8 +------+ v5
+ # / /|
+ # / v1/ |
+ # v4 +------+ |
+ # | | + v6
+ # |(v7) | /
+ # | |/
+ # v3 +------+ v2
+ #
+
+ v1,v2,v3,v4=Vertex(1,1,1),Vertex(1,1,-1),Vertex(1,-1,-1),Vertex(1,-1,1)
+ v5,v6,v7,v8=Vertex(-1,1,1),Vertex(-1,1,-1),Vertex(-1,-1,-1),Vertex(-1,-1,1)
+
+ e12,e23,e34,e14 = Edge(v1,v2), Edge(v2,v3), Edge(v3,v4), Edge(v4,v1)
+ e56,e67,e78,e58 = Edge(v5,v6), Edge(v6,v7), Edge(v7,v8), Edge(v8,v5)
+ e15,e26,e37,e48 = Edge(v1,v5), Edge(v2,v6), Edge(v3,v7), Edge(v4,v8)
+ e13,e16,e18 = Edge(v1,v3), Edge(v1,v6), Edge(v1,v8)
+ e27,e47,e57 = Edge(v7,v2), Edge(v7,v4), Edge(v7,v5)
+
+ faces = [ Face(e12,e23,e13), Face(e13,e34,e14),
+ Face(e12,e26,e16), Face(e15,e56,e16),
+ Face(e15,e58,e18), Face(e14,e48,e18),
+ Face(e58,e78,e57), Face(e56,e67,e57),
+ Face(e26,e67,e27), Face(e37,e23,e27),
+ Face(e37,e47,e34), Face(e78,e48,e47) ]
+
+ faces[0].revert() # Set the orientation of the first face
+
+ s = Surface()
+
+ for face in faces:
+ if not face.is_compatible(s):
+ face.revert()
+ s.add(face)
+
+ return s
+
+
+def tetrahedron():
+ """Returns a tetrahedron of side length 2*sqrt(2) centered at origin.
+
+ The edges of the tetrahedron are perpendicular to the cardinal
+ directions.
+ """
+
+ # v4
+ # +
+ # | \ e6
+ # e5 '|e4 \
+ # v1 . +-e3-+ v3
+ # / .
+ # ./e1. e2
+ # / .
+ # +
+ # v2
+
+
+ # Create vertices
+ v1 = Vertex(1,1,1)
+ v2 = Vertex(-1,-1,1)
+ v3 = Vertex(-1,1,-1)
+ v4 = Vertex(1,-1,-1)
+
+ # Create edges
+ e1 = Edge(v1,v2)
+ e2 = Edge(v2,v3)
+ e3 = Edge(v3,v1)
+ e4 = Edge(v1,v4)
+ e5 = Edge(v4,v2)
+ e6 = Edge(v4,v3)
+
+ # Create faces
+ f1 = Face(e1,e2,e3) # Bottom face
+ f2 = Face(e1,e4,e5) # Left face
+ f3 = Face(e2,e5,e6) # Right face
+ f4 = Face(e3,e4,e6) # Back face
+
+ # Set orientation of first face
+ f1.revert()
+
+ # Assemble surface
+ s = Surface()
+ for face in [f1,f2,f3,f4]:
+ if not face.is_compatible(s):
+ face.revert()
+ s.add(face)
+
+ return s
Added: trunk/lib/py/pygts-0.3.1/segment.c
===================================================================
--- trunk/lib/py/pygts-0.3.1/segment.c 2009-06-24 17:04:39 UTC (rev 1813)
+++ trunk/lib/py/pygts-0.3.1/segment.c 2009-06-24 22:06:24 UTC (rev 1814)
@@ -0,0 +1,570 @@
+/* pygts - python segment for the manipulation of triangulated surfaces
+ *
+ * Copyright (C) 2009 Thomas J. Duck
+ * All rights reserved.
+ *
+ * Thomas J. Duck <tom.duck@xxxxxx>
+ * Department of Physics and Atmospheric Science,
+ * Dalhousie University, Halifax, Nova Scotia, Canada, B3H 3J5
+ *
+ * NOTICE
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "pygts.h"
+
+
+#if PYGTS_DEBUG
+ #define SELF_CHECK if(!pygts_segment_check((PyObject*)self)) { \
+ PyErr_SetString(PyExc_RuntimeError, \
+ "problem with self object (internal error)"); \
+ return NULL; \
+ }
+#else
+ #define SELF_CHECK
+#endif
+
+
+/*-------------------------------------------------------------------------*/
+/* Methods exported to python */
+
+static PyObject*
+is_ok(PygtsSegment *self, PyObject *args)
+{
+ if(pygts_segment_is_ok(self)) {
+ Py_INCREF(Py_True);
+ return Py_True;
+ }
+ else {
+ Py_INCREF(Py_False);
+ return Py_False;
+ }
+}
+
+
+static PyObject*
+intersects(PygtsSegment *self, PyObject *args)
+{
+ PyObject *s_;
+ GtsSegment *s;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &s_) ) {
+ return NULL;
+ }
+
+ /* Convert to PygtsObjects */
+ if(!pygts_segment_check(s_)) {
+ PyErr_SetString(PyExc_TypeError,"expected a Segment");
+ return NULL;
+ }
+ s = PYGTS_SEGMENT_AS_GTS_SEGMENT(s_);
+
+ return Py_BuildValue("i",
+ gts_segments_are_intersecting(PYGTS_SEGMENT_AS_GTS_SEGMENT(self),s));
+}
+
+
+static PyObject*
+connects(PygtsSegment *self, PyObject *args)
+{
+ PyObject *v1_,*v2_;
+ GtsVertex *v1,*v2;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "OO", &v1_, &v2_) ) {
+ return NULL;
+ }
+
+ /* Convert to PygtsObjects */
+ if(!pygts_vertex_check(v1_)) {
+ PyErr_SetString(PyExc_TypeError,"expected a Vertex");
+ return NULL;
+ }
+ v1 = PYGTS_VERTEX_AS_GTS_VERTEX(v1_);
+
+ if(!pygts_vertex_check(v2_)) {
+ PyErr_SetString(PyExc_TypeError,"expected a Vertex");
+ return NULL;
+ }
+ v2 = PYGTS_VERTEX_AS_GTS_VERTEX(v2_);
+
+ if(gts_segment_connect(PYGTS_SEGMENT_AS_GTS_SEGMENT(self),v1,v2)) {
+ Py_INCREF(Py_True);
+ return Py_True;
+ }
+ else {
+ Py_INCREF(Py_False);
+ return Py_False;
+ }
+}
+
+
+static PyObject*
+touches(PygtsSegment *self, PyObject *args)
+{
+ PyObject *s_;
+ GtsSegment *s;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &s_) ) {
+ return NULL;
+ }
+
+ /* Convert to PygtsObjects */
+ if(!pygts_segment_check(s_)) {
+ PyErr_SetString(PyExc_TypeError,"expected a Segment");
+ return NULL;
+ }
+ s = PYGTS_SEGMENT_AS_GTS_SEGMENT(s_);
+
+ if(gts_segments_touch(PYGTS_SEGMENT_AS_GTS_SEGMENT(self),s)) {
+ Py_INCREF(Py_True);
+ return Py_True;
+ }
+ else {
+ Py_INCREF(Py_False);
+ return Py_False;
+ }
+}
+
+
+static PyObject*
+midvertex(PygtsSegment *self, PyObject *args)
+{
+ PygtsVertex *vertex;
+ GtsVertex *v;
+
+ SELF_CHECK
+
+ v = gts_segment_midvertex(PYGTS_SEGMENT_AS_GTS_SEGMENT(self),
+ gts_vertex_class());
+
+ if( (vertex = pygts_vertex_new(v)) == NULL ) {
+ return NULL;
+ }
+
+ return (PyObject*)vertex;
+}
+
+
+static PyObject*
+intersection(PygtsSegment *self, PyObject *args)
+{
+ PyObject *t_,*boundary_=NULL;
+ PygtsTriangle *t;
+ gboolean boundary=TRUE;
+ GtsVertex *v;
+ PygtsObject *vertex;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O|O", &t_, &boundary_) ) {
+ return NULL;
+ }
+
+ /* Convert to PygtsObjects */
+ if(!pygts_triangle_check(t_)) {
+ PyErr_SetString(PyExc_TypeError,"expected a Triangle and boolean");
+ return NULL;
+ }
+ t = PYGTS_TRIANGLE(t_);
+
+ if( boundary_ != NULL ) {
+ if(PyBool_Check(boundary_)==FALSE) {
+ PyErr_SetString(PyExc_TypeError,"expected a Triangle and boolean");
+ return NULL;
+ }
+ if( boundary_ == Py_False ){ /* Default TRUE */
+ boundary = FALSE;
+ }
+ }
+
+ v = GTS_VERTEX( gts_segment_triangle_intersection(
+ PYGTS_SEGMENT_AS_GTS_SEGMENT(self),
+ PYGTS_TRIANGLE_AS_GTS_TRIANGLE(t),
+ boundary,
+ GTS_POINT_CLASS(gts_vertex_class())) );
+
+ if( v == NULL ) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ if( (vertex = pygts_vertex_new(v)) == NULL ) {
+ return NULL;
+ }
+
+ return (PyObject *)vertex;
+}
+
+
+/* Methods table */
+static PyMethodDef methods[] = {
+ {"is_ok", (PyCFunction)is_ok,
+ METH_NOARGS,
+ "True if this Segment s is not degenerate or duplicate.\n"
+ "False otherwise. Degeneracy implies s.v1.id == s.v2.id.\n"
+ "\n"
+ "Signature: s.is_ok().\n"
+ },
+
+ {"intersects", (PyCFunction)intersects,
+ METH_VARARGS,
+ "Checks if this Segment s1 intersects with Segment s2.\n"
+ "Returns 1 if they intersect, 0 if an endpoint of one Segment lies\n"
+ "on the other Segment, -1 otherwise\n"
+ "\n"
+ "Signature: s1.intersects(s2).\n"
+ },
+
+ {"connects", (PyCFunction)connects,
+ METH_VARARGS,
+ "Returns True if this Segment s1 connects Vertices v1 and v2.\n"
+ "False otherwise.\n"
+ "\n"
+ "Signature: s1.connects(v1,v2).\n"
+ },
+
+ {"touches", (PyCFunction)touches,
+ METH_VARARGS,
+ "Returns True if this Segment s1 touches Segment s2\n"
+ "(i.e., they share a common Vertex). False otherwise.\n"
+ "\n"
+ "Signature: s1.touches(s2).\n"
+ },
+
+ {"midvertex", (PyCFunction)midvertex,
+ METH_NOARGS,
+ "Returns a new Vertex at the mid-point of this Segment s.\n"
+ "\n"
+ "Signature: s.midvertex().\n"
+ },
+
+ {"intersection", (PyCFunction)intersection,
+ METH_VARARGS,
+ "Returns the intersection of Segment s with Triangle t\n"
+ "\n"
+ "This function is geometrically robust in the sense that it will\n"
+ "return None if s and t do not intersect and will return a\n"
+ "Vertex if they do. However, the point coordinates are subject\n"
+ "to round-off errors. None will be returned if s is contained\n"
+ "in the plane defined by t.\n"
+ "\n"
+ "Signature: s.intersection(t) or s.intersection(t,boundary).\n"
+ "\n"
+ "If boundary is True (default), the boundary of s is taken into\n"
+ "account.\n"
+ "\n"
+ "Returns a summit of t (if boundary is True), one of the endpoints\n"
+ "of s, a new Vertex at the intersection of s with t, or None if\n"
+ "s and t don't intersect.\n"
+ },
+
+ {NULL} /* Sentinel */
+};
+
+
+/*-------------------------------------------------------------------------*/
+/* Attributes exported to python */
+
+static PyObject *
+get_v1(PygtsSegment *self, void *closure)
+{
+ PygtsObject *v1;
+
+ SELF_CHECK
+
+ if( (v1=pygts_vertex_new(PYGTS_SEGMENT_AS_GTS_SEGMENT(self)->v1)) == NULL ) {
+ return NULL;
+ }
+
+ return (PyObject *)v1;
+}
+
+
+static PyObject *
+get_v2(PygtsSegment *self, void *closure)
+{
+ PygtsObject *v2;
+
+ SELF_CHECK
+
+ if( (v2=pygts_vertex_new(PYGTS_SEGMENT_AS_GTS_SEGMENT(self)->v2)) == NULL ) {
+ return NULL;
+ }
+
+ return (PyObject *)v2;
+}
+
+
+/* Methods table */
+static PyGetSetDef getset[] = {
+ {"v1", (getter)get_v1, NULL, "Vertex 1", NULL},
+ {"v2", (getter)get_v2, NULL, "Vertex 2", NULL},
+ {NULL} /* Sentinel */
+};
+
+
+/*-------------------------------------------------------------------------*/
+/* Python type methods */
+
+static PyObject *
+new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ PyObject *o;
+ PygtsObject *obj;
+ GtsSegment *tmp;
+ GtsObject *segment=NULL;
+ PyObject *v1_=NULL,*v2_=NULL;
+ PygtsVertex *v1,*v2;
+ guint alloc_gtsobj = TRUE;
+ guint N;
+
+ /* Parse the args */
+ if(kwds) {
+ o = PyDict_GetItemString(kwds,"alloc_gtsobj");
+ if(o==Py_False) {
+ alloc_gtsobj = FALSE;
+ }
+ if(o!=NULL) {
+ PyDict_DelItemString(kwds, "alloc_gtsobj");
+ }
+ }
+ if(kwds) {
+ Py_INCREF(Py_False);
+ PyDict_SetItemString(kwds,"alloc_gtsobj", Py_False);
+ }
+
+ /* Allocate the gtsobj (if needed) */
+ if( alloc_gtsobj ) {
+
+ /* Parse the args */
+ if( (N = PyTuple_Size(args)) < 2 ) {
+ PyErr_SetString(PyExc_TypeError,"expected two Vertices");
+ return NULL;
+ }
+ v1_ = PyTuple_GET_ITEM(args,0);
+ v2_ = PyTuple_GET_ITEM(args,1);
+
+ /* Convert to PygtsObjects */
+ if(!pygts_vertex_check(v1_)) {
+ PyErr_SetString(PyExc_TypeError,"expected two Vertices");
+ return NULL;
+ }
+ if(!pygts_vertex_check(v2_)) {
+ PyErr_SetString(PyExc_TypeError,"expected two Vertices");
+ return NULL;
+ }
+ v1 = PYGTS_VERTEX(v1_);
+ v2 = PYGTS_VERTEX(v2_);
+
+ /* Error check */
+ if(PYGTS_OBJECT(v1)->gtsobj == PYGTS_OBJECT(v2)->gtsobj) {
+ PyErr_SetString(PyExc_ValueError,"Vertices are identical");
+ return NULL;
+ }
+
+ /* Create the GtsSegment */
+ segment = GTS_OBJECT(gts_segment_new(gts_segment_class(),
+ GTS_VERTEX(v1->gtsobj),
+ GTS_VERTEX(v2->gtsobj)));
+ if( segment == NULL ) {
+ PyErr_SetString(PyExc_MemoryError, "could not create Segment");
+ return NULL;
+ }
+
+ /* Check for duplicate */
+ tmp = gts_segment_is_duplicate(GTS_SEGMENT(segment));
+ if( tmp != NULL ) {
+ gts_object_destroy(segment);
+ segment = GTS_OBJECT(tmp);
+ }
+
+ /* If corresponding PyObject found in object table, we are done */
+ if( (obj=g_hash_table_lookup(obj_table,segment)) != NULL ) {
+ Py_INCREF(obj);
+ return (PyObject*)obj;
+ }
+ }
+
+ /* Chain up */
+ obj = PYGTS_OBJECT(PygtsObjectType.tp_new(type,args,kwds));
+
+ if( alloc_gtsobj ) {
+ obj->gtsobj = segment;
+ pygts_object_register(PYGTS_OBJECT(obj));
+ }
+
+ return (PyObject*)obj;
+}
+
+
+static int
+init(PygtsSegment *self, PyObject *args, PyObject *kwds)
+{
+ gint ret;
+
+ /* Chain up */
+ if( (ret=PygtsObjectType.tp_init((PyObject*)self,args,kwds)) != 0 ){
+ return ret;
+ }
+
+ return 0;
+}
+
+
+static int
+compare(PygtsSegment *s1_, PygtsSegment *s2_)
+{
+ GtsSegment *s1, *s2;
+
+#if PYGTS_DEBUG
+ pygts_segment_check((PyObject*)s1_);
+ pygts_segment_check((PyObject*)s2_);
+#endif
+
+ s1 = PYGTS_SEGMENT_AS_GTS_SEGMENT(s1_);
+ s2 = PYGTS_SEGMENT_AS_GTS_SEGMENT(s2_);
+
+ return pygts_segment_compare(s1,s2);
+
+}
+
+
+/* Methods table */
+PyTypeObject PygtsSegmentType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "gts.Segment", /* tp_name */
+ sizeof(PygtsSegment), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ (cmpfunc)compare, /* tp_compare */
+ 0, /* 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 */
+ "Segment object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ methods, /* tp_methods */
+ 0, /* tp_members */
+ getset, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)init, /* tp_init */
+ 0, /* tp_alloc */
+ (newfunc)new /* tp_new */
+};
+
+
+/*-------------------------------------------------------------------------*/
+/* Pygts functions */
+
+gboolean
+pygts_segment_check(PyObject* o)
+{
+ if(! PyObject_TypeCheck(o, &PygtsSegmentType)) {
+ return FALSE;
+ }
+ else {
+#if PYGTS_DEBUG
+ return pygts_segment_is_ok(PYGTS_SEGMENT(o));
+#else
+ return TRUE;
+#endif
+ }
+}
+
+
+gboolean
+pygts_segment_is_ok(PygtsSegment *s)
+{
+ if(!pygts_object_is_ok(PYGTS_OBJECT(s))) return FALSE;
+ return gts_segment_is_ok(PYGTS_SEGMENT_AS_GTS_SEGMENT(s));
+}
+
+
+PygtsSegment *
+pygts_segment_new(GtsSegment *s)
+{
+ PyObject *args, *kwds;
+ PygtsObject *segment;
+
+ /* Check for Segment in the object table */
+ if( (segment=PYGTS_OBJECT(g_hash_table_lookup(obj_table,GTS_OBJECT(s))))
+ != NULL ) {
+ Py_INCREF(segment);
+ return PYGTS_FACE(segment);
+ }
+
+ /* Build a new Segment */
+ args = Py_BuildValue("OO",Py_None,Py_None);
+ kwds = Py_BuildValue("{s:O}","alloc_gtsobj",Py_False);
+ segment = PYGTS_SEGMENT(PygtsSegmentType.tp_new(&PygtsSegmentType,
+ args, kwds));
+ Py_DECREF(args);
+ Py_DECREF(kwds);
+ if( segment == NULL ) {
+ PyErr_SetString(PyExc_MemoryError,"could not create Segment");
+ return NULL;
+ }
+ segment->gtsobj = GTS_OBJECT(s);
+
+ /* Register and return */
+ pygts_object_register(segment);
+ return PYGTS_SEGMENT(segment);
+}
+
+
+int
+pygts_segment_compare(GtsSegment* s1,GtsSegment* s2)
+{
+ if( (pygts_point_compare(GTS_POINT(s1->v1),GTS_POINT(s2->v1))==0 &&
+ pygts_point_compare(GTS_POINT(s1->v2),GTS_POINT(s2->v2))==0) ||
+ (pygts_point_compare(GTS_POINT(s1->v1),GTS_POINT(s2->v2))==0 &&
+ pygts_point_compare(GTS_POINT(s1->v2),GTS_POINT(s2->v1))==0) ) {
+ return 0;
+ }
+ return -1;
+}
Added: trunk/lib/py/pygts-0.3.1/segment.h
===================================================================
--- trunk/lib/py/pygts-0.3.1/segment.h 2009-06-24 17:04:39 UTC (rev 1813)
+++ trunk/lib/py/pygts-0.3.1/segment.h 2009-06-24 22:06:24 UTC (rev 1814)
@@ -0,0 +1,46 @@
+/* pygts - python package for the manipulation of triangulated surfaces
+ *
+ * Copyright (C) 2009 Thomas J. Duck
+ * All rights reserved.
+ *
+ * Thomas J. Duck <tom.duck@xxxxxx>
+ * Department of Physics and Atmospheric Science,
+ * Dalhousie University, Halifax, Nova Scotia, Canada, B3H 3J5
+ *
+ * NOTICE
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PYGTS_SEGMENT_H__
+#define __PYGTS_SEGMENT_H__
+
+typedef struct _PygtsObject PygtsSegment;
+
+#define PYGTS_SEGMENT(obj) ((PygtsSegment*)obj)
+
+#define PYGTS_SEGMENT_AS_GTS_SEGMENT(o) (GTS_SEGMENT(PYGTS_OBJECT(o)->gtsobj))
+
+extern PyTypeObject PygtsSegmentType;
+
+gboolean pygts_segment_check(PyObject* o);
+gboolean pygts_segment_is_ok(PygtsSegment *t);
+
+PygtsSegment* pygts_segment_new(GtsSegment *f);
+
+int pygts_segment_compare(GtsSegment* s1,GtsSegment* s2);
+
+#endif /* __PYGTS_SEGMENT_H__ */
Added: trunk/lib/py/pygts-0.3.1/surface.c
===================================================================
--- trunk/lib/py/pygts-0.3.1/surface.c 2009-06-24 17:04:39 UTC (rev 1813)
+++ trunk/lib/py/pygts-0.3.1/surface.c 2009-06-24 22:06:24 UTC (rev 1814)
@@ -0,0 +1,2255 @@
+/* pygts - python package for the manipulation of triangulated surfaces
+ *
+ * Copyright (C) 2009 Thomas J. Duck
+ * All rights reserved.
+ *
+ * Thomas J. Duck <tom.duck@xxxxxx>
+ * Department of Physics and Atmospheric Science,
+ * Dalhousie University, Halifax, Nova Scotia, Canada, B3H 3J5
+ *
+ * NOTICE
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "pygts.h"
+
+#if PYGTS_DEBUG
+ #define SELF_CHECK if(!pygts_surface_check((PyObject*)self)) { \
+ PyErr_SetString(PyExc_RuntimeError, \
+ "problem with self object (internal error)"); \
+ return NULL; \
+ }
+#else
+ #define SELF_CHECK
+#endif
+
+
+/*-------------------------------------------------------------------------*/
+/* Methods exported to python */
+
+static PyObject*
+is_ok(PygtsSurface *self, PyObject *args)
+{
+ if(pygts_surface_is_ok(self)) {
+ Py_INCREF(Py_True);
+ return Py_True;
+ }
+ else {
+ Py_INCREF(Py_False);
+ return Py_False;
+ }
+}
+
+
+static PyObject*
+add(PygtsSurface *self, PyObject *args)
+{
+ PyObject *o_;
+ PygtsFace *f;
+ PygtsSurface *s;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &o_) )
+ return NULL;
+
+ /* Convert to PygtsObjects */
+ if(pygts_face_check(o_)) {
+ f = PYGTS_FACE(o_);
+ gts_surface_add_face(PYGTS_SURFACE_AS_GTS_SURFACE(self),
+ PYGTS_FACE_AS_GTS_FACE(f));
+
+ }
+ else if(pygts_surface_check(o_)) {
+ s = PYGTS_SURFACE(o_);
+
+ /* Make the call */
+ gts_surface_merge(PYGTS_SURFACE_AS_GTS_SURFACE(self),
+ PYGTS_SURFACE_AS_GTS_SURFACE(s));
+
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError,"expected a Face or a Surface");
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+static PyObject*
+pygts_remove(PygtsSurface *self, PyObject *args)
+{
+ PyObject *f_;
+ PygtsFace *f;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &f_) )
+ return NULL;
+
+ /* Convert to PygtsObjects */
+ if(!pygts_face_check(f_)) {
+ PyErr_SetString(PyExc_TypeError,"expected a Face");
+ return NULL;
+ }
+ f = PYGTS_FACE(f_);
+
+ /* Make the call */
+ gts_surface_remove_face(PYGTS_SURFACE_AS_GTS_SURFACE(self),
+ PYGTS_FACE_AS_GTS_FACE(f));
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+static PyObject*
+copy(PygtsSurface *self, PyObject *args)
+{
+ PyObject *s_;
+ PygtsSurface *s;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &s_) )
+ return NULL;
+
+ /* Convert to PygtsObjects */
+ if(!pygts_surface_check(s_)) {
+ PyErr_SetString(PyExc_TypeError,"expected a Surface");
+ return NULL;
+ }
+ s = PYGTS_SURFACE(s_);
+
+ /* Make the call */
+ gts_surface_copy(PYGTS_SURFACE_AS_GTS_SURFACE(self),
+ PYGTS_SURFACE_AS_GTS_SURFACE(s));
+
+ Py_INCREF((PyObject*)self);
+ return (PyObject*)self;
+}
+
+
+static PyObject*
+is_manifold(PygtsSurface *self, PyObject *args)
+{
+
+ SELF_CHECK
+
+ if( gts_surface_is_manifold(PYGTS_SURFACE_AS_GTS_SURFACE(self)) ) {
+ Py_INCREF(Py_True);
+ return Py_True;
+ }
+ else {
+ Py_INCREF(Py_False);
+ return Py_False;
+ }
+}
+
+
+static PyObject*
+manifold_faces(PygtsSurface *self, PyObject *args)
+{
+ PyObject *e_;
+ PygtsEdge *e;
+ GtsFace *f1,*f2;
+ PygtsFace *face1,*face2;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &e_) )
+ return NULL;
+
+ /* Convert to PygtsObjects */
+ if(!pygts_edge_check(e_)) {
+ PyErr_SetString(PyExc_TypeError,"expected an Edge");
+ return NULL;
+ }
+ e = PYGTS_EDGE(e_);
+
+ /* Make the call */
+ if(!gts_edge_manifold_faces(PYGTS_EDGE_AS_GTS_EDGE(e),
+ PYGTS_SURFACE_AS_GTS_SURFACE(self),
+ &f1, &f2)) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ if( (face1 = pygts_face_new(f1)) == NULL ) {
+ return NULL;
+ }
+
+ if( (face2 = pygts_face_new(f2)) == NULL ) {
+ Py_DECREF(face1);
+ return NULL;
+ }
+
+ return Py_BuildValue("OO",face1,face2);
+}
+
+
+static PyObject*
+is_orientable(PygtsSurface *self, PyObject *args)
+{
+ SELF_CHECK
+
+ if(gts_surface_is_orientable(PYGTS_SURFACE_AS_GTS_SURFACE(self))) {
+ Py_INCREF(Py_True);
+ return Py_True;
+ }
+ else {
+ Py_INCREF(Py_False);
+ return Py_False;
+ }
+}
+
+
+static PyObject*
+is_closed(PygtsSurface *self, PyObject *args)
+{
+ SELF_CHECK
+
+ if(gts_surface_is_closed(PYGTS_SURFACE_AS_GTS_SURFACE(self))) {
+ Py_INCREF(Py_True);
+ return Py_True;
+ }
+ else {
+ Py_INCREF(Py_False);
+ return Py_False;
+ }
+}
+
+
+static PyObject*
+boundary(PyObject *self, PyObject *args)
+{
+ PyObject *tuple;
+ guint i,N;
+ GSList *edges=NULL,*e;
+ PygtsEdge *edge;
+
+ SELF_CHECK
+
+ /* Make the call */
+ if( (edges = gts_surface_boundary(PYGTS_SURFACE_AS_GTS_SURFACE(self)))
+ == NULL ) {
+ PyErr_SetString(PyExc_RuntimeError,"could not retrieve edges");
+ return NULL;
+ }
+
+ /* Assemble the return tuple */
+ N = g_slist_length(edges);
+ if( (tuple=PyTuple_New(N)) == NULL) {
+ PyErr_SetString(PyExc_MemoryError,"could not create tuple");
+ return NULL;
+ }
+ e = edges;
+ for(i=0;i<N;i++) {
+ if( (edge = pygts_edge_new(GTS_EDGE(e->data))) == NULL ) {
+ Py_DECREF(tuple);
+ g_slist_free(edges);
+ }
+ PyTuple_SET_ITEM(tuple,i,(PyObject*)edge);
+ e = g_slist_next(e);
+ }
+
+ g_slist_free(edges);
+
+ return tuple;
+}
+
+
+static PyObject*
+area(PygtsSurface *self, PyObject *args)
+{
+ GtsSurface *s;
+
+ SELF_CHECK
+
+ s = PYGTS_SURFACE_AS_GTS_SURFACE(self);
+ return Py_BuildValue("d",gts_surface_area(s));
+}
+
+
+static PyObject*
+volume(PygtsSurface *self, PyObject *args)
+{
+ GtsSurface *s;
+
+ SELF_CHECK
+
+ s = PYGTS_SURFACE_AS_GTS_SURFACE(self);
+
+ if(!gts_surface_is_closed(s)) {
+ PyErr_SetString(PyExc_RuntimeError,"Surface is not closed");
+ return NULL;
+ }
+
+ if(!gts_surface_is_orientable(s)) {
+ PyErr_SetString(PyExc_RuntimeError,"Surface is not orientable");
+ return NULL;
+ }
+
+ return Py_BuildValue("d",gts_surface_volume(s));
+}
+
+
+static PyObject*
+center_of_mass(PygtsSurface *self, PyObject *args)
+{
+ GtsSurface *s;
+ GtsVector cm;
+
+ SELF_CHECK
+
+ s = PYGTS_SURFACE_AS_GTS_SURFACE(self);
+ gts_surface_center_of_mass(s,cm);
+ return Py_BuildValue("ddd",cm[0],cm[1],cm[2]);
+}
+
+
+static PyObject*
+center_of_area(PygtsSurface *self, PyObject *args)
+{
+ GtsSurface *s;
+ GtsVector cm;
+
+ SELF_CHECK
+
+ s = PYGTS_SURFACE_AS_GTS_SURFACE(self);
+ gts_surface_center_of_area(s,cm);
+ return Py_BuildValue("ddd",cm[0],cm[1],cm[2]);
+}
+
+
+static PyObject*
+pygts_write(PygtsSurface *self, PyObject *args)
+{
+ PyObject *f_;
+ FILE *f;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &f_) )
+ return NULL;
+
+ /* Convert to PygtsObjects */
+ if(!PyFile_Check(f_)) {
+ PyErr_SetString(PyExc_TypeError,"expected a File");
+ return NULL;
+ }
+ f = PyFile_AsFile(f_);
+
+ /* Write to the file */
+ gts_surface_write(PYGTS_SURFACE_AS_GTS_SURFACE(self),f);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+static PyObject*
+pygts_write_oogl(PygtsSurface *self, PyObject *args)
+{
+ PyObject *f_;
+ FILE *f;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &f_) )
+ return NULL;
+
+ /* Convert to PygtsObjects */
+ if(!PyFile_Check(f_)) {
+ PyErr_SetString(PyExc_TypeError,"expected a File");
+ return NULL;
+ }
+ f = PyFile_AsFile(f_);
+
+ /* Write to the file */
+ gts_surface_write_oogl(PYGTS_SURFACE_AS_GTS_SURFACE(self),f);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+static PyObject*
+pygts_write_oogl_boundary(PygtsSurface *self, PyObject *args)
+{
+ PyObject *f_;
+ FILE *f;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &f_) )
+ return NULL;
+
+ /* Convert to PygtsObjects */
+ if(!PyFile_Check(f_)) {
+ PyErr_SetString(PyExc_TypeError,"expected a File");
+ return NULL;
+ }
+ f = PyFile_AsFile(f_);
+
+ /* Write to the file */
+ gts_surface_write_oogl_boundary(PYGTS_SURFACE_AS_GTS_SURFACE(self),f);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+static PyObject*
+pygts_write_vtk(PygtsSurface *self, PyObject *args)
+{
+ PyObject *f_;
+ FILE *f;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &f_) )
+ return NULL;
+
+ /* Convert to PygtsObjects */
+ if(!PyFile_Check(f_)) {
+ PyErr_SetString(PyExc_TypeError,"expected a File");
+ return NULL;
+ }
+ f = PyFile_AsFile(f_);
+
+ /* Write to the file */
+ gts_surface_write_vtk(PYGTS_SURFACE_AS_GTS_SURFACE(self),f);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+static PyObject*
+fan_oriented(PygtsSurface *self, PyObject *args)
+{
+ PyObject *v_;
+ PygtsVertex *v;
+ GSList *edges=NULL, *e;
+ guint i,N;
+ PyObject *tuple;
+ PygtsEdge *edge;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &v_) )
+ return NULL;
+
+ /* Convert to PygtsObjects */
+ if(!pygts_vertex_check(v_)) {
+ PyErr_SetString(PyExc_TypeError,"expected a Vertex");
+ return NULL;
+ }
+ v = PYGTS_VERTEX(v_);
+
+ /* Check that the Surface is orientable; the calculation will
+ * fail otherwise.
+ */
+ if(!gts_surface_is_orientable(PYGTS_SURFACE_AS_GTS_SURFACE(self))) {
+ PyErr_SetString(PyExc_RuntimeError,"Surface must be orientable");
+ return NULL;
+ }
+
+ /* Make the call */
+ edges = gts_vertex_fan_oriented(PYGTS_VERTEX_AS_GTS_VERTEX(v),
+ PYGTS_SURFACE_AS_GTS_SURFACE(self));
+
+ /* Build the return tuple */
+ N = g_slist_length(edges);
+ if( (tuple=PyTuple_New(N)) == NULL) {
+ PyErr_SetString(PyExc_MemoryError,"Could not create tuple");
+ return NULL;
+ }
+ e = edges;
+ for(i=0;i<N;i++) {
+ if( (edge = pygts_edge_new(GTS_EDGE(e->data))) == NULL ) {
+ Py_DECREF(tuple);
+ g_slist_free(edges);
+ return NULL;
+ }
+ PyTuple_SET_ITEM(tuple,i,(PyObject*)edge);
+ e = g_slist_next(e);
+ }
+
+ return tuple;
+}
+
+
+static PyObject*
+split(PygtsSurface *self, PyObject *args)
+{
+ GSList *surfaces, *s;
+ PyObject *tuple;
+ PygtsSurface *surface;
+ guint n,N;
+
+ SELF_CHECK
+
+ surfaces = gts_surface_split(PYGTS_SURFACE_AS_GTS_SURFACE(self));
+
+ /* Create a tuple to put the Surfaces into */
+ N = g_slist_length(surfaces);
+ if( (tuple=PyTuple_New(N)) == NULL) {
+ PyErr_SetString(PyExc_MemoryError,"could not create tuple");
+ return NULL;
+ }
+
+ /* Put PygtsSurface objects into the tuple */
+ s = surfaces;
+ for(n=0;n<N;n++) {
+ if( (surface = pygts_surface_new(GTS_SURFACE(s->data))) == NULL ) {
+ Py_DECREF(tuple);
+ return NULL;
+ }
+ surface->traverse = NULL;
+ PyTuple_SET_ITEM(tuple, n, (PyObject*)surface);
+ s = g_slist_next(s);
+ }
+
+ return tuple;
+}
+
+
+/* Helper function for vertices() */
+static void get_vertex(GtsVertex *vertex, GtsVertex ***v)
+{
+ **v = vertex;
+ *v += 1;
+}
+
+static PyObject*
+vertices(PygtsSurface *self, PyObject *args)
+{
+ PyObject *tuple;
+ PygtsVertex *vertex;
+ PygtsVertex **vertices,**v;
+ guint i,N=0;
+
+ SELF_CHECK
+
+ /* Get the number of vertices */
+ N = gts_surface_vertex_number(PYGTS_SURFACE_AS_GTS_SURFACE(self));
+
+ /* Retrieve all of the vertex pointers into a temporary array */
+ if( (vertices = (PygtsVertex**)malloc(N*sizeof(PygtsVertex*))) == NULL ) {
+ PyErr_SetString(PyExc_MemoryError,"could not create array");
+ return NULL;
+ }
+ v = vertices;
+
+ gts_surface_foreach_vertex(PYGTS_SURFACE_AS_GTS_SURFACE(self),
+ (GtsFunc)get_vertex,&v);
+
+ /* Create a tuple to put the vertices into */
+ if( (tuple=PyTuple_New(N)) == NULL) {
+ PyErr_SetString(PyExc_MemoryError,"could not create tuple");
+ return NULL;
+ }
+
+ /* Put PygtsVertex objects into the tuple */
+ v = vertices;
+ for(i=0;i<N;i++) {
+ if( (vertex = pygts_vertex_new(GTS_VERTEX(*v))) == NULL ) {
+ free(vertices);
+ Py_DECREF(tuple);
+ return NULL;
+ }
+ PyTuple_SET_ITEM(tuple, i, (PyObject*)vertex);
+ v += 1;
+ }
+
+ free(vertices);
+ return tuple;
+}
+
+
+/* Helper function for edges() */
+static void get_edge(GtsEdge *edge, GSList **edges)
+{
+ *edges = g_slist_prepend(*edges,edge);
+}
+
+
+static PyObject*
+parent(PygtsSurface *self, PyObject *args)
+{
+ PyObject *e_;
+ PygtsEdge *e;
+ GtsFace *f;
+ PygtsFace *face;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &e_) )
+ return NULL;
+
+ /* Convert to PygtsObjects */
+ if(!pygts_edge_check(e_)) {
+ PyErr_SetString(PyExc_TypeError,"expected an Edge");
+ return NULL;
+ }
+ e = PYGTS_EDGE(e_);
+
+ /* Make the call */
+ if( (f=gts_edge_has_parent_surface(PYGTS_EDGE_AS_GTS_EDGE(e),
+ PYGTS_SURFACE_AS_GTS_SURFACE(self)))
+ == NULL ) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ if( (face = pygts_face_new(f)) == NULL ) {
+ return NULL;
+ }
+
+ return (PyObject*)face;
+}
+
+
+static PyObject*
+edges(PyObject *self, PyObject *args)
+{
+ PyObject *tuple=NULL, *obj;
+ guint i,N;
+ GSList *edges=NULL,*vertices=NULL,*e;
+ PygtsEdge *edge;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "|O", &tuple) ) {
+ return NULL;
+ }
+
+ if(tuple) {
+ if(PyList_Check(tuple)) {
+ tuple = PyList_AsTuple(tuple);
+ }
+ else {
+ Py_INCREF(tuple);
+ }
+ if(!PyTuple_Check(tuple)) {
+ Py_DECREF(tuple);
+ PyErr_SetString(PyExc_TypeError,"expected a list or tuple of vertices");
+ return NULL;
+ }
+
+ /* Assemble the GSList */
+ N = PyTuple_Size(tuple);
+ for(i=0;i<N;i++) {
+ obj = PyTuple_GET_ITEM(tuple,i);
+ if(!pygts_vertex_check(obj)) {
+ Py_DECREF(tuple);
+ g_slist_free(vertices);
+ PyErr_SetString(PyExc_TypeError,"expected a list or tuple of vertices");
+ return NULL;
+ }
+ vertices=g_slist_prepend(vertices,PYGTS_VERTEX_AS_GTS_VERTEX(obj));
+ }
+ Py_DECREF(tuple);
+
+ /* Make the call */
+ if( (edges = gts_edges_from_vertices(vertices,
+ PYGTS_SURFACE_AS_GTS_SURFACE(self))) == NULL ) {
+ PyErr_SetString(PyExc_RuntimeError,"could not retrieve edges");
+ return NULL;
+ }
+ g_slist_free(vertices);
+ }
+ else {
+ /* Get all of the edges */
+ gts_surface_foreach_edge(PYGTS_SURFACE_AS_GTS_SURFACE(self),
+ (GtsFunc)get_edge,&edges);
+ }
+
+ /* Assemble the return tuple */
+ N = g_slist_length(edges);
+ if( (tuple=PyTuple_New(N)) == NULL) {
+ PyErr_SetString(PyExc_MemoryError,"could not create tuple");
+ return NULL;
+ }
+ e = edges;
+ for(i=0;i<N;i++) {
+ if( (edge = pygts_edge_new(GTS_EDGE(e->data))) == NULL ) {
+ Py_DECREF(tuple);
+ g_slist_free(edges);
+ return NULL;
+ }
+ PyTuple_SET_ITEM(tuple,i,(PyObject*)edge);
+ e = g_slist_next(e);
+ }
+
+ g_slist_free(edges);
+
+ return tuple;
+}
+
+
+/* Helper function for edges() */
+static void get_face(GtsFace *face, GSList **faces)
+{
+ *faces = g_slist_prepend(*faces,face);
+}
+
+static PyObject*
+faces(PyObject *self, PyObject *args)
+{
+ PyObject *tuple=NULL, *obj;
+ guint i,N;
+ GSList *edges=NULL,*faces=NULL,*f;
+ PygtsFace *face;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "|O", &tuple) ) {
+ return NULL;
+ }
+
+ if(tuple) {
+ if(PyList_Check(tuple)) {
+ tuple = PyList_AsTuple(tuple);
+ }
+ else {
+ Py_INCREF(tuple);
+ }
+ if(!PyTuple_Check(tuple)) {
+ Py_DECREF(tuple);
+ PyErr_SetString(PyExc_TypeError,"expected a list or tuple of edges");
+ return NULL;
+ }
+
+ /* Assemble the GSList */
+ N = PyTuple_Size(tuple);
+ for(i=0;i<N;i++) {
+ obj = PyTuple_GET_ITEM(tuple,i);
+ if(!pygts_edge_check(obj)) {
+ Py_DECREF(tuple);
+ g_slist_free(edges);
+ PyErr_SetString(PyExc_TypeError,"expected a list or tuple of edges");
+ return NULL;
+ }
+ edges = g_slist_prepend(edges,PYGTS_EDGE_AS_GTS_EDGE(obj));
+ }
+ Py_DECREF(tuple);
+
+ /* Make the call */
+ if( (faces = gts_faces_from_edges(edges,PYGTS_SURFACE_AS_GTS_SURFACE(self)))
+ == NULL ) {
+ PyErr_SetString(PyExc_RuntimeError,"could not retrieve faces");
+ return NULL;
+ }
+ g_slist_free(edges);
+ }
+ else {
+ /* Get all of the edges */
+ gts_surface_foreach_face(PYGTS_SURFACE_AS_GTS_SURFACE(self),
+ (GtsFunc)get_face,&faces);
+ }
+
+ /* Assemble the return tuple */
+ N = g_slist_length(faces);
+ if( (tuple=PyTuple_New(N)) == NULL) {
+ PyErr_SetString(PyExc_MemoryError,"could not create tuple");
+ return NULL;
+ }
+
+ f = faces;
+ for(i=0;i<N;i++) {
+ if( (face = pygts_face_new(GTS_FACE(f->data))) == NULL ) {
+ Py_DECREF(tuple);
+ g_slist_free(faces);
+ return NULL;
+ }
+ PyTuple_SET_ITEM(tuple,i,(PyObject*)face);
+ f = g_slist_next(f);
+ }
+
+ g_slist_free(faces);
+
+ return tuple;
+}
+
+
+/* Helper for face_indices() */
+typedef struct {
+ PyObject *vertices,*indices; /* Vertex and indices tuples */
+ guint Nv,Ni; /* Number of vertices and indices */
+ guint n; /* Current face index */
+ gboolean errflag;
+} IndicesData;
+
+/* Helper for face_indices() */
+static void get_indices(GtsFace *face, IndicesData *data)
+{
+ PyObject *t;
+ GtsVertex *v[3];
+ guint i,j;
+ gboolean flag;
+
+ if(data->errflag) return;
+
+ /* Put the vertex pointers in an array */
+ gts_triangle_vertices( GTS_TRIANGLE(face), &(v[0]), &(v[1]), &(v[2]) );
+
+ /* Create a tuple to put the indices into */
+ if( (t=PyTuple_New(3)) == NULL) {
+ PyErr_SetString(PyExc_MemoryError,"could not create tuple");
+ data->errflag = TRUE;
+ return;
+ }
+ PyTuple_SET_ITEM(data->indices, data->n, t);
+
+ /* Determine the indices */
+ for(i=0;i<3;i++) {
+ flag = FALSE;
+ for(j=0;j<data->Nv;j++) {
+ if( PYGTS_VERTEX_AS_GTS_VERTEX(PyTuple_GET_ITEM(data->vertices,j))
+ ==v[i] ) {
+ PyTuple_SET_ITEM(t, i, PyInt_FromLong(j));
+ flag = TRUE;
+ break;
+ }
+ }
+ if(!flag) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "Could not initialize tuple (internal error)");
+ data->errflag = TRUE;
+ return;
+ }
+ }
+ data->n += 1;
+}
+
+
+static PyObject*
+face_indices(PygtsSurface *self, PyObject *args)
+{
+ PyObject *vertices,*indices;
+ IndicesData data;
+ guint Nv,Nf;
+ guint i;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &vertices) )
+ return NULL;
+
+ /* Make sure that the tuple contains only vertices */
+ Nv = PyTuple_Size(vertices);
+ for(i=0;i<Nv;i++) {
+ if(!pygts_vertex_check(PyTuple_GetItem(vertices,i))){
+ PyErr_SetString(PyExc_TypeError,"Tuple has objects other than Vertices");
+ return NULL;
+ }
+ }
+
+ /* Get the number of faces in this surface */
+ Nf = gts_surface_face_number(PYGTS_SURFACE_AS_GTS_SURFACE(self));
+
+ /* Create a tuple to put the index tuples into */
+ if( (indices=PyTuple_New(Nf)) == NULL) {
+ PyErr_SetString(PyExc_MemoryError,"could not create tuple");
+ return NULL;
+ }
+
+ /* Initialize the IndicesData struct. This is used to maintain state as each
+ * face is processed.
+ */
+ data.vertices = vertices;
+ data.indices = indices;
+ data.Nv = Nv;
+ data.Ni = Nf;
+ data.n = 0;
+ data.errflag = FALSE;
+
+ /* Process each face */
+ gts_surface_foreach_face(PYGTS_SURFACE_AS_GTS_SURFACE(self),
+ (GtsFunc)get_indices,&data);
+ if(data.errflag) {
+ Py_DECREF(data.indices);
+ return NULL;
+ }
+
+ return indices;
+}
+
+
+static PyObject*
+distance(PygtsSurface *self, PyObject *args)
+{
+ PyObject *s_;
+ PygtsSurface *s;
+ gdouble delta=0.1;
+ GtsRange face_range, boundary_range;
+ PyObject *fr, *br;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O|d", &s_,&delta) )
+ return NULL;
+
+ /* Convert to PygtsObjects */
+ if(!pygts_surface_check(s_)) {
+ PyErr_SetString(PyExc_TypeError,"expected a Surface");
+ return NULL;
+ }
+ s = PYGTS_SURFACE(s_);
+
+ gts_surface_distance(PYGTS_SURFACE_AS_GTS_SURFACE(self),
+ PYGTS_SURFACE_AS_GTS_SURFACE(s),
+ delta, &face_range, &boundary_range);
+
+ /* Populate the fr (face range) dict */
+ if( (fr = PyDict_New()) == NULL ) {
+ PyErr_SetString(PyExc_MemoryError,"cannot create dict");
+ return NULL;
+ }
+ PyDict_SetItemString(fr, "min", Py_BuildValue("d",face_range.min));
+ PyDict_SetItemString(fr, "max", Py_BuildValue("d",face_range.max));
+ PyDict_SetItemString(fr, "sum", Py_BuildValue("d",face_range.sum));
+ PyDict_SetItemString(fr, "sum2", Py_BuildValue("d",face_range.sum2));
+ PyDict_SetItemString(fr, "mean", Py_BuildValue("d",face_range.mean));
+ PyDict_SetItemString(fr, "stddev", Py_BuildValue("d",face_range.stddev));
+ PyDict_SetItemString(fr, "n", Py_BuildValue("i",face_range.n));
+
+ /* Populate the br (boundary range) dict */
+ if(gts_surface_boundary(PYGTS_SURFACE_AS_GTS_SURFACE(self))!=NULL) {
+ if( (br = PyDict_New()) == NULL ) {
+ PyErr_SetString(PyExc_MemoryError,"cannot create dict");
+ Py_DECREF(fr);
+ return NULL;
+ }
+ PyDict_SetItemString(br,"min",Py_BuildValue("d",boundary_range.min));
+ PyDict_SetItemString(br,"max",Py_BuildValue("d",boundary_range.max));
+ PyDict_SetItemString(br,"sum",Py_BuildValue("d",boundary_range.sum));
+ PyDict_SetItemString(br,"sum2",Py_BuildValue("d",boundary_range.sum2));
+ PyDict_SetItemString(br,"mean",Py_BuildValue("d",boundary_range.mean));
+ PyDict_SetItemString(br,"stddev",Py_BuildValue("d",boundary_range.stddev));
+ PyDict_SetItemString(br, "n",Py_BuildValue("i",boundary_range.n));
+
+ return Py_BuildValue("OO",fr,br);
+ }
+ else {
+ return Py_BuildValue("O",fr);
+ }
+}
+
+
+static PyObject*
+strip(PygtsSurface *self, PyObject *args)
+{
+ GSList *strips, *s, *f;
+ PyObject *tuple, **tuples;
+ guint i,j,n,N;
+ PygtsFace *face=NULL;
+
+ SELF_CHECK
+
+ strips = gts_surface_strip(PYGTS_SURFACE_AS_GTS_SURFACE(self));
+
+ /* Create tuples to put the Faces into */
+ N = g_slist_length(strips);
+
+ if( (tuple=PyTuple_New(N)) == NULL) {
+ PyErr_SetString(PyExc_MemoryError,"could not create tuple");
+ return NULL;
+ }
+ if( (tuples = (PyObject**)malloc(N*sizeof(PyObject*))) == NULL ) {
+ PyErr_SetString(PyExc_MemoryError,"could not create array");
+ Py_DECREF(tuple);
+ return NULL;
+ }
+ s = strips;
+ for(i=0;i<N;i++) {
+ f = (GSList*)(s->data);
+ n = g_slist_length(f);
+ if( (tuples[i]=PyTuple_New(n)) == NULL) {
+ PyErr_SetString(PyExc_MemoryError,"could not create tuple");
+ Py_DECREF(tuple);
+ free(tuples);
+ return NULL;
+ }
+ PyTuple_SET_ITEM(tuple, i, tuples[i]);
+ s = g_slist_next(s);
+ }
+
+ /* Put PygtsFace objects into the tuple */
+ s = strips;
+ for(i=0;i<N;i++) {
+ f = (GSList*)(s->data);
+ n = g_slist_length(f);
+ for(j=0;j<n;j++) {
+ if( (face = pygts_face_new(GTS_FACE(f->data))) == NULL ) {
+ }
+ PyTuple_SET_ITEM(tuples[i], j, (PyObject*)face);
+ f = g_slist_next(f);
+ }
+ s = g_slist_next(s);
+ }
+
+ free(tuples);
+
+ return tuple;
+}
+
+
+static PyObject*
+stats(PygtsSurface *self, PyObject *args)
+{
+ GtsSurfaceStats stats;
+ PyObject *dict, *edges_per_vertex, *faces_per_edge;
+
+ SELF_CHECK
+
+ /* Make the call */
+ gts_surface_stats(PYGTS_SURFACE_AS_GTS_SURFACE(self),&stats);
+
+ /* Create the dictionaries */
+ if( (dict = PyDict_New()) == NULL ) {
+ PyErr_SetString(PyExc_MemoryError,"cannot create dict");
+ return NULL;
+ }
+ if( (edges_per_vertex = PyDict_New()) == NULL ) {
+ PyErr_SetString(PyExc_MemoryError,"cannot create dict");
+ Py_DECREF(dict);
+ return NULL;
+ }
+ if( (faces_per_edge = PyDict_New()) == NULL ) {
+ PyErr_SetString(PyExc_MemoryError,"cannot create dict");
+ Py_DECREF(dict);
+ Py_DECREF(edges_per_vertex);
+ return NULL;
+ }
+
+ /* Populate the edges_per_vertex dict */
+ PyDict_SetItemString(edges_per_vertex,"min",
+ Py_BuildValue("d",stats.edges_per_vertex.min));
+ PyDict_SetItemString(edges_per_vertex,"max",
+ Py_BuildValue("d",stats.edges_per_vertex.max));
+ PyDict_SetItemString(edges_per_vertex,"sum",
+ Py_BuildValue("d",stats.edges_per_vertex.sum));
+ PyDict_SetItemString(edges_per_vertex,"sum2",
+ Py_BuildValue("d",stats.edges_per_vertex.sum2));
+ PyDict_SetItemString(edges_per_vertex,"mean",
+ Py_BuildValue("d",stats.edges_per_vertex.mean));
+ PyDict_SetItemString(edges_per_vertex,"stddev",
+ Py_BuildValue("d",stats.edges_per_vertex.stddev));
+ PyDict_SetItemString(edges_per_vertex,"n",
+ Py_BuildValue("i",stats.edges_per_vertex.n));
+
+ /* Populate the faces_per_edge dict */
+ PyDict_SetItemString(faces_per_edge,"min",
+ Py_BuildValue("d",stats.faces_per_edge.min));
+ PyDict_SetItemString(faces_per_edge,"max",
+ Py_BuildValue("d",stats.faces_per_edge.max));
+ PyDict_SetItemString(faces_per_edge,"sum",
+ Py_BuildValue("d",stats.faces_per_edge.sum));
+ PyDict_SetItemString(faces_per_edge,"sum2",
+ Py_BuildValue("d",stats.faces_per_edge.sum2));
+ PyDict_SetItemString(faces_per_edge,"mean",
+ Py_BuildValue("d",stats.faces_per_edge.mean));
+ PyDict_SetItemString(faces_per_edge,"stddev",
+ Py_BuildValue("d",stats.faces_per_edge.stddev));
+ PyDict_SetItemString(faces_per_edge,"n",
+ Py_BuildValue("i",stats.faces_per_edge.n));
+
+ /* Populate the main dict */
+ PyDict_SetItemString(dict,"n_faces", Py_BuildValue("i",stats.n_faces));
+ PyDict_SetItemString(dict,"n_incompatible_faces",
+ Py_BuildValue("i",stats.n_incompatible_faces));
+ PyDict_SetItemString(dict,"n_boundary_edges",
+ Py_BuildValue("i",stats.n_boundary_edges));
+ PyDict_SetItemString(dict,"n_non_manifold_edges",
+ Py_BuildValue("i",stats.n_non_manifold_edges));
+ PyDict_SetItemString(dict,"edges_per_vertex", edges_per_vertex);
+ PyDict_SetItemString(dict,"faces_per_edge", faces_per_edge);
+
+ return dict;
+}
+
+
+static PyObject*
+quality_stats(PygtsSurface *self, PyObject *args)
+{
+ GtsSurfaceQualityStats stats;
+ PyObject *dict, *face_quality, *face_area, *edge_length, *edge_angle;
+
+ SELF_CHECK
+
+ /* Make the call */
+ gts_surface_quality_stats(PYGTS_SURFACE_AS_GTS_SURFACE(self),&stats);
+
+ /* Create the dictionaries */
+ if( (dict = PyDict_New()) == NULL ) {
+ PyErr_SetString(PyExc_MemoryError,"cannot create dict");
+ return NULL;
+ }
+ if( (face_quality = PyDict_New()) == NULL ) {
+ PyErr_SetString(PyExc_MemoryError,"cannot create dict");
+ Py_DECREF(dict);
+ return NULL;
+ }
+ if( (face_area = PyDict_New()) == NULL ) {
+ PyErr_SetString(PyExc_MemoryError,"cannot create dict");
+ Py_DECREF(dict);
+ Py_DECREF(face_quality);
+ return NULL;
+ }
+ if( (edge_length = PyDict_New()) == NULL ) {
+ PyErr_SetString(PyExc_MemoryError,"cannot create dict");
+ Py_DECREF(dict);
+ Py_DECREF(face_quality);
+ Py_DECREF(face_area);
+ return NULL;
+ }
+ if( (edge_angle = PyDict_New()) == NULL ) {
+ PyErr_SetString(PyExc_MemoryError,"cannot create dict");
+ Py_DECREF(dict);
+ Py_DECREF(face_quality);
+ Py_DECREF(face_area);
+ Py_DECREF(edge_length);
+ return NULL;
+ }
+
+ /* Populate the face_quality dict */
+ PyDict_SetItemString(face_quality,"min",
+ Py_BuildValue("d",stats.face_quality.min));
+ PyDict_SetItemString(face_quality,"max",
+ Py_BuildValue("d",stats.face_quality.max));
+ PyDict_SetItemString(face_quality,"sum",
+ Py_BuildValue("d",stats.face_quality.sum));
+ PyDict_SetItemString(face_quality,"sum2",
+ Py_BuildValue("d",stats.face_quality.sum2));
+ PyDict_SetItemString(face_quality,"mean",
+ Py_BuildValue("d",stats.face_quality.mean));
+ PyDict_SetItemString(face_quality,"stddev",
+ Py_BuildValue("d",stats.face_quality.stddev));
+ PyDict_SetItemString(face_quality,"n",
+ Py_BuildValue("i",stats.face_quality.n));
+
+ /* Populate the face_area dict */
+ PyDict_SetItemString(face_area,"min",
+ Py_BuildValue("d",stats.face_area.min));
+ PyDict_SetItemString(face_area,"max",
+ Py_BuildValue("d",stats.face_area.max));
+ PyDict_SetItemString(face_area,"sum",
+ Py_BuildValue("d",stats.face_area.sum));
+ PyDict_SetItemString(face_area,"sum2",
+ Py_BuildValue("d",stats.face_area.sum2));
+ PyDict_SetItemString(face_area,"mean",
+ Py_BuildValue("d",stats.face_area.mean));
+ PyDict_SetItemString(face_area,"stddev",
+ Py_BuildValue("d",stats.face_area.stddev));
+ PyDict_SetItemString(face_area,"n",
+ Py_BuildValue("i",stats.face_area.n));
+
+ /* Populate the edge_length dict */
+ PyDict_SetItemString(edge_length,"min",
+ Py_BuildValue("d",stats.edge_length.min));
+ PyDict_SetItemString(edge_length,"max",
+ Py_BuildValue("d",stats.edge_length.max));
+ PyDict_SetItemString(edge_length,"sum",
+ Py_BuildValue("d",stats.edge_length.sum));
+ PyDict_SetItemString(edge_length,"sum2",
+ Py_BuildValue("d",stats.edge_length.sum2));
+ PyDict_SetItemString(edge_length,"mean",
+ Py_BuildValue("d",stats.edge_length.mean));
+ PyDict_SetItemString(edge_length,"stddev",
+ Py_BuildValue("d",stats.edge_length.stddev));
+ PyDict_SetItemString(edge_length,"n",
+ Py_BuildValue("i",stats.edge_length.n));
+
+ /* Populate the edge_angle dict */
+ PyDict_SetItemString(edge_angle,"min",
+ Py_BuildValue("d",stats.edge_angle.min));
+ PyDict_SetItemString(edge_angle,"max",
+ Py_BuildValue("d",stats.edge_angle.max));
+ PyDict_SetItemString(edge_angle,"sum",
+ Py_BuildValue("d",stats.edge_angle.sum));
+ PyDict_SetItemString(edge_angle,"sum2",
+ Py_BuildValue("d",stats.edge_angle.sum2));
+ PyDict_SetItemString(edge_angle,"mean",
+ Py_BuildValue("d",stats.edge_angle.mean));
+ PyDict_SetItemString(edge_angle,"stddev",
+ Py_BuildValue("d",stats.edge_angle.stddev));
+ PyDict_SetItemString(edge_angle,"n",
+ Py_BuildValue("i",stats.edge_angle.n));
+
+ /* Populate the main dict */
+ PyDict_SetItemString(dict,"face_quality", face_quality);
+ PyDict_SetItemString(dict,"face_area", face_area);
+ PyDict_SetItemString(dict,"edge_length", edge_length);
+ PyDict_SetItemString(dict,"edge_angle", edge_angle);
+
+ return dict;
+}
+
+
+static PyObject*
+tessellate(PygtsSurface *self, PyObject *args)
+{
+ SELF_CHECK
+
+ gts_surface_tessellate(PYGTS_SURFACE_AS_GTS_SURFACE(self),NULL,NULL);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+/* Helper function for inter() */
+void
+get_largest_coord(GtsVertex *v,gdouble *val) {
+ if( fabs(GTS_POINT(v)->x) > *val ) *val = fabs(GTS_POINT(v)->x);
+ if( fabs(GTS_POINT(v)->y) > *val ) *val = fabs(GTS_POINT(v)->y);
+ if( fabs(GTS_POINT(v)->z) > *val ) *val = fabs(GTS_POINT(v)->z);
+}
+
+/* Helper function for intersection operations */
+static PyObject*
+inter(PygtsSurface *self, PyObject *args, GtsBooleanOperation op1,
+ GtsBooleanOperation op2)
+{
+ PyObject *obj;
+ PyObject *s_;
+ PygtsSurface *s;
+ GtsSurface *surface;
+ GtsVector cm1, cm2;
+ gdouble area1, area2;
+ GtsSurfaceInter *si;
+ GNode *tree1, *tree2;
+ gboolean is_open1, is_open2, closed;
+ gdouble eps=0.;
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &s_) )
+ return NULL;
+
+ /* Convert to PygtsObjects */
+ if(!pygts_surface_check(s_)) {
+ PyErr_SetString(PyExc_TypeError,"expected a Surface");
+ return NULL;
+ }
+ s = PYGTS_SURFACE(s_);
+
+ /* Make sure that we don't have two pointers to the same surface */
+ if( self == s ) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "can't determine intersection with self");
+ return NULL;
+ }
+
+
+ /* *** ATTENTION ***
+ * Eliminate any active gts traverse objects. They appear to interfere
+ * with the intersection calculation. I would guess that this is due
+ * to the use of the "reserved" field (i.e., it doesn't get properly
+ * reset until the traverse is destroyed).
+ *
+ * I don't expect this to cause problems here, but a bug report should be
+ * filed.
+ */
+ if(self->traverse!=NULL) {
+ gts_surface_traverse_destroy(self->traverse);
+ self->traverse = NULL;
+ }
+ if(s->traverse!=NULL) {
+ gts_surface_traverse_destroy(s->traverse);
+ s->traverse = NULL;
+ }
+ /* *** ATTENTION *** */
+
+ /* Check for self-intersections in either surface */
+ if( gts_surface_is_self_intersecting(PYGTS_SURFACE_AS_GTS_SURFACE(self))
+ != NULL ) {
+ PyErr_SetString(PyExc_RuntimeError,"Surface is self-intersecting");
+ return NULL;
+ }
+ if( gts_surface_is_self_intersecting(PYGTS_SURFACE_AS_GTS_SURFACE(s))
+ != NULL ) {
+ PyErr_SetString(PyExc_RuntimeError,"Surface is self-intersecting");
+ return NULL;
+ }
+
+ /* Avoid complete self-intersection of two surfaces*/
+ if( (gts_surface_face_number(PYGTS_SURFACE_AS_GTS_SURFACE(self)) ==
+ gts_surface_face_number(PYGTS_SURFACE_AS_GTS_SURFACE(s))) &&
+ (gts_surface_edge_number(PYGTS_SURFACE_AS_GTS_SURFACE(self)) ==
+ gts_surface_edge_number(PYGTS_SURFACE_AS_GTS_SURFACE(s))) &&
+ (gts_surface_vertex_number(PYGTS_SURFACE_AS_GTS_SURFACE(self)) ==
+ gts_surface_vertex_number(PYGTS_SURFACE_AS_GTS_SURFACE(s))) &&
+ (gts_surface_area(PYGTS_SURFACE_AS_GTS_SURFACE(self)) ==
+ gts_surface_area(PYGTS_SURFACE_AS_GTS_SURFACE(s))) ) {
+
+ area1 = \
+ gts_surface_center_of_area(PYGTS_SURFACE_AS_GTS_SURFACE(self),cm1);
+
+ area2 = \
+ gts_surface_center_of_area(PYGTS_SURFACE_AS_GTS_SURFACE(s),cm2);
+
+ if( (area1==area2) && (cm1[0]==cm2[0]) && (cm1[1]==cm2[1]) &&
+ (cm1[2]==cm2[2]) ) {
+ PyErr_SetString(PyExc_RuntimeError,"Surfaces mutually intersect");
+ return NULL;
+ }
+ }
+
+ /* Get bounding boxes */
+ if( (tree1=gts_bb_tree_surface(PYGTS_SURFACE_AS_GTS_SURFACE(self)))
+ ==NULL ) {
+ PyErr_SetString(PyExc_MemoryError,"could not create tree");
+ return NULL;
+ }
+ is_open1 = !gts_surface_is_closed(PYGTS_SURFACE_AS_GTS_SURFACE(self));
+ if( (tree2=gts_bb_tree_surface(PYGTS_SURFACE_AS_GTS_SURFACE(s)))
+ ==NULL ) {
+ gts_bb_tree_destroy(tree1, TRUE);
+ PyErr_SetString(PyExc_MemoryError,"could not create tree");
+ return NULL;
+ }
+ is_open2 = !gts_surface_is_closed(PYGTS_SURFACE_AS_GTS_SURFACE(s));
+
+ /* Get the surface intersection object */
+ if( (si = gts_surface_inter_new(gts_surface_inter_class(),
+ PYGTS_SURFACE_AS_GTS_SURFACE(self),
+ PYGTS_SURFACE_AS_GTS_SURFACE(s),
+ tree1, tree2, is_open1, is_open2))==NULL) {
+ gts_bb_tree_destroy(tree1, TRUE);
+ gts_bb_tree_destroy(tree2, TRUE);
+ PyErr_SetString(PyExc_RuntimeError,"could not create GtsSurfaceInter");
+ return NULL;
+ }
+ gts_bb_tree_destroy(tree1, TRUE);
+ gts_bb_tree_destroy(tree2, TRUE);
+
+ /* Check that the surface intersection object is closed */
+ gts_surface_inter_check(si,&closed);
+ if( closed == FALSE ) {
+ gts_object_destroy(GTS_OBJECT(si));
+ PyErr_SetString(PyExc_RuntimeError,"result is not closed");
+ return NULL;
+ }
+
+ /* Create the surface */
+ if( (surface = gts_surface_new(gts_surface_class(), gts_face_class(),
+ gts_edge_class(), gts_vertex_class()))
+ == NULL ) {
+ PyErr_SetString(PyExc_MemoryError, "could not create Surface");
+ return NULL;
+ }
+
+ /* Calculate the new surface */
+ gts_surface_inter_boolean(si, surface ,op1);
+ gts_surface_inter_boolean(si, surface ,op2);
+ gts_object_destroy(GTS_OBJECT(si));
+
+ /* Clean up the result */
+ gts_surface_foreach_vertex(surface, (GtsFunc)get_largest_coord, &eps);
+ eps *= pow(2.,-50);
+ pygts_vertex_cleanup(surface,1.e-9);
+ pygts_edge_cleanup(surface);
+ pygts_face_cleanup(surface);
+
+ /* Check for self-intersection */
+ if( gts_surface_is_self_intersecting(surface) != NULL ) {
+ gts_object_destroy(GTS_OBJECT(surface));
+ PyErr_SetString(PyExc_RuntimeError,"result is self-intersecting surface");
+ return NULL;
+ }
+
+ /* Create the return Surface */
+ if( (obj = (PyObject*)pygts_surface_new(surface)) == NULL ) {
+ gts_object_destroy(GTS_OBJECT(surface));
+ return NULL;
+ }
+
+ return obj;
+}
+
+
+static PyObject*
+intersection(PygtsSurface *self, PyObject *args, GtsBooleanOperation op1,
+ GtsBooleanOperation op2)
+{
+ SELF_CHECK
+ return inter(self,args,GTS_1_IN_2,GTS_2_IN_1);
+}
+
+
+static PyObject*
+pygts_union(PygtsSurface *self, PyObject *args)
+{
+ SELF_CHECK
+ return inter(self,args,GTS_1_OUT_2,GTS_2_OUT_1);
+}
+
+
+static PyObject*
+difference(PygtsSurface *self, PyObject *args)
+{
+ SELF_CHECK
+ return inter(self,args,GTS_1_OUT_2,GTS_2_IN_1);
+}
+
+
+/* Helper for rotate(), scale() and translate() transforms */
+typedef struct {
+ double dx, dy, dz, a;
+ gboolean errflag;
+} TransformData;
+
+/* Helper for rotate() */
+static void
+rotate_point(GtsPoint *p, TransformData *data)
+{
+ if(data->errflag) return;
+
+ if(pygts_point_rotate(p,data->dx,data->dy,data->dz,data->a)==-1)
+ data->errflag=TRUE;
+}
+
+static PyObject*
+rotate(PygtsSurface* self, PyObject *args, PyObject *keywds)
+{
+ TransformData data;
+ static char *kwlist[] = {"dx", "dy", "dz", "a", NULL};
+
+ SELF_CHECK
+
+ data.dx=0; data.dy=0; data.dz=0; data.a=0;
+ data.errflag = FALSE;
+
+ /* Parse the args */
+ if(! PyArg_ParseTupleAndKeywords(args, keywds,"|dddd", kwlist,
+ &(data.dx), &(data.dy), &(data.dz),
+ &(data.a)) ) {
+ return NULL;
+ }
+
+ gts_surface_foreach_vertex(PYGTS_SURFACE_AS_GTS_SURFACE(self),
+ (GtsFunc)rotate_point,&data);
+
+ if(data.errflag) return NULL;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+/* Helper for scale() */
+static void
+scale_point(GtsPoint *p, TransformData *data)
+{
+ if(data->errflag) return;
+
+ if(pygts_point_scale(p,data->dx,data->dy,data->dz)==-1)
+ data->errflag=TRUE;
+}
+
+static PyObject*
+scale(PygtsSurface* self, PyObject *args, PyObject *keywds)
+{
+ TransformData data;
+ static char *kwlist[] = {"dx", "dy", "dz", NULL};
+
+ SELF_CHECK
+
+ data.dx=1; data.dy=1; data.dz=1; data.a=0;
+ data.errflag = FALSE;
+
+ /* Parse the args */
+ if(! PyArg_ParseTupleAndKeywords(args, keywds,"|ddd", kwlist,
+ &(data.dx), &(data.dy), &(data.dz)) ) {
+ return NULL;
+ }
+
+ gts_surface_foreach_vertex(PYGTS_SURFACE_AS_GTS_SURFACE(self),
+ (GtsFunc)scale_point,&data);
+
+ if(data.errflag) return NULL;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+/* Helper for translate() */
+static void
+translate_point(GtsPoint *p, TransformData *data)
+{
+ if(data->errflag) return;
+
+ if(pygts_point_translate(p,data->dx,data->dy,data->dz)==-1)
+ data->errflag=TRUE;
+}
+
+static PyObject*
+translate(PygtsSurface* self, PyObject *args, PyObject *keywds)
+{
+ TransformData data;
+ static char *kwlist[] = {"dx", "dy", "dz", NULL};
+
+ SELF_CHECK
+
+ data.dx=0; data.dy=0; data.dz=0; data.a=0;
+ data.errflag = FALSE;
+
+ /* Parse the args */
+ if(! PyArg_ParseTupleAndKeywords(args, keywds,"|ddd", kwlist,
+ &(data.dx), &(data.dy), &(data.dz)) ) {
+ return NULL;
+ }
+
+ /* Make the call */
+ gts_surface_foreach_vertex(PYGTS_SURFACE_AS_GTS_SURFACE(self),
+ (GtsFunc)translate_point,&data);
+
+ if(data.errflag) return NULL;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+static PyObject*
+is_self_intersecting(PygtsSurface *self, PyObject *args)
+{
+ GtsSurface *s;
+ gboolean ret = FALSE;
+
+ SELF_CHECK
+
+ if( (s=gts_surface_is_self_intersecting(PYGTS_SURFACE_AS_GTS_SURFACE(self)))
+ != NULL) {
+ gts_object_destroy(GTS_OBJECT(s));
+ ret = TRUE;
+ }
+
+ if(ret) {
+ Py_INCREF(Py_True);
+ return Py_True;
+ }
+ else {
+ Py_INCREF(Py_False);
+ return Py_False;
+ }
+}
+
+
+static PyObject*
+cleanup(PygtsSurface *self, PyObject *args)
+{
+ GtsSurface *s;
+ gdouble threshold = 0.;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args,"|d", &threshold) ) {
+ return NULL;
+ }
+
+ s = PYGTS_SURFACE_AS_GTS_SURFACE(self);
+
+ /* Do the cleanup */
+ if( threshold != 0. ) {
+ pygts_vertex_cleanup(s,threshold);
+ }
+ pygts_edge_cleanup(s);
+ pygts_face_cleanup(s);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+static PyObject*
+coarsen(PygtsSurface *self, PyObject *args)
+{
+ guint n;
+ gdouble amin=0.;
+ GtsVolumeOptimizedParams params = {0.5,0.5,1.e-10};
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args,"i|d", &n, &amin) ) {
+ return NULL;
+ }
+
+ /* Make the call */
+ gts_surface_coarsen(PYGTS_SURFACE_AS_GTS_SURFACE(self),
+ (GtsKeyFunc)gts_volume_optimized_cost, ¶ms,
+ (GtsCoarsenFunc)gts_volume_optimized_vertex, ¶ms,
+ (GtsStopFunc)gts_coarsen_stop_number, &n, amin);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+/* Methods table */
+static PyMethodDef methods[] = {
+ {"is_ok", (PyCFunction)is_ok,
+ METH_NOARGS,
+ "True if this Surface s is OK. False otherwise.\n"
+ "\n"
+ "Signature: s.is_ok()\n"
+ },
+
+ {"add", (PyCFunction)add,
+ METH_VARARGS,
+ "Adds a Face f or Surface s2 to Surface s1.\n"
+ "\n"
+ "Signature: s1.add(f) or s2.add(f)\n"
+ },
+
+ {"remove", (PyCFunction)pygts_remove,
+ METH_VARARGS,
+ "Removes Face f from this Surface s.\n"
+ "\n"
+ "Signature: s.remove(f)\n"
+ },
+
+ {"copy", (PyCFunction)copy,
+ METH_VARARGS,
+ "Copys all Faces, Edges and Vertices of Surface s2 to Surface s1.\n"
+ "\n"
+ "Signature: s1.copy(s2)\n"
+ "\n"
+ "Returns s1.\n"
+ },
+
+ {"is_manifold", (PyCFunction)is_manifold,
+ METH_NOARGS,
+ "True if Surface s is a manifold, False otherwise.\n"
+ "\n"
+ "Signature: s.is_manifold()\n"
+ },
+
+ {"manifold_faces", (PyCFunction)manifold_faces,
+ METH_VARARGS,
+ "Returns the 2 manifold Faces of Edge e on this Surface s\n"
+ "if they exist, or None.\n"
+ "\n"
+ "Signature: s.manifold_faces(e)\n"
+ },
+
+ {"is_orientable", (PyCFunction)is_orientable,
+ METH_NOARGS,
+ "True if Faces in Surface s have compatible orientation,\n"
+ "False otherwise.\n"
+ "Note that a closed surface is also a manifold. Note that an\n"
+ "orientable surface is also a manifold.\n"
+ "\n"
+ "Signature: s.is_orientable()\n"
+ },
+
+ {"is_closed", (PyCFunction)is_closed,
+ METH_NOARGS,
+ "True if Surface s is closed, False otherwise.\n"
+ "Note that a closed Surface is also a manifold.\n"
+ "\n"
+ "Signature: s.is_closed()\n"
+ },
+
+ {"boundary", (PyCFunction)boundary,
+ METH_NOARGS,
+ "Returns a tuple of boundary Edges of Surface s.\n"
+ "\n"
+ "Signature: s.boundary()\n"
+ },
+
+ {"area", (PyCFunction)area,
+ METH_NOARGS,
+ "Returns the area of Surface s.\n"
+ "The area is taken as the sum of the signed areas of the Faces of s.\n"
+ "\n"
+ "Signature: s.area()\n"
+ },
+
+ {"volume", (PyCFunction)volume,
+ METH_NOARGS,
+ "Returns the signed volume of the domain bounded by the Surface s.\n"
+ "\n"
+ "Signature: s.volume()\n"
+ },
+
+ {"center_of_mass", (PyCFunction)center_of_mass,
+ METH_NOARGS,
+ "Returns the coordinates of the center of mass of Surface s.\n"
+ "\n"
+ "Signature: s.center_of_mass()\n"
+ },
+
+ {"center_of_area", (PyCFunction)center_of_area,
+ METH_NOARGS,
+ "Returns the coordinates of the center of area of Surface s.\n"
+ "\n"
+ "Signature: s.center_of_area()\n"
+ },
+
+ {"write", (PyCFunction)pygts_write,
+ METH_VARARGS,
+ "Saves Surface s to File f in GTS ascii format.\n"
+ "All the lines beginning with #! are ignored.\n"
+ "\n"
+ "Signature: s.write(f)\n"
+ },
+
+ {"write_oogl", (PyCFunction)pygts_write_oogl,
+ METH_VARARGS,
+ "Saves Surface s to File f in OOGL (Geomview) format.\n"
+ "\n"
+ "Signature: s.write_oogl(f)\n"
+ },
+
+ {"write_oogl_boundary", (PyCFunction)pygts_write_oogl_boundary,
+ METH_VARARGS,
+ "Saves boundary of Surface s to File f in OOGL (Geomview) format.\n"
+ "\n"
+ "Signature: s.write_oogl_boundary(f)\n"
+ },
+
+ {"write_vtk", (PyCFunction)pygts_write_vtk,
+ METH_VARARGS,
+ "Saves Surface s to File f in VTK format.\n"
+ "\n"
+ "Signature: s.write_vtk(f)\n"
+ },
+
+ {"fan_oriented", (PyCFunction)fan_oriented,
+ METH_VARARGS,
+ "Returns a tuple of outside Edges of the Faces fanning from\n"
+ "Vertex v on this Surface s. The Edges are given in \n"
+ "counter-clockwise order.\n"
+ "\n"
+ "Signature: s.fan_oriented(v)\n"
+ },
+
+ {"split", (PyCFunction)split,
+ METH_NOARGS,
+ "Splits a surface into a tuple of connected and manifold components.\n"
+ "\n"
+ "Signature: s.split()\n"
+ },
+
+ {"distance", (PyCFunction)distance,
+ METH_VARARGS,
+ "Calculates the distance between the faces of this Surface s1 and\n"
+ "the nearest Faces of other s2, and (if applicable) the distance\n"
+ "between the boundary of this Surface s1 and the nearest boundary\n"
+ "Edges of other s2.\n"
+ "\n"
+ "One or two dictionaries are returned (where applicable), the first\n"
+ "for the face range and the second for the boundary range. The\n"
+ "fields in each dictionary describe statistical results for each\n"
+ "population: {min,max,sum,sum2,mean,stddev,n}.\n"
+ "\n"
+ "Signature: s1.distance(s2) or s1.distance(s2,delta)\n"
+ "\n"
+ "The value delta is a spatial increment defined as the percentage\n"
+ "of the diagonal of the bounding box of s2 (default 0.1).\n"
+ },
+
+ {"strip", (PyCFunction)strip,
+ METH_NOARGS,
+ "Returns a tuple of strips, where each strip is a tuple of Faces\n"
+ "that are successive and have one edge in common.\n"
+ "\n"
+ "Signature: s.split()\n"
+ },
+
+ {"stats", (PyCFunction)stats,
+ METH_NOARGS,
+ "Returns statistics for this Surface f in a dict.\n"
+ "The stats include n_faces, n_incompatible_faces,, n_boundary_edges,\n"
+ "n_non_manifold_edges, and the statisics {min, max, sum, sum2, mean,\n"
+ "stddev, and n} for populations of edges_per_vertex and\n"
+ "faces_per_edge. Each of these names are dictionary keys.\n"
+ "\n"
+ "Signature: s.stats()\n"
+ },
+
+ {"quality_stats", (PyCFunction)quality_stats,
+ METH_NOARGS,
+ "Returns quality statistics for this Surface f in a dict.\n"
+ "The statistics include the {min, max, sum, sum2, mean, stddev,\n"
+ "and n} for populations of face_quality, face_area, edge_length,\n"
+ "and edge_angle. Each of these names are dictionary keys.\n"
+ "See Triangle.quality() for an explanation of the face_quality.\n"
+ "\n"
+ "Signature: s.quality_stats()\n"
+ },
+
+ {"tessellate", (PyCFunction)tessellate,
+ METH_NOARGS,
+ "Tessellate each face of this Surface s with 4 triangles.\n"
+ "The number of triangles is increased by a factor of 4.\n"
+ "\n"
+ "Signature: s.tessellate()\n"
+ },
+
+ {"vertices", (PyCFunction)vertices,
+ METH_NOARGS,
+ "Returns a tuple containing the vertices of Surface s.\n"
+ "\n"
+ "Signature: s.vertices()\n"
+ },
+
+ {"parent", (PyCFunction)parent,
+ METH_VARARGS,
+ "Returns Face on this Surface s that has Edge e, or None\n"
+ "if the Edge is not on this Surface.\n"
+ "\n"
+ "Signature: s.parent(e)\n"
+ },
+
+ {"edges", (PyCFunction)edges,
+ METH_VARARGS,
+ "Returns tuple of Edges on Surface s that have Vertex in list.\n"
+ "If a list is not given then all of the Edges are returned.\n"
+ "\n"
+ "Signature: s.edges(list) or s.edges()\n"
+ },
+
+ {"faces", (PyCFunction)faces,
+ METH_VARARGS,
+ "Returns tuple of Faces on Surface s that have Edge in list.\n"
+ "If a list is not given then all of the Faces are returned.\n"
+ "\n"
+ "Signature: s.faces(list) s.faces()\n"
+ },
+
+ {"face_indices", (PyCFunction)face_indices,
+ METH_VARARGS,
+ "Returns a tuple of 3-tuples containing Vertex indices for each Face\n"
+ "in Surface s. The index for each Vertex in a face corresponds to\n"
+ "where it is found in the Vertex tuple vs.\n"
+ "\n"
+ "Signature: s.face_indices(vs)\n"
+ },
+
+ {"intersection", (PyCFunction)intersection,
+ METH_VARARGS,
+ "Returns the intersection of this Surface s1 with Surface s2.\n"
+ "\n"
+ "Signature: s1.intersection(s2)\n"
+ },
+
+ {"union", (PyCFunction)pygts_union,
+ METH_VARARGS,
+ "Returns the union of this Surface s1 with Surface s2.\n"
+ "\n"
+ "Signature: s1.union(s2)\n"
+ },
+
+ {"difference", (PyCFunction)difference,
+ METH_VARARGS,
+ "Returns the difference of this Surface s1 with Surface s2.\n"
+ "\n"
+ "Signature: s1.difference(s2)\n"
+ },
+
+ {"rotate", (PyCFunction)rotate,
+ METH_VARARGS | METH_KEYWORDS,
+ "Rotates Surface s about vector dx,dy,dz and angle a.\n"
+ "The sense of the rotation is given by the right-hand-rule.\n"
+ "\n"
+ "Signature: s.rotate(dx,dy,dz,a)\n"
+ },
+
+ {"scale", (PyCFunction)scale,
+ METH_VARARGS | METH_KEYWORDS,
+ "Scales Surface s by vector dx,dy,dz.\n"
+ "\n"
+ "Signature: s.scale(dx=1,dy=1,dz=1)\n"
+ },
+
+ {"translate", (PyCFunction)translate,
+ METH_VARARGS | METH_KEYWORDS,
+ "Translates Surface s by vector dx,dy,dz.\n"
+ "\n"
+ "Signature: s.translate(dx=0,dy=0,dz=0)\n"
+ },
+
+ {"is_self_intersecting", (PyCFunction)is_self_intersecting,
+ METH_NOARGS,
+ "Returns True if this Surface s is self-intersecting.\n"
+ "False otherwise.\n"
+ "\n"
+ "Signature: s.is_self_intersecting()\n"
+ },
+
+ {"cleanup", (PyCFunction)cleanup,
+ METH_VARARGS,
+ "Cleans up the Vertices, Edges, and Faces on a Surface s.\n"
+ "\n"
+ "Signature: s.cleanup() or s.cleanup(threhold)\n"
+ "\n"
+ "If threhold is given, then Vertices that are spaced less than\n"
+ "the threshold are merged. Degenerate Edges and Faces are also\n"
+ "removed.\n"
+ },
+
+ {"coarsen", (PyCFunction)coarsen,
+ METH_VARARGS,
+ "Reduces the number of vertices on Surface s.\n"
+ "\n"
+ "Signature: s.coarsen(n) and s.coarsen(amin)\n"
+ "\n"
+ "n is the smallest number of desired edges (but you may get fewer).\n"
+ "amin is the smallest angle between Faces.\n"
+ },
+
+ {NULL} /* Sentinel */
+};
+
+
+/*-------------------------------------------------------------------------*/
+/* Attributes exported to python */
+
+static PyObject *
+get_Nvertices(PygtsSurface *self, void *closure)
+{
+ SELF_CHECK
+ return Py_BuildValue("i",
+ gts_surface_vertex_number(PYGTS_SURFACE_AS_GTS_SURFACE(self)));
+
+}
+
+
+static PyObject *
+get_Nedges(PygtsSurface *self, void *closure)
+{
+ SELF_CHECK
+ return Py_BuildValue("i",
+ gts_surface_edge_number(PYGTS_SURFACE_AS_GTS_SURFACE(self)));
+}
+
+
+static PyObject *
+get_Nfaces(PygtsSurface *self, void *closure)
+{
+ SELF_CHECK
+ return Py_BuildValue("i",
+ gts_surface_face_number(PYGTS_SURFACE_AS_GTS_SURFACE(self)));
+}
+
+/* Methods table */
+static PyGetSetDef getset[] = {
+ { "Nvertices", (getter)get_Nvertices, NULL,
+ "The number of unique vertices", NULL
+ },
+
+ { "Nedges", (getter)get_Nedges, NULL,
+ "The number of unique edges", NULL
+ },
+
+ { "Nfaces", (getter)get_Nfaces, NULL,
+ "The number of unique faces", NULL
+ },
+
+ {NULL} /* Sentinel */
+};
+
+
+/*-------------------------------------------------------------------------*/
+/* Python type methods */
+
+static void
+dealloc(PygtsSurface* self)
+{
+ if(self->traverse!=NULL) {
+ gts_surface_traverse_destroy(self->traverse);
+ }
+ self->traverse = NULL;
+
+ /* Chain up */
+ PygtsObjectType.tp_dealloc((PyObject*)self);
+}
+
+
+static PyObject *
+new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ PyObject *o;
+ PygtsObject *obj;
+ guint alloc_gtsobj = TRUE;
+
+ /* Parse the args */
+ if(kwds) {
+ o = PyDict_GetItemString(kwds,"alloc_gtsobj");
+ if(o==Py_False) {
+ alloc_gtsobj = FALSE;
+ }
+ if(o!=NULL) {
+ PyDict_DelItemString(kwds, "alloc_gtsobj");
+ }
+ }
+ if(kwds) {
+ Py_INCREF(Py_False);
+ PyDict_SetItemString(kwds,"alloc_gtsobj", Py_False);
+ }
+
+ /* Chain up */
+ obj = PYGTS_OBJECT(PygtsObjectType.tp_new(type,args,kwds));
+
+ PYGTS_SURFACE(obj)->traverse = NULL;
+
+ /* Allocate the gtsobj (if needed) */
+ if( alloc_gtsobj ) {
+ obj->gtsobj = GTS_OBJECT(gts_surface_new(gts_surface_class(),
+ gts_face_class(),
+ gts_edge_class(),
+ gts_vertex_class()));
+
+ if( obj->gtsobj == NULL ) {
+ PyErr_SetString(PyExc_MemoryError, "could not create Surface");
+ return NULL;
+ }
+
+ pygts_object_register(obj);
+ }
+
+ return (PyObject*)obj;
+}
+
+
+static int
+init(PygtsSurface *self, PyObject *args, PyObject *kwds)
+{
+ gint ret;
+
+ if( (ret = PygtsObjectType.tp_init((PyObject*)self,args,kwds)) != 0 ) {
+ return ret;
+ }
+
+ return 0;
+}
+
+
+/* Helper function for iter */
+static void
+get_f0(GtsFace *f,GtsFace **f0)
+{
+ if(*f0==NULL) *f0 = f;
+}
+
+PyObject*
+iter(PygtsSurface *self)
+{
+ GtsFace* f0=NULL;
+
+ SELF_CHECK
+
+ if(self->traverse!=NULL) {
+ gts_surface_traverse_destroy(self->traverse);
+ self->traverse = NULL;
+ }
+
+ /* Assign a "first" face */
+ gts_surface_foreach_face(PYGTS_SURFACE_AS_GTS_SURFACE(self),
+ (GtsFunc)get_f0,&f0);
+ if(f0==NULL) {
+ PyErr_SetString(PyExc_RuntimeError, "No faces to traverse");
+ return NULL;
+ }
+
+ if( (self->traverse=gts_surface_traverse_new(
+ PYGTS_SURFACE_AS_GTS_SURFACE(self),f0)) == NULL ) {
+ PyErr_SetString(PyExc_MemoryError, "could not create Traverse");
+ return NULL;
+ }
+
+ Py_INCREF((PyObject*)self);
+ return (PyObject*)self;
+}
+
+
+PyObject*
+iternext(PygtsSurface *self)
+{
+ PygtsFace *face;
+ GtsFace *f;
+
+ SELF_CHECK
+
+ if( self->traverse == NULL ) {
+ PyErr_SetString(PyExc_RuntimeError, "iterator not initialized");
+ return NULL;
+ }
+
+ /* Get the next face */
+ if( (f = gts_surface_traverse_next(self->traverse,NULL)) == NULL ) {
+ gts_surface_traverse_destroy(self->traverse);
+ self->traverse = NULL;
+ PyErr_SetString(PyExc_StopIteration, "No more faces");
+ return NULL;
+ }
+
+ if( (face = pygts_face_new(f)) == NULL ) {
+ return NULL;
+ }
+
+ return (PyObject*)face;
+}
+
+
+/* Methods table */
+PyTypeObject PygtsSurfaceType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "gts.Surface", /* tp_name */
+ sizeof(PygtsSurface), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* 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 |
+ Py_TPFLAGS_HAVE_ITER, /* tp_flags */
+ "Surface object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ (getiterfunc)iter, /* tp_iter */
+ (iternextfunc)iternext, /* tp_iternext */
+ methods, /* tp_methods */
+ 0, /* tp_members */
+ getset, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)init, /* tp_init */
+ 0, /* tp_alloc */
+ (newfunc)new /* tp_new */
+};
+
+
+/*-------------------------------------------------------------------------*/
+/* Pygts functions */
+
+gboolean
+pygts_surface_check(PyObject* o)
+{
+ if(! PyObject_TypeCheck(o, &PygtsSurfaceType)) {
+ return FALSE;
+ }
+ else {
+#if PYGTS_DEBUG
+ return pygts_surface_is_ok(PYGTS_SURFACE(o));
+#else
+ return TRUE;
+#endif
+ }
+}
+
+
+/* Helper function */
+static void
+face_is_ok(GtsFace *f,gboolean *ret)
+{
+ if( !pygts_gts_triangle_is_ok(GTS_TRIANGLE(f)) ) {
+ *ret = FALSE;
+ }
+}
+
+
+gboolean
+pygts_surface_is_ok(PygtsSurface *s)
+{
+ PygtsObject *obj;
+ gboolean ret=TRUE;
+
+ obj = PYGTS_OBJECT(s);
+
+ if(!pygts_object_is_ok(PYGTS_OBJECT(s))) return FALSE;
+ g_return_val_if_fail(obj->gtsobj_parent==NULL,FALSE);
+
+ /* Check all of the faces this surface contains */
+ gts_surface_foreach_face(GTS_SURFACE(obj->gtsobj),(GtsFunc)face_is_ok,&ret);
+ if( ret == FALSE ) return FALSE;
+
+ return TRUE;
+}
+
+
+PygtsSurface *
+pygts_surface_new(GtsSurface *s) {
+ PyObject *args, *kwds;
+ PygtsObject *surface;
+
+ /* Check for Surface in the object table */
+ if( (surface = PYGTS_OBJECT(g_hash_table_lookup(obj_table,GTS_OBJECT(s))))
+ !=NULL ) {
+ Py_INCREF(surface);
+ return PYGTS_SURFACE(surface);
+ }
+
+ /* Build a new Surface */
+ args = Py_BuildValue("()");
+ kwds = Py_BuildValue("{s:O}","alloc_gtsobj",Py_False);
+ surface = PYGTS_OBJECT(PygtsSurfaceType.tp_new(&PygtsSurfaceType,args,kwds));
+ Py_DECREF(args);
+ Py_DECREF(kwds);
+ if( surface == NULL ) {
+ PyErr_SetString(PyExc_MemoryError, "could not create Surface");
+ return NULL;
+ }
+ surface->gtsobj = GTS_OBJECT(s);
+
+ /* Register and return */
+ pygts_object_register(surface);
+ return PYGTS_SURFACE(surface);
+}
Added: trunk/lib/py/pygts-0.3.1/surface.h
===================================================================
--- trunk/lib/py/pygts-0.3.1/surface.h 2009-06-24 17:04:39 UTC (rev 1813)
+++ trunk/lib/py/pygts-0.3.1/surface.h 2009-06-24 22:06:24 UTC (rev 1814)
@@ -0,0 +1,48 @@
+/* pygts - python package for the manipulation of triangulated surfaces
+ *
+ * Copyright (C) 2009 Thomas J. Duck
+ * All rights reserved.
+ *
+ * Thomas J. Duck <tom.duck@xxxxxx>
+ * Department of Physics and Atmospheric Science,
+ * Dalhousie University, Halifax, Nova Scotia, Canada, B3H 3J5
+ *
+ * NOTICE
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PYGTS_SURFACE_H__
+#define __PYGTS_SURFACE_H__
+
+typedef struct _PygtsSurface PygtsSurface;
+
+#define PYGTS_SURFACE(o) ((PygtsSurface*)o)
+
+#define PYGTS_SURFACE_AS_GTS_SURFACE(o) (GTS_SURFACE(PYGTS_OBJECT(o)->gtsobj))
+
+struct _PygtsSurface {
+ PygtsObject o;
+ GtsSurfaceTraverse* traverse;
+};
+
+extern PyTypeObject PygtsSurfaceType;
+
+gboolean pygts_surface_check(PyObject* o);
+gboolean pygts_surface_is_ok(PygtsSurface *s);
+PygtsSurface* pygts_surface_new(GtsSurface *s);
+
+#endif /* __PYGTS_SURFACE_H__ */
Added: trunk/lib/py/pygts-0.3.1/triangle.c
===================================================================
--- trunk/lib/py/pygts-0.3.1/triangle.c 2009-06-24 17:04:39 UTC (rev 1813)
+++ trunk/lib/py/pygts-0.3.1/triangle.c 2009-06-24 22:06:24 UTC (rev 1814)
@@ -0,0 +1,1049 @@
+/* pygts - python package for the manipulation of triangulated surfaces
+ *
+ * Copyright (C) 2009 Thomas J. Duck
+ * All rights reserved.
+ *
+ * Thomas J. Duck <tom.duck@xxxxxx>
+ * Department of Physics and Atmospheric Science,
+ * Dalhousie University, Halifax, Nova Scotia, Canada, B3H 3J5
+ *
+ * NOTICE
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "pygts.h"
+
+
+#if PYGTS_DEBUG
+ #define SELF_CHECK if(!pygts_triangle_check((PyObject*)self)) { \
+ PyErr_SetString(PyExc_RuntimeError, \
+ "problem with self object (internal error)"); \
+ return NULL; \
+ }
+#else
+ #define SELF_CHECK
+#endif
+
+
+/*-------------------------------------------------------------------------*/
+/* Methods exported to python */
+
+static PyObject*
+is_ok(PygtsTriangle *self, PyObject *args)
+{
+ if(pygts_triangle_is_ok(self)) {
+ Py_INCREF(Py_True);
+ return Py_True;
+ }
+ else {
+ Py_INCREF(Py_False);
+ return Py_False;
+ }
+}
+
+
+static PyObject*
+area(PygtsTriangle *self, PyObject *args)
+{
+ SELF_CHECK
+
+ return Py_BuildValue("d",
+ gts_triangle_area(PYGTS_TRIANGLE_AS_GTS_TRIANGLE(self)));
+}
+
+
+static PyObject*
+perimeter(PygtsTriangle *self, PyObject *args)
+{
+ SELF_CHECK
+
+ return Py_BuildValue("d",
+ gts_triangle_perimeter(PYGTS_TRIANGLE_AS_GTS_TRIANGLE(self)));
+}
+
+
+static PyObject*
+quality(PygtsTriangle *self, PyObject *args)
+{
+ SELF_CHECK
+
+ return Py_BuildValue("d",
+ gts_triangle_quality(PYGTS_TRIANGLE_AS_GTS_TRIANGLE(self)));
+}
+
+
+static PyObject*
+normal(PygtsTriangle *self, PyObject *args)
+{
+ gdouble x,y,z;
+
+ SELF_CHECK
+
+ gts_triangle_normal(PYGTS_TRIANGLE_AS_GTS_TRIANGLE(self),&x,&y,&z);
+ return Py_BuildValue("ddd",x,y,z);
+}
+
+
+static PyObject*
+revert(PygtsTriangle *self, PyObject *args)
+{
+ SELF_CHECK
+
+ gts_triangle_revert(PYGTS_TRIANGLE_AS_GTS_TRIANGLE(self));
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+static PyObject*
+orientation(PygtsTriangle *self, PyObject *args)
+{
+ SELF_CHECK
+
+ return Py_BuildValue("d",
+ gts_triangle_orientation(PYGTS_TRIANGLE_AS_GTS_TRIANGLE(self)));
+}
+
+
+static PyObject*
+angle(PygtsTriangle* self, PyObject *args)
+{
+ PyObject *t_;
+ PygtsTriangle *t;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &t_) ) {
+ return NULL;
+ }
+
+ /* Convert to PygtsObjects */
+ if(!pygts_triangle_check(t_)) {
+ PyErr_SetString(PyExc_TypeError,"expected a Triangle");
+ return NULL;
+ }
+ t = PYGTS_TRIANGLE(t_);
+
+ return Py_BuildValue("d",
+ gts_triangles_angle(PYGTS_TRIANGLE_AS_GTS_TRIANGLE(self),
+ PYGTS_TRIANGLE_AS_GTS_TRIANGLE(t)));
+}
+
+
+static PyObject*
+is_compatible(PygtsTriangle *self, PyObject *args)
+{
+ PyObject *t2_;
+ PygtsTriangle *t2;
+ GtsEdge *e;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &t2_) ) {
+ return NULL;
+ }
+
+ /* Convert to PygtsObjects */
+ if(!pygts_triangle_check(t2_)) {
+ PyErr_SetString(PyExc_TypeError,"expected a Triangle");
+ return NULL;
+ }
+ t2 = PYGTS_TRIANGLE(t2_);
+
+ /* Get the common edge */
+ if( (e = gts_triangles_common_edge(PYGTS_TRIANGLE_AS_GTS_TRIANGLE(self),
+ PYGTS_TRIANGLE_AS_GTS_TRIANGLE(t2)))
+ == NULL ) {
+ PyErr_SetString(PyExc_RuntimeError,"Triangles do not share common edge");
+ return NULL;
+ }
+
+ if( gts_triangles_are_compatible(PYGTS_TRIANGLE_AS_GTS_TRIANGLE(self),
+ PYGTS_TRIANGLE_AS_GTS_TRIANGLE(t2),e) ) {
+ Py_INCREF(Py_True);
+ return Py_True;
+ }
+ else {
+ Py_INCREF(Py_False);
+ return Py_False;
+ }
+}
+
+
+static PyObject*
+common_edge(PygtsTriangle *self, PyObject *args)
+{
+ PyObject *t2_;
+ PygtsTriangle *t2;
+ GtsEdge *e;
+ PygtsEdge *edge;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &t2_) ) {
+ return NULL;
+ }
+
+ /* Convert to PygtsObjects */
+ if(!pygts_triangle_check(t2_)) {
+ PyErr_SetString(PyExc_TypeError,"expected a Triangle");
+ return NULL;
+ }
+ t2 = PYGTS_TRIANGLE(t2_);
+
+ /* Get the common edge */
+ if( (e = gts_triangles_common_edge(PYGTS_TRIANGLE_AS_GTS_TRIANGLE(self),
+ PYGTS_TRIANGLE_AS_GTS_TRIANGLE(t2)))
+ == NULL ) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ if( (edge = pygts_edge_new(GTS_EDGE(e))) == NULL ) {
+ return NULL;
+ }
+
+ return (PyObject*)edge;
+}
+
+
+static PyObject*
+opposite(PygtsTriangle *self, PyObject *args)
+{
+ PyObject *o_;
+ PygtsEdge *e=NULL;
+ PygtsVertex *v=NULL;
+ GtsVertex *vertex=NULL,*v1,*v2,*v3;
+ GtsEdge *edge=NULL;
+ GtsTriangle *triangle;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &o_) ) {
+ return NULL;
+ }
+
+ /* Convert to PygtsObjects */
+ if(pygts_edge_check(o_)) {
+ e = PYGTS_TRIANGLE(o_);
+ }
+ else {
+ if(pygts_vertex_check(o_)) {
+ v = PYGTS_TRIANGLE(o_);
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError,"expected an Edge or a Vertex");
+ return NULL;
+ }
+ }
+
+ /* Error check */
+ triangle = PYGTS_TRIANGLE_AS_GTS_TRIANGLE(self);
+ if( e!=NULL ) {
+ edge = PYGTS_EDGE_AS_GTS_EDGE(e);
+ if(! ((triangle->e1==edge)||(triangle->e2==edge)||(triangle->e3==edge)) ) {
+ PyErr_SetString(PyExc_RuntimeError,"Edge not in Triangle");
+ return NULL;
+ }
+ }
+ else {
+ vertex = PYGTS_VERTEX_AS_GTS_VERTEX(v);
+ gts_triangle_vertices(triangle,&v1,&v2,&v3);
+ if(! ((vertex==v1)||(vertex==v2)||(vertex==v3)) ) {
+ PyErr_SetString(PyExc_RuntimeError,"Vertex not in Triangle");
+ return NULL;
+ }
+ }
+
+ /* Get the opposite and return */
+ if( e!=NULL) {
+ vertex = gts_triangle_vertex_opposite(triangle, edge);
+ if( (v = pygts_vertex_new(vertex)) == NULL ) {
+ return NULL;
+ }
+ return (PyObject*)v;
+ }
+ else{
+ edge = gts_triangle_edge_opposite(triangle, vertex);
+ if( (e = pygts_edge_new(edge)) == NULL ) {
+ return NULL;
+ }
+ return (PyObject*)e;
+ }
+}
+
+
+static PyObject *
+vertices(PygtsTriangle *self,PyObject *args)
+{
+ GtsVertex *v1_,*v2_,*v3_;
+ PygtsObject *v1,*v2,*v3;
+
+ SELF_CHECK
+
+ /* Get the vertices */
+ gts_triangle_vertices(PYGTS_TRIANGLE_AS_GTS_TRIANGLE(self),
+ &v1_, &v2_, &v3_);
+
+ if( (v1 = pygts_vertex_new(v1_)) == NULL ) {
+ return NULL;
+ }
+
+ if( (v2 = pygts_vertex_new(v2_)) == NULL ) {
+ Py_DECREF(v1);
+ return NULL;
+ }
+
+ if( (v3 = pygts_vertex_new(v3_)) == NULL ) {
+ Py_DECREF(v1);
+ Py_DECREF(v2);
+ return NULL;
+ }
+
+ return Py_BuildValue("OOO",v1,v2,v3);
+}
+
+
+static PyObject *
+vertex(PygtsTriangle *self,PyObject *args)
+{
+ GtsVertex *v1_;
+ PygtsObject *v1;
+
+ SELF_CHECK
+
+ /* Get the vertices */
+ v1_ = gts_triangle_vertex(PYGTS_TRIANGLE_AS_GTS_TRIANGLE(self));
+
+ if( (v1 = pygts_vertex_new(v1_)) == NULL ) {
+ return NULL;
+ }
+
+ return (PyObject*)v1;
+}
+
+
+static PyObject *
+circumcenter(PygtsTriangle *self,PyObject *args)
+{
+ PygtsVertex *v;
+ GtsVertex *vertex;
+
+ SELF_CHECK
+
+ /* Get the Vertex */
+ vertex = GTS_VERTEX(
+ gts_triangle_circumcircle_center(
+ PYGTS_TRIANGLE_AS_GTS_TRIANGLE(self),
+ GTS_POINT_CLASS(gts_vertex_class())));
+
+ if( vertex == NULL ) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ if( (v = pygts_vertex_new(vertex)) == NULL ) {
+ return NULL;
+ }
+
+ return (PyObject*)v;
+}
+
+
+static PyObject *
+is_stabbed(PygtsTriangle *self,PyObject *args)
+{
+ PyObject *p_;
+ PygtsVertex *p;
+ GtsObject *obj;
+ PygtsVertex *vertex;
+ PygtsEdge *edge;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &p_) ) {
+ return NULL;
+ }
+
+ /* Convert to PygtsObjects */
+ if(!pygts_point_check(p_)) {
+ PyErr_SetString(PyExc_TypeError,"expected a Point");
+ return NULL;
+ }
+ p = PYGTS_POINT(p_);
+
+ obj = gts_triangle_is_stabbed(PYGTS_TRIANGLE_AS_GTS_TRIANGLE(self),
+ GTS_POINT(PYGTS_OBJECT(p)->gtsobj),
+ NULL);
+
+ if( obj == NULL ) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ if(GTS_IS_VERTEX(obj)) {
+ if( (vertex = pygts_vertex_new(GTS_VERTEX(obj))) == NULL ) {
+ return NULL;
+ }
+ return (PyObject*)vertex;
+ }
+
+ if(GTS_IS_EDGE(obj)) {
+ if( (edge = pygts_edge_new(GTS_EDGE(obj))) == NULL ) {
+ return NULL;
+ }
+ return (PyObject*)edge;
+ }
+
+ Py_INCREF(self);
+ return (PyObject*)self;
+}
+
+
+static PyObject *
+interpolate_height(PygtsTriangle *self,PyObject *args)
+{
+ PyObject *p_;
+ PygtsPoint *p;
+ GtsPoint point;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &p_) ) {
+ return NULL;
+ }
+
+ /* Convert to PygtsObjects */
+ if(!pygts_point_check(p_)) {
+ PyErr_SetString(PyExc_TypeError,"expected a Point");
+ return NULL;
+ }
+ p = PYGTS_POINT(p_);
+
+ point.x = PYGTS_POINT_AS_GTS_POINT(p)->x;
+ point.y = PYGTS_POINT_AS_GTS_POINT(p)->y;
+
+ gts_triangle_interpolate_height(PYGTS_TRIANGLE_AS_GTS_TRIANGLE(self),
+ &point);
+
+ return Py_BuildValue("d",point.z);
+}
+
+
+/* Methods table */
+static PyMethodDef methods[] = {
+ {"is_ok", (PyCFunction)is_ok,
+ METH_NOARGS,
+ "True if this Triangle t is non-degenerate and non-duplicate.\n"
+ "False otherwise.\n"
+ "\n"
+ "Signature: t.is_ok()\n"
+ },
+
+ {"area", (PyCFunction)area,
+ METH_NOARGS,
+ "Returns the area of Triangle t.\n"
+ "\n"
+ "Signature: t.area()\n"
+ },
+
+ {"perimeter", (PyCFunction)perimeter,
+ METH_NOARGS,
+ "Returns the perimeter of Triangle t.\n"
+ "\n"
+ "Signature: t.perimeter()\n"
+ },
+
+ {"quality", (PyCFunction)quality,
+ METH_NOARGS,
+ "Returns the quality of Triangle t.\n"
+ "\n"
+ "The quality of a triangle is defined as the ratio of the square\n"
+ "root of its surface area to its perimeter relative to this same\n"
+ "ratio for an equilateral triangle with the same area. The quality\n"
+ "is then one for an equilateral triangle and tends to zero for a\n"
+ "very stretched triangle."
+ "\n"
+ "Signature: t.quality()\n"
+ },
+
+ {"normal", (PyCFunction)normal,
+ METH_NOARGS,
+ "Returns a tuple of coordinates of the oriented normal of Triangle t\n"
+ "as the cross-product of two edges, using the left-hand rule. The\n"
+ "normal is not normalized. If this triangle is part of a closed and\n"
+ "oriented surface, the normal points to the outside of the surface.\n"
+ "\n"
+ "Signature: t.normal()\n"
+ },
+
+ {"revert", (PyCFunction)revert,
+ METH_NOARGS,
+ "Changes the orientation of triangle t, turning it inside out.\n"
+ "\n"
+ "Signature: t.revert()\n"
+ },
+
+ {"orientation", (PyCFunction)orientation,
+ METH_NOARGS,
+ "Determines orientation of the plane (x,y) projection of Triangle t\n"
+ "\n"
+ "Signature: t.orientation()\n"
+ "\n"
+ "Returns a positive value if Points p1, p2 and p3 in Triangle t\n"
+ "appear in counterclockwise order, a negative value if they appear\n"
+ "in clockwise order and zero if they are colinear.\n"
+ },
+
+ {"angle", (PyCFunction)angle,
+ METH_VARARGS,
+ "Returns the angle (radians) between Triangles t1 and t2\n"
+ "\n"
+ "Signature: t1.angle(t2)\n"
+ },
+
+ {"is_compatible", (PyCFunction)is_compatible,
+ METH_VARARGS,
+ "True if this triangle t1 and other t2 are compatible;\n"
+ "otherwise False.\n"
+ "\n"
+ "Checks if this triangle t1 and other t2, which share a common\n"
+ "Edge, can be part of the same surface without conflict in the\n"
+ "surface normal orientation.\n"
+ "\n"
+ "Signature: t1.is_compatible(t2)\n"
+ },
+
+ {"common_edge", (PyCFunction)common_edge,
+ METH_VARARGS,
+ "Returns Edge common to both this Triangle t1 and other t2.\n"
+ "Returns None if the triangles do not share an Edge.\n"
+ "\n"
+ "Signature: t1.common_edge(t2)\n"
+ },
+
+ {"opposite", (PyCFunction)opposite,
+ METH_VARARGS,
+ "Returns Vertex opposite to Edge e or Edge opposite to Vertex v\n"
+ "for this Triangle t.\n"
+ "\n"
+ "Signature: t.opposite(e) or t.opposite(v)\n"
+ },
+
+ {"vertices", (PyCFunction)vertices,
+ METH_NOARGS,
+ "Returns the three oriented set of vertices in Triangle t.\n"
+ "\n"
+ "Signature: t.vertices()\n"
+ },
+
+ {"vertex", (PyCFunction)vertex,
+ METH_NOARGS,
+ "Returns the Vertex of this Triangle t not in t.e1.\n"
+ "\n"
+ "Signature: t.vertex()\n"
+ },
+
+ {"circumcenter", (PyCFunction)circumcenter,
+ METH_NOARGS,
+ "Returns a Vertex at the center of the circumscribing circle of\n"
+ "this Triangle t, or None if the circumscribing circle is not\n"
+ "defined.\n"
+ "\n"
+ "Signature: t.circumcircle_center()\n"
+ },
+
+ {"is_stabbed", (PyCFunction)is_stabbed,
+ METH_VARARGS,
+ "Returns the component of this Triangle t that is stabbed by a\n"
+ "ray projecting from Point p to z=infinity. The result\n"
+ "can be this Triangle t, one of its Edges or Vertices, or None.\n"
+ "If the ray is contained in the plan of this Triangle then None is\n"
+ "also returned.\n"
+ "\n"
+ "Signature: t.is_stabbed(p)\n"
+ },
+
+ {"interpolate_height", (PyCFunction)interpolate_height,
+ METH_VARARGS,
+ "Returns the height of the plane defined by Triangle t at Point p.\n"
+ "Only the x- and y-coordinates of p are considered.\n"
+ "\n"
+ "Signature: t.interpolate_height(p)\n"
+ },
+
+ {NULL} /* Sentinel */
+};
+
+
+/*-------------------------------------------------------------------------*/
+/* Attributes exported to python */
+
+static PyObject *
+get_e1(PygtsTriangle *self, void *closure)
+{
+ PygtsEdge *e1;
+
+ SELF_CHECK
+
+ if( (e1=pygts_edge_new(PYGTS_TRIANGLE_AS_GTS_TRIANGLE(self)->e1)) == NULL ) {
+ return NULL;
+ }
+
+ return (PyObject *)e1;
+}
+
+
+static PyObject *
+get_e2(PygtsTriangle *self, void *closure)
+{
+ PygtsEdge *e2;
+
+ SELF_CHECK
+
+ if( (e2=pygts_edge_new(PYGTS_TRIANGLE_AS_GTS_TRIANGLE(self)->e2)) == NULL ) {
+ return NULL;
+ }
+
+ return (PyObject *)e2;
+}
+
+
+static PyObject *
+get_e3(PygtsTriangle *self, void *closure)
+{
+ PygtsEdge *e3;
+
+ SELF_CHECK
+
+ if( (e3=pygts_edge_new(PYGTS_TRIANGLE_AS_GTS_TRIANGLE(self)->e3)) == NULL ) {
+ return NULL;
+ }
+
+ return (PyObject *)e3;
+}
+
+
+/* Methods table */
+static PyGetSetDef getset[] = {
+ {"e1", (getter)get_e1, NULL, "Edge 1", NULL},
+
+ {"e2", (getter)get_e2, NULL, "Edge 2", NULL},
+
+ {"e3", (getter)get_e3, NULL, "Edge 3", NULL},
+
+ {NULL} /* Sentinel */
+};
+
+
+/*-------------------------------------------------------------------------*/
+/* Python type methods */
+
+static PyObject *
+new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ PyObject *o;
+ PygtsObject *obj;
+ guint alloc_gtsobj = TRUE;
+ PyObject *o1_,*o2_,*o3_;
+ GtsVertex *v1=NULL, *v2=NULL, *v3=NULL;
+ GtsEdge *e1=NULL,*e2=NULL,*e3=NULL,*e;
+ GtsSegment *s1,*s2,*s3;
+ gboolean flag=FALSE; /* Flag when the args are gts.Point objects */
+ GtsTriangle *t,*t_;
+ guint N;
+
+ /* Parse the args */
+ if(kwds) {
+ o = PyDict_GetItemString(kwds,"alloc_gtsobj");
+ if(o==Py_False) {
+ alloc_gtsobj = FALSE;
+ }
+ if(o!=NULL) {
+ PyDict_DelItemString(kwds, "alloc_gtsobj");
+ }
+ }
+ if(kwds) {
+ Py_INCREF(Py_False);
+ PyDict_SetItemString(kwds,"alloc_gtsobj", Py_False);
+ }
+
+ /* Allocate the gtsobj (if needed) */
+ if( alloc_gtsobj ) {
+
+ /* Parse the args */
+ if( (N = PyTuple_Size(args)) < 3 ) {
+ PyErr_SetString(PyExc_TypeError,"expected three Edges or three Vertices");
+ return NULL;
+ }
+ o1_ = PyTuple_GET_ITEM(args,0);
+ o2_ = PyTuple_GET_ITEM(args,1);
+ o3_ = PyTuple_GET_ITEM(args,2);
+
+ /* Convert to PygtsObjects */
+ if( pygts_edge_check(o1_) ) {
+ e1 = PYGTS_EDGE_AS_GTS_EDGE(o1_);
+ }
+ else {
+ if( pygts_vertex_check(o1_) ) {
+ v1 = PYGTS_VERTEX_AS_GTS_VERTEX(o1_);
+ flag = TRUE;
+ }
+ }
+
+ if( pygts_edge_check(o2_) ) {
+ e2 = PYGTS_EDGE_AS_GTS_EDGE(o2_);
+ }
+ else {
+ if( pygts_vertex_check(o2_) ) {
+ v2 = PYGTS_VERTEX_AS_GTS_VERTEX(o2_);
+ flag = TRUE;
+ }
+ }
+
+ if( pygts_edge_check(o3_) ) {
+ e3 = PYGTS_EDGE_AS_GTS_EDGE(o3_);
+ }
+ else {
+ if(pygts_vertex_check(o3_)) {
+ v3 = PYGTS_VERTEX_AS_GTS_VERTEX(o3_);
+ flag = TRUE;
+ }
+ }
+
+ /* Check for three edges or three vertices */
+ if( !((e1!=NULL && e2!=NULL && e3!=NULL) ||
+ (v1!=NULL && v2!=NULL && v3!=NULL)) ) {
+ PyErr_SetString(PyExc_TypeError,"expected three Edges or three Vertices");
+ return NULL;
+ }
+ if( (v1==v2 || v2==v3 || v1==v3) && v1!=NULL ) {
+ PyErr_SetString(PyExc_ValueError,"three Vertices must be different");
+ return NULL;
+ }
+
+ /* Get gts edges */
+ if(flag) {
+
+ /* Create gts edges */
+ if( (e1 = gts_edge_new(gts_edge_class(),v1,v2)) == NULL ) {
+ PyErr_SetString(PyExc_MemoryError, "could not create Edge");
+ return NULL;
+ }
+ if( (e2 = gts_edge_new(gts_edge_class(),v2,v3)) == NULL ) {
+ PyErr_SetString(PyExc_MemoryError, "could not create Edge");
+ gts_object_destroy(GTS_OBJECT(e1));
+ return NULL;
+ }
+ if( (e3 = gts_edge_new(gts_edge_class(),v3,v1)) == NULL ) {
+ PyErr_SetString(PyExc_MemoryError, "could not create Edge");
+ gts_object_destroy(GTS_OBJECT(e1));
+ gts_object_destroy(GTS_OBJECT(e2));
+ return NULL;
+ }
+
+ /* Check for duplicates */
+ if( (e = gts_edge_is_duplicate(e1)) != NULL ) {
+ gts_object_destroy(GTS_OBJECT(e1));
+ e1 = e;
+ }
+ if( (e = gts_edge_is_duplicate(e2)) != NULL ) {
+ gts_object_destroy(GTS_OBJECT(e2));
+ e2 = e;
+ }
+ if( (e = gts_edge_is_duplicate(e3)) != NULL ) {
+ gts_object_destroy(GTS_OBJECT(e3));
+ e3 = e;
+ }
+ }
+
+ /* Check that edges connect with common vertices */
+ s1 = GTS_SEGMENT(e1);
+ s2 = GTS_SEGMENT(e2);
+ s3 = GTS_SEGMENT(e3);
+ if( !((s1->v1==s3->v2 && s1->v2==s2->v1 && s2->v2==s3->v1) ||
+ (s1->v1==s3->v2 && s1->v2==s2->v2 && s2->v1==s3->v1) ||
+ (s1->v1==s3->v1 && s1->v2==s2->v1 && s2->v2==s3->v2) ||
+ (s1->v2==s3->v2 && s1->v1==s2->v1 && s2->v2==s3->v1) ||
+ (s1->v1==s3->v1 && s1->v2==s2->v2 && s2->v1==s3->v2) ||
+ (s1->v2==s3->v2 && s1->v1==s2->v2 && s2->v1==s3->v1) ||
+ (s1->v2==s3->v1 && s1->v1==s2->v1 && s2->v2==s3->v2) ||
+ (s1->v2==s3->v1 && s1->v1==s2->v2 && s2->v1==s3->v2)) ) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "Edges in triangle must connect");
+ if(!g_hash_table_lookup(obj_table,GTS_OBJECT(e1))) {
+ gts_object_destroy(GTS_OBJECT(e1));
+ }
+ if(!g_hash_table_lookup(obj_table,GTS_OBJECT(e1))) {
+ gts_object_destroy(GTS_OBJECT(e2));
+ }
+ if(!g_hash_table_lookup(obj_table,GTS_OBJECT(e1))) {
+ gts_object_destroy(GTS_OBJECT(e3));
+ }
+ return NULL;
+ }
+
+ /* Create the GtsTriangle */
+ if( (t = gts_triangle_new(gts_triangle_class(),e1,e2,e3)) == NULL ) {
+ PyErr_SetString(PyExc_MemoryError, "could not create Face");
+ if(!g_hash_table_lookup(obj_table,GTS_OBJECT(e1))) {
+ gts_object_destroy(GTS_OBJECT(e1));
+ }
+ if(!g_hash_table_lookup(obj_table,GTS_OBJECT(e1))) {
+ gts_object_destroy(GTS_OBJECT(e2));
+ }
+ if(!g_hash_table_lookup(obj_table,GTS_OBJECT(e1))) {
+ gts_object_destroy(GTS_OBJECT(e3));
+ }
+ return NULL;
+ }
+
+ /* Check for duplicate */
+ t_ = gts_triangle_is_duplicate(GTS_TRIANGLE(t));
+ if( t_ != NULL ) {
+ gts_object_destroy(GTS_OBJECT(t));
+ t = t_;
+ }
+
+ /* If corresponding PyObject found in object table, we are done */
+ if( (obj=g_hash_table_lookup(obj_table,GTS_OBJECT(t))) != NULL ) {
+ Py_INCREF(obj);
+ return (PyObject*)obj;
+ }
+ }
+
+ /* Chain up */
+ obj = PYGTS_OBJECT(PygtsObjectType.tp_new(type,args,kwds));
+
+ if( alloc_gtsobj ) {
+ obj->gtsobj = GTS_OBJECT(t);
+ pygts_object_register(PYGTS_OBJECT(obj));
+ }
+
+ return (PyObject*)obj;
+}
+
+
+static int
+init(PygtsTriangle *self, PyObject *args, PyObject *kwds)
+{
+ gint ret;
+
+ /* Chain up */
+ if( (ret=PygtsObjectType.tp_init((PyObject*)self,args,kwds)) != 0 ){
+ return ret;
+ }
+
+#if PYGTS_DEBUG
+ if(!pygts_triangle_check((PyObject*)self)) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "problem with self object (internal error)");
+ return -1;
+ }
+#endif
+
+ return 0;
+}
+
+
+static int
+compare(PyObject *o1, PyObject *o2)
+{
+ GtsTriangle *t1, *t2;
+
+ if( !(pygts_triangle_check(o1) && pygts_triangle_check(o2)) ) {
+ return -1;
+ }
+ t1 = PYGTS_TRIANGLE_AS_GTS_TRIANGLE(o1);
+ t2 = PYGTS_TRIANGLE_AS_GTS_TRIANGLE(o2);
+
+ return pygts_triangle_compare(t1,t2);
+}
+
+
+/* Methods table */
+PyTypeObject PygtsTriangleType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "gts.Triangle", /* tp_name */
+ sizeof(PygtsTriangle), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ (cmpfunc)compare, /* tp_compare */
+ 0, /* 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 */
+ "Triangle object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ methods, /* tp_methods */
+ 0, /* tp_members */
+ getset, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)init, /* tp_init */
+ 0, /* tp_alloc */
+ (newfunc)new /* tp_new */
+};
+
+
+/*-------------------------------------------------------------------------*/
+/* Pygts functions */
+
+gboolean
+pygts_triangle_check(PyObject* o)
+{
+ if(! PyObject_TypeCheck(o, &PygtsTriangleType)) {
+ return FALSE;
+ }
+ else {
+#if PYGTS_DEBUG
+ return pygts_triangle_is_ok(PYGTS_TRIANGLE(o));
+#else
+ return TRUE;
+#endif
+ }
+}
+
+
+gboolean
+pygts_triangle_is_ok(PygtsTriangle *t)
+{
+ if(!pygts_object_is_ok(PYGTS_OBJECT(t))) return FALSE;
+ return pygts_gts_triangle_is_ok(PYGTS_TRIANGLE_AS_GTS_TRIANGLE(t));
+}
+
+
+PygtsTriangle *
+pygts_triangle_new(GtsTriangle *t)
+{
+ PyObject *args, *kwds;
+ PygtsObject *triangle;
+
+ /* Check for Triangle in the object table */
+ if( (triangle = PYGTS_OBJECT(g_hash_table_lookup(obj_table,GTS_OBJECT(t))))
+ !=NULL ) {
+ Py_INCREF(triangle);
+ return PYGTS_TRIANGLE(triangle);
+ }
+
+ /* Build a new Triangle */
+ args = Py_BuildValue("OOO",Py_None,Py_None,Py_None);
+ kwds = Py_BuildValue("{s:O}","alloc_gtsobj",Py_False);
+ triangle = PYGTS_OBJECT(PygtsTriangleType.tp_new(&PygtsTriangleType,
+ args, kwds));
+ Py_DECREF(args);
+ Py_DECREF(kwds);
+ if( triangle == NULL ) {
+ PyErr_SetString(PyExc_MemoryError,"could not create Triangle");
+ return NULL;
+ }
+ triangle->gtsobj = GTS_OBJECT(t);
+
+ /* Register and return */
+ pygts_object_register(triangle);
+ return PYGTS_TRIANGLE(triangle);
+}
+
+
+int
+pygts_triangle_compare(GtsTriangle* t1,GtsTriangle* t2)
+{
+ if( (pygts_segment_compare(GTS_SEGMENT(t1->e1),GTS_SEGMENT(t2->e1))==0 &&
+ pygts_segment_compare(GTS_SEGMENT(t1->e2),GTS_SEGMENT(t2->e2))==0 &&
+ pygts_segment_compare(GTS_SEGMENT(t1->e3),GTS_SEGMENT(t2->e3))==0) ||
+ (pygts_segment_compare(GTS_SEGMENT(t1->e1),GTS_SEGMENT(t2->e3))==0 &&
+ pygts_segment_compare(GTS_SEGMENT(t1->e2),GTS_SEGMENT(t2->e1))==0 &&
+ pygts_segment_compare(GTS_SEGMENT(t1->e3),GTS_SEGMENT(t2->e2))==0) ||
+ (pygts_segment_compare(GTS_SEGMENT(t1->e1),GTS_SEGMENT(t2->e2))==0 &&
+ pygts_segment_compare(GTS_SEGMENT(t1->e2),GTS_SEGMENT(t2->e3))==0 &&
+ pygts_segment_compare(GTS_SEGMENT(t1->e3),GTS_SEGMENT(t2->e1))==0) ||
+
+ (pygts_segment_compare(GTS_SEGMENT(t1->e1),GTS_SEGMENT(t2->e3))==0 &&
+ pygts_segment_compare(GTS_SEGMENT(t1->e2),GTS_SEGMENT(t2->e2))==0 &&
+ pygts_segment_compare(GTS_SEGMENT(t1->e3),GTS_SEGMENT(t2->e1))==0) ||
+ (pygts_segment_compare(GTS_SEGMENT(t1->e1),GTS_SEGMENT(t2->e2))==0 &&
+ pygts_segment_compare(GTS_SEGMENT(t1->e2),GTS_SEGMENT(t2->e1))==0 &&
+ pygts_segment_compare(GTS_SEGMENT(t1->e3),GTS_SEGMENT(t2->e3))==0) ||
+ (pygts_segment_compare(GTS_SEGMENT(t1->e1),GTS_SEGMENT(t2->e1))==0 &&
+ pygts_segment_compare(GTS_SEGMENT(t1->e2),GTS_SEGMENT(t2->e3))==0 &&
+ pygts_segment_compare(GTS_SEGMENT(t1->e3),GTS_SEGMENT(t2->e2))==0) ) {
+ return 0;
+ }
+ return -1;
+}
+
+
+/**
+ * gts_triangle_is_ok:
+ * @t: a #GtsTriangle.
+ *
+ * Returns: %TRUE if @t is a non-degenerate, non-duplicate triangle,
+ * %FALSE otherwise.
+ */
+gboolean pygts_gts_triangle_is_ok (GtsTriangle * t)
+{
+ g_return_val_if_fail (t != NULL, FALSE);
+ g_return_val_if_fail (t->e1 != NULL, FALSE);
+ g_return_val_if_fail (t->e2 != NULL, FALSE);
+ g_return_val_if_fail (t->e3 != NULL, FALSE);
+ g_return_val_if_fail (t->e1 != t->e2 && t->e1 != t->e3 && t->e2 != t->e3,
+ FALSE);
+ g_return_val_if_fail (gts_segments_touch (GTS_SEGMENT (t->e1),
+ GTS_SEGMENT (t->e2)),
+ FALSE);
+ g_return_val_if_fail (gts_segments_touch (GTS_SEGMENT (t->e1),
+ GTS_SEGMENT (t->e3)),
+ FALSE);
+ g_return_val_if_fail (gts_segments_touch (GTS_SEGMENT (t->e2),
+ GTS_SEGMENT (t->e3)),
+ FALSE);
+ g_return_val_if_fail (GTS_SEGMENT (t->e1)->v1 != GTS_SEGMENT (t->e1)->v2,
+ FALSE);
+ g_return_val_if_fail (GTS_SEGMENT (t->e2)->v1 != GTS_SEGMENT (t->e2)->v2,
+ FALSE);
+ g_return_val_if_fail (GTS_SEGMENT (t->e3)->v1 != GTS_SEGMENT (t->e3)->v2,
+ FALSE);
+ /* g_return_val_if_fail (GTS_OBJECT (t)->reserved == NULL, FALSE); */
+ g_return_val_if_fail (!gts_triangle_is_duplicate (t), FALSE);
+ return TRUE;
+}
Added: trunk/lib/py/pygts-0.3.1/triangle.h
===================================================================
--- trunk/lib/py/pygts-0.3.1/triangle.h 2009-06-24 17:04:39 UTC (rev 1813)
+++ trunk/lib/py/pygts-0.3.1/triangle.h 2009-06-24 22:06:24 UTC (rev 1814)
@@ -0,0 +1,58 @@
+/* pygts - python package for the manipulation of triangulated surfaces
+ *
+ * Copyright (C) 2009 Thomas J. Duck
+ * All rights reserved.
+ *
+ * Thomas J. Duck <tom.duck@xxxxxx>
+ * Department of Physics and Atmospheric Science,
+ * Dalhousie University, Halifax, Nova Scotia, Canada, B3H 3J5
+ *
+ * NOTICE
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PYGTS_TRIANGLE_H__
+#define __PYGTS_TRIANGLE_H__
+
+typedef struct _PygtsObject PygtsTriangle;
+
+#define PYGTS_TRIANGLE(obj) ((PygtsTriangle*)obj)
+
+#define PYGTS_TRIANGLE_AS_GTS_TRIANGLE(o) \
+ (GTS_TRIANGLE(PYGTS_OBJECT(o)->gtsobj))
+
+extern PyTypeObject PygtsTriangleType;
+
+gboolean pygts_triangle_check(PyObject* o);
+gboolean pygts_triangle_is_ok(PygtsTriangle *t);
+
+PygtsTriangle* pygts_triangle_new(GtsTriangle *t);
+
+int pygts_triangle_compare(GtsTriangle* t1,GtsTriangle* t2);
+
+
+
+/* Replacement for gts_triangle_is_ok(). The problem is that sometimes the
+ * "reserved" variable is set in a face by gts, and so this function fails.
+ * e.g., The error occurs when gts_triangle_is_ok() is called during
+ * iteration over faces in a surface. This function ignores that check so
+ * that there is no failure when PYGTS_DEBUG is set. A bug report should be
+ * submitted.
+ */
+gboolean pygts_gts_triangle_is_ok(GtsTriangle *t);
+
+#endif /* __PYGTS_TRIANGLE_H__ */
Added: trunk/lib/py/pygts-0.3.1/vertex.c
===================================================================
--- trunk/lib/py/pygts-0.3.1/vertex.c 2009-06-24 17:04:39 UTC (rev 1813)
+++ trunk/lib/py/pygts-0.3.1/vertex.c 2009-06-24 22:06:24 UTC (rev 1814)
@@ -0,0 +1,874 @@
+/* pygts - python package for the manipulation of triangulated surfaces
+ *
+ * Copyright (C) 2009 Thomas J. Duck
+ * All rights reserved.
+ *
+ * Thomas J. Duck <tom.duck@xxxxxx>
+ * Department of Physics and Atmospheric Science,
+ * Dalhousie University, Halifax, Nova Scotia, Canada, B3H 3J5
+ *
+ * NOTICE
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "pygts.h"
+
+
+#if PYGTS_DEBUG
+ #define SELF_CHECK if(!pygts_vertex_check((PyObject*)self)) { \
+ PyErr_SetString(PyExc_RuntimeError, \
+ "problem with self object (internal error)"); \
+ return NULL; \
+ }
+#else
+ #define SELF_CHECK
+#endif
+
+
+/*-------------------------------------------------------------------------*/
+/* Methods exported to python */
+
+static PyObject*
+is_ok(PygtsVertex *self, PyObject *args)
+{
+ if(pygts_vertex_is_ok(self)) {
+ Py_INCREF(Py_True);
+ return Py_True;
+ }
+ else {
+ Py_INCREF(Py_False);
+ return Py_False;
+ }
+}
+
+
+static PyObject*
+is_unattached(PygtsVertex *self, PyObject *args)
+{
+ guint n;
+
+ SELF_CHECK
+
+ /* Check for attachments other than to the gtsobj_parent */
+ n = g_slist_length(PYGTS_VERTEX_AS_GTS_VERTEX(self)->segments);
+ if( n > 1 ) {
+ Py_INCREF(Py_False);
+ return Py_False;
+ }
+ else {
+ Py_INCREF(Py_True);
+ return Py_True;
+ }
+}
+
+
+static PyObject*
+is_boundary(PygtsVertex* self, PyObject *args)
+{
+ PyObject *s_;
+ PygtsObject *s;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &s_) ) {
+ return NULL;
+ }
+
+ /* Convert to PygtsObjects */
+ if(!pygts_surface_check(s_)) {
+ PyErr_SetString(PyExc_TypeError,"expected a Surface");
+ return NULL;
+ }
+ s = PYGTS_OBJECT(s_);
+
+ if( gts_vertex_is_boundary(PYGTS_VERTEX_AS_GTS_VERTEX(self),
+ PYGTS_SURFACE_AS_GTS_SURFACE(s)) ) {
+ Py_INCREF(Py_True);
+ return Py_True;
+ }
+ else {
+ Py_INCREF(Py_False);
+ return Py_False;
+ }
+}
+
+
+static PyObject*
+contacts(PygtsVertex* self, PyObject *args)
+{
+ PyObject *sever_=NULL;
+ gboolean sever=FALSE;
+ guint n;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "|O", &sever_) ) {
+ return NULL;
+ }
+
+ /* Convert to PygtsObjects */
+ if( sever_ != NULL ) {
+ if(!PyBool_Check(sever_)) {
+ PyErr_SetString(PyExc_TypeError,"expected a Boolean");
+ return NULL;
+ }
+ if( sever_ == Py_True ) {
+ sever = TRUE;
+ }
+ }
+
+ n = gts_vertex_is_contact(PYGTS_VERTEX_AS_GTS_VERTEX(self),sever);
+ return Py_BuildValue("i",n);
+}
+
+
+static PyObject*
+is_connected(PygtsVertex *self, PyObject *args)
+{
+ PyObject *v_;
+ PygtsVertex *v;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &v_) ) {
+ return NULL;
+ }
+
+ /* Convert to PygtsObjects */
+ if(!pygts_vertex_check(v_)) {
+ PyErr_SetString(PyExc_TypeError,"expected a Vertex");
+ return NULL;
+ }
+ v = PYGTS_VERTEX(v_);
+
+ if( gts_vertices_are_connected(PYGTS_VERTEX_AS_GTS_VERTEX(self),
+ PYGTS_VERTEX_AS_GTS_VERTEX(v)) != NULL ) {
+ Py_INCREF(Py_True);
+ return Py_True;
+ }
+ else {
+ Py_INCREF(Py_False);
+ return Py_False;
+ }
+}
+
+
+static PyObject*
+replace(PygtsVertex *self, PyObject *args)
+{
+ PyObject *p2_;
+ PygtsVertex *p2;
+ GSList *parents=NULL, *i, *cur;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &p2_) ) {
+ return NULL;
+ }
+
+ /* Convert to PygtsObjects */
+ if(!pygts_vertex_check(p2_)) {
+ PyErr_SetString(PyExc_TypeError,"expected a Vertex");
+ return NULL;
+ }
+ p2 = PYGTS_VERTEX(p2_);
+
+ if( self != p2 ) {
+ /* (Ignore self-replacement) */
+
+ /* Detach and save any parent segments */
+ i = PYGTS_VERTEX_AS_GTS_VERTEX(self)->segments;
+ while(i!=NULL) {
+ cur = i;
+ i = g_slist_next(i);
+ if(PYGTS_IS_PARENT_SEGMENT(cur->data)) {
+ PYGTS_VERTEX_AS_GTS_VERTEX(self)->segments =
+ g_slist_remove_link(PYGTS_VERTEX_AS_GTS_VERTEX(self)->segments,
+ cur);
+ parents = g_slist_prepend(parents,cur->data);
+ g_slist_free_1(cur);
+ }
+ }
+
+ /* Perform the replace operation */
+ gts_vertex_replace(PYGTS_VERTEX_AS_GTS_VERTEX(self),
+ PYGTS_VERTEX_AS_GTS_VERTEX(p2));
+
+ /* Reattach the parent segments */
+ i = parents;
+ while(i!=NULL) {
+ PYGTS_VERTEX_AS_GTS_VERTEX(self)->segments =
+ g_slist_prepend(PYGTS_VERTEX_AS_GTS_VERTEX(self)->segments,i->data);
+ i = g_slist_next(i);
+ }
+ g_slist_free(parents);
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+static PyObject*
+neighbors(PygtsVertex* self, PyObject *args)
+{
+ PyObject *s_=NULL;
+ GtsSurface *s=NULL;
+ GSList *vertices,*v;
+ PygtsVertex *vertex;
+ PyObject *tuple;
+ guint n,N;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "|O", &s_) ) {
+ return NULL;
+ }
+
+ /* Convert */
+ if( s_ != NULL ) {
+ if(!pygts_surface_check(s_)) {
+ PyErr_SetString(PyExc_TypeError,"expected a Surface");
+ return NULL;
+ }
+ s = PYGTS_SURFACE_AS_GTS_SURFACE(s_);
+ }
+
+ /* Get the neighbors */
+ vertices = gts_vertex_neighbors(PYGTS_VERTEX_AS_GTS_VERTEX(self),
+ NULL,s);
+ N = g_slist_length(vertices);
+
+ /* Create the tuple */
+ if( (tuple=PyTuple_New(N)) == NULL) {
+ PyErr_SetString(PyExc_MemoryError,"could not create tuple");
+ return NULL;
+ }
+
+ /* Put PygtsVertex objects into the tuple */
+ v = vertices;
+ for(n=0;n<N;n++) {
+
+ /* Skip this vertex if it is a parent */
+ while( v!=NULL && PYGTS_IS_PARENT_VERTEX(GTS_VERTEX(v->data)) ) {
+ v = g_slist_next(v);
+ }
+ if( v==NULL ) break;
+
+ if( (vertex = pygts_vertex_new(GTS_VERTEX(v->data))) == NULL ) {
+ Py_DECREF((PyObject*)tuple);
+ return NULL;
+ }
+
+ PyTuple_SET_ITEM(tuple, n, (PyObject*)vertex);
+
+ v = g_slist_next(v);
+ }
+
+ if(_PyTuple_Resize(&tuple,n)!=0) {
+ Py_DECREF(tuple);
+ return NULL;
+ }
+
+ return tuple;
+}
+
+
+static PyObject*
+faces(PygtsVertex* self, PyObject *args)
+{
+ PyObject *s_=NULL;
+ GtsSurface *s=NULL;
+ GSList *faces,*f;
+ PygtsFace *face;
+ PyObject *tuple;
+ guint n,N;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "|O", &s_) ) {
+ return NULL;
+ }
+
+ /* Convert */
+ if( s_ != NULL ) {
+ if(!pygts_surface_check(s_)) {
+ PyErr_SetString(PyExc_TypeError,"expected a Surface");
+ return NULL;
+ }
+ s = PYGTS_SURFACE_AS_GTS_SURFACE(s_);
+ }
+
+ /* Get the faces */
+ faces = gts_vertex_faces(PYGTS_VERTEX_AS_GTS_VERTEX(self),s,NULL);
+ N = g_slist_length(faces);
+
+ /* Create the tuple */
+ if( (tuple=PyTuple_New(N)) == NULL) {
+ PyErr_SetString(PyExc_MemoryError,"expected a tuple");
+ return NULL;
+ }
+
+ /* Put PygtsVertex objects into the tuple */
+ f = faces;
+ for(n=0;n<N;n++) {
+
+ if( (face = pygts_face_new(GTS_FACE(f->data))) == NULL ) {
+ Py_DECREF(tuple);
+ return NULL;
+ }
+
+ PyTuple_SET_ITEM(tuple, n, (PyObject*)face);
+
+ f = g_slist_next(f);
+ }
+
+ return tuple;
+}
+
+
+static PyObject*
+encroaches(PygtsVertex *self, PyObject *args)
+{
+ PyObject *e_;
+ PygtsEdge *e;
+
+ SELF_CHECK
+
+ /* Parse the args */
+ if(! PyArg_ParseTuple(args, "O", &e_) ) {
+ return NULL;
+ }
+
+ /* Convert to PygtsObjects */
+ if(!pygts_edge_check(e_)) {
+ PyErr_SetString(PyExc_TypeError,"expected an Edge");
+ return NULL;
+ }
+ e = PYGTS_EDGE(e_);
+
+ if(gts_vertex_encroaches_edge(PYGTS_VERTEX_AS_GTS_VERTEX(self),
+ PYGTS_EDGE_AS_GTS_EDGE(e))) {
+ Py_INCREF(Py_True);
+ return Py_True;
+ }
+ else {
+ Py_INCREF(Py_False);
+ return Py_False;
+ }
+}
+
+
+static PyObject*
+triangles(PygtsVertex *self, PyObject *args)
+{
+ GSList *triangles, *t;
+ PygtsTriangle *triangle;
+ guint i,N;
+ PyObject *tuple;
+
+ SELF_CHECK
+
+ triangles = gts_vertex_triangles(PYGTS_VERTEX_AS_GTS_VERTEX(self),NULL);
+ N = g_slist_length(triangles);
+
+ /* Create the tuple */
+ if( (tuple=PyTuple_New(N)) == NULL) {
+ PyErr_SetString(PyExc_MemoryError,"could not create tuple");
+ return NULL;
+ }
+
+ /* Put PygtsVertex objects into the tuple */
+ t = triangles;
+ for(i=0;i<N;i++) {
+
+ if( (triangle = pygts_triangle_new(GTS_TRIANGLE(t->data))) == NULL ) {
+ Py_DECREF(tuple);
+ return NULL;
+ }
+
+ PyTuple_SET_ITEM(tuple, i, (PyObject*)triangle);
+
+ t = g_slist_next(t);
+ }
+
+ return tuple;
+}
+
+
+/* Methods table */
+static PyMethodDef methods[] = {
+
+ {"is_ok", (PyCFunction)is_ok,
+ METH_NOARGS,
+ "True if this Vertex v is OK. False otherwise.\n"
+ "This method is useful for unit testing and debugging.\n"
+ "\n"
+ "Signature: v.is_ok().\n"
+ },
+
+ {"is_unattached", (PyCFunction)is_unattached,
+ METH_NOARGS,
+ "True if this Vertex v is not the endpoint of any Segment.\n"
+ "\n"
+ "Signature: v.is_unattached().\n"
+ },
+
+ {"is_boundary", (PyCFunction)is_boundary,
+ METH_VARARGS,
+ "True if this Vertex v is used by a boundary Edge of Surface s.\n"
+ "\n"
+ "Signature: v.is_boundary().\n"
+ },
+
+ {"contacts", (PyCFunction)contacts,
+ METH_VARARGS,
+ "Returns the number of sets of connected Triangles sharing this\n"
+ "Vertex v.\n"
+ "\n"
+ "Signature: v.contacts().\n"
+ "\n"
+ "If sever is True (default: False) and v is a contact vertex then\n"
+ "the vertex is replaced in each Triangle with clones.\n"
+ },
+
+ {"is_connected", (PyCFunction)is_connected,
+ METH_VARARGS,
+ "Return True if this Vertex v1 is connected to Vertex v2\n"
+ "by a Segment.\n"
+ "\n"
+ "Signature: v1.is_connected().\n"
+ },
+
+ {"replace", (PyCFunction)replace,
+ METH_VARARGS,
+ "Replaces this Vertex v1 with Vertex v2 in all Segments that have v1.\n"
+ "Vertex v1 itself is left unchanged.\n"
+ "\n"
+ "Signature: v1.replace(v2).\n"
+ },
+
+ {"neighbors", (PyCFunction)neighbors,
+ METH_VARARGS,
+ "Returns a tuple of Vertices attached to this Vertex v\n"
+ "by a Segment.\n"
+ "\n"
+ "If a Surface s is given, only Vertices on s are considered.\n"
+ "\n"
+ "Signature: v.neighbors() or v.neighbors(s).\n"
+ },
+
+ {"faces", (PyCFunction)faces,
+ METH_VARARGS,
+ "Returns a tuple of Faces that have this Vertex v.\n"
+ "\n"
+ "If a Surface s is given, only Vertices on s are considered.\n"
+ "\n"
+ "Signature: v.faces() or v.faces(s).\n"
+ },
+
+ {"encroaches", (PyCFunction)encroaches,
+ METH_VARARGS,
+ "Returns True if this Vertex v is strictly contained in the\n"
+ "diametral circle of Edge e. False otherwise.\n"
+ "\n"
+ "Only the projection onto the x-y plane is considered.\n"
+ "\n"
+ "Signature: v.encroaches(e)\n"
+ },
+
+ {"triangles", (PyCFunction)triangles,
+ METH_NOARGS,
+ "Returns a list of Triangles that have this Vertex v.\n"
+ "\n"
+ "Signature: v.triangles()\n"
+ },
+
+ {NULL} /* Sentinel */
+};
+
+
+/*-------------------------------------------------------------------------*/
+/* Python type methods */
+
+static GtsObject * parent(GtsVertex *v1);
+
+static PyObject *
+new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ PyObject *o;
+ PygtsObject *obj;
+ guint alloc_gtsobj = TRUE;
+
+ /* Parse the args */
+ if(kwds) {
+ o = PyDict_GetItemString(kwds,"alloc_gtsobj");
+ if(o==Py_False) {
+ alloc_gtsobj = FALSE;
+ }
+ if(o!=NULL) {
+ PyDict_DelItemString(kwds, "alloc_gtsobj");
+ }
+ }
+ if(kwds) {
+ Py_INCREF(Py_False);
+ PyDict_SetItemString(kwds,"alloc_gtsobj", Py_False);
+ }
+
+ /* Chain up */
+ obj = PYGTS_OBJECT(PygtsPointType.tp_new(type,args,kwds));
+
+ /* Allocate the gtsobj (if needed) */
+ if( alloc_gtsobj ) {
+ obj->gtsobj = GTS_OBJECT(gts_vertex_new(gts_vertex_class(),0,0,0));
+ if( obj->gtsobj == NULL ) {
+ PyErr_SetString(PyExc_MemoryError, "could not create Vertex");
+ return NULL;
+ }
+
+ /* Create the parent GtsSegment */
+ if( (obj->gtsobj_parent=parent(GTS_VERTEX(obj->gtsobj))) == NULL ) {
+ gts_object_destroy(obj->gtsobj);
+ obj->gtsobj = NULL;
+ return NULL;
+ }
+
+ pygts_object_register(obj);
+ }
+
+ return (PyObject*)obj;
+}
+
+
+static int
+init(PygtsVertex *self, PyObject *args, PyObject *kwds)
+{
+ gint ret;
+
+ /* Chain up */
+ if( (ret=PygtsPointType.tp_init((PyObject*)self,args,kwds)) != 0 ) {
+ return ret;
+ }
+
+ return 0;
+}
+
+
+/* Methods table */
+PyTypeObject PygtsVertexType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "gts.Vertex", /* tp_name */
+ sizeof(PygtsVertex), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* 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 */
+ "Vertex object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base: attached in pygts.c */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)init, /* tp_init */
+ 0, /* tp_alloc */
+ (newfunc)new /* tp_new */
+};
+
+
+/*-------------------------------------------------------------------------*/
+/* Pygts functions */
+
+gboolean
+pygts_vertex_check(PyObject* o)
+{
+ gboolean check = FALSE;
+ guint i,N;
+ PyObject *obj;
+
+ /* Check for a Vertex */
+ if( PyObject_TypeCheck(o, &PygtsVertexType) ) {
+ check = TRUE;
+ }
+
+ /* Convert list into tuple */
+ if(PyList_Check(o)) {
+ o = PyList_AsTuple(o);
+ }
+ else {
+ Py_INCREF(o);
+ }
+
+ /* Check for a tuple of floats */
+ if( PyTuple_Check(o) ) {
+ if( (N = PyTuple_Size(o)) <= 3 ) {
+ check = TRUE;
+ for(i=0;i<N;i++) {
+ obj = PyTuple_GET_ITEM(o,i);
+ if(!PyFloat_Check(obj) && !PyInt_Check(obj)) {
+ check = FALSE;
+ }
+ }
+ }
+ }
+ Py_DECREF(o);
+
+ if( !check ) {
+ return FALSE;
+ }
+ else {
+#if PYGTS_DEBUG
+ if( PyObject_TypeCheck(o, &PygtsVertexType) ) {
+ return pygts_vertex_is_ok(PYGTS_VERTEX(o));
+ }
+#endif
+ return TRUE;
+ }
+}
+
+
+gboolean
+pygts_vertex_is_ok(PygtsVertex *v)
+{
+ GSList *parent;
+ PygtsObject *obj;
+
+ obj = PYGTS_OBJECT(v);
+
+ if(!pygts_point_is_ok(PYGTS_POINT(v))) return FALSE;
+
+ /* Check for a valid parent */
+ g_return_val_if_fail(obj->gtsobj_parent!=NULL,FALSE);
+ g_return_val_if_fail(PYGTS_IS_PARENT_SEGMENT(obj->gtsobj_parent),FALSE);
+ parent = g_slist_find(GTS_VERTEX(obj->gtsobj)->segments,
+ obj->gtsobj_parent);
+ g_return_val_if_fail(parent!=NULL,FALSE);
+
+ return TRUE;
+}
+
+
+static GtsObject *
+parent(GtsVertex *v1) {
+ GtsPoint *p1;
+ GtsVertex *v2;
+ GtsSegment *p;
+
+ /* Create another Vertex */
+ p1 = GTS_POINT(v1);
+ if( (v2 = gts_vertex_new(pygts_parent_vertex_class(),p1->x,p1->y,p1->z+1))
+ == NULL ) {
+ PyErr_SetString(PyExc_MemoryError, "could not create parent");
+ return NULL;
+ }
+
+ /* Create and return the parent */
+ if( (p = gts_segment_new(pygts_parent_segment_class(),v1,v2))
+ == NULL ) {
+ PyErr_SetString(PyExc_MemoryError, "could not create parent");
+ gts_object_destroy(GTS_OBJECT(v2));
+ return NULL;
+ }
+
+ return GTS_OBJECT(p);
+}
+
+
+PygtsVertex *
+pygts_vertex_new(GtsVertex *v)
+{
+ PyObject *args, *kwds;
+ PygtsObject *vertex;
+
+ /* Check for Vertex in the object table */
+ if( (vertex = PYGTS_OBJECT(g_hash_table_lookup(obj_table,GTS_OBJECT(v))))
+ !=NULL ) {
+ Py_INCREF(vertex);
+ return PYGTS_VERTEX(vertex);
+ }
+
+ /* Build a new Vertex */
+ args = Py_BuildValue("ddd",0,0,0);
+ kwds = Py_BuildValue("{s:O}","alloc_gtsobj",Py_False);
+ vertex = PYGTS_VERTEX(PygtsVertexType.tp_new(&PygtsVertexType, args, kwds));
+ Py_DECREF(args);
+ Py_DECREF(kwds);
+ if( vertex == NULL ) {
+ PyErr_SetString(PyExc_MemoryError,"could not create Vertex");
+ return NULL;
+ }
+ vertex->gtsobj = GTS_OBJECT(v);
+
+ /* Attach the parent */
+ if( (vertex->gtsobj_parent=parent(v)) == NULL ) {
+ Py_DECREF(vertex);
+ return NULL;
+ }
+
+ /* Register and return */
+ pygts_object_register(vertex);
+ return PYGTS_VERTEX(vertex);
+}
+
+
+PygtsVertex *
+pygts_vertex_from_sequence(PyObject *tuple) {
+ guint i,N;
+ gdouble x=0,y=0,z=0;
+ PyObject *obj;
+ GtsVertex *v;
+ PygtsVertex *vertex;
+
+ /* Convert list into tuple */
+ if(PyList_Check(tuple)) {
+ tuple = PyList_AsTuple(tuple);
+ }
+ else {
+ Py_INCREF(tuple);
+ }
+ if(!PyTuple_Check(tuple)) {
+ Py_DECREF(tuple);
+ PyErr_SetString(PyExc_TypeError,"expected a list or tuple of vertices");
+ return NULL;
+ }
+
+ /* Get the tuple size */
+ if( (N = PyTuple_Size(tuple)) > 3 ) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "expected a list or tuple of up to three floats");
+ Py_DECREF(tuple);
+ return NULL;
+ }
+
+ /* Get the coordinates */
+ for(i=0;i<N;i++) {
+ obj = PyTuple_GET_ITEM(tuple,i);
+
+ if(!PyFloat_Check(obj) && !PyInt_Check(obj)) {
+ PyErr_SetString(PyExc_TypeError,"expected a list or tuple of floats");
+ Py_DECREF(tuple);
+ return NULL;
+ }
+ if(i==0) {
+ if(PyFloat_Check(obj)) x = PyFloat_AsDouble(obj);
+ else x = (double)PyInt_AsLong(obj);
+ }
+ if(i==1) {
+ if(PyFloat_Check(obj)) y = PyFloat_AsDouble(obj);
+ else y = (double)PyInt_AsLong(obj);
+ }
+ if(i==2) {
+ if(PyFloat_Check(obj)) z = PyFloat_AsDouble(obj);
+ else z = (double)PyInt_AsLong(obj);
+ }
+ }
+ Py_DECREF(tuple);
+
+ /* Create the vertex */
+ if( (v = gts_vertex_new(gts_vertex_class(),x,y,z)) == NULL ) {
+ PyErr_SetString(PyExc_MemoryError,"could not create Vertex");
+ }
+ if( (vertex = pygts_vertex_new(v)) == NULL ) {
+ gts_object_destroy(GTS_OBJECT(v));
+ return NULL;
+ }
+
+ return vertex;
+}
+
+
+GtsSegmentClass*
+pygts_parent_segment_class(void)
+{
+ static GtsSegmentClass *klass = NULL;
+ GtsObjectClass *super = NULL;
+
+ if (klass == NULL) {
+
+ super = GTS_OBJECT_CLASS(gts_segment_class());
+
+ GtsObjectClassInfo pygts_parent_segment_info = {
+ "PygtsParentSegment",
+ sizeof(PygtsParentSegment),
+ sizeof(GtsSegmentClass),
+ (GtsObjectClassInitFunc)(super->info.class_init_func),
+ (GtsObjectInitFunc)(super->info.object_init_func),
+ (GtsArgSetFunc) NULL,
+ (GtsArgGetFunc) NULL
+ };
+ klass = gts_object_class_new(gts_object_class(),
+ &pygts_parent_segment_info);
+ }
+
+ return klass;
+}
+
+
+GtsVertexClass*
+pygts_parent_vertex_class(void)
+{
+ static GtsVertexClass *klass = NULL;
+ GtsObjectClass *super = NULL;
+
+ if (klass == NULL) {
+
+ super = GTS_OBJECT_CLASS(gts_vertex_class());
+
+ GtsObjectClassInfo pygts_parent_vertex_info = {
+ "PygtsParentVertex",
+ sizeof(PygtsParentVertex),
+ sizeof(GtsVertexClass),
+ (GtsObjectClassInitFunc)(super->info.class_init_func),
+ (GtsObjectInitFunc)(super->info.object_init_func),
+ (GtsArgSetFunc) NULL,
+ (GtsArgGetFunc) NULL
+ };
+ klass = gts_object_class_new(gts_object_class(),
+ &pygts_parent_vertex_info);
+ }
+
+ return klass;
+}
Added: trunk/lib/py/pygts-0.3.1/vertex.h
===================================================================
--- trunk/lib/py/pygts-0.3.1/vertex.h 2009-06-24 17:04:39 UTC (rev 1813)
+++ trunk/lib/py/pygts-0.3.1/vertex.h 2009-06-24 22:06:24 UTC (rev 1814)
@@ -0,0 +1,86 @@
+/* pygts - python package for the manipulation of triangulated surfaces
+ *
+ * Copyright (C) 2009 Thomas J. Duck
+ * All rights reserved.
+ *
+ * Thomas J. Duck <tom.duck@xxxxxx>
+ * Department of Physics and Atmospheric Science,
+ * Dalhousie University, Halifax, Nova Scotia, Canada, B3H 3J5
+ *
+ * NOTICE
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PYGTS_VERTEX_H__
+#define __PYGTS_VERTEX_H__
+
+typedef struct _PygtsObject PygtsVertex;
+
+
+#define PYGTS_VERTEX(o) \
+ ( PyObject_TypeCheck((PyObject*)o, &PygtsVertexType) ? \
+ (PygtsVertex*)o : \
+ pygts_vertex_from_sequence((PyObject*)o) )
+
+#define PYGTS_VERTEX_AS_GTS_VERTEX(o) \
+ ( PyObject_TypeCheck((PyObject*)o, &PygtsVertexType) ? \
+ GTS_VERTEX(PYGTS_OBJECT(o)->gtsobj) : \
+ GTS_VERTEX(PYGTS_OBJECT(PYGTS_VERTEX(o))->gtsobj) )
+
+extern PyTypeObject PygtsVertexType;
+
+gboolean pygts_vertex_check(PyObject* o);
+gboolean pygts_vertex_is_ok(PygtsVertex *v);
+
+PygtsVertex* pygts_vertex_new(GtsVertex *f);
+PygtsVertex* pygts_vertex_from_sequence(PyObject *tuple);
+
+
+/*-------------------------------------------------------------------------*/
+/* Parent GTS segment for GTS vertices */
+
+/* Define a GtsSegment subclass that can be readily identified as the parent
+ * of an encapsulated GtsVertex. The pygts_parent_segment_class() function
+ * is defined at the bottom, and is what ultimately allows the distinction
+ * to be made. This capability is used for vertex replacement operations.
+ */
+typedef struct _GtsSegment PygtsParentSegment;
+
+#define PYGTS_PARENT_SEGMENT(obj) GTS_OBJECT_CAST(obj,\
+ GtsSegment,\
+ pygts_parent_segment_class())
+
+#define PYGTS_IS_PARENT_SEGMENT(obj)(gts_object_is_from_class(obj,\
+ pygts_parent_segment_class()))
+
+GtsSegmentClass* pygts_parent_segment_class(void);
+
+
+/* GTS vertices in parent segments */
+
+typedef struct _GtsVertex PygtsParentVertex;
+
+#define PYGTS_PARENT_VERTEX(obj) GTS_OBJECT_CAST(obj,\
+ GtsVertex,\
+ pygts_parent_vertex_class())
+
+#define PYGTS_IS_PARENT_VERTEX(obj)(gts_object_is_from_class(obj,\
+ pygts_parent_vertex_class()))
+
+GtsVertexClass *pygts_parent_vertex_class(void);
+
+#endif /* __PYGTS_VERTEX_H__ */