commit 80506a9f82f64073dbe9a1ed72e77ed205f6d709
parent 818e40e24d75578d1aeb2153aa5e804bb9018836
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Tue, 23 Aug 2016 16:43:36 +0200
Simplify the setup of the Weiler & Atherton algorithm
Do not pre-compute the polygon/mesh edge intersections.
Diffstat:
| M | src/cpr_mesh.c | | | 454 | +++++++++++++++++++++++++++++++++---------------------------------------------- |
1 file changed, 192 insertions(+), 262 deletions(-)
diff --git a/src/cpr_mesh.c b/src/cpr_mesh.c
@@ -51,7 +51,7 @@ struct node {
#define DARRAY_DATA struct node
#include <rsys/dynamic_array.h>
-struct polygon {
+struct poly {
struct darray_double coords;
};
@@ -70,24 +70,70 @@ struct cpr_mesh {
};
/*******************************************************************************
- * Helper function
+ * Helper functions
******************************************************************************/
+static int
+intersect_edges
+ (double edge0[2][2],
+ double edge1[2][2],
+ struct hit* hit)
+{
+ double org0[2], org1[2];
+ double dir0[2], dir1[2];
+ double tmp[2];
+ double a, b;
+ int i;
+
+ /* Express the edges as org<0|1> + t<0|1>*dir<0|1> */
+ d2_set(org0, edge0[0]);
+ d2_set(org1, edge1[0]);
+ d2_sub(dir0, edge0[1], edge0[0]);
+ d2_sub(dir1, edge1[1], edge1[0]);
+
+ /* Solve org0 + t0*dir0 = org1 + t1*dir1
+ * (org0 + t0*dir0) x dir1 = (org1 + t1*dir1) x dir1
+ * org0 x dir1 + t0*(dir0 x dir1) = org1 x dir1
+ * t0 = (org1 - org0) x dir1 / (dir0 x dir1) */
+ d2_sub(tmp, org1, org0);
+ b = d2_cross(dir0, dir1);
+ if(b == 0) return 0; /* Edges are colinear => i.e. no intersection */
+ a = d2_cross(tmp, dir1);
+ hit->t0 = a / b;
+
+ /* Compute the hit position */
+ d2_muld(hit->pos, dir0, hit->t0);
+ d2_add(hit->pos, org0, hit->pos);
+
+ /* Compute the paremtric hit coordinate on the edge1 */
+ i = dir1[0] != 0 ? 0 : 1;
+ hit->t1 = (hit->pos[i] - org1[i]) / dir1[i];
+
+#ifndef NDEBUG
+ d2_muld(tmp, dir1, hit->t1);
+ d2_add(tmp, org1, tmp);
+ ASSERT(d2_eq_eps(hit->pos, tmp, 1.e-6));
+#endif
+
+ /* Ensure that the hit lie in the edge boundaries */
+ return hit->t0 >= 0.0 && hit->t0 <= 1.0 && hit->t1 >= 0.0 && hit->t1 <= 1.0;
+}
+
static INLINE void
-polygon_init(struct mem_allocator* allocator, struct polygon* poly)
+poly_init(struct mem_allocator* allocator, struct poly* poly)
{
ASSERT(allocator && poly);
darray_double_init(allocator, &poly->coords);
}
static INLINE void
-polygon_release(struct polygon* poly)
+poly_release(struct poly* poly)
{
ASSERT(poly);
darray_double_release(&poly->coords);
}
static res_T
-polygon_setup(struct polygon* poly, const struct cpr_polygon* desc)
+poly_setup(struct poly* poly, const struct cpr_polygon* desc)
{
size_t ivert;
res_T res = RES_OK;
@@ -114,7 +160,7 @@ error:
}
static res_T
-polygon_setup_nodes(struct polygon* poly, struct darray_node* nodes)
+poly_setup_nodes(struct poly* poly, struct darray_node* nodes)
{
size_t nverts;
size_t ivert;
@@ -125,7 +171,7 @@ polygon_setup_nodes(struct polygon* poly, struct darray_node* nodes)
nverts = darray_double_size_get(&poly->coords)/2/*#coords*/;
res = darray_node_resize(nodes, nverts);
- if(res != RES_OK) goto error;
+ if(res != RES_OK) return res;
FOR_EACH(ivert, 0, nverts) {
struct node* node = darray_node_data_get(nodes) + ivert;
@@ -136,224 +182,122 @@ polygon_setup_nodes(struct polygon* poly, struct darray_node* nodes)
node->t = -1.0;
}
-exit:
- return res;
-error:
- darray_node_clear(nodes);
- goto exit;
+ return RES_OK;
}
static res_T
-mesh_setup_edge_nodes
- (struct cpr_mesh* mesh,
- struct darray_node* nodes,
- struct htable_edge* edges)
+triangle_setup_nodes(const size_t triangle[3], struct darray_node* nodes)
{
- size_t itri, ntris;
+ size_t ivert;
res_T res = RES_OK;
- ASSERT(mesh && nodes);
+ ASSERT(triangle && nodes);
darray_node_clear(nodes);
- htable_edge_clear(edges);
-
- CPR(mesh_get_triangles_count(mesh, &ntris));
-
- FOR_EACH(itri, 0, ntris) {
- struct edge edge;
- size_t iedge;
- size_t ids[3];
-
- CPR(mesh_get_indices(mesh, itri, ids));
- FOR_EACH(iedge, 0, 3) {
- struct node* node;
- size_t inode;
- edge.v0 = ids[iedge];
- edge.v1 = ids[(iedge + 1)%3];
- if(edge.v0 > edge.v1) SWAP(size_t, edge.v0, edge.v1);
+ res = darray_node_resize(nodes, 3);
+ if(res != RES_OK) return res;
- if(htable_edge_find(edges, &edge)) continue;
-
- inode = darray_node_size_get(nodes);
-
- res = htable_edge_set(edges, &edge, &inode);
- if(res != RES_OK) goto error;
- res = darray_node_resize(nodes, inode + 2);
- if(res != RES_OK) goto error;
-
- node = darray_node_data_get(nodes) + inode;
- node[0].next = inode + 1;
- node[0].prev = SIZE_MAX;
- node[0].link = SIZE_MAX;
- node[0].id = edge.v0;
- node[0].t = -1.0;
-
- node[1].next = SIZE_MAX;
- node[1].prev = inode;
- node[1].link = SIZE_MAX;
- node[1].id = edge.v1;
- node[1].t = -1.0;
- }
+ FOR_EACH(ivert, 0, 3) {
+ struct node* node = darray_node_data_get(nodes) + ivert;
+ node->next = ivert + 1;
+ node->prev = ivert - 1;
+ node->link = SIZE_MAX;
+ node->id = triangle[ivert];
+ node->t = -1.0;
}
-
-exit:
- return res;
-error:
- darray_node_clear(nodes);
- goto exit;
-}
-
-static int
-intersect_edges
- (double edge0[2][2],
- double edge1[2][2],
- struct hit* hit)
-{
- double org0[2], org1[2];
- double dir0[2], dir1[2];
- double tmp[2];
- double a, b;
- int i;
-
- /* Express the edges as org<0|1> + t<0|1>*dir<0|1> */
- d2_set(org0, edge0[0]);
- d2_set(org1, edge1[0]);
- d2_sub(dir0, edge0[1], edge0[0]);
- d2_sub(dir1, edge1[1], edge1[0]);
-
- /* Solve org0 + t0*dir0 = org1 + t1*dir1
- * (org0 + t0*dir0) x dir1 = (org1 + t1*dir1) x dir1
- * org0 x dir1 + t0*(dir0 x dir1) = org1 x dir1
- * t0 = (org1 - org0) x dir1 / (dir0 x dir1) */
- d2_sub(tmp, org1, org0);
- b = d2_cross(dir0, dir1);
- if(b == 0) return 0; /* Edges are colinear => i.e. no intersection */
- a = d2_cross(tmp, dir1);
- hit->t0 = a / b;
-
- /* Compute the hit position */
- d2_muld(hit->pos, dir0, hit->t0);
- d2_add(hit->pos, org0, hit->pos);
-
- /* Compute the paremtric hit coordinate on the edge1 */
- i = dir1[0] != 0 ? 0 : 1;
- hit->t1 = (hit->pos[i] - org1[i]) / dir1[i];
-
-#ifndef NDEBUG
- d2_muld(tmp, dir1, hit->t1);
- d2_add(tmp, org1, tmp);
- ASSERT(d2_eq_eps(hit->pos, tmp, 1.e-6));
-#endif
-
- /* Ensure that the hit lie in the edge boundaries */
- return hit->t0 >= 0.0 && hit->t0 <= 1.0 && hit->t1 >= 0.0 && hit->t1 <= 1.0;
+ darray_node_data_get(nodes)[0].prev = 2;
+ darray_node_data_get(nodes)[2].next = 0;
+ return RES_OK;
}
static res_T
-compute_hit_nodes
- (struct darray_node* mesh_nodes,
- struct darray_double* mesh_coords,
- struct darray_node* poly_nodes,
- struct darray_double* poly_coords)
+setup_intersection_nodes
+ (struct darray_node* nodes0,
+ struct darray_double* coords0,
+ struct darray_node* nodes1,
+ struct darray_double* coords1)
{
- size_t nmesh_edges, npoly_edges;
- size_t imesh_edge, ipoly_edge;
+ size_t inode0, nnodes0;
+ size_t inode1, nnodes1;
res_T res = RES_OK;
- ASSERT(mesh_nodes && mesh_coords && poly_nodes && poly_coords);
+ ASSERT(nodes0 && coords0 && nodes1 && coords1);
- nmesh_edges = darray_node_size_get(mesh_nodes)/2;
- npoly_edges = darray_node_size_get(poly_nodes);
+ nnodes0 = darray_node_size_get(nodes0);
+ nnodes1 = darray_node_size_get(nodes1);
- FOR_EACH(imesh_edge, 0, nmesh_edges) {
- struct node* mesh_node = darray_node_data_get(mesh_nodes) + imesh_edge;
- double mesh_edge[2][2];
+ #define POS(Array) darray_double_data_get(Array)
+ #define NODES(Array) darray_node_data_get(Array)
+ FOR_EACH(inode0, 0, nnodes0) {
+ double edge0[2][2];
- /* Fetch the coordinates of the edge0 vertices */
- d2_set(mesh_edge[0], darray_double_data_get(mesh_coords) + mesh_node[0].id*2);
- d2_set(mesh_edge[1], darray_double_data_get(mesh_coords) + mesh_node[1].id*2);
+ /* Fetch the coordinates of the edge0 */
+ d2_set(edge0[0], POS(coords0) + NODES(nodes0)[inode0].id*2);
+ d2_set(edge0[1], POS(coords0) + NODES(nodes0)[(inode0+1)%nnodes0].id*2);
- FOR_EACH(ipoly_edge, 0, npoly_edges) {
- const size_t ipoly_node0 = ipoly_edge;
- const size_t ipoly_node1 = (ipoly_edge + 1) % npoly_edges;
- struct node* poly_node0;
- struct node* poly_node1;
+ FOR_EACH(inode1, 0, nnodes1) {
struct node* node;
- struct node* mesh_hit_node;
- struct node* poly_hit_node;
struct hit hit;
- size_t inode;
- size_t imesh_hit_node, ipoly_hit_node;
- size_t imesh_hit_pos, ipoly_hit_pos;
- double poly_edge[2][2];
-
- poly_node0 = darray_node_data_get(poly_nodes) + ipoly_node0;
- poly_node1 = darray_node_data_get(poly_nodes) + ipoly_node1;
+ double edge1[2][2];
+ size_t ihit_node0, ihit_node1;
+ size_t ihit_pos;
- /* Fetch the coordinates of the edge1 vertices */
- d2_set(poly_edge[0], darray_double_data_get(poly_coords) + poly_node0->id*2);
- d2_set(poly_edge[1], darray_double_data_get(poly_coords) + poly_node1->id*2);
+ /* Fetch the coordinates of the edge1 */
+ d2_set(edge1[0], POS(coords1) + NODES(nodes1)[inode1].id*2);
+ d2_set(edge1[1], POS(coords1) + NODES(nodes1)[(inode1+1)%nnodes1].id*2);
- /* Find the intersection between the 2 edges */
- if(!intersect_edges(mesh_edge, poly_edge, &hit))
- continue;
+ /* Find the edge intersection */
+ if(!intersect_edges(edge0, edge1, &hit)) continue;
- /* Allocate the hit node in the mesh node list */
- imesh_hit_node = darray_node_size_get(mesh_nodes);
- res = darray_node_resize(mesh_nodes, imesh_hit_node + 1);
+ /* Allocate the hit node into the node list 0 */
+ ihit_node0 = darray_node_size_get(nodes0);
+ res = darray_node_resize(nodes0, ihit_node0 + 1);
if(res != RES_OK) goto error;
- mesh_hit_node = darray_node_data_get(mesh_nodes) + imesh_hit_node;
- /* Allocate the hit node in the polygon node list */
- ipoly_hit_node = darray_node_size_get(poly_nodes);
- res = darray_node_resize(poly_nodes, ipoly_hit_node + 1);
+ /* Allocate the hit node into the node list 1 */
+ ihit_node1 = darray_node_size_get(nodes1);
+ res = darray_node_resize(nodes1, ihit_node1 + 1);
if(res != RES_OK) goto error;
- poly_hit_node = darray_node_data_get(poly_nodes) + ipoly_hit_node;
- /* Register the hit position in the mesh vertex buffer */
- imesh_hit_pos = darray_double_size_get(mesh_coords);
- res = darray_double_resize(mesh_coords, imesh_hit_pos + 2);
+ /* Register the hit position into the coords0 */
+ ihit_pos = darray_double_size_get(coords0);
+ res = darray_double_resize(coords0, ihit_pos + 2);
if(res != RES_OK) goto error;
- d2_set(darray_double_data_get(mesh_coords) + imesh_hit_pos, hit.pos);
- imesh_hit_pos /= 2/*#coords per vertex*/;
+ d2_set(POS(coords0) + ihit_pos, hit.pos);
+ ihit_pos /= 2/* #coords per vertex */;
- /* Register the hit position in the vertex buffer 1 */
- ipoly_hit_pos = darray_double_size_get(poly_coords);
- res = darray_double_resize(poly_coords, ipoly_hit_pos + 2);
- if(res != RES_OK) goto error;
- d2_set(darray_double_data_get(poly_coords) + ipoly_hit_pos, hit.pos);
- ipoly_hit_pos /= 2/*#coords per vertex*/;
-
- /* Insert the hit node in the mesh node list */
- mesh_node = darray_node_data_get(mesh_nodes) + imesh_edge*2;
- node = darray_node_data_get(mesh_nodes) + mesh_node[0].next;
- while(node->link != SIZE_MAX && node->t <= hit.t0) {
- node = darray_node_data_get(mesh_nodes) + node->next;
+ /*
+ * Note that the hit position is not registered in the coords1 array
+ */
+
+ /* Insert the hit node into the node list 0 */
+ node = NODES(nodes0) + NODES(nodes0)[inode0].next;
+ while(node->link != SIZE_MAX && node->t < hit.t0) {
+ node = NODES(nodes0) + node->next;
}
- inode = (size_t)(node - darray_node_data_get(mesh_nodes));
- mesh_hit_node->next = inode;
- mesh_hit_node->prev = node->prev;
- mesh_hit_node->link = ipoly_hit_node; /* Hit id in the poly node list */
- mesh_hit_node->id = imesh_hit_pos;
- mesh_hit_node->t = hit.t0;
- darray_node_data_get(mesh_nodes)[node->prev].next = imesh_hit_node;
- node->prev = imesh_hit_node;
-
- /* Insert the hit node in the poly node list 1 */
- poly_node0 = darray_node_data_get(poly_nodes) + ipoly_node0;
- node = darray_node_data_get(poly_nodes) + poly_node0->next;
- while(node->link != SIZE_MAX && node->t <= hit.t1) {
- node = darray_node_data_get(poly_nodes) + node->next;
+ NODES(nodes0)[ihit_node0].next = (size_t)(node - NODES(nodes0));
+ NODES(nodes0)[ihit_node0].prev = node->prev;
+ NODES(nodes0)[ihit_node0].link = ihit_node1;
+ NODES(nodes0)[ihit_node0].id = ihit_pos;
+ NODES(nodes0)[ihit_node0].t = hit.t0;
+ NODES(nodes0)[node->prev].next = ihit_node0;
+ node->prev = ihit_node0;
+
+ /* Inser the hit node into the node list 1 */
+ node = NODES(nodes1) + NODES(nodes1)[inode1].next;
+ while(node->link != SIZE_MAX && node->t < hit.t1) {
+ node = NODES(nodes1) + node->next;
}
- inode = (size_t)(node - darray_node_data_get(poly_nodes));
- poly_hit_node->next = inode;
- poly_hit_node->prev = node->prev;
- poly_hit_node->link = imesh_hit_node; /* Hit id in the mesh node list */
- poly_hit_node->id = ipoly_hit_pos;
- poly_hit_node->t = hit.t1;
- darray_node_data_get(poly_nodes)[node->prev].next = ipoly_hit_node;
- node->prev = ipoly_hit_node;
+ NODES(nodes1)[ihit_node1].next = (size_t)(node - NODES(nodes1));
+ NODES(nodes1)[ihit_node1].prev = node->prev;
+ NODES(nodes1)[ihit_node1].link = ihit_node0;
+ NODES(nodes1)[ihit_node1].id = ihit_pos;
+ NODES(nodes1)[ihit_node1].t = hit.t1;
+ NODES(nodes1)[node->prev].next = ihit_node1;
+ node->prev = ihit_node1;
}
}
+ #undef POS
+ #undef NODES
exit:
return res;
@@ -362,7 +306,7 @@ error:
}
static void
-vertices_setup_inside_polygon_flag
+vertices_setup_inside_poly_flag
(const struct darray_double* coords,
const struct darray_node* poly_nodes,
const struct darray_double* poly_coords,
@@ -393,69 +337,51 @@ vertices_setup_inside_polygon_flag
}
static res_T
-mesh_setup_candidate_nodes
- (const struct cpr_mesh* mesh,
- const size_t itri,
- struct htable_edge* edges,
- const struct darray_node* mesh_nodes,
- struct darray_node* poly_nodes,
- struct darray_node* cand_nodes)
+clip
+ (const struct darray_node* cand_nodes,
+ const struct darray_node* clip_nodes,
+ const char* is_inside,
+ struct darray_size_t* output)
{
- const struct node* msh_nodes;
- size_t ids[3];
- size_t iedge;
- size_t icand_node_last;
+ enum { CAND, CLIP };
+ size_t icand_node, ncand_nodes;
+ const struct node* node_lists[2];
res_T res = RES_OK;
+ ASSERT(cand_nodes && clip_nodes && is_inside && output);
- ASSERT(mesh_nodes && cand_nodes);
- ASSERT(itri < darray_node_size_get(mesh_nodes) /
- (3/*#edge per triangle*/*2/*#node per edge*/));
-
- darray_node_clear(cand_nodes);
- CPR(mesh_get_indices(mesh, itri, ids));
+ ncand_nodes = darray_node_size_get(cand_nodes);
+ node_lists[CAND] = darray_node_cdata_get(cand_nodes);
+ node_lists[CLIP] = darray_node_cdata_get(clip_nodes);
- msh_nodes = darray_node_cdata_get(mesh_nodes);
+ FOR_EACH(icand_node, 0, ncand_nodes) {
+ size_t ilist = CAND;
+ const struct node* n0 = node_lists[CAND] + icand_node;
+ const struct node* n1 = node_lists[CAND] + node_lists[CAND][icand_node].next;
+ const struct node* node_start;
+ const struct node* node;
- FOR_EACH(iedge, 0, 3) {
- struct edge edge;
- size_t imesh_node;
- int flip_edge;
+ if(n0->link != SIZE_MAX || n1->link == SIZE_MAX || is_inside[n1->id])
+ continue;
- edge.v0 = ids[iedge], edge.v1 = ids[(iedge+1)%3];
- if((flip_edge = edge.v0 > edge.v1)) SWAP(size_t, edge.v0, edge.v1);
-
- imesh_node = *htable_edge_find(edges, &edge) + (size_t)flip_edge;
+ darray_size_t_clear(output);
+ node_start = node = n1;
do {
- struct node* cand_node;
- const size_t icand_node = darray_node_size_get(cand_nodes);
-
- res = darray_node_resize(cand_nodes, icand_node + 1);
- if(res != RES_OK) goto error;
- cand_node = darray_node_data_get(cand_nodes) + icand_node;
-
- cand_node->prev = icand_node - 1;
- cand_node->next = icand_node + 1;
- cand_node->link = msh_nodes[imesh_node].link;
- cand_node->id = msh_nodes[imesh_node].id;
- cand_node->t = msh_nodes[imesh_node].t;
- if(cand_node->link) {
- darray_node_data_get(poly_nodes)[cand_node->link].link =
- icand_node;
- }
- } while(flip_edge
- ? msh_nodes[msh_nodes[imesh_node].prev].prev != SIZE_MAX
- : msh_nodes[msh_nodes[imesh_node].next].next != SIZE_MAX);
+ res = darray_size_t_push_back(output, &node->id);
+ if(res != RES_OK) goto error;
- icand_node_last = darray_node_size_get(cand_nodes) - 1;
- darray_node_data_get(cand_nodes)[0].prev = icand_node_last;
- darray_node_data_get(cand_nodes)[icand_node_last].next = 0;
+ node = node_lists[ilist] + node->next;
+ if(node->link != SIZE_MAX) {
+ ilist = !ilist;
+ node = node_lists[ilist] + node->link;
+ }
+ } while(node != node_start);
}
exit:
return res;
error:
- darray_node_clear(cand_nodes);
+ darray_size_t_clear(output);
goto exit;
}
@@ -624,56 +550,60 @@ cpr_mesh_get_position
res_T
cpr_mesh_clip(struct cpr_mesh* mesh, struct cpr_polygon* polygon)
{
- struct darray_node mesh_nodes;
struct darray_node poly_nodes;
struct darray_node cand_nodes; /* Candidate */
+ struct darray_node clip_nodes;
struct darray_char is_inside;
- struct htable_edge edges;
- struct polygon poly;
- size_t itri, ntris;
+ struct poly poly;
+ size_t itri, ntris, nverts;
res_T res = RES_OK;
- darray_node_init(mesh->allocator, &mesh_nodes);
darray_node_init(mesh->allocator, &poly_nodes);
darray_node_init(mesh->allocator, &cand_nodes);
+ darray_node_init(mesh->allocator, &clip_nodes);
darray_char_init(mesh->allocator, &is_inside);
- htable_edge_init(mesh->allocator, &edges);
- polygon_init(mesh->allocator, &poly);
+ poly_init(mesh->allocator, &poly);
if(!mesh || !polygon) {
res = RES_BAD_ARG;
goto error;
}
- res = polygon_setup(&poly, polygon);
+ /* Setup the polygon */
+ res = poly_setup(&poly, polygon);
if(res != RES_OK) goto error;
- res = polygon_setup_nodes(&poly, &poly_nodes);
+ res = poly_setup_nodes(&poly, &poly_nodes);
if(res != RES_OK) goto error;
- vertices_setup_inside_polygon_flag(&mesh->coords, &poly_nodes,
- &poly.coords, darray_char_data_get(&is_inside));
- res = mesh_setup_edge_nodes(mesh, &mesh_nodes, &edges);
- if(res != RES_OK) goto error;
- res = compute_hit_nodes
- (&mesh_nodes, &mesh->coords, &poly_nodes, &poly.coords);
+ /* Define which mesh vertices are inside the polygon */
+ CPR(mesh_get_vertices_count(mesh, &nverts));
+ res = darray_char_resize(&is_inside, nverts);
if(res != RES_OK) goto error;
+ vertices_setup_inside_poly_flag(&mesh->coords, &poly_nodes,
+ &poly.coords, darray_char_data_get(&is_inside));
CPR(mesh_get_triangles_count(mesh, &ntris));
FOR_EACH(itri, 0, ntris) {
- res = mesh_setup_candidate_nodes
- (mesh, itri, &edges, &mesh_nodes, &poly_nodes, &cand_nodes);
+ size_t ids[3];
+
+ CPR(mesh_get_indices(mesh, itri, ids));
+ res = triangle_setup_nodes(ids, &cand_nodes);
+ if(res != RES_OK) goto error;
+
+ res = darray_node_copy(&clip_nodes, &poly_nodes);
if(res != RES_OK) goto error;
- /*TODO clip(&cand_nodes, &poly_nodes);*/
+ res = setup_intersection_nodes
+ (&cand_nodes, &mesh->coords, &poly_nodes, &poly.coords);
+ if(res != RES_OK) goto error;
}
exit:
- darray_node_release(&mesh_nodes);
darray_node_release(&poly_nodes);
darray_node_release(&cand_nodes);
+ darray_node_release(&clip_nodes);
darray_char_release(&is_inside);
- htable_edge_release(&edges);
- polygon_release(&poly);
+ poly_release(&poly);
return res;
error: