From: Barak Itkin Date: Fri, 1 Jun 2012 17:21:30 +0000 (+0300) Subject: Convert line endings to unix format (\n instead of \r\n) X-Git-Tag: p2tc-0.1.0~49 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=21f1236ddac6d893b815d8ce2b322eabee5755e8;p=poly2tri-c Convert line endings to unix format (\n instead of \r\n) --- diff --git a/p2t/common/utils.h b/p2t/common/utils.h index 014fc16..0031b65 100644 --- a/p2t/common/utils.h +++ b/p2t/common/utils.h @@ -1,63 +1,63 @@ -/* - * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors - * http://code.google.com/p/poly2tri/ - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of Poly2Tri nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef UTILS_H -#define UTILS_H - -#include -#include "poly2tri-private.h" -#include "cutils.h" -#include "shapes.h" - -#define PI_3div4 (3 * G_PI / 4) -#define EPSILON (1e-6) - -typedef enum -{ - CW, CCW, COLLINEAR -} P2tOrientation; - -/** - * Forumla to calculate signed area
- * Positive if CCW
- * Negative if CW
- * 0 if collinear
- *
- * A[P1,P2,P3]  =  (x1*y2 - y1*x2) + (x2*y3 - y2*x3) + (x3*y1 - y3*x1)
- *              =  (x1-x3)*(y2-y3) - (y1-y3)*(x2-x3)
- * 
- */ -P2tOrientation p2t_orient2d (P2tPoint* pa, P2tPoint* pb, P2tPoint* pc); - -gboolean p2t_utils_in_scan_area (P2tPoint* pa, P2tPoint* pb, P2tPoint* pc, P2tPoint* pd); - -#endif - +/* + * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors + * http://code.google.com/p/poly2tri/ + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Poly2Tri nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UTILS_H +#define UTILS_H + +#include +#include "poly2tri-private.h" +#include "cutils.h" +#include "shapes.h" + +#define PI_3div4 (3 * G_PI / 4) +#define EPSILON (1e-6) + +typedef enum +{ + CW, CCW, COLLINEAR +} P2tOrientation; + +/** + * Forumla to calculate signed area
+ * Positive if CCW
+ * Negative if CW
+ * 0 if collinear
+ *
+ * A[P1,P2,P3]  =  (x1*y2 - y1*x2) + (x2*y3 - y2*x3) + (x3*y1 - y3*x1)
+ *              =  (x1-x3)*(y2-y3) - (y1-y3)*(x2-x3)
+ * 
+ */ +P2tOrientation p2t_orient2d (P2tPoint* pa, P2tPoint* pb, P2tPoint* pc); + +gboolean p2t_utils_in_scan_area (P2tPoint* pa, P2tPoint* pb, P2tPoint* pc, P2tPoint* pd); + +#endif + diff --git a/p2t/sweep/cdt.c b/p2t/sweep/cdt.c index 49785e6..4ed0503 100644 --- a/p2t/sweep/cdt.c +++ b/p2t/sweep/cdt.c @@ -1,90 +1,90 @@ -/* - * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors - * http://code.google.com/p/poly2tri/ - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of Poly2Tri nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include "cdt.h" - -void -p2t_cdt_init (P2tCDT* THIS, P2tPointPtrArray polyline) -{ - THIS->sweep_context_ = p2t_sweepcontext_new (polyline); - THIS->sweep_ = p2t_sweep_new (); -} - -P2tCDT* -p2t_cdt_new (P2tPointPtrArray polyline) -{ - P2tCDT* THIS = g_slice_new (P2tCDT); - p2t_cdt_init (THIS, polyline); - return THIS; -} - -void -p2t_cdt_destroy (P2tCDT* THIS) -{ - p2t_sweepcontext_delete (THIS->sweep_context_); - p2t_sweep_free (THIS->sweep_); -} - -void -p2t_cdt_free (P2tCDT* THIS) -{ - p2t_cdt_destroy (THIS); - g_slice_free (P2tCDT, THIS); -} - -void -p2t_cdt_add_hole (P2tCDT *THIS, P2tPointPtrArray polyline) -{ - p2t_sweepcontext_add_hole (THIS->sweep_context_, polyline); -} - -void -p2t_cdt_add_point (P2tCDT *THIS, P2tPoint* point) -{ - p2t_sweepcontext_add_point (THIS->sweep_context_, point); -} - -void -p2t_cdt_triangulate (P2tCDT *THIS) -{ - p2t_sweep_triangulate (THIS->sweep_, THIS->sweep_context_); -} - -P2tTrianglePtrArray -p2t_cdt_get_triangles (P2tCDT *THIS) -{ - return p2t_sweepcontext_get_triangles (THIS->sweep_context_); -} - -P2tTrianglePtrList -p2t_cdt_get_map (P2tCDT *THIS) -{ - return p2t_sweepcontext_get_map (THIS->sweep_context_); -} +/* + * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors + * http://code.google.com/p/poly2tri/ + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Poly2Tri nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "cdt.h" + +void +p2t_cdt_init (P2tCDT* THIS, P2tPointPtrArray polyline) +{ + THIS->sweep_context_ = p2t_sweepcontext_new (polyline); + THIS->sweep_ = p2t_sweep_new (); +} + +P2tCDT* +p2t_cdt_new (P2tPointPtrArray polyline) +{ + P2tCDT* THIS = g_slice_new (P2tCDT); + p2t_cdt_init (THIS, polyline); + return THIS; +} + +void +p2t_cdt_destroy (P2tCDT* THIS) +{ + p2t_sweepcontext_delete (THIS->sweep_context_); + p2t_sweep_free (THIS->sweep_); +} + +void +p2t_cdt_free (P2tCDT* THIS) +{ + p2t_cdt_destroy (THIS); + g_slice_free (P2tCDT, THIS); +} + +void +p2t_cdt_add_hole (P2tCDT *THIS, P2tPointPtrArray polyline) +{ + p2t_sweepcontext_add_hole (THIS->sweep_context_, polyline); +} + +void +p2t_cdt_add_point (P2tCDT *THIS, P2tPoint* point) +{ + p2t_sweepcontext_add_point (THIS->sweep_context_, point); +} + +void +p2t_cdt_triangulate (P2tCDT *THIS) +{ + p2t_sweep_triangulate (THIS->sweep_, THIS->sweep_context_); +} + +P2tTrianglePtrArray +p2t_cdt_get_triangles (P2tCDT *THIS) +{ + return p2t_sweepcontext_get_triangles (THIS->sweep_context_); +} + +P2tTrianglePtrList +p2t_cdt_get_map (P2tCDT *THIS) +{ + return p2t_sweepcontext_get_map (THIS->sweep_context_); +} diff --git a/p2t/sweep/cdt.h b/p2t/sweep/cdt.h index fdc57af..4428467 100644 --- a/p2t/sweep/cdt.h +++ b/p2t/sweep/cdt.h @@ -1,101 +1,101 @@ -/* - * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors - * http://code.google.com/p/poly2tri/ - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of Poly2Tri nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef CDT_H -#define CDT_H - -#include "../common/poly2tri-private.h" -#include "advancing_front.h" -#include "sweep_context.h" -#include "sweep.h" - -/** - * - * @author Mason Green - * - */ - -struct CDT_ -{ - /*private: */ - - /** - * Internals - */ - - P2tSweepContext* sweep_context_; - P2tSweep* sweep_; - -}; -/** - * Constructor - add polyline with non repeating points - * - * @param polyline - */ -void p2t_cdt_init (P2tCDT* THIS, P2tPointPtrArray polyline); -P2tCDT* p2t_cdt_new (P2tPointPtrArray polyline); - -/** - * Destructor - clean up memory - */ -void p2t_cdt_destroy (P2tCDT* THIS); -void p2t_cdt_free (P2tCDT* THIS); - -/** - * Add a hole - * - * @param polyline - */ -void p2t_cdt_add_hole (P2tCDT *THIS, P2tPointPtrArray polyline); - -/** - * Add a steiner point - * - * @param point - */ -void p2t_cdt_add_point (P2tCDT *THIS, P2tPoint* point); - -/** - * Triangulate - do this AFTER you've added the polyline, holes, and Steiner points - */ -void p2t_cdt_triangulate (P2tCDT *THIS); - -/** - * Get CDT triangles - */ -P2tTrianglePtrArray p2t_cdt_get_triangles (P2tCDT *THIS); - -/** - * Get triangle map - */ -P2tTrianglePtrList p2t_cdt_get_map (P2tCDT *THIS); - -#endif +/* + * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors + * http://code.google.com/p/poly2tri/ + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Poly2Tri nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CDT_H +#define CDT_H + +#include "../common/poly2tri-private.h" +#include "advancing_front.h" +#include "sweep_context.h" +#include "sweep.h" + +/** + * + * @author Mason Green + * + */ + +struct CDT_ +{ + /*private: */ + + /** + * Internals + */ + + P2tSweepContext* sweep_context_; + P2tSweep* sweep_; + +}; +/** + * Constructor - add polyline with non repeating points + * + * @param polyline + */ +void p2t_cdt_init (P2tCDT* THIS, P2tPointPtrArray polyline); +P2tCDT* p2t_cdt_new (P2tPointPtrArray polyline); + +/** + * Destructor - clean up memory + */ +void p2t_cdt_destroy (P2tCDT* THIS); +void p2t_cdt_free (P2tCDT* THIS); + +/** + * Add a hole + * + * @param polyline + */ +void p2t_cdt_add_hole (P2tCDT *THIS, P2tPointPtrArray polyline); + +/** + * Add a steiner point + * + * @param point + */ +void p2t_cdt_add_point (P2tCDT *THIS, P2tPoint* point); + +/** + * Triangulate - do this AFTER you've added the polyline, holes, and Steiner points + */ +void p2t_cdt_triangulate (P2tCDT *THIS); + +/** + * Get CDT triangles + */ +P2tTrianglePtrArray p2t_cdt_get_triangles (P2tCDT *THIS); + +/** + * Get triangle map + */ +P2tTrianglePtrList p2t_cdt_get_map (P2tCDT *THIS); + +#endif diff --git a/p2t/sweep/sweep.c b/p2t/sweep/sweep.c index 3a63399..71c084e 100644 --- a/p2t/sweep/sweep.c +++ b/p2t/sweep/sweep.c @@ -1,958 +1,958 @@ -/* - * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors - * http://code.google.com/p/poly2tri/ - * - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of Poly2Tri nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include - -#include "sweep.h" -#include "sweep_context.h" -#include "advancing_front.h" -#include "../common/utils.h" -#include "../common/shapes.h" - -void -p2t_sweep_init (P2tSweep* THIS) -{ - THIS->nodes_ = g_ptr_array_new (); -} - -P2tSweep* -p2t_sweep_new () -{ - P2tSweep* THIS = g_new (P2tSweep, 1); - p2t_sweep_init (THIS); - return THIS; -} - -/** - * Destructor - clean up memory - */ -void -p2t_sweep_destroy (P2tSweep* THIS) -{ - int i; - /* Clean up memory */ - for (i = 0; i < THIS->nodes_->len; i++) - { - p2t_node_free (node_index (THIS->nodes_, i)); - } - - g_ptr_array_free (THIS->nodes_, TRUE); -} - -void -p2t_sweep_free (P2tSweep* THIS) -{ - p2t_sweep_destroy (THIS); - g_free (THIS); -} - -/* Triangulate simple polygon with holes */ - -void -p2t_sweep_triangulate (P2tSweep *THIS, P2tSweepContext *tcx) -{ - p2t_sweepcontext_init_triangulation (tcx); - p2t_sweepcontext_create_advancingfront (tcx, THIS->nodes_); - /* Sweep points; build mesh */ - p2t_sweep_sweep_points (THIS, tcx); - /* Clean up */ - p2t_sweep_finalization_polygon (THIS, tcx); -} - -void -p2t_sweep_sweep_points (P2tSweep *THIS, P2tSweepContext *tcx) -{ - int i, j; - for (i = 1; i < p2t_sweepcontext_point_count (tcx); i++) - { - P2tPoint* point = p2t_sweepcontext_get_point (tcx, i); - P2tNode* node = p2t_sweep_point_event (THIS, tcx, point); - for (j = 0; j < point->edge_list->len; j++) - { - p2t_sweep_edge_event_ed_n (THIS, tcx, edge_index (point->edge_list, j), node); - } - } -} - -void -p2t_sweep_finalization_polygon (P2tSweep *THIS, P2tSweepContext *tcx) -{ - /* Get an Internal triangle to start with */ - P2tTriangle* t = p2t_advancingfront_head (p2t_sweepcontext_front (tcx))->next->triangle; - P2tPoint* p = p2t_advancingfront_head (p2t_sweepcontext_front (tcx))->next->point; - while (!p2t_triangle_get_constrained_edge_cw (t, p)) - { - t = p2t_triangle_neighbor_ccw (t, p); - } - - /* Collect interior triangles constrained by edges */ - p2t_sweepcontext_mesh_clean (tcx, t); -} - -P2tNode* -p2t_sweep_point_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tPoint* point) -{ - P2tNode* node = p2t_sweepcontext_locate_node (tcx, point); - P2tNode* new_node = p2t_sweep_new_front_triangle (THIS, tcx, point, node); - - /* Only need to check +epsilon since point never have smaller - * x value than node due to how we fetch nodes from the front */ - if (point->x <= node->point->x + EPSILON) - { - p2t_sweep_fill (THIS, tcx, node); - } - - /*tcx.AddNode(new_node); */ - - p2t_sweep_fill_advancingfront (THIS, tcx, new_node); - return new_node; -} - -void -p2t_sweep_edge_event_ed_n (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node) -{ - tcx->edge_event.constrained_edge = edge; - tcx->edge_event.right = (edge->p->x > edge->q->x); - - if (p2t_sweep_is_edge_side_of_triangle (THIS, node->triangle, edge->p, edge->q)) - { - return; - } - - /* For now we will do all needed filling - * TODO: integrate with flip process might give some better performance - * but for now this avoid the issue with cases that needs both flips and fills - */ - p2t_sweep_fill_edge_event (THIS, tcx, edge, node); - p2t_sweep_edge_event_pt_pt_tr_pt (THIS, tcx, edge->p, edge->q, node->triangle, edge->q); -} - -void -p2t_sweep_edge_event_pt_pt_tr_pt (P2tSweep *THIS, P2tSweepContext *tcx, P2tPoint* ep, P2tPoint* eq, P2tTriangle* triangle, P2tPoint* point) -{ - P2tPoint *p1, *p2; - P2tOrientation o1, o2; - - if (p2t_sweep_is_edge_side_of_triangle (THIS, triangle, ep, eq)) - { - return; - } - - p1 = p2t_triangle_point_ccw (triangle, point); - o1 = p2t_orient2d (eq, p1, ep); - if (o1 == COLLINEAR) - { - if (p2t_triangle_contains_pt_pt (triangle, eq, p1)) - { - p2t_triangle_mark_constrained_edge_pt_pt (triangle, eq, p1); - /* We are modifying the constraint maybe it would be better to - * not change the given constraint and just keep a variable for the new constraint - */ - tcx->edge_event.constrained_edge->q = p1; - triangle = p2t_triangle_neighbor_across (triangle, point); - p2t_sweep_edge_event_pt_pt_tr_pt (THIS, tcx, ep, p1, triangle, p1); - } - else - { - g_error ("EdgeEvent - collinear points not supported"); - } - return; - } - - p2 = p2t_triangle_point_cw (triangle, point); - o2 = p2t_orient2d (eq, p2, ep); - if (o2 == COLLINEAR) - { - if (p2t_triangle_contains_pt_pt (triangle, eq, p2)) - { - p2t_triangle_mark_constrained_edge_pt_pt (triangle, eq, p2); - /* We are modifying the constraint maybe it would be better to - * not change the given constraint and just keep a variable for the new constraint - */ - tcx->edge_event.constrained_edge->q = p2; - triangle = p2t_triangle_neighbor_across (triangle, point); - p2t_sweep_edge_event_pt_pt_tr_pt (THIS, tcx, ep, p2, triangle, p2); - } - else - { - g_error ("EdgeEvent - collinear points not supported"); - } - return; - } - - if (o1 == o2) - { - /* Need to decide if we are rotating CW or CCW to get to a triangle - * that will cross edge */ - if (o1 == CW) - { - triangle = p2t_triangle_neighbor_ccw (triangle, point); - } - else - { - triangle = p2t_triangle_neighbor_cw (triangle, point); - } - p2t_sweep_edge_event_pt_pt_tr_pt (THIS, tcx, ep, eq, triangle, point); - } - else - { - /* This triangle crosses constraint so lets flippin start! */ - p2t_sweep_flip_edge_event (THIS, tcx, ep, eq, triangle, point); - } -} - -gboolean -p2t_sweep_is_edge_side_of_triangle (P2tSweep *THIS, P2tTriangle *triangle, P2tPoint* ep, P2tPoint* eq) -{ - int index = p2t_triangle_edge_index (triangle, ep, eq); - - if (index != -1) - { - P2tTriangle *t; - p2t_triangle_mark_constrained_edge_i (triangle, index); - t = p2t_triangle_get_neighbor (triangle, index); - if (t) - { - p2t_triangle_mark_constrained_edge_pt_pt (t, ep, eq); - } - return TRUE; - } - return FALSE; -} - -P2tNode* -p2t_sweep_new_front_triangle (P2tSweep *THIS, P2tSweepContext *tcx, P2tPoint* point, P2tNode *node) -{ - P2tTriangle* triangle = p2t_triangle_new (point, node->point, node->next->point); - P2tNode *new_node; - - p2t_triangle_mark_neighbor_tr (triangle, node->triangle); - p2t_sweepcontext_add_to_map (tcx, triangle); - - new_node = p2t_node_new_pt (point); - g_ptr_array_add (THIS->nodes_, new_node); - - new_node->next = node->next; - new_node->prev = node; - node->next->prev = new_node; - node->next = new_node; - - if (!p2t_sweep_legalize (THIS, tcx, triangle)) - { - p2t_sweepcontext_map_triangle_to_nodes (tcx, triangle); - } - - return new_node; -} - -void -p2t_sweep_fill (P2tSweep *THIS, P2tSweepContext *tcx, P2tNode* node) -{ - P2tTriangle* triangle = p2t_triangle_new (node->prev->point, node->point, node->next->point); - - /* TODO: should copy the constrained_edge value from neighbor triangles - * for now constrained_edge values are copied during the legalize */ - p2t_triangle_mark_neighbor_tr (triangle, node->prev->triangle); - p2t_triangle_mark_neighbor_tr (triangle, node->triangle); - - p2t_sweepcontext_add_to_map (tcx, triangle); - - /* Update the advancing front */ - node->prev->next = node->next; - node->next->prev = node->prev; - - /* If it was legalized the triangle has already been mapped */ - if (!p2t_sweep_legalize (THIS, tcx, triangle)) - { - p2t_sweepcontext_map_triangle_to_nodes (tcx, triangle); - } - -} - -void -p2t_sweep_fill_advancingfront (P2tSweep *THIS, P2tSweepContext *tcx, P2tNode* n) -{ - - /* Fill right holes */ - P2tNode* node = n->next; - - while (node->next) - { - double angle = p2t_sweep_hole_angle (THIS, node); - if (angle > G_PI_2 || angle < -G_PI_2) break; - p2t_sweep_fill (THIS, tcx, node); - node = node->next; - } - - /* Fill left holes */ - node = n->prev; - - while (node->prev) - { - double angle = p2t_sweep_hole_angle (THIS, node); - if (angle > G_PI_2 || angle < -G_PI_2) break; - p2t_sweep_fill (THIS, tcx, node); - node = node->prev; - } - - /* Fill right basins */ - if (n->next && n->next->next) - { - double angle = p2t_sweep_basin_angle (THIS, n); - if (angle < PI_3div4) - { - p2t_sweep_fill_basin (THIS, tcx, n); - } - } -} - -double -p2t_sweep_basin_angle (P2tSweep *THIS, P2tNode* node) -{ - double ax = node->point->x - node->next->next->point->x; - double ay = node->point->y - node->next->next->point->y; - return atan2 (ay, ax); -} - -double -p2t_sweep_hole_angle (P2tSweep *THIS, P2tNode* node) -{ - /* Complex plane - * ab = cosA +i*sinA - * ab = (ax + ay*i)(bx + by*i) = (ax*bx + ay*by) + i(ax*by-ay*bx) - * atan2(y,x) computes the principal value of the argument function - * applied to the complex number x+iy - * Where x = ax*bx + ay*by - * y = ax*by - ay*bx - */ - double ax = node->next->point->x - node->point->x; - double ay = node->next->point->y - node->point->y; - double bx = node->prev->point->x - node->point->x; - double by = node->prev->point->y - node->point->y; - return atan2 (ax * by - ay * bx, ax * bx + ay * by); -} - -gboolean -p2t_sweep_legalize (P2tSweep *THIS, P2tSweepContext *tcx, P2tTriangle *t) -{ - int i; - /* To legalize a triangle we start by finding if any of the three edges - * violate the Delaunay condition */ - for (i = 0; i < 3; i++) - { - P2tTriangle *ot; - - if (t->delaunay_edge[i]) - continue; - - ot = p2t_triangle_get_neighbor (t, i); - - if (ot) - { - P2tPoint* p = p2t_triangle_get_point (t, i); - P2tPoint* op = p2t_triangle_opposite_point (ot, t, p); - int oi = p2t_triangle_index (ot, op); - gboolean inside; - - /* If this is a Constrained Edge or a Delaunay Edge(only during recursive legalization) - * then we should not try to legalize */ - if (ot->constrained_edge[oi] || ot->delaunay_edge[oi]) - { - t->constrained_edge[i] = ot->constrained_edge[oi]; - continue; - } - - inside = p2t_sweep_incircle (THIS, p, p2t_triangle_point_ccw (t, p), p2t_triangle_point_cw (t, p), op); - - if (inside) - { - gboolean not_legalized; - /* Lets mark this shared edge as Delaunay */ - t->delaunay_edge[i] = TRUE; - ot->delaunay_edge[oi] = TRUE; - - /* Lets rotate shared edge one vertex CW to legalize it */ - p2t_sweep_rotate_triangle_pair (THIS, t, p, ot, op); - - /* We now got one valid Delaunay Edge shared by two triangles - * This gives us 4 new edges to check for Delaunay */ - - /* Make sure that triangle to node mapping is done only one time for a specific triangle */ - not_legalized = !p2t_sweep_legalize (THIS, tcx, t); - if (not_legalized) - { - p2t_sweepcontext_map_triangle_to_nodes (tcx, t); - } - - not_legalized = !p2t_sweep_legalize (THIS, tcx, ot); - if (not_legalized) - p2t_sweepcontext_map_triangle_to_nodes (tcx, ot); - - /* Reset the Delaunay edges, since they only are valid Delaunay edges - * until we add a new triangle or point. - * XXX: need to think about this. Can these edges be tried after we - * return to previous recursive level? */ - t->delaunay_edge[i] = FALSE; - ot->delaunay_edge[oi] = FALSE; - - /* If triangle have been legalized no need to check the other edges since - * the recursive legalization will handles those so we can end here.*/ - return TRUE; - } - } - } - return FALSE; -} - -gboolean -p2t_sweep_incircle (P2tSweep *THIS, P2tPoint* pa, P2tPoint* pb, P2tPoint* pc, P2tPoint* pd) -{ - double adx = pa->x - pd->x; - double ady = pa->y - pd->y; - double bdx = pb->x - pd->x; - double bdy = pb->y - pd->y; - - double adxbdy = adx * bdy; - double bdxady = bdx * ady; - double oabd = adxbdy - bdxady; - - double cdx, cdy; - double cdxady, adxcdy, ocad; - - double bdxcdy, cdxbdy; - double alift, blift, clift; - double det; - - if (oabd <= 0) - return FALSE; - - cdx = pc->x - pd->x; - cdy = pc->y - pd->y; - - cdxady = cdx * ady; - adxcdy = adx * cdy; - ocad = cdxady - adxcdy; - - if (ocad <= 0) - return FALSE; - - bdxcdy = bdx * cdy; - cdxbdy = cdx * bdy; - - alift = adx * adx + ady * ady; - blift = bdx * bdx + bdy * bdy; - clift = cdx * cdx + cdy * cdy; - - det = alift * (bdxcdy - cdxbdy) + blift * ocad + clift * oabd; - - return det > 0; -} - -void -p2t_sweep_rotate_triangle_pair (P2tSweep *THIS, P2tTriangle *t, P2tPoint* p, P2tTriangle *ot, P2tPoint* op) -{ - P2tTriangle *n1, *n2, *n3, *n4; - gboolean ce1, ce2, ce3, ce4; - gboolean de1, de2, de3, de4; - - n1 = p2t_triangle_neighbor_ccw (t, p); - n2 = p2t_triangle_neighbor_cw (t, p); - n3 = p2t_triangle_neighbor_ccw (ot, op); - n4 = p2t_triangle_neighbor_cw (ot, op); - - ce1 = p2t_triangle_get_constrained_edge_ccw (t, p); - ce2 = p2t_triangle_get_constrained_edge_cw (t, p); - ce3 = p2t_triangle_get_constrained_edge_ccw (ot, op); - ce4 = p2t_triangle_get_constrained_edge_cw (ot, op); - - de1 = p2t_triangle_get_delunay_edge_ccw (t, p); - de2 = p2t_triangle_get_delunay_edge_cw (t, p); - de3 = p2t_triangle_get_delunay_edge_ccw (ot, op); - de4 = p2t_triangle_get_delunay_edge_cw (ot, op); - - p2t_triangle_legalize_pt_pt (t, p, op); - p2t_triangle_legalize_pt_pt (ot, op, p); - - /* Remap delaunay_edge */ - p2t_triangle_set_delunay_edge_ccw (ot, p, de1); - p2t_triangle_set_delunay_edge_cw (t, p, de2); - p2t_triangle_set_delunay_edge_ccw (t, op, de3); - p2t_triangle_set_delunay_edge_cw (ot, op, de4); - - /* Remap constrained_edge */ - p2t_triangle_set_constrained_edge_ccw (ot, p, ce1); - p2t_triangle_set_constrained_edge_cw (t, p, ce2); - p2t_triangle_set_constrained_edge_ccw (t, op, ce3); - p2t_triangle_set_constrained_edge_cw (ot, op, ce4); - - /* Remap neighbors - * XXX: might optimize the markNeighbor by keeping track of - * what side should be assigned to what neighbor after the - * rotation. Now mark neighbor does lots of testing to find - * the right side. */ - p2t_triangle_clear_neighbors (t); - p2t_triangle_clear_neighbors (ot); - if (n1) p2t_triangle_mark_neighbor_tr (ot, n1); - if (n2) p2t_triangle_mark_neighbor_tr (t, n2); - if (n3) p2t_triangle_mark_neighbor_tr (t, n3); - if (n4) p2t_triangle_mark_neighbor_tr (ot, n4); - p2t_triangle_mark_neighbor_tr (t, ot); -} - -void -p2t_sweep_fill_basin (P2tSweep *THIS, P2tSweepContext *tcx, P2tNode* node) -{ - if (p2t_orient2d (node->point, node->next->point, node->next->next->point) == CCW) - { - tcx->basin.left_node = node->next->next; - } - else - { - tcx->basin.left_node = node->next; - } - - /* Find the bottom and right node */ - tcx->basin.bottom_node = tcx->basin.left_node; - while (tcx->basin.bottom_node->next - && tcx->basin.bottom_node->point->y >= tcx->basin.bottom_node->next->point->y) - { - tcx->basin.bottom_node = tcx->basin.bottom_node->next; - } - if (tcx->basin.bottom_node == tcx->basin.left_node) - { - /* No valid basin */ - return; - } - - tcx->basin.right_node = tcx->basin.bottom_node; - while (tcx->basin.right_node->next - && tcx->basin.right_node->point->y < tcx->basin.right_node->next->point->y) - { - tcx->basin.right_node = tcx->basin.right_node->next; - } - if (tcx->basin.right_node == tcx->basin.bottom_node) - { - /* No valid basins */ - return; - } - - tcx->basin.width = tcx->basin.right_node->point->x - tcx->basin.left_node->point->x; - tcx->basin.left_highest = tcx->basin.left_node->point->y > tcx->basin.right_node->point->y; - - p2t_sweep_fill_basin_req (THIS, tcx, tcx->basin.bottom_node); -} - -void -p2t_sweep_fill_basin_req (P2tSweep *THIS, P2tSweepContext *tcx, P2tNode* node) -{ - /* if shallow stop filling */ - if (p2t_sweep_is_shallow (THIS, tcx, node)) - { - return; - } - - p2t_sweep_fill (THIS, tcx, node); - - if (node->prev == tcx->basin.left_node && node->next == tcx->basin.right_node) - { - return; - } - else if (node->prev == tcx->basin.left_node) - { - P2tOrientation o = p2t_orient2d (node->point, node->next->point, node->next->next->point); - if (o == CW) - { - return; - } - node = node->next; - } - else if (node->next == tcx->basin.right_node) - { - P2tOrientation o = p2t_orient2d (node->point, node->prev->point, node->prev->prev->point); - if (o == CCW) - { - return; - } - node = node->prev; - } - else - { - /* Continue with the neighbor node with lowest Y value */ - if (node->prev->point->y < node->next->point->y) - { - node = node->prev; - } - else - { - node = node->next; - } - } - - p2t_sweep_fill_basin_req (THIS, tcx, node); -} - -gboolean -p2t_sweep_is_shallow (P2tSweep *THIS, P2tSweepContext *tcx, P2tNode* node) -{ - double height; - - if (tcx->basin.left_highest) - { - height = tcx->basin.left_node->point->y - node->point->y; - } - else - { - height = tcx->basin.right_node->point->y - node->point->y; - } - - /* if shallow stop filling */ - if (tcx->basin.width > height) - { - return TRUE; - } - return FALSE; -} - -void -p2t_sweep_fill_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node) -{ - if (tcx->edge_event.right) - { - p2t_sweep_fill_right_above_edge_event (THIS, tcx, edge, node); - } - else - { - p2t_sweep_fill_left_above_edge_event (THIS, tcx, edge, node); - } -} - -void -p2t_sweep_fill_right_above_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node) -{ - while (node->next->point->x < edge->p->x) - { - /* Check if next node is below the edge */ - if (p2t_orient2d (edge->q, node->next->point, edge->p) == CCW) - { - p2t_sweep_fill_right_below_edge_event (THIS, tcx, edge, node); - } - else - { - node = node->next; - } - } -} - -void -p2t_sweep_fill_right_below_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node) -{ - if (node->point->x < edge->p->x) - { - if (p2t_orient2d (node->point, node->next->point, node->next->next->point) == CCW) - { - /* Concave */ - p2t_sweep_fill_right_concave_edge_event (THIS, tcx, edge, node); - } - else - { - /* Convex */ - p2t_sweep_fill_right_convex_edge_event (THIS, tcx, edge, node); - /* Retry this one */ - p2t_sweep_fill_right_below_edge_event (THIS, tcx, edge, node); - } - } -} - -void -p2t_sweep_fill_right_concave_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node) -{ - p2t_sweep_fill (THIS, tcx, node->next); - if (node->next->point != edge->p) - { - /* Next above or below edge? */ - if (p2t_orient2d (edge->q, node->next->point, edge->p) == CCW) - { - /* Below */ - if (p2t_orient2d (node->point, node->next->point, node->next->next->point) == CCW) - { - /* Next is concave */ - p2t_sweep_fill_right_concave_edge_event (THIS, tcx, edge, node); - } - else - { - /* Next is convex */ - } - } - } - -} - -void -p2t_sweep_fill_right_convex_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node) -{ - /* Next concave or convex? */ - if (p2t_orient2d (node->next->point, node->next->next->point, node->next->next->next->point) == CCW) - { - /* Concave */ - p2t_sweep_fill_right_concave_edge_event (THIS, tcx, edge, node->next); - } - else - { - /* Convex - * Next above or below edge? */ - if (p2t_orient2d (edge->q, node->next->next->point, edge->p) == CCW) - { - /* Below */ - p2t_sweep_fill_right_convex_edge_event (THIS, tcx, edge, node->next); - } - else - { - /* Above */ - } - } -} - -void -p2t_sweep_fill_left_above_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node) -{ - while (node->prev->point->x > edge->p->x) - { - /* Check if next node is below the edge */ - if (p2t_orient2d (edge->q, node->prev->point, edge->p) == CW) - { - p2t_sweep_fill_left_below_edge_event (THIS, tcx, edge, node); - } - else - { - node = node->prev; - } - } -} - -void -p2t_sweep_fill_left_below_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node) -{ - if (node->point->x > edge->p->x) - { - if (p2t_orient2d (node->point, node->prev->point, node->prev->prev->point) == CW) - { - /* Concave */ - p2t_sweep_fill_left_concave_edge_event (THIS, tcx, edge, node); - } - else - { - /* Convex */ - p2t_sweep_fill_left_convex_edge_event (THIS, tcx, edge, node); - /* Retry this one */ - p2t_sweep_fill_left_below_edge_event (THIS, tcx, edge, node); - } - } -} - -void -p2t_sweep_fill_left_convex_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node) -{ - /* Next concave or convex? */ - if (p2t_orient2d (node->prev->point, node->prev->prev->point, node->prev->prev->prev->point) == CW) - { - /* Concave */ - p2t_sweep_fill_left_concave_edge_event (THIS, tcx, edge, node->prev); - } - else - { - /* Convex - * Next above or below edge? */ - if (p2t_orient2d (edge->q, node->prev->prev->point, edge->p) == CW) - { - /* Below */ - p2t_sweep_fill_left_convex_edge_event (THIS, tcx, edge, node->prev); - } - else - { - /* Above */ - } - } -} - -void -p2t_sweep_fill_left_concave_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node) -{ - p2t_sweep_fill (THIS, tcx, node->prev); - if (node->prev->point != edge->p) - { - /* Next above or below edge? */ - if (p2t_orient2d (edge->q, node->prev->point, edge->p) == CW) - { - /* Below */ - if (p2t_orient2d (node->point, node->prev->point, node->prev->prev->point) == CW) - { - /* Next is concave */ - p2t_sweep_fill_left_concave_edge_event (THIS, tcx, edge, node); - } - else - { - /* Next is convex */ - } - } - } - -} - -void -p2t_sweep_flip_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tPoint* ep, P2tPoint* eq, P2tTriangle* t, P2tPoint* p) -{ - P2tTriangle* ot = p2t_triangle_neighbor_across (t, p); - P2tPoint* op = p2t_triangle_opposite_point (ot, t, p); - - if (ot == NULL) - { - /* If we want to integrate the fillEdgeEvent do it here - * With current implementation we should never get here - *throw new RuntimeException( "[BUG:FIXME] FLIP failed due to missing triangle"); - */ - assert (0); - } - - if (p2t_utils_in_scan_area (p, p2t_triangle_point_ccw (t, p), p2t_triangle_point_cw (t, p), op)) - { - /* Lets rotate shared edge one vertex CW */ - p2t_sweep_rotate_triangle_pair (THIS, t, p, ot, op); - p2t_sweepcontext_map_triangle_to_nodes (tcx, t); - p2t_sweepcontext_map_triangle_to_nodes (tcx, ot); - - if (p == eq && op == ep) - { - if (p2t_point_equals (eq, tcx->edge_event.constrained_edge->q) && p2t_point_equals (ep, tcx->edge_event.constrained_edge->p)) - { - p2t_triangle_mark_constrained_edge_pt_pt (t, ep, eq); - p2t_triangle_mark_constrained_edge_pt_pt (ot, ep, eq); - p2t_sweep_legalize (THIS, tcx, t); - p2t_sweep_legalize (THIS, tcx, ot); - } - else - { - /* XXX: I think one of the triangles should be legalized here? */ - } - } - else - { - P2tOrientation o = p2t_orient2d (eq, op, ep); - t = p2t_sweep_next_flip_triangle (THIS, tcx, (int) o, t, ot, p, op); - p2t_sweep_flip_edge_event (THIS, tcx, ep, eq, t, p); - } - } - else - { - P2tPoint* newP = p2t_sweep_next_flip_point (THIS, ep, eq, ot, op); - p2t_sweep_flip_scan_edge_event (THIS, tcx, ep, eq, t, ot, newP); - p2t_sweep_edge_event_pt_pt_tr_pt (THIS, tcx, ep, eq, t, p); - } -} - -P2tTriangle* -p2t_sweep_next_flip_triangle (P2tSweep *THIS, P2tSweepContext *tcx, int o, P2tTriangle *t, P2tTriangle *ot, P2tPoint* p, P2tPoint* op) -{ - int edge_index; - - if (o == CCW) - { - /* ot is not crossing edge after flip */ - int edge_index = p2t_triangle_edge_index (ot, p, op); - ot->delaunay_edge[edge_index] = TRUE; - p2t_sweep_legalize (THIS, tcx, ot); - p2t_triangle_clear_delunay_edges (ot); - return t; - } - - /* t is not crossing edge after flip */ - edge_index = p2t_triangle_edge_index (t, p, op); - - t->delaunay_edge[edge_index] = TRUE; - p2t_sweep_legalize (THIS, tcx, t); - p2t_triangle_clear_delunay_edges (t); - return ot; -} - -P2tPoint* -p2t_sweep_next_flip_point (P2tSweep *THIS, P2tPoint* ep, P2tPoint* eq, P2tTriangle *ot, P2tPoint* op) -{ - P2tOrientation o2d = p2t_orient2d (eq, op, ep); - if (o2d == CW) - { - /* Right */ - return p2t_triangle_point_ccw (ot, op); - } - else if (o2d == CCW) - { - /* Left */ - return p2t_triangle_point_cw (ot, op); - } - else - { - /*throw new RuntimeException("[Unsupported] Opposing point on constrained edge");*/ - assert (0); - } -} - -void -p2t_sweep_flip_scan_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tPoint* ep, P2tPoint* eq, P2tTriangle *flip_triangle, - P2tTriangle *t, P2tPoint* p) -{ - P2tTriangle* ot = p2t_triangle_neighbor_across (t, p); - P2tPoint* op = p2t_triangle_opposite_point (ot, t, p); - - if (p2t_triangle_neighbor_across (t, p) == NULL) - { - /* If we want to integrate the fillEdgeEvent do it here - * With current implementation we should never get here - *throw new RuntimeException( "[BUG:FIXME] FLIP failed due to missing triangle"); - */ - assert (0); - } - - if (p2t_utils_in_scan_area (eq, p2t_triangle_point_ccw (flip_triangle, eq), p2t_triangle_point_cw (flip_triangle, eq), op)) - { - /* flip with new edge op->eq */ - p2t_sweep_flip_edge_event (THIS, tcx, eq, op, ot, op); - /* TODO: Actually I just figured out that it should be possible to - * improve this by getting the next ot and op before the the above - * flip and continue the flipScanEdgeEvent here - * set new ot and op here and loop back to inScanArea test - * also need to set a new flip_triangle first - * Turns out at first glance that this is somewhat complicated - * so it will have to wait. */ - } - else - { - P2tPoint* newP = p2t_sweep_next_flip_point (THIS, ep, eq, ot, op); - p2t_sweep_flip_scan_edge_event (THIS, tcx, ep, eq, flip_triangle, ot, newP); - } -} +/* + * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors + * http://code.google.com/p/poly2tri/ + * + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Poly2Tri nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include + +#include "sweep.h" +#include "sweep_context.h" +#include "advancing_front.h" +#include "../common/utils.h" +#include "../common/shapes.h" + +void +p2t_sweep_init (P2tSweep* THIS) +{ + THIS->nodes_ = g_ptr_array_new (); +} + +P2tSweep* +p2t_sweep_new () +{ + P2tSweep* THIS = g_new (P2tSweep, 1); + p2t_sweep_init (THIS); + return THIS; +} + +/** + * Destructor - clean up memory + */ +void +p2t_sweep_destroy (P2tSweep* THIS) +{ + int i; + /* Clean up memory */ + for (i = 0; i < THIS->nodes_->len; i++) + { + p2t_node_free (node_index (THIS->nodes_, i)); + } + + g_ptr_array_free (THIS->nodes_, TRUE); +} + +void +p2t_sweep_free (P2tSweep* THIS) +{ + p2t_sweep_destroy (THIS); + g_free (THIS); +} + +/* Triangulate simple polygon with holes */ + +void +p2t_sweep_triangulate (P2tSweep *THIS, P2tSweepContext *tcx) +{ + p2t_sweepcontext_init_triangulation (tcx); + p2t_sweepcontext_create_advancingfront (tcx, THIS->nodes_); + /* Sweep points; build mesh */ + p2t_sweep_sweep_points (THIS, tcx); + /* Clean up */ + p2t_sweep_finalization_polygon (THIS, tcx); +} + +void +p2t_sweep_sweep_points (P2tSweep *THIS, P2tSweepContext *tcx) +{ + int i, j; + for (i = 1; i < p2t_sweepcontext_point_count (tcx); i++) + { + P2tPoint* point = p2t_sweepcontext_get_point (tcx, i); + P2tNode* node = p2t_sweep_point_event (THIS, tcx, point); + for (j = 0; j < point->edge_list->len; j++) + { + p2t_sweep_edge_event_ed_n (THIS, tcx, edge_index (point->edge_list, j), node); + } + } +} + +void +p2t_sweep_finalization_polygon (P2tSweep *THIS, P2tSweepContext *tcx) +{ + /* Get an Internal triangle to start with */ + P2tTriangle* t = p2t_advancingfront_head (p2t_sweepcontext_front (tcx))->next->triangle; + P2tPoint* p = p2t_advancingfront_head (p2t_sweepcontext_front (tcx))->next->point; + while (!p2t_triangle_get_constrained_edge_cw (t, p)) + { + t = p2t_triangle_neighbor_ccw (t, p); + } + + /* Collect interior triangles constrained by edges */ + p2t_sweepcontext_mesh_clean (tcx, t); +} + +P2tNode* +p2t_sweep_point_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tPoint* point) +{ + P2tNode* node = p2t_sweepcontext_locate_node (tcx, point); + P2tNode* new_node = p2t_sweep_new_front_triangle (THIS, tcx, point, node); + + /* Only need to check +epsilon since point never have smaller + * x value than node due to how we fetch nodes from the front */ + if (point->x <= node->point->x + EPSILON) + { + p2t_sweep_fill (THIS, tcx, node); + } + + /*tcx.AddNode(new_node); */ + + p2t_sweep_fill_advancingfront (THIS, tcx, new_node); + return new_node; +} + +void +p2t_sweep_edge_event_ed_n (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node) +{ + tcx->edge_event.constrained_edge = edge; + tcx->edge_event.right = (edge->p->x > edge->q->x); + + if (p2t_sweep_is_edge_side_of_triangle (THIS, node->triangle, edge->p, edge->q)) + { + return; + } + + /* For now we will do all needed filling + * TODO: integrate with flip process might give some better performance + * but for now this avoid the issue with cases that needs both flips and fills + */ + p2t_sweep_fill_edge_event (THIS, tcx, edge, node); + p2t_sweep_edge_event_pt_pt_tr_pt (THIS, tcx, edge->p, edge->q, node->triangle, edge->q); +} + +void +p2t_sweep_edge_event_pt_pt_tr_pt (P2tSweep *THIS, P2tSweepContext *tcx, P2tPoint* ep, P2tPoint* eq, P2tTriangle* triangle, P2tPoint* point) +{ + P2tPoint *p1, *p2; + P2tOrientation o1, o2; + + if (p2t_sweep_is_edge_side_of_triangle (THIS, triangle, ep, eq)) + { + return; + } + + p1 = p2t_triangle_point_ccw (triangle, point); + o1 = p2t_orient2d (eq, p1, ep); + if (o1 == COLLINEAR) + { + if (p2t_triangle_contains_pt_pt (triangle, eq, p1)) + { + p2t_triangle_mark_constrained_edge_pt_pt (triangle, eq, p1); + /* We are modifying the constraint maybe it would be better to + * not change the given constraint and just keep a variable for the new constraint + */ + tcx->edge_event.constrained_edge->q = p1; + triangle = p2t_triangle_neighbor_across (triangle, point); + p2t_sweep_edge_event_pt_pt_tr_pt (THIS, tcx, ep, p1, triangle, p1); + } + else + { + g_error ("EdgeEvent - collinear points not supported"); + } + return; + } + + p2 = p2t_triangle_point_cw (triangle, point); + o2 = p2t_orient2d (eq, p2, ep); + if (o2 == COLLINEAR) + { + if (p2t_triangle_contains_pt_pt (triangle, eq, p2)) + { + p2t_triangle_mark_constrained_edge_pt_pt (triangle, eq, p2); + /* We are modifying the constraint maybe it would be better to + * not change the given constraint and just keep a variable for the new constraint + */ + tcx->edge_event.constrained_edge->q = p2; + triangle = p2t_triangle_neighbor_across (triangle, point); + p2t_sweep_edge_event_pt_pt_tr_pt (THIS, tcx, ep, p2, triangle, p2); + } + else + { + g_error ("EdgeEvent - collinear points not supported"); + } + return; + } + + if (o1 == o2) + { + /* Need to decide if we are rotating CW or CCW to get to a triangle + * that will cross edge */ + if (o1 == CW) + { + triangle = p2t_triangle_neighbor_ccw (triangle, point); + } + else + { + triangle = p2t_triangle_neighbor_cw (triangle, point); + } + p2t_sweep_edge_event_pt_pt_tr_pt (THIS, tcx, ep, eq, triangle, point); + } + else + { + /* This triangle crosses constraint so lets flippin start! */ + p2t_sweep_flip_edge_event (THIS, tcx, ep, eq, triangle, point); + } +} + +gboolean +p2t_sweep_is_edge_side_of_triangle (P2tSweep *THIS, P2tTriangle *triangle, P2tPoint* ep, P2tPoint* eq) +{ + int index = p2t_triangle_edge_index (triangle, ep, eq); + + if (index != -1) + { + P2tTriangle *t; + p2t_triangle_mark_constrained_edge_i (triangle, index); + t = p2t_triangle_get_neighbor (triangle, index); + if (t) + { + p2t_triangle_mark_constrained_edge_pt_pt (t, ep, eq); + } + return TRUE; + } + return FALSE; +} + +P2tNode* +p2t_sweep_new_front_triangle (P2tSweep *THIS, P2tSweepContext *tcx, P2tPoint* point, P2tNode *node) +{ + P2tTriangle* triangle = p2t_triangle_new (point, node->point, node->next->point); + P2tNode *new_node; + + p2t_triangle_mark_neighbor_tr (triangle, node->triangle); + p2t_sweepcontext_add_to_map (tcx, triangle); + + new_node = p2t_node_new_pt (point); + g_ptr_array_add (THIS->nodes_, new_node); + + new_node->next = node->next; + new_node->prev = node; + node->next->prev = new_node; + node->next = new_node; + + if (!p2t_sweep_legalize (THIS, tcx, triangle)) + { + p2t_sweepcontext_map_triangle_to_nodes (tcx, triangle); + } + + return new_node; +} + +void +p2t_sweep_fill (P2tSweep *THIS, P2tSweepContext *tcx, P2tNode* node) +{ + P2tTriangle* triangle = p2t_triangle_new (node->prev->point, node->point, node->next->point); + + /* TODO: should copy the constrained_edge value from neighbor triangles + * for now constrained_edge values are copied during the legalize */ + p2t_triangle_mark_neighbor_tr (triangle, node->prev->triangle); + p2t_triangle_mark_neighbor_tr (triangle, node->triangle); + + p2t_sweepcontext_add_to_map (tcx, triangle); + + /* Update the advancing front */ + node->prev->next = node->next; + node->next->prev = node->prev; + + /* If it was legalized the triangle has already been mapped */ + if (!p2t_sweep_legalize (THIS, tcx, triangle)) + { + p2t_sweepcontext_map_triangle_to_nodes (tcx, triangle); + } + +} + +void +p2t_sweep_fill_advancingfront (P2tSweep *THIS, P2tSweepContext *tcx, P2tNode* n) +{ + + /* Fill right holes */ + P2tNode* node = n->next; + + while (node->next) + { + double angle = p2t_sweep_hole_angle (THIS, node); + if (angle > G_PI_2 || angle < -G_PI_2) break; + p2t_sweep_fill (THIS, tcx, node); + node = node->next; + } + + /* Fill left holes */ + node = n->prev; + + while (node->prev) + { + double angle = p2t_sweep_hole_angle (THIS, node); + if (angle > G_PI_2 || angle < -G_PI_2) break; + p2t_sweep_fill (THIS, tcx, node); + node = node->prev; + } + + /* Fill right basins */ + if (n->next && n->next->next) + { + double angle = p2t_sweep_basin_angle (THIS, n); + if (angle < PI_3div4) + { + p2t_sweep_fill_basin (THIS, tcx, n); + } + } +} + +double +p2t_sweep_basin_angle (P2tSweep *THIS, P2tNode* node) +{ + double ax = node->point->x - node->next->next->point->x; + double ay = node->point->y - node->next->next->point->y; + return atan2 (ay, ax); +} + +double +p2t_sweep_hole_angle (P2tSweep *THIS, P2tNode* node) +{ + /* Complex plane + * ab = cosA +i*sinA + * ab = (ax + ay*i)(bx + by*i) = (ax*bx + ay*by) + i(ax*by-ay*bx) + * atan2(y,x) computes the principal value of the argument function + * applied to the complex number x+iy + * Where x = ax*bx + ay*by + * y = ax*by - ay*bx + */ + double ax = node->next->point->x - node->point->x; + double ay = node->next->point->y - node->point->y; + double bx = node->prev->point->x - node->point->x; + double by = node->prev->point->y - node->point->y; + return atan2 (ax * by - ay * bx, ax * bx + ay * by); +} + +gboolean +p2t_sweep_legalize (P2tSweep *THIS, P2tSweepContext *tcx, P2tTriangle *t) +{ + int i; + /* To legalize a triangle we start by finding if any of the three edges + * violate the Delaunay condition */ + for (i = 0; i < 3; i++) + { + P2tTriangle *ot; + + if (t->delaunay_edge[i]) + continue; + + ot = p2t_triangle_get_neighbor (t, i); + + if (ot) + { + P2tPoint* p = p2t_triangle_get_point (t, i); + P2tPoint* op = p2t_triangle_opposite_point (ot, t, p); + int oi = p2t_triangle_index (ot, op); + gboolean inside; + + /* If this is a Constrained Edge or a Delaunay Edge(only during recursive legalization) + * then we should not try to legalize */ + if (ot->constrained_edge[oi] || ot->delaunay_edge[oi]) + { + t->constrained_edge[i] = ot->constrained_edge[oi]; + continue; + } + + inside = p2t_sweep_incircle (THIS, p, p2t_triangle_point_ccw (t, p), p2t_triangle_point_cw (t, p), op); + + if (inside) + { + gboolean not_legalized; + /* Lets mark this shared edge as Delaunay */ + t->delaunay_edge[i] = TRUE; + ot->delaunay_edge[oi] = TRUE; + + /* Lets rotate shared edge one vertex CW to legalize it */ + p2t_sweep_rotate_triangle_pair (THIS, t, p, ot, op); + + /* We now got one valid Delaunay Edge shared by two triangles + * This gives us 4 new edges to check for Delaunay */ + + /* Make sure that triangle to node mapping is done only one time for a specific triangle */ + not_legalized = !p2t_sweep_legalize (THIS, tcx, t); + if (not_legalized) + { + p2t_sweepcontext_map_triangle_to_nodes (tcx, t); + } + + not_legalized = !p2t_sweep_legalize (THIS, tcx, ot); + if (not_legalized) + p2t_sweepcontext_map_triangle_to_nodes (tcx, ot); + + /* Reset the Delaunay edges, since they only are valid Delaunay edges + * until we add a new triangle or point. + * XXX: need to think about this. Can these edges be tried after we + * return to previous recursive level? */ + t->delaunay_edge[i] = FALSE; + ot->delaunay_edge[oi] = FALSE; + + /* If triangle have been legalized no need to check the other edges since + * the recursive legalization will handles those so we can end here.*/ + return TRUE; + } + } + } + return FALSE; +} + +gboolean +p2t_sweep_incircle (P2tSweep *THIS, P2tPoint* pa, P2tPoint* pb, P2tPoint* pc, P2tPoint* pd) +{ + double adx = pa->x - pd->x; + double ady = pa->y - pd->y; + double bdx = pb->x - pd->x; + double bdy = pb->y - pd->y; + + double adxbdy = adx * bdy; + double bdxady = bdx * ady; + double oabd = adxbdy - bdxady; + + double cdx, cdy; + double cdxady, adxcdy, ocad; + + double bdxcdy, cdxbdy; + double alift, blift, clift; + double det; + + if (oabd <= 0) + return FALSE; + + cdx = pc->x - pd->x; + cdy = pc->y - pd->y; + + cdxady = cdx * ady; + adxcdy = adx * cdy; + ocad = cdxady - adxcdy; + + if (ocad <= 0) + return FALSE; + + bdxcdy = bdx * cdy; + cdxbdy = cdx * bdy; + + alift = adx * adx + ady * ady; + blift = bdx * bdx + bdy * bdy; + clift = cdx * cdx + cdy * cdy; + + det = alift * (bdxcdy - cdxbdy) + blift * ocad + clift * oabd; + + return det > 0; +} + +void +p2t_sweep_rotate_triangle_pair (P2tSweep *THIS, P2tTriangle *t, P2tPoint* p, P2tTriangle *ot, P2tPoint* op) +{ + P2tTriangle *n1, *n2, *n3, *n4; + gboolean ce1, ce2, ce3, ce4; + gboolean de1, de2, de3, de4; + + n1 = p2t_triangle_neighbor_ccw (t, p); + n2 = p2t_triangle_neighbor_cw (t, p); + n3 = p2t_triangle_neighbor_ccw (ot, op); + n4 = p2t_triangle_neighbor_cw (ot, op); + + ce1 = p2t_triangle_get_constrained_edge_ccw (t, p); + ce2 = p2t_triangle_get_constrained_edge_cw (t, p); + ce3 = p2t_triangle_get_constrained_edge_ccw (ot, op); + ce4 = p2t_triangle_get_constrained_edge_cw (ot, op); + + de1 = p2t_triangle_get_delunay_edge_ccw (t, p); + de2 = p2t_triangle_get_delunay_edge_cw (t, p); + de3 = p2t_triangle_get_delunay_edge_ccw (ot, op); + de4 = p2t_triangle_get_delunay_edge_cw (ot, op); + + p2t_triangle_legalize_pt_pt (t, p, op); + p2t_triangle_legalize_pt_pt (ot, op, p); + + /* Remap delaunay_edge */ + p2t_triangle_set_delunay_edge_ccw (ot, p, de1); + p2t_triangle_set_delunay_edge_cw (t, p, de2); + p2t_triangle_set_delunay_edge_ccw (t, op, de3); + p2t_triangle_set_delunay_edge_cw (ot, op, de4); + + /* Remap constrained_edge */ + p2t_triangle_set_constrained_edge_ccw (ot, p, ce1); + p2t_triangle_set_constrained_edge_cw (t, p, ce2); + p2t_triangle_set_constrained_edge_ccw (t, op, ce3); + p2t_triangle_set_constrained_edge_cw (ot, op, ce4); + + /* Remap neighbors + * XXX: might optimize the markNeighbor by keeping track of + * what side should be assigned to what neighbor after the + * rotation. Now mark neighbor does lots of testing to find + * the right side. */ + p2t_triangle_clear_neighbors (t); + p2t_triangle_clear_neighbors (ot); + if (n1) p2t_triangle_mark_neighbor_tr (ot, n1); + if (n2) p2t_triangle_mark_neighbor_tr (t, n2); + if (n3) p2t_triangle_mark_neighbor_tr (t, n3); + if (n4) p2t_triangle_mark_neighbor_tr (ot, n4); + p2t_triangle_mark_neighbor_tr (t, ot); +} + +void +p2t_sweep_fill_basin (P2tSweep *THIS, P2tSweepContext *tcx, P2tNode* node) +{ + if (p2t_orient2d (node->point, node->next->point, node->next->next->point) == CCW) + { + tcx->basin.left_node = node->next->next; + } + else + { + tcx->basin.left_node = node->next; + } + + /* Find the bottom and right node */ + tcx->basin.bottom_node = tcx->basin.left_node; + while (tcx->basin.bottom_node->next + && tcx->basin.bottom_node->point->y >= tcx->basin.bottom_node->next->point->y) + { + tcx->basin.bottom_node = tcx->basin.bottom_node->next; + } + if (tcx->basin.bottom_node == tcx->basin.left_node) + { + /* No valid basin */ + return; + } + + tcx->basin.right_node = tcx->basin.bottom_node; + while (tcx->basin.right_node->next + && tcx->basin.right_node->point->y < tcx->basin.right_node->next->point->y) + { + tcx->basin.right_node = tcx->basin.right_node->next; + } + if (tcx->basin.right_node == tcx->basin.bottom_node) + { + /* No valid basins */ + return; + } + + tcx->basin.width = tcx->basin.right_node->point->x - tcx->basin.left_node->point->x; + tcx->basin.left_highest = tcx->basin.left_node->point->y > tcx->basin.right_node->point->y; + + p2t_sweep_fill_basin_req (THIS, tcx, tcx->basin.bottom_node); +} + +void +p2t_sweep_fill_basin_req (P2tSweep *THIS, P2tSweepContext *tcx, P2tNode* node) +{ + /* if shallow stop filling */ + if (p2t_sweep_is_shallow (THIS, tcx, node)) + { + return; + } + + p2t_sweep_fill (THIS, tcx, node); + + if (node->prev == tcx->basin.left_node && node->next == tcx->basin.right_node) + { + return; + } + else if (node->prev == tcx->basin.left_node) + { + P2tOrientation o = p2t_orient2d (node->point, node->next->point, node->next->next->point); + if (o == CW) + { + return; + } + node = node->next; + } + else if (node->next == tcx->basin.right_node) + { + P2tOrientation o = p2t_orient2d (node->point, node->prev->point, node->prev->prev->point); + if (o == CCW) + { + return; + } + node = node->prev; + } + else + { + /* Continue with the neighbor node with lowest Y value */ + if (node->prev->point->y < node->next->point->y) + { + node = node->prev; + } + else + { + node = node->next; + } + } + + p2t_sweep_fill_basin_req (THIS, tcx, node); +} + +gboolean +p2t_sweep_is_shallow (P2tSweep *THIS, P2tSweepContext *tcx, P2tNode* node) +{ + double height; + + if (tcx->basin.left_highest) + { + height = tcx->basin.left_node->point->y - node->point->y; + } + else + { + height = tcx->basin.right_node->point->y - node->point->y; + } + + /* if shallow stop filling */ + if (tcx->basin.width > height) + { + return TRUE; + } + return FALSE; +} + +void +p2t_sweep_fill_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node) +{ + if (tcx->edge_event.right) + { + p2t_sweep_fill_right_above_edge_event (THIS, tcx, edge, node); + } + else + { + p2t_sweep_fill_left_above_edge_event (THIS, tcx, edge, node); + } +} + +void +p2t_sweep_fill_right_above_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node) +{ + while (node->next->point->x < edge->p->x) + { + /* Check if next node is below the edge */ + if (p2t_orient2d (edge->q, node->next->point, edge->p) == CCW) + { + p2t_sweep_fill_right_below_edge_event (THIS, tcx, edge, node); + } + else + { + node = node->next; + } + } +} + +void +p2t_sweep_fill_right_below_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node) +{ + if (node->point->x < edge->p->x) + { + if (p2t_orient2d (node->point, node->next->point, node->next->next->point) == CCW) + { + /* Concave */ + p2t_sweep_fill_right_concave_edge_event (THIS, tcx, edge, node); + } + else + { + /* Convex */ + p2t_sweep_fill_right_convex_edge_event (THIS, tcx, edge, node); + /* Retry this one */ + p2t_sweep_fill_right_below_edge_event (THIS, tcx, edge, node); + } + } +} + +void +p2t_sweep_fill_right_concave_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node) +{ + p2t_sweep_fill (THIS, tcx, node->next); + if (node->next->point != edge->p) + { + /* Next above or below edge? */ + if (p2t_orient2d (edge->q, node->next->point, edge->p) == CCW) + { + /* Below */ + if (p2t_orient2d (node->point, node->next->point, node->next->next->point) == CCW) + { + /* Next is concave */ + p2t_sweep_fill_right_concave_edge_event (THIS, tcx, edge, node); + } + else + { + /* Next is convex */ + } + } + } + +} + +void +p2t_sweep_fill_right_convex_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node) +{ + /* Next concave or convex? */ + if (p2t_orient2d (node->next->point, node->next->next->point, node->next->next->next->point) == CCW) + { + /* Concave */ + p2t_sweep_fill_right_concave_edge_event (THIS, tcx, edge, node->next); + } + else + { + /* Convex + * Next above or below edge? */ + if (p2t_orient2d (edge->q, node->next->next->point, edge->p) == CCW) + { + /* Below */ + p2t_sweep_fill_right_convex_edge_event (THIS, tcx, edge, node->next); + } + else + { + /* Above */ + } + } +} + +void +p2t_sweep_fill_left_above_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node) +{ + while (node->prev->point->x > edge->p->x) + { + /* Check if next node is below the edge */ + if (p2t_orient2d (edge->q, node->prev->point, edge->p) == CW) + { + p2t_sweep_fill_left_below_edge_event (THIS, tcx, edge, node); + } + else + { + node = node->prev; + } + } +} + +void +p2t_sweep_fill_left_below_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node) +{ + if (node->point->x > edge->p->x) + { + if (p2t_orient2d (node->point, node->prev->point, node->prev->prev->point) == CW) + { + /* Concave */ + p2t_sweep_fill_left_concave_edge_event (THIS, tcx, edge, node); + } + else + { + /* Convex */ + p2t_sweep_fill_left_convex_edge_event (THIS, tcx, edge, node); + /* Retry this one */ + p2t_sweep_fill_left_below_edge_event (THIS, tcx, edge, node); + } + } +} + +void +p2t_sweep_fill_left_convex_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node) +{ + /* Next concave or convex? */ + if (p2t_orient2d (node->prev->point, node->prev->prev->point, node->prev->prev->prev->point) == CW) + { + /* Concave */ + p2t_sweep_fill_left_concave_edge_event (THIS, tcx, edge, node->prev); + } + else + { + /* Convex + * Next above or below edge? */ + if (p2t_orient2d (edge->q, node->prev->prev->point, edge->p) == CW) + { + /* Below */ + p2t_sweep_fill_left_convex_edge_event (THIS, tcx, edge, node->prev); + } + else + { + /* Above */ + } + } +} + +void +p2t_sweep_fill_left_concave_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tEdge* edge, P2tNode* node) +{ + p2t_sweep_fill (THIS, tcx, node->prev); + if (node->prev->point != edge->p) + { + /* Next above or below edge? */ + if (p2t_orient2d (edge->q, node->prev->point, edge->p) == CW) + { + /* Below */ + if (p2t_orient2d (node->point, node->prev->point, node->prev->prev->point) == CW) + { + /* Next is concave */ + p2t_sweep_fill_left_concave_edge_event (THIS, tcx, edge, node); + } + else + { + /* Next is convex */ + } + } + } + +} + +void +p2t_sweep_flip_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tPoint* ep, P2tPoint* eq, P2tTriangle* t, P2tPoint* p) +{ + P2tTriangle* ot = p2t_triangle_neighbor_across (t, p); + P2tPoint* op = p2t_triangle_opposite_point (ot, t, p); + + if (ot == NULL) + { + /* If we want to integrate the fillEdgeEvent do it here + * With current implementation we should never get here + *throw new RuntimeException( "[BUG:FIXME] FLIP failed due to missing triangle"); + */ + assert (0); + } + + if (p2t_utils_in_scan_area (p, p2t_triangle_point_ccw (t, p), p2t_triangle_point_cw (t, p), op)) + { + /* Lets rotate shared edge one vertex CW */ + p2t_sweep_rotate_triangle_pair (THIS, t, p, ot, op); + p2t_sweepcontext_map_triangle_to_nodes (tcx, t); + p2t_sweepcontext_map_triangle_to_nodes (tcx, ot); + + if (p == eq && op == ep) + { + if (p2t_point_equals (eq, tcx->edge_event.constrained_edge->q) && p2t_point_equals (ep, tcx->edge_event.constrained_edge->p)) + { + p2t_triangle_mark_constrained_edge_pt_pt (t, ep, eq); + p2t_triangle_mark_constrained_edge_pt_pt (ot, ep, eq); + p2t_sweep_legalize (THIS, tcx, t); + p2t_sweep_legalize (THIS, tcx, ot); + } + else + { + /* XXX: I think one of the triangles should be legalized here? */ + } + } + else + { + P2tOrientation o = p2t_orient2d (eq, op, ep); + t = p2t_sweep_next_flip_triangle (THIS, tcx, (int) o, t, ot, p, op); + p2t_sweep_flip_edge_event (THIS, tcx, ep, eq, t, p); + } + } + else + { + P2tPoint* newP = p2t_sweep_next_flip_point (THIS, ep, eq, ot, op); + p2t_sweep_flip_scan_edge_event (THIS, tcx, ep, eq, t, ot, newP); + p2t_sweep_edge_event_pt_pt_tr_pt (THIS, tcx, ep, eq, t, p); + } +} + +P2tTriangle* +p2t_sweep_next_flip_triangle (P2tSweep *THIS, P2tSweepContext *tcx, int o, P2tTriangle *t, P2tTriangle *ot, P2tPoint* p, P2tPoint* op) +{ + int edge_index; + + if (o == CCW) + { + /* ot is not crossing edge after flip */ + int edge_index = p2t_triangle_edge_index (ot, p, op); + ot->delaunay_edge[edge_index] = TRUE; + p2t_sweep_legalize (THIS, tcx, ot); + p2t_triangle_clear_delunay_edges (ot); + return t; + } + + /* t is not crossing edge after flip */ + edge_index = p2t_triangle_edge_index (t, p, op); + + t->delaunay_edge[edge_index] = TRUE; + p2t_sweep_legalize (THIS, tcx, t); + p2t_triangle_clear_delunay_edges (t); + return ot; +} + +P2tPoint* +p2t_sweep_next_flip_point (P2tSweep *THIS, P2tPoint* ep, P2tPoint* eq, P2tTriangle *ot, P2tPoint* op) +{ + P2tOrientation o2d = p2t_orient2d (eq, op, ep); + if (o2d == CW) + { + /* Right */ + return p2t_triangle_point_ccw (ot, op); + } + else if (o2d == CCW) + { + /* Left */ + return p2t_triangle_point_cw (ot, op); + } + else + { + /*throw new RuntimeException("[Unsupported] Opposing point on constrained edge");*/ + assert (0); + } +} + +void +p2t_sweep_flip_scan_edge_event (P2tSweep *THIS, P2tSweepContext *tcx, P2tPoint* ep, P2tPoint* eq, P2tTriangle *flip_triangle, + P2tTriangle *t, P2tPoint* p) +{ + P2tTriangle* ot = p2t_triangle_neighbor_across (t, p); + P2tPoint* op = p2t_triangle_opposite_point (ot, t, p); + + if (p2t_triangle_neighbor_across (t, p) == NULL) + { + /* If we want to integrate the fillEdgeEvent do it here + * With current implementation we should never get here + *throw new RuntimeException( "[BUG:FIXME] FLIP failed due to missing triangle"); + */ + assert (0); + } + + if (p2t_utils_in_scan_area (eq, p2t_triangle_point_ccw (flip_triangle, eq), p2t_triangle_point_cw (flip_triangle, eq), op)) + { + /* flip with new edge op->eq */ + p2t_sweep_flip_edge_event (THIS, tcx, eq, op, ot, op); + /* TODO: Actually I just figured out that it should be possible to + * improve this by getting the next ot and op before the the above + * flip and continue the flipScanEdgeEvent here + * set new ot and op here and loop back to inScanArea test + * also need to set a new flip_triangle first + * Turns out at first glance that this is somewhat complicated + * so it will have to wait. */ + } + else + { + P2tPoint* newP = p2t_sweep_next_flip_point (THIS, ep, eq, ot, op); + p2t_sweep_flip_scan_edge_event (THIS, tcx, ep, eq, flip_triangle, ot, newP); + } +} diff --git a/p2t/sweep/sweep_context.h b/p2t/sweep/sweep_context.h index 73cb4ca..0596ecc 100644 --- a/p2t/sweep/sweep_context.h +++ b/p2t/sweep/sweep_context.h @@ -1,133 +1,133 @@ -/* - * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors - * http://code.google.com/p/poly2tri/ - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * * Neither the name of Poly2Tri nor the names of its contributors may be - * used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef SWEEP_CONTEXT_H -#define SWEEP_CONTEXT_H - -#include "../common/poly2tri-private.h" -#include "../common/shapes.h" -#include "advancing_front.h" - -/* Inital triangle factor, seed triangle will extend 30% of - * PointSet width to both left and right. */ -#define kAlpha 0.3 - -struct P2tSweepContextBasin_ -{ - P2tNode* left_node; - P2tNode* bottom_node; - P2tNode* right_node; - double width; - gboolean left_highest; -}; - -void p2t_sweepcontext_basin_init (P2tSweepContextBasin* THIS); -void p2t_sweepcontext_basin_clear (P2tSweepContextBasin* THIS); - -struct P2tSweepContextEdgeEvent_ -{ - P2tEdge* constrained_edge; - gboolean right; -}; - -void p2t_sweepcontext_edgeevent_init (P2tSweepContextEdgeEvent* THIS); - -struct SweepContext_ -{ - P2tEdgePtrArray edge_list; - - P2tSweepContextBasin basin; - P2tSweepContextEdgeEvent edge_event; - - P2tTrianglePtrArray triangles_; - P2tTrianglePtrList map_; - P2tPointPtrArray points_; - - /** Advancing front */ - P2tAdvancingFront* front_; - /** head point used with advancing front */ - P2tPoint* head_; - /** tail point used with advancing front */ - P2tPoint* tail_; - - P2tNode *af_head_, *af_middle_, *af_tail_; -}; - -/** Constructor */ -void p2t_sweepcontext_init (P2tSweepContext* THIS, P2tPointPtrArray polyline); -P2tSweepContext* p2t_sweepcontext_new (P2tPointPtrArray polyline); - -/** Destructor */ -void p2t_sweepcontext_destroy (P2tSweepContext* THIS); -void p2t_sweepcontext_delete (P2tSweepContext* THIS); - -void p2t_sweepcontext_set_head (P2tSweepContext *THIS, P2tPoint* p1); - -P2tPoint* p2t_sweepcontext_head (P2tSweepContext *THIS); - -void p2t_sweepcontext_set_tail (P2tSweepContext *THIS, P2tPoint* p1); - -P2tPoint* p2t_sweepcontext_tail (P2tSweepContext *THIS); - -int p2t_sweepcontext_point_count (P2tSweepContext *THIS); - -P2tNode* p2t_sweepcontext_locate_node (P2tSweepContext *THIS, P2tPoint* point); - -void p2t_sweepcontext_remove_node (P2tSweepContext *THIS, P2tNode* node); - -void p2t_sweepcontext_create_advancingfront (P2tSweepContext *THIS, P2tNodePtrArray nodes); - -/** Try to map a node to all sides of this triangle that don't have a neighbor */ -void p2t_sweepcontext_map_triangle_to_nodes (P2tSweepContext *THIS, P2tTriangle* t); - -void p2t_sweepcontext_add_to_map (P2tSweepContext *THIS, P2tTriangle* triangle); - -P2tPoint* p2t_sweepcontext_get_point (P2tSweepContext *THIS, const int index); - -P2tPoint* SweepContext_GetPoints (P2tSweepContext *THIS); - -void p2t_sweepcontext_remove_from_map (P2tSweepContext *THIS, P2tTriangle* triangle); - -void p2t_sweepcontext_add_hole (P2tSweepContext *THIS, P2tPointPtrArray polyline); - -void p2t_sweepcontext_add_point (P2tSweepContext *THIS, P2tPoint* point); - -P2tAdvancingFront* p2t_sweepcontext_front (P2tSweepContext *THIS); - -void p2t_sweepcontext_mesh_clean (P2tSweepContext *THIS, P2tTriangle* triangle); - -P2tTrianglePtrArray p2t_sweepcontext_get_triangles (P2tSweepContext *THIS); -P2tTrianglePtrList p2t_sweepcontext_get_map (P2tSweepContext *THIS); - -void p2t_sweepcontext_init_triangulation (P2tSweepContext *THIS); -void p2t_sweepcontext_init_edges (P2tSweepContext *THIS, P2tPointPtrArray polyline); - -#endif +/* + * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors + * http://code.google.com/p/poly2tri/ + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Poly2Tri nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SWEEP_CONTEXT_H +#define SWEEP_CONTEXT_H + +#include "../common/poly2tri-private.h" +#include "../common/shapes.h" +#include "advancing_front.h" + +/* Inital triangle factor, seed triangle will extend 30% of + * PointSet width to both left and right. */ +#define kAlpha 0.3 + +struct P2tSweepContextBasin_ +{ + P2tNode* left_node; + P2tNode* bottom_node; + P2tNode* right_node; + double width; + gboolean left_highest; +}; + +void p2t_sweepcontext_basin_init (P2tSweepContextBasin* THIS); +void p2t_sweepcontext_basin_clear (P2tSweepContextBasin* THIS); + +struct P2tSweepContextEdgeEvent_ +{ + P2tEdge* constrained_edge; + gboolean right; +}; + +void p2t_sweepcontext_edgeevent_init (P2tSweepContextEdgeEvent* THIS); + +struct SweepContext_ +{ + P2tEdgePtrArray edge_list; + + P2tSweepContextBasin basin; + P2tSweepContextEdgeEvent edge_event; + + P2tTrianglePtrArray triangles_; + P2tTrianglePtrList map_; + P2tPointPtrArray points_; + + /** Advancing front */ + P2tAdvancingFront* front_; + /** head point used with advancing front */ + P2tPoint* head_; + /** tail point used with advancing front */ + P2tPoint* tail_; + + P2tNode *af_head_, *af_middle_, *af_tail_; +}; + +/** Constructor */ +void p2t_sweepcontext_init (P2tSweepContext* THIS, P2tPointPtrArray polyline); +P2tSweepContext* p2t_sweepcontext_new (P2tPointPtrArray polyline); + +/** Destructor */ +void p2t_sweepcontext_destroy (P2tSweepContext* THIS); +void p2t_sweepcontext_delete (P2tSweepContext* THIS); + +void p2t_sweepcontext_set_head (P2tSweepContext *THIS, P2tPoint* p1); + +P2tPoint* p2t_sweepcontext_head (P2tSweepContext *THIS); + +void p2t_sweepcontext_set_tail (P2tSweepContext *THIS, P2tPoint* p1); + +P2tPoint* p2t_sweepcontext_tail (P2tSweepContext *THIS); + +int p2t_sweepcontext_point_count (P2tSweepContext *THIS); + +P2tNode* p2t_sweepcontext_locate_node (P2tSweepContext *THIS, P2tPoint* point); + +void p2t_sweepcontext_remove_node (P2tSweepContext *THIS, P2tNode* node); + +void p2t_sweepcontext_create_advancingfront (P2tSweepContext *THIS, P2tNodePtrArray nodes); + +/** Try to map a node to all sides of this triangle that don't have a neighbor */ +void p2t_sweepcontext_map_triangle_to_nodes (P2tSweepContext *THIS, P2tTriangle* t); + +void p2t_sweepcontext_add_to_map (P2tSweepContext *THIS, P2tTriangle* triangle); + +P2tPoint* p2t_sweepcontext_get_point (P2tSweepContext *THIS, const int index); + +P2tPoint* SweepContext_GetPoints (P2tSweepContext *THIS); + +void p2t_sweepcontext_remove_from_map (P2tSweepContext *THIS, P2tTriangle* triangle); + +void p2t_sweepcontext_add_hole (P2tSweepContext *THIS, P2tPointPtrArray polyline); + +void p2t_sweepcontext_add_point (P2tSweepContext *THIS, P2tPoint* point); + +P2tAdvancingFront* p2t_sweepcontext_front (P2tSweepContext *THIS); + +void p2t_sweepcontext_mesh_clean (P2tSweepContext *THIS, P2tTriangle* triangle); + +P2tTrianglePtrArray p2t_sweepcontext_get_triangles (P2tSweepContext *THIS); +P2tTrianglePtrList p2t_sweepcontext_get_map (P2tSweepContext *THIS); + +void p2t_sweepcontext_init_triangulation (P2tSweepContext *THIS); +void p2t_sweepcontext_init_edges (P2tSweepContext *THIS, P2tPointPtrArray polyline); + +#endif diff --git a/refine/bounded-line.c b/refine/bounded-line.c index fdf96d5..59b9986 100644 --- a/refine/bounded-line.c +++ b/refine/bounded-line.c @@ -1,52 +1,52 @@ #include #include "bounded-line.h" -P2trBoundedLine* -p2tr_bounded_line_new (const P2trVector2 *start, - const P2trVector2 *end) -{ - P2trBoundedLine* line = g_slice_new (P2trBoundedLine); - p2tr_bounded_line_init (line, start, end); - return line; -} - -void -p2tr_bounded_line_init (P2trBoundedLine *line, - const P2trVector2 *start, - const P2trVector2 *end) -{ - /* Traditional line Equation: - * y - mx - n = 0 <==> y = mx + n - * Slope Equation: - * m = dy / dx - * Slope + Traditional: - * dx * y - dy * x - dx * n = 0 - * And the remaining part can be found as - * dx * y0 - dy * x0 = dx * n - * So the final equation is: - * dx * y - dy * x - (dx * y0 - dy * x0) = 0 - */ - gdouble dx = end->x - start->x; - gdouble dy = end->y - start->y; - - gdouble dxXn = start->y * dx - start->x * dy; - - p2tr_line_init(&line->infinite, -dy, dx, -dxXn); - - p2tr_vector2_copy(&line->start, start); - p2tr_vector2_copy(&line->end, end); -} - -gboolean -p2tr_bounded_line_intersect (const P2trBoundedLine *l1, - const P2trBoundedLine *l2) -{ - return p2tr_line_different_sides (&l1->infinite, &l2->start, &l2->end) - && p2tr_line_different_sides (&l2->infinite, &l1->start, &l1->end); -} - -void -p2tr_bounded_line_free (P2trBoundedLine *line) -{ - g_slice_free (P2trBoundedLine, line); -} +P2trBoundedLine* +p2tr_bounded_line_new (const P2trVector2 *start, + const P2trVector2 *end) +{ + P2trBoundedLine* line = g_slice_new (P2trBoundedLine); + p2tr_bounded_line_init (line, start, end); + return line; +} + +void +p2tr_bounded_line_init (P2trBoundedLine *line, + const P2trVector2 *start, + const P2trVector2 *end) +{ + /* Traditional line Equation: + * y - mx - n = 0 <==> y = mx + n + * Slope Equation: + * m = dy / dx + * Slope + Traditional: + * dx * y - dy * x - dx * n = 0 + * And the remaining part can be found as + * dx * y0 - dy * x0 = dx * n + * So the final equation is: + * dx * y - dy * x - (dx * y0 - dy * x0) = 0 + */ + gdouble dx = end->x - start->x; + gdouble dy = end->y - start->y; + + gdouble dxXn = start->y * dx - start->x * dy; + + p2tr_line_init(&line->infinite, -dy, dx, -dxXn); + + p2tr_vector2_copy(&line->start, start); + p2tr_vector2_copy(&line->end, end); +} + +gboolean +p2tr_bounded_line_intersect (const P2trBoundedLine *l1, + const P2trBoundedLine *l2) +{ + return p2tr_line_different_sides (&l1->infinite, &l2->start, &l2->end) + && p2tr_line_different_sides (&l2->infinite, &l1->start, &l1->end); +} + +void +p2tr_bounded_line_free (P2trBoundedLine *line) +{ + g_slice_free (P2trBoundedLine, line); +} diff --git a/refine/bounded-line.h b/refine/bounded-line.h index 5e33eaf..db5c40c 100644 --- a/refine/bounded-line.h +++ b/refine/bounded-line.h @@ -1,26 +1,26 @@ -#ifndef __P2TC_REFINE_BOUNDED_LINE_H__ -#define __P2TC_REFINE_BOUNDED_LINE_H__ +#ifndef __P2TC_REFINE_BOUNDED_LINE_H__ +#define __P2TC_REFINE_BOUNDED_LINE_H__ -#include +#include #include "vector2.h" #include "line.h" - -typedef struct -{ - P2trLine infinite; - P2trVector2 start, end; -} P2trBoundedLine; - -P2trBoundedLine* p2tr_bounded_line_new (const P2trVector2 *start, - const P2trVector2 *end); - -void p2tr_bounded_line_init (P2trBoundedLine *line, - const P2trVector2 *start, - const P2trVector2 *end); - -gboolean p2tr_bounded_line_intersect (const P2trBoundedLine *l1, - const P2trBoundedLine *l2); - -void p2tr_bounded_line_free (P2trBoundedLine *line); - + +typedef struct +{ + P2trLine infinite; + P2trVector2 start, end; +} P2trBoundedLine; + +P2trBoundedLine* p2tr_bounded_line_new (const P2trVector2 *start, + const P2trVector2 *end); + +void p2tr_bounded_line_init (P2trBoundedLine *line, + const P2trVector2 *start, + const P2trVector2 *end); + +gboolean p2tr_bounded_line_intersect (const P2trBoundedLine *l1, + const P2trBoundedLine *l2); + +void p2tr_bounded_line_free (P2trBoundedLine *line); + #endif \ No newline at end of file diff --git a/refine/circle.c b/refine/circle.c index ad6e1ab..9f0cc20 100644 --- a/refine/circle.c +++ b/refine/circle.c @@ -1,15 +1,15 @@ #include #include "circle.h" -gboolean -p2tr_circle_test_point_outside (P2trCircle *circle, - P2trVector2 *pt) -{ - gdouble dx = circle->center.x - pt->x; - gdouble dy = circle->center.y - pt->y; - - gdouble d_squared = dx * dx + dy * dy; - gdouble radius_squared = circle->radius * circle->radius; - - return d_squared > radius_squared; +gboolean +p2tr_circle_test_point_outside (P2trCircle *circle, + P2trVector2 *pt) +{ + gdouble dx = circle->center.x - pt->x; + gdouble dy = circle->center.y - pt->y; + + gdouble d_squared = dx * dx + dy * dy; + gdouble radius_squared = circle->radius * circle->radius; + + return d_squared > radius_squared; } \ No newline at end of file diff --git a/refine/circle.h b/refine/circle.h index 02b1cc3..845f737 100644 --- a/refine/circle.h +++ b/refine/circle.h @@ -1,14 +1,14 @@ -#ifndef __P2TC_REFINE_CIRCLE_H__ -#define __P2TC_REFINE_CIRCLE_H__ - -#include +#ifndef __P2TC_REFINE_CIRCLE_H__ +#define __P2TC_REFINE_CIRCLE_H__ + +#include #include "vector2.h" - -typedef struct { - P2trVector2 center; - gdouble radius; -} P2trCircle; - -gboolean p2tr_circle_test_point_outside (P2trCircle *circle, P2trVector2 *pt); - + +typedef struct { + P2trVector2 center; + gdouble radius; +} P2trCircle; + +gboolean p2tr_circle_test_point_outside (P2trCircle *circle, P2trVector2 *pt); + #endif \ No newline at end of file diff --git a/refine/line.c b/refine/line.c index 4b0457f..9c20e0e 100644 --- a/refine/line.c +++ b/refine/line.c @@ -1,70 +1,70 @@ #include #include "line.h" -void -p2tr_line_init (P2trLine *line, - gdouble a, - gdouble b, - gdouble c) -{ - line->a = a; - line->b = b; - line->c = c; -} - -gboolean -p2tr_line_different_sides (const P2trLine *line, - const P2trVector2 *pt1, - const P2trVector2 *pt2) -{ - gdouble side1 = line->a * pt1->x + line->b * pt1->y + line->c; - gdouble side2 = line->a * pt2->x + line->b * pt2->y + line->c; - - /* Signs are different if the product is negative */ - return side1 * side2 < 0; -} - -P2trLineRelation -p2tr_line_intersection (const P2trLine *l1, - const P2trLine *l2, - P2trVector2 *out_intersection) -{ - /* In order to find the intersection, we intend to solve - * the following set of equations: - * - * ( A1 B1 ) ( x ) = ( -C1 ) - * ( A2 B2 ) ( y ) = ( -C2 ) - * - * We can simplify the solution using Cramers Rule which - * gives the following results: - * - * x = (-C1 * B2) - (-C2 * B1) / (A1 * B2 - A2 * B1) - * y = (A1 * -C2) - (A2 * -C1) / (A1 * B2 - A2 * B1) - */ - double d = l1->a * l2->b - l2->a * l1->b; - - /* If the denominator in the result of applying Cramers rule - * is zero, then the lines have exactly the same slope, meaning - * they are either exactly the same or they are parallel and - * never intersect */ - if (d == 0) - { - /* We want to check if the offsets of boths the lines are the - * same, i.e. whether: C1 / A1 = C2 / A2 - * This test can be done without zero division errors if we do - * it in like this: C1 * A2 = C2 * A1 - */ - if (l1->c * l2->a == l1->a * l2->c) - return P2TR_LINE_RELATION_SAME; - else - return P2TR_LINE_RELATION_PARALLEL; - } - - if (out_intersection != NULL) - { - out_intersection->x = (-l1->c * l2->b + l2->c * l1->b) / d; - out_intersection->y = (l1->a * -l2->c + l2->a * l1->c) / d; - } - - return P2TR_LINE_RELATION_INTERSECTING; +void +p2tr_line_init (P2trLine *line, + gdouble a, + gdouble b, + gdouble c) +{ + line->a = a; + line->b = b; + line->c = c; +} + +gboolean +p2tr_line_different_sides (const P2trLine *line, + const P2trVector2 *pt1, + const P2trVector2 *pt2) +{ + gdouble side1 = line->a * pt1->x + line->b * pt1->y + line->c; + gdouble side2 = line->a * pt2->x + line->b * pt2->y + line->c; + + /* Signs are different if the product is negative */ + return side1 * side2 < 0; +} + +P2trLineRelation +p2tr_line_intersection (const P2trLine *l1, + const P2trLine *l2, + P2trVector2 *out_intersection) +{ + /* In order to find the intersection, we intend to solve + * the following set of equations: + * + * ( A1 B1 ) ( x ) = ( -C1 ) + * ( A2 B2 ) ( y ) = ( -C2 ) + * + * We can simplify the solution using Cramers Rule which + * gives the following results: + * + * x = (-C1 * B2) - (-C2 * B1) / (A1 * B2 - A2 * B1) + * y = (A1 * -C2) - (A2 * -C1) / (A1 * B2 - A2 * B1) + */ + double d = l1->a * l2->b - l2->a * l1->b; + + /* If the denominator in the result of applying Cramers rule + * is zero, then the lines have exactly the same slope, meaning + * they are either exactly the same or they are parallel and + * never intersect */ + if (d == 0) + { + /* We want to check if the offsets of boths the lines are the + * same, i.e. whether: C1 / A1 = C2 / A2 + * This test can be done without zero division errors if we do + * it in like this: C1 * A2 = C2 * A1 + */ + if (l1->c * l2->a == l1->a * l2->c) + return P2TR_LINE_RELATION_SAME; + else + return P2TR_LINE_RELATION_PARALLEL; + } + + if (out_intersection != NULL) + { + out_intersection->x = (-l1->c * l2->b + l2->c * l1->b) / d; + out_intersection->y = (l1->a * -l2->c + l2->a * l1->c) / d; + } + + return P2TR_LINE_RELATION_INTERSECTING; } \ No newline at end of file diff --git a/refine/line.h b/refine/line.h index c68e05f..9431fef 100644 --- a/refine/line.h +++ b/refine/line.h @@ -1,34 +1,34 @@ -#ifndef __P2TC_REFINE_LINE_H__ -#define __P2TC_REFINE_LINE_H__ - +#ifndef __P2TC_REFINE_LINE_H__ +#define __P2TC_REFINE_LINE_H__ + #include -#include "vector2.h" - -/* A line is the equation of the following form: - * a * X + b * Y + c = 0 - */ -typedef struct { - gdouble a, b, c; -} P2trLine; - -typedef enum -{ - P2TR_LINE_RELATION_INTERSECTING = 0, - P2TR_LINE_RELATION_PARALLEL = 1, - P2TR_LINE_RELATION_SAME = 2 -} P2trLineRelation; - -void p2tr_line_init (P2trLine *line, - gdouble a, - gdouble b, - gdouble c); - -gboolean p2tr_line_different_sides (const P2trLine *line, - const P2trVector2 *pt1, - const P2trVector2 *pt2); - -P2trLineRelation p2tr_line_intersection (const P2trLine *l1, - const P2trLine *l2, - P2trVector2 *out_intersection); - +#include "vector2.h" + +/* A line is the equation of the following form: + * a * X + b * Y + c = 0 + */ +typedef struct { + gdouble a, b, c; +} P2trLine; + +typedef enum +{ + P2TR_LINE_RELATION_INTERSECTING = 0, + P2TR_LINE_RELATION_PARALLEL = 1, + P2TR_LINE_RELATION_SAME = 2 +} P2trLineRelation; + +void p2tr_line_init (P2trLine *line, + gdouble a, + gdouble b, + gdouble c); + +gboolean p2tr_line_different_sides (const P2trLine *line, + const P2trVector2 *pt1, + const P2trVector2 *pt2); + +P2trLineRelation p2tr_line_intersection (const P2trLine *l1, + const P2trLine *l2, + P2trVector2 *out_intersection); + #endif \ No newline at end of file diff --git a/refine/rmath.c b/refine/rmath.c index b6279c7..954a0fd 100644 --- a/refine/rmath.c +++ b/refine/rmath.c @@ -1,66 +1,66 @@ -#include -#include -#include "rmath.h" - -gdouble -p2tr_math_length_sq (gdouble x1, gdouble y1, - gdouble x2, gdouble y2) -{ - return P2TR_VECTOR2_DISTANCE_SQ2 (x1, y1, x2, y2); -} - -gdouble -p2tr_math_length_sq2 (const P2trVector2 *pt1, - const P2trVector2 *pt2) -{ - return p2tr_math_length_sq (pt1->x, pt1->y, pt2->x, pt2->y); -} - -static inline gdouble -p2tr_matrix_det2 (gdouble a00, gdouble a01, - gdouble a10, gdouble a11) -{ - return a00 * a11 - a10 * a01; -} - -static inline gdouble -p2tr_matrix_det3 (gdouble a00, gdouble a01, gdouble a02, - gdouble a10, gdouble a11, gdouble a12, - gdouble a20, gdouble a21, gdouble a22) -{ - return - + a00 * (a11 * a22 - a21 * a12) - - a01 * (a10 * a22 - a20 * a12) - + a02 * (a10 * a21 - a20 * a11); -} - -static inline gdouble -p2tr_matrix_det4 (gdouble a00, gdouble a01, gdouble a02, gdouble a03, - gdouble a10, gdouble a11, gdouble a12, gdouble a13, - gdouble a20, gdouble a21, gdouble a22, gdouble a23, - gdouble a30, gdouble a31, gdouble a32, gdouble a33) -{ - return - + a00 * p2tr_matrix_det3 (a11, a12, a13, - a21, a22, a23, - a31, a32, a33) - - a01 * p2tr_matrix_det3 (a10, a12, a13, - a20, a22, a23, - a30, a32, a33) - + a02 * p2tr_matrix_det3 (a10, a11, a13, - a20, a21, a23, - a30, a31, a33) - - a03 * p2tr_matrix_det3 (a10, a11, a12, - a20, a21, a22, - a30, a31, a32); -} - -void -p2tr_math_triangle_circumcircle (const P2trVector2 *A, - const P2trVector2 *B, - const P2trVector2 *C, - P2trCircle *circle) -{ +#include +#include +#include "rmath.h" + +gdouble +p2tr_math_length_sq (gdouble x1, gdouble y1, + gdouble x2, gdouble y2) +{ + return P2TR_VECTOR2_DISTANCE_SQ2 (x1, y1, x2, y2); +} + +gdouble +p2tr_math_length_sq2 (const P2trVector2 *pt1, + const P2trVector2 *pt2) +{ + return p2tr_math_length_sq (pt1->x, pt1->y, pt2->x, pt2->y); +} + +static inline gdouble +p2tr_matrix_det2 (gdouble a00, gdouble a01, + gdouble a10, gdouble a11) +{ + return a00 * a11 - a10 * a01; +} + +static inline gdouble +p2tr_matrix_det3 (gdouble a00, gdouble a01, gdouble a02, + gdouble a10, gdouble a11, gdouble a12, + gdouble a20, gdouble a21, gdouble a22) +{ + return + + a00 * (a11 * a22 - a21 * a12) + - a01 * (a10 * a22 - a20 * a12) + + a02 * (a10 * a21 - a20 * a11); +} + +static inline gdouble +p2tr_matrix_det4 (gdouble a00, gdouble a01, gdouble a02, gdouble a03, + gdouble a10, gdouble a11, gdouble a12, gdouble a13, + gdouble a20, gdouble a21, gdouble a22, gdouble a23, + gdouble a30, gdouble a31, gdouble a32, gdouble a33) +{ + return + + a00 * p2tr_matrix_det3 (a11, a12, a13, + a21, a22, a23, + a31, a32, a33) + - a01 * p2tr_matrix_det3 (a10, a12, a13, + a20, a22, a23, + a30, a32, a33) + + a02 * p2tr_matrix_det3 (a10, a11, a13, + a20, a21, a23, + a30, a31, a33) + - a03 * p2tr_matrix_det3 (a10, a11, a12, + a20, a21, a22, + a30, a31, a32); +} + +void +p2tr_math_triangle_circumcircle (const P2trVector2 *A, + const P2trVector2 *B, + const P2trVector2 *C, + P2trCircle *circle) +{ /* | Ax Bx Cx | * D = + | Ay By Cy | * 2 * | +1 +1 +1 | @@ -93,176 +93,176 @@ p2tr_math_triangle_circumcircle (const P2trVector2 *A, 1, 1, 1) * invD; circle->radius = sqrt (P2TR_VECTOR2_DISTANCE_SQ (A, &circle->center)); -} - -/* The point in triangle test which is implemented below is based on the - * algorithm which appears on: - * - * http://www.blackpawn.com/texts/pointinpoly/default.html - */ -void -p2tr_math_triangle_barcycentric (const P2trVector2 *A, - const P2trVector2 *B, - const P2trVector2 *C, - const P2trVector2 *P, - gdouble *u, - gdouble *v) -{ - gdouble dot00, dot01, dot02, dot11, dot12, invDenom; - - /* Compute the vectors offsetted so that A is the origin */ - P2trVector2 v0, v1, v2; - p2tr_vector2_sub(C, A, &v0); - p2tr_vector2_sub(B, A, &v1); - p2tr_vector2_sub(P, A, &v2); - - /* Compute dot products */ - dot00 = P2TR_VECTOR2_DOT(&v0, &v0); - dot01 = P2TR_VECTOR2_DOT(&v0, &v1); - dot02 = P2TR_VECTOR2_DOT(&v0, &v2); - dot11 = P2TR_VECTOR2_DOT(&v1, &v1); - dot12 = P2TR_VECTOR2_DOT(&v1, &v2); - - /* Compute barycentric coordinates */ - invDenom = 1 / (dot00 * dot11 - dot01 * dot01); - *u = (dot11 * dot02 - dot01 * dot12) * invDenom; - *v = (dot00 * dot12 - dot01 * dot02) * invDenom; -} - -#define INTRIANGLE_EPSILON 0e-9 - -P2trInTriangle -p2tr_math_intriangle (const P2trVector2 *A, - const P2trVector2 *B, - const P2trVector2 *C, - const P2trVector2 *P) -{ - gdouble u, v; - return p2tr_math_intriangle2 (A, B, C, P, &u, &v); -} - -P2trInTriangle -p2tr_math_intriangle2 (const P2trVector2 *A, - const P2trVector2 *B, - const P2trVector2 *C, - const P2trVector2 *P, - gdouble *u, - gdouble *v) -{ - p2tr_math_triangle_barcycentric (A, B, C, P, u, v); - - /* Check if point is in triangle - i.e. whether (u + v) < 1 and both - * u and v are positive */ - if ((*u >= INTRIANGLE_EPSILON) && (*v >= INTRIANGLE_EPSILON) && (*u + *v < 1 - INTRIANGLE_EPSILON)) - return P2TR_INTRIANGLE_IN; - else if ((*u >= -INTRIANGLE_EPSILON) && (*v >= -INTRIANGLE_EPSILON) && (*u + *v <= 1 + INTRIANGLE_EPSILON)) - return P2TR_INTRIANGLE_ON; - else - return P2TR_INTRIANGLE_OUT; -} - -/* The point in triangle circumcircle test, and the 3-point orientation - * test, are both based on the work of Jonathan Richard Shewchuk. The - * technique used here is described in his paper "Adaptive Precision - * Floating-Point Arithmetic and Fast Robust Geometric Predicates" - */ - -#define ORIENT2D_EPSILON 1e-9 - -P2trOrientation p2tr_math_orient2d (const P2trVector2 *A, - const P2trVector2 *B, - const P2trVector2 *C) -{ - /* We are trying to compute this determinant: - * |Ax Ay 1| - * |Bx By 1| - * |Cx Cy 1| - */ - gdouble result = p2tr_matrix_det3 ( - A->x, A->y, 1, - B->x, B->y, 1, - C->x, C->y, 1 - ); - - if (result > ORIENT2D_EPSILON) - return P2TR_ORIENTATION_CCW; - else if (result < -ORIENT2D_EPSILON) - return P2TR_ORIENTATION_CW; - else - return P2TR_ORIENTATION_LINEAR; -} - -#define INCIRCLE_EPSILON 1e-9 - -P2trInCircle -p2tr_math_incircle (const P2trVector2 *A, - const P2trVector2 *B, - const P2trVector2 *C, - const P2trVector2 *D) -{ - /* We are trying to compute this determinant: - * |Ax Ay Ax^2+Ay^2 1| - * |Bx By Bx^2+By^2 1| - * |Cx Cy Cx^2+Cy^2 1| - * |Dx Dy Dx^2+Dy^2 1| - */ - gdouble result = p2tr_matrix_det4 ( - A->x, A->y, P2TR_VECTOR2_LEN_SQ(A), 1, - B->x, B->y, P2TR_VECTOR2_LEN_SQ(B), 1, - C->x, C->y, P2TR_VECTOR2_LEN_SQ(C), 1, - D->x, D->y, P2TR_VECTOR2_LEN_SQ(D), 1 - ); - - if (result > INCIRCLE_EPSILON) - return P2TR_INCIRCLE_IN; - else if (result < INCIRCLE_EPSILON) - return P2TR_INCIRCLE_OUT; - else - return P2TR_INCIRCLE_ON; -} - -/* The point inside diametral-circle test and the point inside diametral - * lens test, are both based on the work of Jonathan Richard Shewchuk. - * The techniques used here are partially described in his paper - * "Delaunay Refinement Algorithms for Triangular Mesh Generation". - * - * W is inside the diametral circle (lens) of the line XY if and only if - * the angle XWY is larger than 90 (120) degrees. We know how to compute - * the cosine of that angle very easily like so: - * - * cos XWY = (WX * WY) / (|WX| * |WY|) - * - * Since XWY is larger than 90 (120) degrees, cos XWY <= 0 (-0.5) so: - * - * Diametral Circle | Diametral Lens - * -------------------------------+----------------------------------- - * 0 >= (WX * WY) / (|WX| * |WY|) | - 0.5 >= (WX * WY) / (|WX| * |WY|) - * 0 >= WX * WY | - 0.5 * |WX| * |WY| >= WX * WY - */ - -gboolean -p2tr_math_diametral_circle_contains (const P2trVector2 *X, - const P2trVector2 *Y, - const P2trVector2 *W) -{ - P2trVector2 WX, WY; - - p2tr_vector2_sub(X, W, &WX); - p2tr_vector2_sub(Y, W, &WY); - - return P2TR_VECTOR2_DOT(&WX, &WY) <= 0; -} - -gboolean -p2tr_math_diametral_lens_contains (const P2trVector2 *X, - const P2trVector2 *Y, - const P2trVector2 *W) -{ - P2trVector2 WX, WY; - - p2tr_vector2_sub(X, W, &WX); - p2tr_vector2_sub(Y, W, &WY); - - return P2TR_VECTOR2_DOT(&WX, &WY) - <= 0.5 * p2tr_vector2_norm(&WX) * p2tr_vector2_norm(&WY); -} +} + +/* The point in triangle test which is implemented below is based on the + * algorithm which appears on: + * + * http://www.blackpawn.com/texts/pointinpoly/default.html + */ +void +p2tr_math_triangle_barcycentric (const P2trVector2 *A, + const P2trVector2 *B, + const P2trVector2 *C, + const P2trVector2 *P, + gdouble *u, + gdouble *v) +{ + gdouble dot00, dot01, dot02, dot11, dot12, invDenom; + + /* Compute the vectors offsetted so that A is the origin */ + P2trVector2 v0, v1, v2; + p2tr_vector2_sub(C, A, &v0); + p2tr_vector2_sub(B, A, &v1); + p2tr_vector2_sub(P, A, &v2); + + /* Compute dot products */ + dot00 = P2TR_VECTOR2_DOT(&v0, &v0); + dot01 = P2TR_VECTOR2_DOT(&v0, &v1); + dot02 = P2TR_VECTOR2_DOT(&v0, &v2); + dot11 = P2TR_VECTOR2_DOT(&v1, &v1); + dot12 = P2TR_VECTOR2_DOT(&v1, &v2); + + /* Compute barycentric coordinates */ + invDenom = 1 / (dot00 * dot11 - dot01 * dot01); + *u = (dot11 * dot02 - dot01 * dot12) * invDenom; + *v = (dot00 * dot12 - dot01 * dot02) * invDenom; +} + +#define INTRIANGLE_EPSILON 0e-9 + +P2trInTriangle +p2tr_math_intriangle (const P2trVector2 *A, + const P2trVector2 *B, + const P2trVector2 *C, + const P2trVector2 *P) +{ + gdouble u, v; + return p2tr_math_intriangle2 (A, B, C, P, &u, &v); +} + +P2trInTriangle +p2tr_math_intriangle2 (const P2trVector2 *A, + const P2trVector2 *B, + const P2trVector2 *C, + const P2trVector2 *P, + gdouble *u, + gdouble *v) +{ + p2tr_math_triangle_barcycentric (A, B, C, P, u, v); + + /* Check if point is in triangle - i.e. whether (u + v) < 1 and both + * u and v are positive */ + if ((*u >= INTRIANGLE_EPSILON) && (*v >= INTRIANGLE_EPSILON) && (*u + *v < 1 - INTRIANGLE_EPSILON)) + return P2TR_INTRIANGLE_IN; + else if ((*u >= -INTRIANGLE_EPSILON) && (*v >= -INTRIANGLE_EPSILON) && (*u + *v <= 1 + INTRIANGLE_EPSILON)) + return P2TR_INTRIANGLE_ON; + else + return P2TR_INTRIANGLE_OUT; +} + +/* The point in triangle circumcircle test, and the 3-point orientation + * test, are both based on the work of Jonathan Richard Shewchuk. The + * technique used here is described in his paper "Adaptive Precision + * Floating-Point Arithmetic and Fast Robust Geometric Predicates" + */ + +#define ORIENT2D_EPSILON 1e-9 + +P2trOrientation p2tr_math_orient2d (const P2trVector2 *A, + const P2trVector2 *B, + const P2trVector2 *C) +{ + /* We are trying to compute this determinant: + * |Ax Ay 1| + * |Bx By 1| + * |Cx Cy 1| + */ + gdouble result = p2tr_matrix_det3 ( + A->x, A->y, 1, + B->x, B->y, 1, + C->x, C->y, 1 + ); + + if (result > ORIENT2D_EPSILON) + return P2TR_ORIENTATION_CCW; + else if (result < -ORIENT2D_EPSILON) + return P2TR_ORIENTATION_CW; + else + return P2TR_ORIENTATION_LINEAR; +} + +#define INCIRCLE_EPSILON 1e-9 + +P2trInCircle +p2tr_math_incircle (const P2trVector2 *A, + const P2trVector2 *B, + const P2trVector2 *C, + const P2trVector2 *D) +{ + /* We are trying to compute this determinant: + * |Ax Ay Ax^2+Ay^2 1| + * |Bx By Bx^2+By^2 1| + * |Cx Cy Cx^2+Cy^2 1| + * |Dx Dy Dx^2+Dy^2 1| + */ + gdouble result = p2tr_matrix_det4 ( + A->x, A->y, P2TR_VECTOR2_LEN_SQ(A), 1, + B->x, B->y, P2TR_VECTOR2_LEN_SQ(B), 1, + C->x, C->y, P2TR_VECTOR2_LEN_SQ(C), 1, + D->x, D->y, P2TR_VECTOR2_LEN_SQ(D), 1 + ); + + if (result > INCIRCLE_EPSILON) + return P2TR_INCIRCLE_IN; + else if (result < INCIRCLE_EPSILON) + return P2TR_INCIRCLE_OUT; + else + return P2TR_INCIRCLE_ON; +} + +/* The point inside diametral-circle test and the point inside diametral + * lens test, are both based on the work of Jonathan Richard Shewchuk. + * The techniques used here are partially described in his paper + * "Delaunay Refinement Algorithms for Triangular Mesh Generation". + * + * W is inside the diametral circle (lens) of the line XY if and only if + * the angle XWY is larger than 90 (120) degrees. We know how to compute + * the cosine of that angle very easily like so: + * + * cos XWY = (WX * WY) / (|WX| * |WY|) + * + * Since XWY is larger than 90 (120) degrees, cos XWY <= 0 (-0.5) so: + * + * Diametral Circle | Diametral Lens + * -------------------------------+----------------------------------- + * 0 >= (WX * WY) / (|WX| * |WY|) | - 0.5 >= (WX * WY) / (|WX| * |WY|) + * 0 >= WX * WY | - 0.5 * |WX| * |WY| >= WX * WY + */ + +gboolean +p2tr_math_diametral_circle_contains (const P2trVector2 *X, + const P2trVector2 *Y, + const P2trVector2 *W) +{ + P2trVector2 WX, WY; + + p2tr_vector2_sub(X, W, &WX); + p2tr_vector2_sub(Y, W, &WY); + + return P2TR_VECTOR2_DOT(&WX, &WY) <= 0; +} + +gboolean +p2tr_math_diametral_lens_contains (const P2trVector2 *X, + const P2trVector2 *Y, + const P2trVector2 *W) +{ + P2trVector2 WX, WY; + + p2tr_vector2_sub(X, W, &WX); + p2tr_vector2_sub(Y, W, &WY); + + return P2TR_VECTOR2_DOT(&WX, &WY) + <= 0.5 * p2tr_vector2_norm(&WX) * p2tr_vector2_norm(&WY); +} diff --git a/refine/rmath.h b/refine/rmath.h index 2109cac..167fe8e 100644 --- a/refine/rmath.h +++ b/refine/rmath.h @@ -1,78 +1,78 @@ -#ifndef __P2TC_REFINE_MATH_H__ -#define __P2TC_REFINE_MATH_H__ - -#include -#include "vector2.h" +#ifndef __P2TC_REFINE_MATH_H__ +#define __P2TC_REFINE_MATH_H__ + +#include +#include "vector2.h" #include "circle.h" - + gdouble p2tr_math_length_sq (gdouble x1, gdouble y1, gdouble x2, gdouble y2); - + gdouble p2tr_math_length_sq2 (const P2trVector2 *pt1, - const P2trVector2 *pt2); - - -/** - * Find the circumscribing circle of a triangle defined by the given - * points. - * @param[in] A The first vertex of the triangle - * @param[in] B The second vertex of the triangle - * @param[in] C The third vertex of the triangle - * @param[out] circle The circumscribing circle of the triangle + const P2trVector2 *pt2); + + +/** + * Find the circumscribing circle of a triangle defined by the given + * points. + * @param[in] A The first vertex of the triangle + * @param[in] B The second vertex of the triangle + * @param[in] C The third vertex of the triangle + * @param[out] circle The circumscribing circle of the triangle */ -void p2tr_math_triangle_circumcircle (const P2trVector2 *A, - const P2trVector2 *B, - const P2trVector2 *C, - P2trCircle *circle); - -typedef enum -{ - P2TR_INTRIANGLE_OUT = -1, - P2TR_INTRIANGLE_ON = 0, - P2TR_INTRIANGLE_IN = 1 +void p2tr_math_triangle_circumcircle (const P2trVector2 *A, + const P2trVector2 *B, + const P2trVector2 *C, + P2trCircle *circle); + +typedef enum +{ + P2TR_INTRIANGLE_OUT = -1, + P2TR_INTRIANGLE_ON = 0, + P2TR_INTRIANGLE_IN = 1 } P2trInTriangle; -/** - * Return the barycentric coordinates of a point inside a triangle. This - * means that the computation returns @ref u and @ref v so that the - * following equation is satisfied: - * {{{ AP = u * AB + v * AC }}} - * - * @param[in] A The first point of the triangle - * @param[in] B The second point of the triangle - * @param[in] C The third point of the triangle - * @param[in] P The point whose barycentric coordinates should be - * computed - * @param[out] u The first barycentric coordinate - * @param[out] v The second barycentric coordinate - */ -void p2tr_math_triangle_barcycentric (const P2trVector2 *A, - const P2trVector2 *B, - const P2trVector2 *C, - const P2trVector2 *P, - gdouble *u, - gdouble *v); - -P2trInTriangle p2tr_math_intriangle (const P2trVector2 *A, - const P2trVector2 *B, - const P2trVector2 *C, - const P2trVector2 *P); - -P2trInTriangle p2tr_math_intriangle2 (const P2trVector2 *A, - const P2trVector2 *B, - const P2trVector2 *C, - const P2trVector2 *P, - gdouble *u, - gdouble *v); +/** + * Return the barycentric coordinates of a point inside a triangle. This + * means that the computation returns @ref u and @ref v so that the + * following equation is satisfied: + * {{{ AP = u * AB + v * AC }}} + * + * @param[in] A The first point of the triangle + * @param[in] B The second point of the triangle + * @param[in] C The third point of the triangle + * @param[in] P The point whose barycentric coordinates should be + * computed + * @param[out] u The first barycentric coordinate + * @param[out] v The second barycentric coordinate + */ +void p2tr_math_triangle_barcycentric (const P2trVector2 *A, + const P2trVector2 *B, + const P2trVector2 *C, + const P2trVector2 *P, + gdouble *u, + gdouble *v); + +P2trInTriangle p2tr_math_intriangle (const P2trVector2 *A, + const P2trVector2 *B, + const P2trVector2 *C, + const P2trVector2 *P); -typedef enum -{ - P2TR_ORIENTATION_CW = -1, - P2TR_ORIENTATION_LINEAR = 0, - P2TR_ORIENTATION_CCW = 1 -} P2trOrientation; +P2trInTriangle p2tr_math_intriangle2 (const P2trVector2 *A, + const P2trVector2 *B, + const P2trVector2 *C, + const P2trVector2 *P, + gdouble *u, + gdouble *v); + +typedef enum +{ + P2TR_ORIENTATION_CW = -1, + P2TR_ORIENTATION_LINEAR = 0, + P2TR_ORIENTATION_CCW = 1 +} P2trOrientation; P2trOrientation p2tr_math_orient2d (const P2trVector2 *A, const P2trVector2 *B, @@ -85,16 +85,16 @@ typedef enum P2TR_INCIRCLE_OUT } P2trInCircle; -P2trInCircle p2tr_math_incircle (const P2trVector2 *A, - const P2trVector2 *B, - const P2trVector2 *C, - const P2trVector2 *D); - -gboolean p2tr_math_diametral_circle_contains (const P2trVector2 *X, - const P2trVector2 *Y, - const P2trVector2 *W); - -gboolean p2tr_math_diametral_lens_contains (const P2trVector2 *X, - const P2trVector2 *Y, - const P2trVector2 *W); +P2trInCircle p2tr_math_incircle (const P2trVector2 *A, + const P2trVector2 *B, + const P2trVector2 *C, + const P2trVector2 *D); + +gboolean p2tr_math_diametral_circle_contains (const P2trVector2 *X, + const P2trVector2 *Y, + const P2trVector2 *W); + +gboolean p2tr_math_diametral_lens_contains (const P2trVector2 *X, + const P2trVector2 *Y, + const P2trVector2 *W); #endif \ No newline at end of file diff --git a/refine/vector2.c b/refine/vector2.c index 45a6b7f..2b3ea0f 100644 --- a/refine/vector2.c +++ b/refine/vector2.c @@ -1,52 +1,52 @@ -#include -#include -#include "vector2.h" - -gdouble -p2tr_vector2_dot (const P2trVector2 *a, - const P2trVector2 *b) -{ - return P2TR_VECTOR2_DOT (a, b); -} - -gboolean -p2tr_vector2_is_same (const P2trVector2 *a, - const P2trVector2 *b) -{ - if (a == NULL || b == NULL) - return ! ((a == NULL) ^ (b == NULL)); - else - return a->x == b->x && a->y == b->y; -} - -void -p2tr_vector2_sub (const P2trVector2 *a, - const P2trVector2 *b, - P2trVector2 *dest) -{ - dest->x = a->x - b->x; - dest->y = a->y - b->y; -} - -void -p2tr_vector2_center (const P2trVector2 *a, - const P2trVector2 *b, - P2trVector2 *dest) -{ - dest->x = (a->x + b->x) * 0.5; - dest->y = (a->y + b->y) * 0.5; -} - -gdouble -p2tr_vector2_norm (const P2trVector2 *v) -{ - return sqrt (P2TR_VECTOR2_LEN_SQ (v)); -} - -void -p2tr_vector2_copy (P2trVector2 *dest, - const P2trVector2 *src) -{ - dest->x = src->x; - dest->y = src->y; -} +#include +#include +#include "vector2.h" + +gdouble +p2tr_vector2_dot (const P2trVector2 *a, + const P2trVector2 *b) +{ + return P2TR_VECTOR2_DOT (a, b); +} + +gboolean +p2tr_vector2_is_same (const P2trVector2 *a, + const P2trVector2 *b) +{ + if (a == NULL || b == NULL) + return ! ((a == NULL) ^ (b == NULL)); + else + return a->x == b->x && a->y == b->y; +} + +void +p2tr_vector2_sub (const P2trVector2 *a, + const P2trVector2 *b, + P2trVector2 *dest) +{ + dest->x = a->x - b->x; + dest->y = a->y - b->y; +} + +void +p2tr_vector2_center (const P2trVector2 *a, + const P2trVector2 *b, + P2trVector2 *dest) +{ + dest->x = (a->x + b->x) * 0.5; + dest->y = (a->y + b->y) * 0.5; +} + +gdouble +p2tr_vector2_norm (const P2trVector2 *v) +{ + return sqrt (P2TR_VECTOR2_LEN_SQ (v)); +} + +void +p2tr_vector2_copy (P2trVector2 *dest, + const P2trVector2 *src) +{ + dest->x = src->x; + dest->y = src->y; +} diff --git a/refine/vector2.h b/refine/vector2.h index 08386ad..e202b3d 100644 --- a/refine/vector2.h +++ b/refine/vector2.h @@ -1,69 +1,69 @@ -#ifndef __P2TR_REFINE_VECTOR2_H__ -#define __P2TR_REFINE_VECTOR2_H__ - -#include - -/** - * \struct P2trVector2 - * A struct for representing a vector with 2 coordinates (a point in 2D) - */ -typedef struct { - /** The first coordinate of the vector */ - gdouble x; - /** The second coordinate of the vector */ - gdouble y; -} P2trVector2; - -#define P2TR_VECTOR2_LEN_SQ2(X, Y) \ - ((X) * (X) + (Y) * (Y)) - -#define P2TR_VECTOR2_LEN_SQ(V) \ - (P2TR_VECTOR2_LEN_SQ2((V)->x, (V)->y)) - -#define P2TR_VECTOR2_DOT(V1,V2) \ - ((V1)->x * (V2)->x + (V1)->y * (V2)->y) - -#define P2TR_VECTOR2_DISTANCE_SQ2(X1,Y1,X2,Y2) \ - (P2TR_VECTOR2_LEN_SQ2((X1) - (X2), (Y1) - (Y2))) - -#define P2TR_VECTOR2_DISTANCE_SQ(V1,V2) \ - (P2TR_VECTOR2_DISTANCE_SQ2((V1)->x, (V1)->y, (V2)->x, (V2)->y)) - -/** Compute the dot product of two vectors */ -gdouble p2tr_vector2_dot (const P2trVector2 *a, const P2trVector2 *b); - -/** Check if all the coordinates of the two vectors are the same */ -gboolean p2tr_vector2_is_same (const P2trVector2 *a, const P2trVector2 *b); - -/** - * Compute the difference of two vectors - * @param[in] a The vector to subtract from - * @param[in] b The vector to be subtracted - * @param[out] dest The vector in which the result should be stored - */ -void p2tr_vector2_sub (const P2trVector2 *a, const P2trVector2 *b, P2trVector2 *dest); - -/** - * Compute the center point of the edge defined between two points - * @param[in] a The first side of the edge - * @param[in] b The second side of the edge - * @param[out] dest The vector in which the result should be stored - */ -void p2tr_vector2_center (const P2trVector2 *a, const P2trVector2 *b, P2trVector2 *dest); - -/** - * Compute the norm of a vector (the length of the line from the origin - * to the 2D point it represents) - * @param[in] v The vector whose norm should be computed - * @return The norm of the vector - */ -gdouble p2tr_vector2_norm (const P2trVector2 *v); - -/** - * Copy a vector - * @param[out] dest The destination of the copy operation - * @param[in] src The vector to copy - */ -void p2tr_vector2_copy (P2trVector2 *dest, const P2trVector2 *src); - +#ifndef __P2TR_REFINE_VECTOR2_H__ +#define __P2TR_REFINE_VECTOR2_H__ + +#include + +/** + * \struct P2trVector2 + * A struct for representing a vector with 2 coordinates (a point in 2D) + */ +typedef struct { + /** The first coordinate of the vector */ + gdouble x; + /** The second coordinate of the vector */ + gdouble y; +} P2trVector2; + +#define P2TR_VECTOR2_LEN_SQ2(X, Y) \ + ((X) * (X) + (Y) * (Y)) + +#define P2TR_VECTOR2_LEN_SQ(V) \ + (P2TR_VECTOR2_LEN_SQ2((V)->x, (V)->y)) + +#define P2TR_VECTOR2_DOT(V1,V2) \ + ((V1)->x * (V2)->x + (V1)->y * (V2)->y) + +#define P2TR_VECTOR2_DISTANCE_SQ2(X1,Y1,X2,Y2) \ + (P2TR_VECTOR2_LEN_SQ2((X1) - (X2), (Y1) - (Y2))) + +#define P2TR_VECTOR2_DISTANCE_SQ(V1,V2) \ + (P2TR_VECTOR2_DISTANCE_SQ2((V1)->x, (V1)->y, (V2)->x, (V2)->y)) + +/** Compute the dot product of two vectors */ +gdouble p2tr_vector2_dot (const P2trVector2 *a, const P2trVector2 *b); + +/** Check if all the coordinates of the two vectors are the same */ +gboolean p2tr_vector2_is_same (const P2trVector2 *a, const P2trVector2 *b); + +/** + * Compute the difference of two vectors + * @param[in] a The vector to subtract from + * @param[in] b The vector to be subtracted + * @param[out] dest The vector in which the result should be stored + */ +void p2tr_vector2_sub (const P2trVector2 *a, const P2trVector2 *b, P2trVector2 *dest); + +/** + * Compute the center point of the edge defined between two points + * @param[in] a The first side of the edge + * @param[in] b The second side of the edge + * @param[out] dest The vector in which the result should be stored + */ +void p2tr_vector2_center (const P2trVector2 *a, const P2trVector2 *b, P2trVector2 *dest); + +/** + * Compute the norm of a vector (the length of the line from the origin + * to the 2D point it represents) + * @param[in] v The vector whose norm should be computed + * @return The norm of the vector + */ +gdouble p2tr_vector2_norm (const P2trVector2 *v); + +/** + * Copy a vector + * @param[out] dest The destination of the copy operation + * @param[in] src The vector to copy + */ +void p2tr_vector2_copy (P2trVector2 *dest, const P2trVector2 *src); + #endif \ No newline at end of file diff --git a/render/svg-plot.h b/render/svg-plot.h index 0431c90..659f7fd 100644 --- a/render/svg-plot.h +++ b/render/svg-plot.h @@ -33,8 +33,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef __P2TC_RENDER_SVG_PLOT_H__ -#define __P2TC_RENDER_SVG_PLOT_H__ +#ifndef __P2TC_RENDER_SVG_PLOT_H__ +#define __P2TC_RENDER_SVG_PLOT_H__ #include