1
/* pygts - python package for the manipulation of triangulated surfaces
3
* Copyright (C) 2009 Thomas J. Duck
6
* Thomas J. Duck <tom.duck@dal.ca>
7
* Department of Physics and Atmospheric Science,
8
* Dalhousie University, Halifax, Nova Scotia, Canada, B3H 3J5
12
* This library is free software; you can redistribute it and/or
13
* modify it under the terms of the GNU Library General Public
14
* License as published by the Free Software Foundation; either
15
* version 2 of the License, or (at your option) any later version.
17
* This library is distributed in the hope that it will be useful,
18
* but WITHOUT ANY WARRANTY; without even the implied warranty of
19
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20
* Library General Public License for more details.
22
* You should have received a copy of the GNU Library General Public
23
* License along with this library; if not, write to the
24
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25
* Boston, MA 02111-1307, USA.
32
#define SELF_CHECK if(!pygts_edge_check((PyObject*)self)) { \
33
PyErr_SetString(PyExc_RuntimeError, \
34
"problem with self object (internal error)"); \
42
/*-------------------------------------------------------------------------*/
43
/* Methods exported to python */
46
is_ok(PygtsEdge *self, PyObject *args)
48
if(pygts_edge_is_ok(self)) {
60
is_unattached(PygtsEdge *self, PyObject *args)
66
/* Check for attachments other than to the gtsobj_parent */
67
n = g_slist_length(PYGTS_EDGE_AS_GTS_EDGE(self)->triangles);
77
PyErr_SetString(PyExc_RuntimeError,"Edge lost parent (internal error)");
83
/* replace() works, but can break Triangles and so is disabled */
85
/* static PyObject* */
86
/* replace(PygtsEdge *self, PyObject *args) */
90
/* GSList *parents=NULL, *i, *cur; */
93
/* if(!pygts_edge_check((PyObject*)self)) { */
94
/* PyErr_SetString(PyExc_TypeError, */
95
/* "problem with self object (internal error)"); */
100
/* /\* Parse the args *\/ */
101
/* if(! PyArg_ParseTuple(args, "O", &e2_) ) { */
105
/* /\* Convert to PygtsObjects *\/ */
106
/* if(!pygts_edge_check(e2_)) { */
107
/* PyErr_SetString(PyExc_TypeError,"expected an Edge"); */
110
/* e2 = PYGTS_EDGE(e2_); */
112
/* if(PYGTS_OBJECT(self)->gtsobj!=PYGTS_OBJECT(e2)->gtsobj) { */
113
/* /\* (Ignore self-replacement) *\/ */
115
/* /\* Detach and save any parent triangles *\/ */
116
/* i = GTS_EDGE(PYGTS_OBJECT(self)->gtsobj)->triangles; */
117
/* while(i!=NULL) { */
120
/* if(PYGTS_IS_PARENT_TRIANGLE(cur->data)) { */
121
/* GTS_EDGE(PYGTS_OBJECT(self)->gtsobj)->triangles = */
122
/* g_slist_remove_link(GTS_EDGE(PYGTS_OBJECT(self)->gtsobj)->triangles, */
124
/* parents = g_slist_prepend(parents,cur->data); */
125
/* g_slist_free_1(cur); */
129
/* /\* Perform the replace operation *\/ */
130
/* gts_edge_replace(GTS_EDGE(PYGTS_OBJECT(self)->gtsobj), */
131
/* GTS_EDGE(PYGTS_OBJECT(e2)->gtsobj)); */
133
/* /\* Reattach the parent segments *\/ */
135
/* while(i!=NULL) { */
136
/* GTS_EDGE(PYGTS_OBJECT(self)->gtsobj)->triangles = */
137
/* g_slist_prepend(GTS_EDGE(PYGTS_OBJECT(self)->gtsobj)->triangles, */
141
/* g_slist_free(parents); */
144
/* #if PYGTS_DEBUG */
145
/* if(!pygts_edge_check((PyObject*)self)) { */
146
/* PyErr_SetString(PyExc_TypeError, */
147
/* "problem with self object (internal error)"); */
152
/* Py_INCREF(Py_None); */
153
/* return Py_None; */
158
face_number(PygtsEdge *self, PyObject *args)
166
if(! PyArg_ParseTuple(args, "O", &s_) ) {
170
/* Convert to PygtsObjects */
171
if(!pygts_surface_check(s_)) {
172
PyErr_SetString(PyExc_TypeError,"expected a Surface");
175
s = PYGTS_SURFACE_AS_GTS_SURFACE(s_);
177
return Py_BuildValue("i",
178
gts_edge_face_number(PYGTS_EDGE_AS_GTS_EDGE(self),s));
183
belongs_to_tetrahedron(PygtsEdge *self, PyObject *args)
187
if(gts_edge_belongs_to_tetrahedron(PYGTS_EDGE_AS_GTS_EDGE(self))) {
199
is_boundary(PygtsEdge *self, PyObject *args)
207
if(! PyArg_ParseTuple(args, "O", &s_) ) {
211
/* Convert to PygtsObjects */
212
if(!pygts_surface_check(s_)) {
213
PyErr_SetString(PyExc_TypeError,"expected a Surface");
216
s = PYGTS_SURFACE_AS_GTS_SURFACE(s_);
218
/* Make the call and return */
219
if(gts_edge_is_boundary(PYGTS_EDGE_AS_GTS_EDGE(self),s)!=NULL) {
231
contacts(PygtsEdge *self, PyObject *args)
235
return Py_BuildValue("i",
236
gts_edge_is_contact(PYGTS_EDGE_AS_GTS_EDGE(self)));
241
static PyMethodDef methods[] = {
242
{"is_ok", (PyCFunction)is_ok,
244
"True if this Edge e is not degenerate or duplicate.\n"
245
"False otherwise. Degeneracy implies e.v1.id == e.v2.id.\n"
247
"Signature: e.is_ok()\n"
250
{"is_unattached", (PyCFunction)is_unattached,
252
"True if this Edge e is not part of any Triangle.\n"
254
"Signature: e.is_unattached()\n"
257
/* Edge replace() method works but results in Triangles that are "not ok";
258
* i.e., they have edges that don't connect. We don't want that problem
259
* and so the method has been disabled.
262
{"replace", (PyCFunction)replace,
264
"Replaces this Edge e1 with Edge e2 in all Triangles that have e1.\n"
265
"Edge e1 itself is left unchanged.\n"
267
"Signature: e1.replace(e2).\n"
271
{"face_number", (PyCFunction)face_number,
273
"Returns number of faces using this Edge e on Surface s.\n"
275
"Signature: e.face_number(s)\n"
278
{"is_boundary", (PyCFunction)is_boundary,
280
"Returns True if this Edge e is a boundary on Surface s.\n"
283
"Signature: e.is_boundary(s)\n"
286
{"belongs_to_tetrahedron", (PyCFunction)belongs_to_tetrahedron,
288
"Returns True if this Edge e belongs to a tetrahedron.\n"
291
"Signature: e.belongs_to_tetrahedron()\n"
294
{"contacts", (PyCFunction)contacts,
296
"Returns number of sets of connected triangles share this Edge e\n"
297
"as a contact Edge.\n"
299
"Signature: e.contacts()\n"
302
{NULL} /* Sentinel */
306
/*-------------------------------------------------------------------------*/
307
/* Python type methods */
309
static GtsObject* parent(GtsEdge *e1);
312
new(PyTypeObject *type, PyObject *args, PyObject *kwds)
317
GtsObject *edge=NULL;
320
guint alloc_gtsobj = TRUE;
325
o = PyDict_GetItemString(kwds,"alloc_gtsobj");
327
alloc_gtsobj = FALSE;
330
PyDict_DelItemString(kwds, "alloc_gtsobj");
335
PyDict_SetItemString(kwds,"alloc_gtsobj", Py_False);
338
/* Allocate the gtsobj (if needed) */
342
if( (N = PyTuple_Size(args)) < 2 ) {
343
PyErr_SetString(PyExc_TypeError,"expected two Vertices");
346
v1_ = PyTuple_GET_ITEM(args,0);
347
v2_ = PyTuple_GET_ITEM(args,1);
349
/* Convert to PygtsObjects */
350
if(!pygts_vertex_check(v1_)) {
351
PyErr_SetString(PyExc_TypeError,"expected two Vertices");
354
if(!pygts_vertex_check(v2_)) {
355
PyErr_SetString(PyExc_TypeError,"expected two Vertices");
358
v1 = PYGTS_VERTEX(v1_);
359
v2 = PYGTS_VERTEX(v2_);
362
if(PYGTS_OBJECT(v1)->gtsobj == PYGTS_OBJECT(v2)->gtsobj) {
363
PyErr_SetString(PyExc_ValueError,"Vertices given are the same");
367
/* Create the GtsEdge */
368
edge = GTS_OBJECT(gts_edge_new(gts_edge_class(),
369
GTS_VERTEX(v1->gtsobj),
370
GTS_VERTEX(v2->gtsobj)));
372
PyErr_SetString(PyExc_MemoryError, "could not create Edge");
376
/* Check for duplicate */
377
tmp = gts_edge_is_duplicate(GTS_EDGE(edge));
379
gts_object_destroy(edge);
380
edge = GTS_OBJECT(tmp);
383
/* If corresponding PyObject found in object table, we are done */
384
if( (obj=g_hash_table_lookup(obj_table,edge)) != NULL ) {
386
return (PyObject*)obj;
391
obj = PYGTS_OBJECT(PygtsSegmentType.tp_new(type,args,kwds));
396
/* Create a parent GtsTriangle */
397
if( (obj->gtsobj_parent = parent(GTS_EDGE(obj->gtsobj))) == NULL ) {
398
gts_object_destroy(obj->gtsobj);
403
pygts_object_register(PYGTS_OBJECT(obj));
406
return (PyObject*)obj;
411
init(PygtsEdge *self, PyObject *args, PyObject *kwds)
416
if( (ret=PygtsSegmentType.tp_init((PyObject*)self,args,kwds)) != 0 ){
425
PyTypeObject PygtsEdgeType = {
426
PyObject_HEAD_INIT(NULL)
428
"gts.Edge", /* tp_name */
429
sizeof(PygtsEdge), /* tp_basicsize */
437
0, /* tp_as_number */
438
0, /* tp_as_sequence */
439
0, /* tp_as_mapping */
445
0, /* tp_as_buffer */
447
Py_TPFLAGS_BASETYPE, /* tp_flags */
448
"Edge object", /* tp_doc */
451
0, /* tp_richcompare */
452
0, /* tp_weaklistoffset */
455
methods, /* tp_methods */
460
0, /* tp_descr_get */
461
0, /* tp_descr_set */
462
0, /* tp_dictoffset */
463
(initproc)init, /* tp_init */
465
(newfunc)new /* tp_new */
469
/*-------------------------------------------------------------------------*/
470
/* Pygts functions */
473
pygts_edge_check(PyObject* o)
475
if(! PyObject_TypeCheck(o, &PygtsEdgeType)) {
480
return pygts_edge_is_ok(PYGTS_EDGE(o));
488
pygts_edge_is_ok(PygtsEdge *e)
493
obj = PYGTS_OBJECT(e);
495
if(!pygts_segment_is_ok(PYGTS_SEGMENT(e))) return FALSE;
497
/* Check for a valid parent */
498
g_return_val_if_fail(obj->gtsobj_parent!=NULL,FALSE);
499
g_return_val_if_fail(PYGTS_IS_PARENT_TRIANGLE(obj->gtsobj_parent),FALSE);
500
parent = g_slist_find(GTS_EDGE(obj->gtsobj)->triangles,
502
g_return_val_if_fail(parent!=NULL,FALSE);
509
parent(GtsEdge *e1) {
510
GtsVertex *v1,*v2,*v3;
515
/* Create a third vertex for the triangle */
516
v1 = GTS_SEGMENT(e1)->v1;
517
v2 = GTS_SEGMENT(e1)->v2;
520
v3 = gts_vertex_new(pygts_parent_vertex_class(),
521
p1->x+p2->x,p1->y+p2->y,p1->z+p2->z);
523
PyErr_SetString(PyExc_MemoryError, "could not create Vertex");
527
/* Create another two edges */
528
if( (e2 = gts_edge_new(pygts_parent_edge_class(),v2,v3)) == NULL ) {
529
PyErr_SetString(PyExc_MemoryError, "could not create Edge");
532
if( (e3 = gts_edge_new(pygts_parent_edge_class(),v3,v1)) == NULL ) {
533
PyErr_SetString(PyExc_MemoryError, "could not create Edge");
534
gts_object_destroy(GTS_OBJECT(e2));
538
/* Create and return the parent */
539
if( (p = gts_triangle_new(pygts_parent_triangle_class(),e1,e2,e3))
541
gts_object_destroy(GTS_OBJECT(e2));
542
gts_object_destroy(GTS_OBJECT(e3));
543
PyErr_SetString(PyExc_MemoryError, "could not create Triangle");
547
return GTS_OBJECT(p);
552
pygts_edge_new(GtsEdge *e)
554
PyObject *args, *kwds;
557
/* Check for Edge in the object table */
558
if( (edge = PYGTS_OBJECT(g_hash_table_lookup(obj_table,GTS_OBJECT(e))))
561
return PYGTS_EDGE(edge);
564
/* Build a new Edge */
565
args = Py_BuildValue("OO",Py_None,Py_None);
566
kwds = Py_BuildValue("{s:O}","alloc_gtsobj",Py_False);
567
edge = PYGTS_EDGE(PygtsEdgeType.tp_new(&PygtsEdgeType, args, kwds));
571
PyErr_SetString(PyExc_MemoryError,"could not create Edge");
574
edge->gtsobj = GTS_OBJECT(e);
576
/* Attach the parent */
577
if( (edge->gtsobj_parent = parent(e)) == NULL ) {
582
/* Register and return */
583
pygts_object_register(edge);
584
return PYGTS_EDGE(edge);
589
pygts_parent_triangle_class(void)
591
static GtsTriangleClass *klass = NULL;
592
GtsObjectClass *super = NULL;
596
super = GTS_OBJECT_CLASS(gts_triangle_class());
598
GtsObjectClassInfo pygts_parent_triangle_info = {
599
"PygtsParentTriangle",
600
sizeof(PygtsParentTriangle),
601
sizeof(GtsTriangleClass),
602
(GtsObjectClassInitFunc)(super->info.class_init_func),
603
(GtsObjectInitFunc)(super->info.object_init_func),
604
(GtsArgSetFunc) NULL,
607
klass = gts_object_class_new(gts_object_class(),
608
&pygts_parent_triangle_info);
616
pygts_parent_edge_class(void)
618
static GtsEdgeClass *klass = NULL;
619
GtsObjectClass *super = NULL;
623
super = GTS_OBJECT_CLASS(pygts_parent_segment_class());
625
GtsObjectClassInfo pygts_parent_edge_info = {
627
sizeof(PygtsParentEdge),
628
sizeof(GtsEdgeClass),
629
(GtsObjectClassInitFunc)(super->info.class_init_func),
630
(GtsObjectInitFunc)(super->info.object_init_func),
631
(GtsArgSetFunc) NULL,
634
klass = gts_object_class_new(gts_object_class(),
635
&pygts_parent_edge_info);