cytriangle 1.0.4__cp313-cp313-macosx_13_0_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of cytriangle might be problematic. Click here for more details.
- cytriangle/__init__.py +4 -0
- cytriangle/ctriangle.pxd +39 -0
- cytriangle/cytriangle.c +13653 -0
- cytriangle/cytriangle.cpython-313-darwin.so +0 -0
- cytriangle/cytriangle.pyx +239 -0
- cytriangle/cytriangleio.c +21095 -0
- cytriangle/cytriangleio.cpython-313-darwin.so +0 -0
- cytriangle/cytriangleio.pxd +4 -0
- cytriangle/cytriangleio.pyx +561 -0
- cytriangle-1.0.4.dist-info/LICENSE +165 -0
- cytriangle-1.0.4.dist-info/METADATA +40 -0
- cytriangle-1.0.4.dist-info/RECORD +20 -0
- cytriangle-1.0.4.dist-info/WHEEL +4 -0
- src/c/A.poly +62 -0
- src/c/README +198 -0
- src/c/makefile +116 -0
- src/c/showme.c +3375 -0
- src/c/triangle.c +14913 -0
- src/c/triangle.h +296 -0
- src/c/tricall.c +273 -0
|
Binary file
|
|
@@ -0,0 +1,561 @@
|
|
|
1
|
+
from libc.stdlib cimport free, malloc
|
|
2
|
+
import numpy as np
|
|
3
|
+
from cytriangle.ctriangle cimport triangulateio
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def validate_input_attributes(attributes):
|
|
7
|
+
num_attr = list(set([len(sublist) for sublist in attributes]))
|
|
8
|
+
if len(num_attr) > 1:
|
|
9
|
+
raise ValueError(
|
|
10
|
+
"Attribute lists must have the same number of attributes for each element"
|
|
11
|
+
)
|
|
12
|
+
return num_attr[0]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def validate_attribute_number(attributes, base_quantity):
|
|
16
|
+
if len(attributes) != base_quantity:
|
|
17
|
+
raise ValueError(
|
|
18
|
+
"""Attribute list must have the same number of elements as the
|
|
19
|
+
input it decorates"""
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
cdef class TriangleIO:
|
|
24
|
+
|
|
25
|
+
def __cinit__(self):
|
|
26
|
+
# Initialize the triangulateio struct with NULL pointers
|
|
27
|
+
self._io = <triangulateio*> NULL
|
|
28
|
+
|
|
29
|
+
def __dealloc__(self):
|
|
30
|
+
# Free allocated memory when the instance is deallocated
|
|
31
|
+
if self._io is not NULL:
|
|
32
|
+
# add all the allocation releases
|
|
33
|
+
if self._io.pointlist is not NULL:
|
|
34
|
+
free(self._io.pointlist)
|
|
35
|
+
if self._io.pointattributelist is not NULL:
|
|
36
|
+
free(self._io.pointattributelist)
|
|
37
|
+
if self._io.pointmarkerlist is not NULL:
|
|
38
|
+
free(self._io.pointmarkerlist)
|
|
39
|
+
if self._io.trianglelist is not NULL:
|
|
40
|
+
free(self._io.trianglelist)
|
|
41
|
+
if self._io.triangleattributelist is not NULL:
|
|
42
|
+
free(self._io.triangleattributelist)
|
|
43
|
+
if self._io.trianglearealist is not NULL:
|
|
44
|
+
free(self._io.trianglearealist)
|
|
45
|
+
if self._io.neighborlist is not NULL:
|
|
46
|
+
free(self._io.neighborlist)
|
|
47
|
+
if self._io.segmentlist is not NULL:
|
|
48
|
+
free(self._io.segmentlist)
|
|
49
|
+
if self._io.segmentmarkerlist is not NULL:
|
|
50
|
+
free(self._io.segmentmarkerlist)
|
|
51
|
+
if self._io.holelist is not NULL:
|
|
52
|
+
free(self._io.holelist)
|
|
53
|
+
if self._io.regionlist is not NULL:
|
|
54
|
+
free(self._io.regionlist)
|
|
55
|
+
if self._io.edgelist is not NULL:
|
|
56
|
+
free(self._io.edgelist)
|
|
57
|
+
if self._io.edgemarkerlist is not NULL:
|
|
58
|
+
free(self._io.edgemarkerlist)
|
|
59
|
+
if self._io.normlist is not NULL:
|
|
60
|
+
free(self._io.normlist)
|
|
61
|
+
free(self._io)
|
|
62
|
+
|
|
63
|
+
def __init__(self, input_dict=None):
|
|
64
|
+
# Assemble the triangulateio struct from a Python dictionary (default)
|
|
65
|
+
self._io = <triangulateio*> malloc(sizeof(triangulateio))
|
|
66
|
+
|
|
67
|
+
# Allocate null fields
|
|
68
|
+
self._io.pointlist = <double*> NULL
|
|
69
|
+
self._io.numberofpoints = 0
|
|
70
|
+
|
|
71
|
+
self._io.pointattributelist = <double*> NULL
|
|
72
|
+
self._io.numberofpointattributes = 0
|
|
73
|
+
self._io.pointmarkerlist = <int*> NULL
|
|
74
|
+
|
|
75
|
+
self._io.trianglelist = <int*> NULL
|
|
76
|
+
self._io.numberoftriangles = 0
|
|
77
|
+
self._io.numberofcorners = 0
|
|
78
|
+
self._io.numberoftriangleattributes = 0
|
|
79
|
+
self._io.triangleattributelist = <double*> NULL
|
|
80
|
+
self._io.trianglearealist = <double*> NULL
|
|
81
|
+
self._io.neighborlist = <int*> NULL
|
|
82
|
+
|
|
83
|
+
# input - p switch
|
|
84
|
+
self._io.segmentlist = <int*> NULL
|
|
85
|
+
self._io.segmentmarkerlist = <int*> NULL
|
|
86
|
+
self._io.numberofsegments = 0
|
|
87
|
+
|
|
88
|
+
# input - p switch without r
|
|
89
|
+
self._io.holelist = <double*> NULL
|
|
90
|
+
self._io.numberofholes = 0
|
|
91
|
+
self._io.regionlist = <double*> NULL
|
|
92
|
+
self._io.numberofregions = 0
|
|
93
|
+
|
|
94
|
+
# input - always ignored
|
|
95
|
+
self._io.edgelist = <int*> NULL
|
|
96
|
+
self._io.edgemarkerlist = <int*> NULL
|
|
97
|
+
self._io.normlist = <double*> NULL
|
|
98
|
+
self._io.numberofedges = 0
|
|
99
|
+
|
|
100
|
+
# Populate based on input_dict
|
|
101
|
+
if input_dict is not None:
|
|
102
|
+
if 'vertices' in input_dict:
|
|
103
|
+
self.set_vertices(input_dict['vertices'])
|
|
104
|
+
# set other vertex related optional fields
|
|
105
|
+
if 'vertex_attributes' in input_dict:
|
|
106
|
+
self.set_vertex_attributes(input_dict['vertex_attributes'])
|
|
107
|
+
if 'vertex_markers' in input_dict:
|
|
108
|
+
self.set_vertex_markers(input_dict['vertex_markers'])
|
|
109
|
+
if 'triangles' in input_dict:
|
|
110
|
+
# fetch number of corners from triangle input
|
|
111
|
+
self._io.numberofcorners = len(input_dict['triangles'][0])
|
|
112
|
+
self.set_triangles(input_dict['triangles'])
|
|
113
|
+
if 'triangle_attributes' in input_dict:
|
|
114
|
+
self.set_triangle_attributes(input_dict['triangle_attributes'])
|
|
115
|
+
if 'triangle_max_area' in input_dict:
|
|
116
|
+
self.set_triangle_areas(input_dict['triangle_max_area'])
|
|
117
|
+
if 'segments' in input_dict:
|
|
118
|
+
self.set_segments(input_dict['segments'])
|
|
119
|
+
if 'segment_markers' in input_dict:
|
|
120
|
+
self.set_segment_markers(input_dict['segment_markers'])
|
|
121
|
+
if 'holes' in input_dict:
|
|
122
|
+
self.set_holes(input_dict['holes'])
|
|
123
|
+
if 'regions' in input_dict:
|
|
124
|
+
self.set_regions(input_dict['regions'])
|
|
125
|
+
|
|
126
|
+
def to_dict(self, opt=''):
|
|
127
|
+
"""
|
|
128
|
+
Converts the internal C TriangleIO data structure into a dictionary format.
|
|
129
|
+
|
|
130
|
+
Parameters:
|
|
131
|
+
- opt: A string that indicates the format of the output. If 'np',
|
|
132
|
+
numpy arrays are used.
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
- A dictionary containing the triangulation data.
|
|
136
|
+
"""
|
|
137
|
+
output_dict = {}
|
|
138
|
+
|
|
139
|
+
if opt == 'np':
|
|
140
|
+
if self.vertices:
|
|
141
|
+
output_dict['vertices'] = np.asarray(self.vertices)
|
|
142
|
+
if self.vertex_attributes:
|
|
143
|
+
output_dict['vertex_attributes'] = np.asarray(self.vertex_attributes)
|
|
144
|
+
if self.vertex_markers:
|
|
145
|
+
output_dict['vertex_markers'] = np.asarray(self.vertex_markers)
|
|
146
|
+
if self.triangles:
|
|
147
|
+
output_dict['triangles'] = np.asarray(self.triangles)
|
|
148
|
+
if self.triangle_attributes:
|
|
149
|
+
output_dict['triangle_attributes'] = np.asarray(
|
|
150
|
+
self.triangle_attributes)
|
|
151
|
+
else:
|
|
152
|
+
if self.vertices:
|
|
153
|
+
output_dict['vertices'] = self.vertices
|
|
154
|
+
if self.vertex_attributes:
|
|
155
|
+
output_dict['vertex_attributes'] = self.vertex_attributes
|
|
156
|
+
if self.vertex_markers:
|
|
157
|
+
output_dict['vertex_markers'] = self.vertex_markers
|
|
158
|
+
if self.triangles:
|
|
159
|
+
output_dict['triangles'] = self.triangles
|
|
160
|
+
if self.triangle_attributes:
|
|
161
|
+
output_dict['triangle_attributes'] = self.triangle_attributes
|
|
162
|
+
if self.triangle_max_area:
|
|
163
|
+
output_dict['triangle_max_area'] = self.triangle_max_area
|
|
164
|
+
if self.neighbors:
|
|
165
|
+
output_dict['neighbors'] = self.neighbors
|
|
166
|
+
if self.segments:
|
|
167
|
+
output_dict['segments'] = self.segments
|
|
168
|
+
if self.segment_markers:
|
|
169
|
+
output_dict['segment_markers'] = self.segment_markers
|
|
170
|
+
if self.holes:
|
|
171
|
+
output_dict['holes'] = self.holes
|
|
172
|
+
if self.regions:
|
|
173
|
+
output_dict['regions'] = self.regions
|
|
174
|
+
if self.edges:
|
|
175
|
+
output_dict['edges'] = self.edges
|
|
176
|
+
if self.edge_markers:
|
|
177
|
+
output_dict['edge_markers'] = self.edge_markers
|
|
178
|
+
if self.norms:
|
|
179
|
+
output_dict['norms'] = self.norms
|
|
180
|
+
|
|
181
|
+
return output_dict
|
|
182
|
+
|
|
183
|
+
@property
|
|
184
|
+
def vertices(self):
|
|
185
|
+
"""
|
|
186
|
+
`vertices`: A list of pairs [x, y] that are vertex coordinates.
|
|
187
|
+
|
|
188
|
+
Returns:
|
|
189
|
+
- A list of pairs [x, y] that are vertex coordinates.
|
|
190
|
+
"""
|
|
191
|
+
if self._io.pointlist is not NULL:
|
|
192
|
+
return [[self._io.pointlist[2*i], self._io.pointlist[2*i + 1]]
|
|
193
|
+
for i in range(self._io.numberofpoints)]
|
|
194
|
+
|
|
195
|
+
@vertices.setter
|
|
196
|
+
def vertices(self, vertices):
|
|
197
|
+
self.set_vertices(vertices)
|
|
198
|
+
|
|
199
|
+
@property
|
|
200
|
+
def vertex_attributes(self):
|
|
201
|
+
"""
|
|
202
|
+
`vertex_attributes`: An list of lists of vertex attributes (floats).
|
|
203
|
+
Each vertex must have the same number of attributes, and
|
|
204
|
+
len(vertex_attributes) must match the number of points.
|
|
205
|
+
|
|
206
|
+
Returns:
|
|
207
|
+
- A list of lists, where each inner list contains attributes for a vertex.
|
|
208
|
+
"""
|
|
209
|
+
if self._io.pointattributelist is not NULL:
|
|
210
|
+
vertex_attributes = []
|
|
211
|
+
for i in range(self._io.numberofpoints):
|
|
212
|
+
vertex_attr = []
|
|
213
|
+
for j in range(self._io.numberofpointattributes):
|
|
214
|
+
vertex_attr.append(
|
|
215
|
+
self._io.pointattributelist[
|
|
216
|
+
i*self._io.numberofpointattributes + j
|
|
217
|
+
]
|
|
218
|
+
)
|
|
219
|
+
vertex_attributes.append(vertex_attr)
|
|
220
|
+
return vertex_attributes
|
|
221
|
+
|
|
222
|
+
@vertex_attributes.setter
|
|
223
|
+
def vertex_attributes(self, vertex_attributes):
|
|
224
|
+
self.set_vertex_attributes(vertex_attributes)
|
|
225
|
+
|
|
226
|
+
@property
|
|
227
|
+
def vertex_markers(self):
|
|
228
|
+
"""
|
|
229
|
+
`vertex_markers`: A list of vertex markers; one int per point.
|
|
230
|
+
|
|
231
|
+
Returns:
|
|
232
|
+
- A list of integers representing markers for each vertex.
|
|
233
|
+
"""
|
|
234
|
+
if self._io.pointmarkerlist is not NULL:
|
|
235
|
+
return [self._io.pointmarkerlist[i] for i in range(self._io.numberofpoints)]
|
|
236
|
+
|
|
237
|
+
@vertex_markers.setter
|
|
238
|
+
def vertex_markers(self, vertex_markers):
|
|
239
|
+
self.set_vertex_markers(vertex_markers)
|
|
240
|
+
|
|
241
|
+
@property
|
|
242
|
+
def triangles(self):
|
|
243
|
+
"""
|
|
244
|
+
`triangles`: A list of triangle corners (not necessarily 3).
|
|
245
|
+
Corners are designated in a counterclockwise order,
|
|
246
|
+
followed by any other nodes if the triangle represents a
|
|
247
|
+
nonlinear element (e.g. num_corners > 3).
|
|
248
|
+
|
|
249
|
+
Returns:
|
|
250
|
+
- A list of lists, where each inner list contains vertex indices for a triangle.
|
|
251
|
+
"""
|
|
252
|
+
if self._io.trianglelist is not NULL:
|
|
253
|
+
triangles = []
|
|
254
|
+
for i in range(self._io.numberoftriangles):
|
|
255
|
+
tri_order = []
|
|
256
|
+
for j in range(self._io.numberofcorners):
|
|
257
|
+
tri_order.append(self._io.trianglelist[
|
|
258
|
+
i * self._io.numberofcorners + j
|
|
259
|
+
])
|
|
260
|
+
triangles.append(tri_order)
|
|
261
|
+
return triangles
|
|
262
|
+
|
|
263
|
+
@triangles.setter
|
|
264
|
+
def triangles(self, triangles):
|
|
265
|
+
self.set_triangles(triangles)
|
|
266
|
+
|
|
267
|
+
@property
|
|
268
|
+
def triangle_attributes(self):
|
|
269
|
+
"""
|
|
270
|
+
`triangle_attributes`: A list of triangle attributes. Each triangle must have
|
|
271
|
+
the same number of attributes.
|
|
272
|
+
|
|
273
|
+
Returns:
|
|
274
|
+
- A list of lists, where each inner list contains attributes for a triangle.
|
|
275
|
+
"""
|
|
276
|
+
if self._io.triangleattributelist is not NULL:
|
|
277
|
+
triangle_attributes = []
|
|
278
|
+
for i in range(self._io.numberoftriangles):
|
|
279
|
+
triangle_attr = []
|
|
280
|
+
for j in range(self._io.numberoftriangleattributes):
|
|
281
|
+
triangle_attr.append(
|
|
282
|
+
self._io.triangleattributelist[
|
|
283
|
+
i*self._io.numberoftriangleattributes + j
|
|
284
|
+
]
|
|
285
|
+
)
|
|
286
|
+
triangle_attributes.append(triangle_attr)
|
|
287
|
+
return triangle_attributes
|
|
288
|
+
|
|
289
|
+
@triangle_attributes.setter
|
|
290
|
+
def triangle_attributes(self, triangle_attributes):
|
|
291
|
+
self.set_triangle_attributes(triangle_attributes)
|
|
292
|
+
|
|
293
|
+
@property
|
|
294
|
+
def triangle_max_area(self):
|
|
295
|
+
"""
|
|
296
|
+
`triangle_max_area`: A list of triangle area constraints;
|
|
297
|
+
one per triangle, 0 if not set.
|
|
298
|
+
Input only.
|
|
299
|
+
|
|
300
|
+
Returns:
|
|
301
|
+
- A list of floats representing the maximum area for each triangle.
|
|
302
|
+
"""
|
|
303
|
+
if self._io.trianglearealist is not NULL:
|
|
304
|
+
return [self._io.trianglearealist[i]
|
|
305
|
+
for i in range(self._io.numberoftriangles)]
|
|
306
|
+
|
|
307
|
+
@triangle_max_area.setter
|
|
308
|
+
def triangle_max_area(self, triangle_areas):
|
|
309
|
+
self.set_triangle_areas(triangle_areas)
|
|
310
|
+
|
|
311
|
+
@property
|
|
312
|
+
def neighbors(self):
|
|
313
|
+
"""
|
|
314
|
+
`neighbors`: A list of triangle neighbors; three ints per triangle. Output only.
|
|
315
|
+
|
|
316
|
+
Returns:
|
|
317
|
+
- A list of lists, where each inner list contains indices of neighboring
|
|
318
|
+
triangles.
|
|
319
|
+
"""
|
|
320
|
+
max_neighbors = 3
|
|
321
|
+
if self._io.neighborlist is not NULL:
|
|
322
|
+
neighbor_list = []
|
|
323
|
+
for i in range(self._io.numberoftriangles):
|
|
324
|
+
neighbors = [self._io.neighborlist[i*max_neighbors + j]
|
|
325
|
+
for j in range(max_neighbors)]
|
|
326
|
+
# remove sentinel values (-1)
|
|
327
|
+
neighbors = [neighbor for neighbor in neighbors if neighbor != -1]
|
|
328
|
+
neighbor_list.append(neighbors)
|
|
329
|
+
return neighbor_list
|
|
330
|
+
|
|
331
|
+
@property
|
|
332
|
+
def segments(self):
|
|
333
|
+
"""
|
|
334
|
+
`segments`: A list of segment endpoints.
|
|
335
|
+
|
|
336
|
+
Returns:
|
|
337
|
+
- A list of lists, where each inner list contains vertex indices for
|
|
338
|
+
a segment.
|
|
339
|
+
"""
|
|
340
|
+
if self._io.segmentlist is not NULL:
|
|
341
|
+
segments = []
|
|
342
|
+
for i in range(self._io.numberofsegments):
|
|
343
|
+
start_pt_index = self._io.segmentlist[2 * i]
|
|
344
|
+
end_pt_index = self._io.segmentlist[2 * i + 1]
|
|
345
|
+
segments.append([start_pt_index, end_pt_index])
|
|
346
|
+
return segments
|
|
347
|
+
|
|
348
|
+
@segments.setter
|
|
349
|
+
def segments(self, segments):
|
|
350
|
+
self.set_segments(segments)
|
|
351
|
+
|
|
352
|
+
@property
|
|
353
|
+
def holes(self):
|
|
354
|
+
"""
|
|
355
|
+
`holes`: A list of hole coordinates.
|
|
356
|
+
|
|
357
|
+
Returns:
|
|
358
|
+
- A list of pairs [x, y] representing coordinates of holes.
|
|
359
|
+
"""
|
|
360
|
+
if self._io.holelist is not NULL:
|
|
361
|
+
return [[self._io.holelist[2*i], self._io.holelist[2*i + 1]]
|
|
362
|
+
for i in range(self._io.numberofholes)]
|
|
363
|
+
|
|
364
|
+
@holes.setter
|
|
365
|
+
def holes(self, holes):
|
|
366
|
+
self.set_holes(holes)
|
|
367
|
+
|
|
368
|
+
# unmarked segments have a value of 0
|
|
369
|
+
@property
|
|
370
|
+
def segment_markers(self):
|
|
371
|
+
"""
|
|
372
|
+
`segment_markers`: An array of segment markers; one int per segment.
|
|
373
|
+
|
|
374
|
+
Returns:
|
|
375
|
+
- A list of integers representing markers for each segment.
|
|
376
|
+
"""
|
|
377
|
+
if self._io.segmentmarkerlist is not NULL:
|
|
378
|
+
segment_markers = []
|
|
379
|
+
for i in range(self._io.numberofsegments):
|
|
380
|
+
segment_markers.append(self._io.segmentmarkerlist[i])
|
|
381
|
+
return segment_markers
|
|
382
|
+
|
|
383
|
+
@segment_markers.setter
|
|
384
|
+
def segment_markers(self, segment_markers):
|
|
385
|
+
self.set_segment_markers(segment_markers)
|
|
386
|
+
|
|
387
|
+
@property
|
|
388
|
+
def regions(self):
|
|
389
|
+
"""
|
|
390
|
+
`regions`: An array of regional attributes and area constraints. Note that
|
|
391
|
+
each regional attribute is used only if you select the `A` switch, and each area
|
|
392
|
+
constraint is used only if you select the `a` switch (with no number following).
|
|
393
|
+
|
|
394
|
+
Returns:
|
|
395
|
+
- A list of dictionaries, each containing 'vertex' (coordinates of the region's
|
|
396
|
+
vertex), 'marker' (integer marker for the region), and 'max_area' (maximum area
|
|
397
|
+
constraint for the region).
|
|
398
|
+
"""
|
|
399
|
+
if self._io.regionlist is not NULL:
|
|
400
|
+
regions = []
|
|
401
|
+
for i in range(self._io.numberofregions):
|
|
402
|
+
region = {}
|
|
403
|
+
region['vertex'] = [self._io.regionlist[4*i],
|
|
404
|
+
self._io.regionlist[4*i + 1]]
|
|
405
|
+
region['marker'] = int(self._io.regionlist[4*i + 2])
|
|
406
|
+
region['max_area'] = self._io.regionlist[4*i + 3]
|
|
407
|
+
regions.append(region)
|
|
408
|
+
return regions
|
|
409
|
+
|
|
410
|
+
@regions.setter
|
|
411
|
+
def regions(self, regions):
|
|
412
|
+
self.set_regions(regions)
|
|
413
|
+
|
|
414
|
+
@property
|
|
415
|
+
def edges(self):
|
|
416
|
+
"""
|
|
417
|
+
`edges`: An array of edge endpoints. The first edge's endpoints are at
|
|
418
|
+
indices [0] and [1], followed by the remaining edges. Two ints per
|
|
419
|
+
edge. Output only.
|
|
420
|
+
|
|
421
|
+
Returns:
|
|
422
|
+
- A list of lists, where each inner list contains vertex indices for an edge.
|
|
423
|
+
"""
|
|
424
|
+
if self._io.edgelist is not NULL:
|
|
425
|
+
edges = []
|
|
426
|
+
for i in range(self._io.numberofedges):
|
|
427
|
+
edges.append([self._io.edgelist[i * 2], self._io.edgelist[i * 2 + 1]])
|
|
428
|
+
return edges
|
|
429
|
+
|
|
430
|
+
@property
|
|
431
|
+
def edge_markers(self):
|
|
432
|
+
"""
|
|
433
|
+
`edge_markers`: An array of edge markers; one int per edge. Output only.
|
|
434
|
+
|
|
435
|
+
Returns:
|
|
436
|
+
- A list of integers representing markers for each edge.
|
|
437
|
+
"""
|
|
438
|
+
if self._io.edgemarkerlist is not NULL:
|
|
439
|
+
return [self._io.edgemarkerlist[i] for i in range(self._io.numberofedges)]
|
|
440
|
+
|
|
441
|
+
@property
|
|
442
|
+
def norms(self):
|
|
443
|
+
"""
|
|
444
|
+
`norms`: An array of normal vectors, used for infinite rays in Voronoi
|
|
445
|
+
diagrams. For each finite edge in a Voronoi diagram, the normal vector written
|
|
446
|
+
is the zero vector. Output only.
|
|
447
|
+
|
|
448
|
+
Returns:
|
|
449
|
+
- A list of dictionaries, each containing 'ray_origin' (start
|
|
450
|
+
point of the ray) and 'ray_direction' (direction of the ray),
|
|
451
|
+
represented as [x, y] pairs.
|
|
452
|
+
"""
|
|
453
|
+
if self._io.normlist is not NULL:
|
|
454
|
+
norm_list = []
|
|
455
|
+
for i in range(self._io.numberofedges):
|
|
456
|
+
norm_list.append({'ray_origin': [self._io.normlist[i * 4],
|
|
457
|
+
self._io.normlist[i * 4 + 1]],
|
|
458
|
+
'ray_direction': [self._io.normlist[i * 4 + 2],
|
|
459
|
+
self._io.normlist[i * 4 + 3]]})
|
|
460
|
+
return norm_list
|
|
461
|
+
|
|
462
|
+
def set_vertices(self, vertices):
|
|
463
|
+
num_vertices = len(vertices)
|
|
464
|
+
self._io.numberofpoints = num_vertices
|
|
465
|
+
if num_vertices < 3:
|
|
466
|
+
raise ValueError('Valid input requires three or more vertices')
|
|
467
|
+
vertices = np.ascontiguousarray(vertices)
|
|
468
|
+
self._io.pointlist = <double*>malloc(2 * num_vertices * sizeof(double))
|
|
469
|
+
for i in range(num_vertices):
|
|
470
|
+
self._io.pointlist[2 * i] = vertices[i, 0]
|
|
471
|
+
self._io.pointlist[2 * i + 1] = vertices[i, 1]
|
|
472
|
+
|
|
473
|
+
def set_vertex_attributes(self, vertex_attributes):
|
|
474
|
+
num_attr = validate_input_attributes(vertex_attributes)
|
|
475
|
+
num_vertices = self._io.numberofpoints
|
|
476
|
+
validate_attribute_number(vertex_attributes, num_vertices)
|
|
477
|
+
vertex_attributes = np.ascontiguousarray(vertex_attributes)
|
|
478
|
+
self._io.pointattributelist = <double*>malloc(
|
|
479
|
+
num_attr * num_vertices * sizeof(double))
|
|
480
|
+
self._io.numberofpointattributes = num_attr
|
|
481
|
+
for i in range(num_vertices):
|
|
482
|
+
for j in range(num_attr):
|
|
483
|
+
self._io.pointattributelist[i * num_attr + j] = vertex_attributes[i, j]
|
|
484
|
+
|
|
485
|
+
def set_vertex_markers(self, vertex_markers):
|
|
486
|
+
vertex_markers = np.ascontiguousarray(vertex_markers, dtype=int)
|
|
487
|
+
self._io.pointmarkerlist = <int*>malloc(len(vertex_markers) * sizeof(int))
|
|
488
|
+
for i in range(len(vertex_markers)):
|
|
489
|
+
self._io.pointmarkerlist[i] = vertex_markers[i]
|
|
490
|
+
|
|
491
|
+
def set_triangles(self, triangles):
|
|
492
|
+
num_triangles = len(triangles)
|
|
493
|
+
num_corners = self._io.numberofcorners
|
|
494
|
+
triangles = np.ascontiguousarray(triangles, dtype=int)
|
|
495
|
+
self._io.trianglelist = <int*>malloc(num_triangles * num_corners * sizeof(int))
|
|
496
|
+
self._io.numberoftriangles = num_triangles
|
|
497
|
+
for i in range(num_triangles):
|
|
498
|
+
for j in range(num_corners):
|
|
499
|
+
self._io.trianglelist[i*num_corners + j] = triangles[i, j]
|
|
500
|
+
|
|
501
|
+
def set_triangle_attributes(self, triangle_attributes):
|
|
502
|
+
num_attr = validate_input_attributes(triangle_attributes)
|
|
503
|
+
num_triangles = self._io.numberoftriangles
|
|
504
|
+
validate_attribute_number(triangle_attributes, num_triangles)
|
|
505
|
+
triangle_attributes = np.ascontiguousarray(triangle_attributes)
|
|
506
|
+
self._io.triangleattributelist = <double*>malloc(
|
|
507
|
+
num_attr * num_triangles * sizeof(double))
|
|
508
|
+
self._io.numberoftriangleattributes = num_attr
|
|
509
|
+
for i in range(num_triangles):
|
|
510
|
+
for j in range(num_attr):
|
|
511
|
+
self._io.triangleattributelist[
|
|
512
|
+
i * num_attr + j] = triangle_attributes[i, j]
|
|
513
|
+
|
|
514
|
+
def set_triangle_areas(self, triangle_areas):
|
|
515
|
+
num_triangles = self._io.numberoftriangles
|
|
516
|
+
validate_attribute_number(triangle_areas, num_triangles)
|
|
517
|
+
triangle_max_area = np.ascontiguousarray(triangle_areas)
|
|
518
|
+
self._io.trianglearealist = <double*>malloc(num_triangles * sizeof(double))
|
|
519
|
+
for i in range(num_triangles):
|
|
520
|
+
self._io.trianglearealist[i] = triangle_max_area[i]
|
|
521
|
+
|
|
522
|
+
def set_segments(self, segments):
|
|
523
|
+
num_segments = len(segments)
|
|
524
|
+
self._io.numberofsegments = num_segments
|
|
525
|
+
segments = np.ascontiguousarray(segments, dtype=int)
|
|
526
|
+
self._io.segmentlist = <int*>malloc(num_segments * 2 * sizeof(int))
|
|
527
|
+
for i in range(num_segments):
|
|
528
|
+
self._io.segmentlist[i * 2] = segments[i, 0]
|
|
529
|
+
self._io.segmentlist[i * 2 + 1] = segments[i, 1]
|
|
530
|
+
|
|
531
|
+
def set_segment_markers(self, segment_markers):
|
|
532
|
+
segment_markers = np.ascontiguousarray(segment_markers, dtype=int)
|
|
533
|
+
validate_attribute_number(segment_markers, self._io.numberofsegments)
|
|
534
|
+
self._io.segmentmarkerlist = <int*>malloc(
|
|
535
|
+
self._io.numberofsegments * sizeof(int))
|
|
536
|
+
for i in range(self._io.numberofsegments):
|
|
537
|
+
self._io.segmentmarkerlist[i] = segment_markers[i]
|
|
538
|
+
|
|
539
|
+
def set_holes(self, holes):
|
|
540
|
+
num_holes = len(holes)
|
|
541
|
+
self._io.numberofholes = num_holes
|
|
542
|
+
holes = np.ascontiguousarray(holes)
|
|
543
|
+
self._io.holelist = <double*>malloc(num_holes * 2 * sizeof(double))
|
|
544
|
+
for i in range(num_holes):
|
|
545
|
+
self._io.holelist[2 * i] = holes[i, 0]
|
|
546
|
+
self._io.holelist[2 * i + 1] = holes[i, 1]
|
|
547
|
+
|
|
548
|
+
def set_regions(self, regions):
|
|
549
|
+
num_regions = len(regions)
|
|
550
|
+
self._io.numberofregions = num_regions
|
|
551
|
+
# unpack region dict
|
|
552
|
+
region_array = [[region['vertex'][0],
|
|
553
|
+
region['vertex'][1],
|
|
554
|
+
region['marker'],
|
|
555
|
+
region['max_area']]
|
|
556
|
+
for region in regions]
|
|
557
|
+
regions = np.ascontiguousarray(region_array)
|
|
558
|
+
self._io.regionlist = <double*>malloc(num_regions * 4 * sizeof(double))
|
|
559
|
+
for i in range(num_regions):
|
|
560
|
+
for j in range(4):
|
|
561
|
+
self._io.regionlist[i * 4 + j] = regions[i, j]
|