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