Revision: 74177
          http://sourceforge.net/p/brlcad/code/74177
Author:   starseeker
Date:     2019-10-18 15:00:40 +0000 (Fri, 18 Oct 2019)
Log Message:
-----------
This can now be a straightforward C file

Modified Paths:
--------------
    brlcad/trunk/src/libbg/CMakeLists.txt

Added Paths:
-----------
    brlcad/trunk/src/libbg/trimesh_pt_in.c

Removed Paths:
-------------
    brlcad/trunk/src/libbg/trimesh_pt_in.cpp

Modified: brlcad/trunk/src/libbg/CMakeLists.txt
===================================================================
--- brlcad/trunk/src/libbg/CMakeLists.txt       2019-10-18 14:59:54 UTC (rev 
74176)
+++ brlcad/trunk/src/libbg/CMakeLists.txt       2019-10-18 15:00:40 UTC (rev 
74177)
@@ -24,7 +24,7 @@
   tri_tri.c
   trimesh.cpp
   trimesh_isect.cpp
-  trimesh_pt_in.cpp
+  trimesh_pt_in.c
   util.c
   )
 

Copied: brlcad/trunk/src/libbg/trimesh_pt_in.c (from rev 74176, 
brlcad/trunk/src/libbg/trimesh_pt_in.cpp)
===================================================================
--- brlcad/trunk/src/libbg/trimesh_pt_in.c                              (rev 0)
+++ brlcad/trunk/src/libbg/trimesh_pt_in.c      2019-10-18 15:00:40 UTC (rev 
74177)
@@ -0,0 +1,399 @@
+/* This is a C translation of Mark Dickinson's point-in-polyhedron test from
+ * https://github.com/mdickinson/polyhedron/ */
+
+/*
+ * BSD 3-Clause License
+ *
+ * Copyright (c) 2019, Mark Dickinson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, 
this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. Neither the name of the copyright holder 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 HOLDER 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.
+ */
+
+/*
+ * Robust point-in-polyhedron test.
+ *
+ * Given an closed, oriented surface in R^3 described by a triangular mesh, the
+ * code below gives a robust algorithm for determining whether a given point is
+ * inside, on the boundary of, or outside, the surface.  The algorithm should 
give
+ * correct results even in degenerate cases, and applies to disconnected
+ * polyhedra, non simply-connected surfaces, and so on.  There are no 
requirements
+ * for the surface to be convex, simple, connected or simply-connected.
+ *
+ * More precisely, we give a method for computing the *winding number* of a 
closed
+ * oriented surface S around a point TP that doesn't lie on S.  Roughly 
speaking,
+ * the winding number of the closed oriented surface S around a point TP not 
on S
+ * is the number of times that the surface encloses that point; for a simple
+ * outward-oriented surface (like that of a convex polyhedron, for example), 
the
+ * winding number will be 1 for points inside the surface and 0 for points
+ * outside.
+ *
+ * For a precise definition of winding number, we can turn to algebraic 
topology:
+ * our oriented surface is presented as a collection of combinatorial data
+ * defining abstract vertices, edges and triangles, together with a mapping of
+ * those vertices to R^3.  The combinatorial data describe a simplicial 
complex C,
+ * and assuming that TP doesn't lie on the surface, the mapping of the 
vertices to
+ * R^3 gives a continuous map from the geometric realization of C to R^3 - 
{TP}.
+ * This in turn induces a map on second homology groups:
+ *
+ *    H^2(C, Z) -> H^2(R^3 - {TP}, Z)
+ *
+ * and by taking the usual right-handed orientation in R^3 we identify H^2(R^3 
-
+ * {TP}, Z) with Z.  The image of [S] under this map gives the winding number. 
 In
+ * particular, the well-definedness of the winding number does not depend on
+ * topological properties of the embedding: it doesn't matter if the surface is
+ * self-intersecting, or has degenerate triangles.  The only condition is that 
TP
+ * does not lie on the surface S.
+ *
+ * Algorithm
+ * ---------
+ * The algorithm is based around the usual method of ray-casting: we take a
+ * vertical line L through TP and count the intersections of this line with the
+ * triangles of the surface, keeping track of orientations as we go.  Let's 
ignore
+ * corner cases for a moment and assume that:
+ *
+ * (1) TP does not lie on the surface, and
+ * (2) for each triangle T (thought of as a closed subset of R^3) touched by
+ *     our vertical line L, L meets the interior of T in exactly one point Q
+ *
+ * Then there are four possibilities for each such triangle T:
+ *
+ * 1. T lies *above* TP and is oriented *upwards* (*away* from TP).
+ * 2. T lies *above* TP and is oriented *downwards* (*towards* TP).
+ * 3. T lies *below* TP and is oriented *downwards* (*away* from TP).
+ * 4. T lies *below* TP and is oriented *upwards* (*towards* TP).
+ *
+ * Let's write N1, N2, N3 and N4 for the counts of triangles satisfying 
conditions
+ * 1, 2, 3 and 4 respectively.  Since we have a closed surface, these numbers
+ * are not independent; they satisfy the relation:
+ *
+ *     N1 + N4 == N2 + N3
+ *
+ * That is, the number of upward-facing triangles must match the number of
+ * downward-facing triangles.  The winding number w is then given by:
+ *
+ *     w = N1 - N2 == N3 - N4
+ *
+ * In the code below, we simply compute 2*w = (N1 + N3) - (N2 + N4), so each
+ * triangle oriented away from TP contributes 1 to 2w, while each triangle 
oriented
+ * towards TP contributes -1.
+ *
+ *
+ * Making the algorithm robust
+ * ---------------------------
+ * Now we describe how to augment the basic algorithm described above to 
include:
+ *
+ * - correct treatment of corner cases (vertical triangles, cases where L 
meets an
+ *   edge or vertex directly, etc.)
+ *
+ * - detection of the case where the point lies directly on the surface.
+ *
+ * It turns out that to make the algorithm robust, all we need to do is be 
careful
+ * and consistent about classifying vertices, edges and triangles.  We do this 
as
+ * follows:
+ *
+ * - Each vertex of the surface that's not equal to TP is considered 
*positive* if
+ *   its coordinates are lexicographically greater than TP, and *negative*
+ *   otherwise.
+ *
+ * - For an edge PQ of the surface that's not collinear with TP, we first 
describe
+ *   the classification in the case that P is negative and Q is positive, and
+ *   then extend to arbitrary PQ.
+ *
+ *   For P negative and Q positive, there are two cases:
+ *
+ *   1. P and Q have distinct x coordinates.  In that case we classify the edge
+ *      PQ by its intersection with the plane passing through TP and parallel
+ *      to the yz-plane: the edge is *positive* if the intersection point is
+ *      positive, and *negative* otherwise.
+ *
+ *   2. P and Q have the same x coordinate, in which case they must have
+ *      distinct y coordinates.  (If the x and the y coordinates both match
+ *      then PQ passes through TP.)  We classify by the intersection of PQ
+ *      with the line parallel to the y-axis through TP.
+ *
+ *   For P positive and Q negative, we classify as above but reverse the sign.
+ *   For like-signed P and Q, the classification isn't used.
+ *
+ *   Computationally, in case 1 above, the y-coordinate of the intersection
+ *   point is:
+ *
+ *       Py + (Qy - Py) * (TPx - Px) / (Qx - Px)
+ *
+ *   and this is greater than TPy iff
+ *
+ *       (Py - TPy) * (Qx - TPx) - (Px - TPx) * (Qy - TPy)
+ *
+ *   is positive, so the sign of the edge is the sign of the above expression.
+ *   Similarly, if this quantity is zero then we need to look at the 
z-coordinate
+ *   of the intersection, and the sign of the edge is given by
+ *
+ *       (Pz - TPz) * (Qx - TPx) - (Px - TPx) * (Qz - TPz)
+ *
+ *   In case 2, both of the above quantities are zero, and the sign of the 
edge is
+ *   the sign of
+ *
+ *       (Pz - TPz) * (Qy - TPy) - (Py - TPy) * (Qz - TPz)
+ *
+ *   Another way to look at this: if P, Q and TP are not collinear then the
+ *   matrix
+ *
+ *    ( Px Qx TPx )
+ *    ( Py Qy TPx )
+ *    ( Pz Qz TPx )
+ *    (  1  1  1 )
+ *
+ *   has rank 3.  It follows that at least one of the three 3x3 minors
+ *
+ *    | Px Qx TPx |  | Px Qx TPx |  | Py Qy TPy |
+ *    | Py Qy TPy |  | Pz Qz TPz |  | Pz Qz TPz |
+ *    |  1  1  1 |  |  1  1  1 |  |  1  1  1 |
+ *
+ *   is nonzero.  We define the sign of PQ to be the *negative* of the sign of 
the
+ *   first nonzero minor in that list.
+ *
+ * - Each triangle PQR of the surface that's not coplanar with TP is considered
+ *   *positive* if its normal points away from TP, and *negative* if its normal
+ *   points towards TP.
+ *
+ *   Computationally, the sign of the triangle PQR is the sign of the 4x4
+ *   determinant
+ *
+ *     | Px Qx Rx TPx |
+ *     | Py Qy Ry TPy |
+ *     | Pz Qz Rz TPz |
+ *     |  1  1  1  1 |
+ *
+ *   or equivalently of the 3x3 determinant
+ *
+ *     | Px-TPx Qx-TPx Rx-TPx |
+ *     | Py-TPy Qy-TPy Ry-TPy |
+ *     | Pz-TPz Qz-TPz Rz-TPz |
+ *
+ *
+ * Now to compute the contribution of any given triangle to the total winding
+ * number:
+ *
+ * 1. Classify the vertices of the triangle.  At the same time, we can check 
that
+ *    none of the vertices is equal to TP.  If all vertices have the same sign,
+ *    then the winding number contribution is zero.
+ *
+ * 2. Assuming that the vertices do not all have the same sign, two of the 
three
+ *    edges connect two differently-signed vertices.  Classify both those edges
+ *    (and simultaneously check that they don't pass through TP).  If the edges
+ *    have opposite classification, then the winding number contribution is 
zero.
+ *
+ * 3. Now two of the edges have the same sign: classify the triangle itself.  
If
+ *    the triangle is positive it contributes 1/2 to the winding number total; 
if
+ *    negative it contributes -1/2.  In practice we count contributions of 1 
and
+ *    -1, and halve the total at the end.
+ *
+ * Note that an edge between two like-signed vertices can never pass through 
TP, so
+ * there's no need to check the third edge in step 2.  Similarly, a triangle 
whose
+ * edge-cycle is trivial can't contain TP in its interior.
+ *
+ * To understand what's going on above, it's helpful to step into the world of
+ * homology again. The homology of R^3 - {TP} can be identified with that of 
the
+ * two-sphere S^2 by deformation retract, and we can decompose the two-sphere 
as a
+ * CW complex consisting of six cells, as follows:
+ *
+ * 0-cells B and F, where B = (-1, 0, 0) and F = (1, 0, 0)
+ * 1-cells L and R, where
+ *      L = {(cos t, sin t, 0) | -pi <= t <= 0 }
+ *      R = {(cos t, sin t, 0) | 0 <= t <= pi }
+ * 2-cells U and D, where U is the top half of the sphere (z >= 0)
+ *   and D is the bottom half (z <= 0), both oriented outwards.
+ *
+ * And the homology of the CW complex is now representable in terms of cellular
+ * homology:
+ *
+ *                d               d
+ *   Z[U] + Z[D] --> Z[L] + Z[R] --> Z[B] + Z[F]
+ *
+ * with boundary maps given by:
+ *
+ *   d[U] = [L] + [R]; d[D] = -[L] - [R]
+ *   d[R] = [B] - [F]; d[L] = [F] - [B]
+ *
+ * Now the original map C -> R^3 - {TP} from the geometric realization of the
+ * simplicial complex is homotopic to a map C -> S^2 that sends:
+ *
+ * * each positive vertex to F and each negative vertex to B
+ * * each edge with boundary [F] - [B] to L if the edge is negative, and -R if 
the
+ *   edge is positive
+ * * each edge with boundary [B] - [F] to R if the edge is positive, and -L if 
the
+ *   edge is negative
+ * * all other edges to 0
+ * * each triangle whose boundary is [L] + [R] to either U or -D,
+ *   depending on whether the triangle is positive or negative
+ * * each triangle whose boundary is -[L] - [R] to either D or -U,
+ *   depending on whether the triangle is positive or negative
+ * * all other triangles to 0
+ *
+ * Mapping all of the triangles in the surface this way, and summing the 
results
+ * in second homology, we end up with (winding number)*([U] + [D]).
+ */
+
+#include "common.h"
+
+#include "vmath.h"
+#include "bu/log.h"
+#include "bg/trimesh.h"
+
+/* Return 1 if x is positive, -1 if it's negative, and 0 if it's zero. */
+static int ptm_sign(double x)
+{
+    if (x > 0) return 1;
+    if (x < 0) return -1;
+    return 0;
+}
+
+/* Sign of the vertex P with respect to O, as defined above. */
+static int ptm_vertex_sign(point_t V, point_t TP, int *exact_flag)
+{
+    int rx,ry, rz;
+    rx = ptm_sign(V[X] - TP[X]);
+    if (rx) return rx;
+
+    ry = ptm_sign(V[Y] - TP[Y]);
+    if (ry) return ry;
+
+    rz = ptm_sign(V[Z] - TP[Z]);
+    if (rz) return rz;
+
+    (*exact_flag) = 1;
+    /*bu_log("Error: vertex coincides with test point\n");*/
+    return 0;
+}
+
+/* Sign of the edge PQ with respect to O, as defined above. */
+static int ptm_edge_sign(point_t P, point_t Q, point_t TP, int *exact_flag)
+{
+    int r1, r2, r3;
+    r1 = ptm_sign((P[Y] - TP[Y]) * (Q[X] - TP[X]) - (P[X] - TP[X]) * (Q[Y] - 
TP[Y]));
+    if (r1) return r1;
+
+    r2 = ptm_sign((P[Z] - TP[Z]) * (Q[X] - TP[X]) - (P[X] - TP[X]) * (Q[Z] - 
TP[Z]));
+    if (r2) return r2;
+
+    r3 = ptm_sign((P[Z] - TP[Z]) * (Q[Y] - TP[Y]) - (P[Y] - TP[Y]) * (Q[Z] - 
TP[Z]));
+    if (r3) return r3;
+
+    (*exact_flag) = 1;
+    /*bu_log("Error: vertices collinear with origin\n");*/
+    return 0;
+}
+
+/* Sign of the triangle PQR with respect to O, as defined above. */
+static int ptm_triangle_sign(point_t P, point_t Q, point_t R, point_t TP, int 
*exact_flag)
+{
+    double m1_0 = P[X] - TP[X];
+    double m1_1 = P[Y] - TP[Y];
+    double m2_0 = Q[X] - TP[X];
+    double m2_1 = Q[Y] - TP[Y];
+    double m3_0 = R[X] - TP[X];
+    double m3_1 = R[Y] - TP[Y];
+
+    int r = ptm_sign(
+           (m1_0 * m2_1 - m1_1 * m2_0) * (R[Z] - TP[Z]) +
+           (m2_0 * m3_1 - m2_1 * m3_0) * (P[Z] - TP[Z]) +
+           (m3_0 * m1_1 - m3_1 * m1_0) * (Q[Z] - TP[Z]));
+
+    if (!r) {
+       (*exact_flag) = 1;
+       /*bu_log("vertices coplanar with origin\n");*/
+    }
+    return r;
+}
+
+/* Return the contribution of this triangle to the winding number. */
+int
+bg_ptm_triangle_chain(point_t v1, point_t v2, point_t v3, point_t tp, int 
*exact_flag)
+{
+    int ef = 0;
+    int v1sign = ptm_vertex_sign(v1, tp, &ef);
+    int v2sign = ptm_vertex_sign(v2, tp, &ef);
+    int v3sign = ptm_vertex_sign(v3, tp, &ef);
+    int face_boundary = 0;
+    int tsign;
+
+    if (v1sign != v2sign) {
+       face_boundary += ptm_edge_sign(v1, v2, tp, &ef);
+    }
+    if (v2sign != v3sign) {
+       face_boundary += ptm_edge_sign(v2, v3, tp, &ef);
+    }
+    if (v3sign != v1sign) {
+       face_boundary += ptm_edge_sign(v3, v1, tp, &ef);
+    }
+    if (!face_boundary) {
+       if (ef) {
+           (*exact_flag) = 1;
+       }
+       return 0;
+    }
+
+    tsign = ptm_triangle_sign(v1, v2, v3, tp, &ef);
+    if (ef) {
+       (*exact_flag) = 1;
+    }
+    return tsign;
+}
+
+
+int
+bg_trimesh_pt_in(point_t tp, int num_faces, int *faces, int num_vertices, 
point_t *pts)
+{
+    int exact = 0;
+    int wn = 0;
+    int not_solid = bg_trimesh_solid2(num_vertices, num_faces, (fastf_t *)pts, 
faces, NULL);
+    if (not_solid) {
+       return -1;
+    }
+
+    for (int i = 0; i < num_faces; i++) {
+       point_t v1, v2, v3;
+       VMOVE(v1, pts[faces[3*i+0]]);
+       VMOVE(v2, pts[faces[3*i+1]]);
+       VMOVE(v3, pts[faces[3*i+2]]);
+       wn += bg_ptm_triangle_chain(v1, v2, v3, tp, &exact);
+       if (exact) return 2;
+    }
+
+    return wn;
+}
+
+
+
+/*
+ * Local Variables:
+ * tab-width: 8
+ * mode: C
+ * indent-tabs-mode: t
+ * c-file-style: "stroustrup"
+ * End:
+ * ex: shiftwidth=4 tabstop=8
+ */

Deleted: brlcad/trunk/src/libbg/trimesh_pt_in.cpp
===================================================================
--- brlcad/trunk/src/libbg/trimesh_pt_in.cpp    2019-10-18 14:59:54 UTC (rev 
74176)
+++ brlcad/trunk/src/libbg/trimesh_pt_in.cpp    2019-10-18 15:00:40 UTC (rev 
74177)
@@ -1,399 +0,0 @@
-/* This is a C translation of Mark Dickinson's point-in-polyhedron test from
- * https://github.com/mdickinson/polyhedron/ */
-
-/*
- * BSD 3-Clause License
- *
- * Copyright (c) 2019, Mark Dickinson
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, 
this
- *    list of conditions and the following disclaimer.
- *
- * 2. 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.
- *
- * 3. Neither the name of the copyright holder 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 HOLDER 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.
- */
-
-/*
- * Robust point-in-polyhedron test.
- *
- * Given an closed, oriented surface in R^3 described by a triangular mesh, the
- * code below gives a robust algorithm for determining whether a given point is
- * inside, on the boundary of, or outside, the surface.  The algorithm should 
give
- * correct results even in degenerate cases, and applies to disconnected
- * polyhedra, non simply-connected surfaces, and so on.  There are no 
requirements
- * for the surface to be convex, simple, connected or simply-connected.
- *
- * More precisely, we give a method for computing the *winding number* of a 
closed
- * oriented surface S around a point TP that doesn't lie on S.  Roughly 
speaking,
- * the winding number of the closed oriented surface S around a point TP not 
on S
- * is the number of times that the surface encloses that point; for a simple
- * outward-oriented surface (like that of a convex polyhedron, for example), 
the
- * winding number will be 1 for points inside the surface and 0 for points
- * outside.
- *
- * For a precise definition of winding number, we can turn to algebraic 
topology:
- * our oriented surface is presented as a collection of combinatorial data
- * defining abstract vertices, edges and triangles, together with a mapping of
- * those vertices to R^3.  The combinatorial data describe a simplicial 
complex C,
- * and assuming that TP doesn't lie on the surface, the mapping of the 
vertices to
- * R^3 gives a continuous map from the geometric realization of C to R^3 - 
{TP}.
- * This in turn induces a map on second homology groups:
- *
- *    H^2(C, Z) -> H^2(R^3 - {TP}, Z)
- *
- * and by taking the usual right-handed orientation in R^3 we identify H^2(R^3 
-
- * {TP}, Z) with Z.  The image of [S] under this map gives the winding number. 
 In
- * particular, the well-definedness of the winding number does not depend on
- * topological properties of the embedding: it doesn't matter if the surface is
- * self-intersecting, or has degenerate triangles.  The only condition is that 
TP
- * does not lie on the surface S.
- *
- * Algorithm
- * ---------
- * The algorithm is based around the usual method of ray-casting: we take a
- * vertical line L through TP and count the intersections of this line with the
- * triangles of the surface, keeping track of orientations as we go.  Let's 
ignore
- * corner cases for a moment and assume that:
- *
- * (1) TP does not lie on the surface, and
- * (2) for each triangle T (thought of as a closed subset of R^3) touched by
- *     our vertical line L, L meets the interior of T in exactly one point Q
- *
- * Then there are four possibilities for each such triangle T:
- *
- * 1. T lies *above* TP and is oriented *upwards* (*away* from TP).
- * 2. T lies *above* TP and is oriented *downwards* (*towards* TP).
- * 3. T lies *below* TP and is oriented *downwards* (*away* from TP).
- * 4. T lies *below* TP and is oriented *upwards* (*towards* TP).
- *
- * Let's write N1, N2, N3 and N4 for the counts of triangles satisfying 
conditions
- * 1, 2, 3 and 4 respectively.  Since we have a closed surface, these numbers
- * are not independent; they satisfy the relation:
- *
- *     N1 + N4 == N2 + N3
- *
- * That is, the number of upward-facing triangles must match the number of
- * downward-facing triangles.  The winding number w is then given by:
- *
- *     w = N1 - N2 == N3 - N4
- *
- * In the code below, we simply compute 2*w = (N1 + N3) - (N2 + N4), so each
- * triangle oriented away from TP contributes 1 to 2w, while each triangle 
oriented
- * towards TP contributes -1.
- *
- *
- * Making the algorithm robust
- * ---------------------------
- * Now we describe how to augment the basic algorithm described above to 
include:
- *
- * - correct treatment of corner cases (vertical triangles, cases where L 
meets an
- *   edge or vertex directly, etc.)
- *
- * - detection of the case where the point lies directly on the surface.
- *
- * It turns out that to make the algorithm robust, all we need to do is be 
careful
- * and consistent about classifying vertices, edges and triangles.  We do this 
as
- * follows:
- *
- * - Each vertex of the surface that's not equal to TP is considered 
*positive* if
- *   its coordinates are lexicographically greater than TP, and *negative*
- *   otherwise.
- *
- * - For an edge PQ of the surface that's not collinear with TP, we first 
describe
- *   the classification in the case that P is negative and Q is positive, and
- *   then extend to arbitrary PQ.
- *
- *   For P negative and Q positive, there are two cases:
- *
- *   1. P and Q have distinct x coordinates.  In that case we classify the edge
- *      PQ by its intersection with the plane passing through TP and parallel
- *      to the yz-plane: the edge is *positive* if the intersection point is
- *      positive, and *negative* otherwise.
- *
- *   2. P and Q have the same x coordinate, in which case they must have
- *      distinct y coordinates.  (If the x and the y coordinates both match
- *      then PQ passes through TP.)  We classify by the intersection of PQ
- *      with the line parallel to the y-axis through TP.
- *
- *   For P positive and Q negative, we classify as above but reverse the sign.
- *   For like-signed P and Q, the classification isn't used.
- *
- *   Computationally, in case 1 above, the y-coordinate of the intersection
- *   point is:
- *
- *       Py + (Qy - Py) * (TPx - Px) / (Qx - Px)
- *
- *   and this is greater than TPy iff
- *
- *       (Py - TPy) * (Qx - TPx) - (Px - TPx) * (Qy - TPy)
- *
- *   is positive, so the sign of the edge is the sign of the above expression.
- *   Similarly, if this quantity is zero then we need to look at the 
z-coordinate
- *   of the intersection, and the sign of the edge is given by
- *
- *       (Pz - TPz) * (Qx - TPx) - (Px - TPx) * (Qz - TPz)
- *
- *   In case 2, both of the above quantities are zero, and the sign of the 
edge is
- *   the sign of
- *
- *       (Pz - TPz) * (Qy - TPy) - (Py - TPy) * (Qz - TPz)
- *
- *   Another way to look at this: if P, Q and TP are not collinear then the
- *   matrix
- *
- *    ( Px Qx TPx )
- *    ( Py Qy TPx )
- *    ( Pz Qz TPx )
- *    (  1  1  1 )
- *
- *   has rank 3.  It follows that at least one of the three 3x3 minors
- *
- *    | Px Qx TPx |  | Px Qx TPx |  | Py Qy TPy |
- *    | Py Qy TPy |  | Pz Qz TPz |  | Pz Qz TPz |
- *    |  1  1  1 |  |  1  1  1 |  |  1  1  1 |
- *
- *   is nonzero.  We define the sign of PQ to be the *negative* of the sign of 
the
- *   first nonzero minor in that list.
- *
- * - Each triangle PQR of the surface that's not coplanar with TP is considered
- *   *positive* if its normal points away from TP, and *negative* if its normal
- *   points towards TP.
- *
- *   Computationally, the sign of the triangle PQR is the sign of the 4x4
- *   determinant
- *
- *     | Px Qx Rx TPx |
- *     | Py Qy Ry TPy |
- *     | Pz Qz Rz TPz |
- *     |  1  1  1  1 |
- *
- *   or equivalently of the 3x3 determinant
- *
- *     | Px-TPx Qx-TPx Rx-TPx |
- *     | Py-TPy Qy-TPy Ry-TPy |
- *     | Pz-TPz Qz-TPz Rz-TPz |
- *
- *
- * Now to compute the contribution of any given triangle to the total winding
- * number:
- *
- * 1. Classify the vertices of the triangle.  At the same time, we can check 
that
- *    none of the vertices is equal to TP.  If all vertices have the same sign,
- *    then the winding number contribution is zero.
- *
- * 2. Assuming that the vertices do not all have the same sign, two of the 
three
- *    edges connect two differently-signed vertices.  Classify both those edges
- *    (and simultaneously check that they don't pass through TP).  If the edges
- *    have opposite classification, then the winding number contribution is 
zero.
- *
- * 3. Now two of the edges have the same sign: classify the triangle itself.  
If
- *    the triangle is positive it contributes 1/2 to the winding number total; 
if
- *    negative it contributes -1/2.  In practice we count contributions of 1 
and
- *    -1, and halve the total at the end.
- *
- * Note that an edge between two like-signed vertices can never pass through 
TP, so
- * there's no need to check the third edge in step 2.  Similarly, a triangle 
whose
- * edge-cycle is trivial can't contain TP in its interior.
- *
- * To understand what's going on above, it's helpful to step into the world of
- * homology again. The homology of R^3 - {TP} can be identified with that of 
the
- * two-sphere S^2 by deformation retract, and we can decompose the two-sphere 
as a
- * CW complex consisting of six cells, as follows:
- *
- * 0-cells B and F, where B = (-1, 0, 0) and F = (1, 0, 0)
- * 1-cells L and R, where
- *      L = {(cos t, sin t, 0) | -pi <= t <= 0 }
- *      R = {(cos t, sin t, 0) | 0 <= t <= pi }
- * 2-cells U and D, where U is the top half of the sphere (z >= 0)
- *   and D is the bottom half (z <= 0), both oriented outwards.
- *
- * And the homology of the CW complex is now representable in terms of cellular
- * homology:
- *
- *                d               d
- *   Z[U] + Z[D] --> Z[L] + Z[R] --> Z[B] + Z[F]
- *
- * with boundary maps given by:
- *
- *   d[U] = [L] + [R]; d[D] = -[L] - [R]
- *   d[R] = [B] - [F]; d[L] = [F] - [B]
- *
- * Now the original map C -> R^3 - {TP} from the geometric realization of the
- * simplicial complex is homotopic to a map C -> S^2 that sends:
- *
- * * each positive vertex to F and each negative vertex to B
- * * each edge with boundary [F] - [B] to L if the edge is negative, and -R if 
the
- *   edge is positive
- * * each edge with boundary [B] - [F] to R if the edge is positive, and -L if 
the
- *   edge is negative
- * * all other edges to 0
- * * each triangle whose boundary is [L] + [R] to either U or -D,
- *   depending on whether the triangle is positive or negative
- * * each triangle whose boundary is -[L] - [R] to either D or -U,
- *   depending on whether the triangle is positive or negative
- * * all other triangles to 0
- *
- * Mapping all of the triangles in the surface this way, and summing the 
results
- * in second homology, we end up with (winding number)*([U] + [D]).
- */
-
-#include "common.h"
-
-#include "vmath.h"
-#include "bu/log.h"
-#include "bg/trimesh.h"
-
-/* Return 1 if x is positive, -1 if it's negative, and 0 if it's zero. */
-static int ptm_sign(double x)
-{
-    if (x > 0) return 1;
-    if (x < 0) return -1;
-    return 0;
-}
-
-/* Sign of the vertex P with respect to O, as defined above. */
-static int ptm_vertex_sign(point_t V, point_t TP, int *exact_flag)
-{
-    int rx,ry, rz;
-    rx = ptm_sign(V[X] - TP[X]);
-    if (rx) return rx;
-
-    ry = ptm_sign(V[Y] - TP[Y]);
-    if (ry) return ry;
-
-    rz = ptm_sign(V[Z] - TP[Z]);
-    if (rz) return rz;
-
-    (*exact_flag) = 1;
-    /*bu_log("Error: vertex coincides with test point\n");*/
-    return 0;
-}
-
-/* Sign of the edge PQ with respect to O, as defined above. */
-static int ptm_edge_sign(point_t P, point_t Q, point_t TP, int *exact_flag)
-{
-    int r1, r2, r3;
-    r1 = ptm_sign((P[Y] - TP[Y]) * (Q[X] - TP[X]) - (P[X] - TP[X]) * (Q[Y] - 
TP[Y]));
-    if (r1) return r1;
-
-    r2 = ptm_sign((P[Z] - TP[Z]) * (Q[X] - TP[X]) - (P[X] - TP[X]) * (Q[Z] - 
TP[Z]));
-    if (r2) return r2;
-
-    r3 = ptm_sign((P[Z] - TP[Z]) * (Q[Y] - TP[Y]) - (P[Y] - TP[Y]) * (Q[Z] - 
TP[Z]));
-    if (r3) return r3;
-
-    (*exact_flag) = 1;
-    /*bu_log("Error: vertices collinear with origin\n");*/
-    return 0;
-}
-
-/* Sign of the triangle PQR with respect to O, as defined above. */
-static int ptm_triangle_sign(point_t P, point_t Q, point_t R, point_t TP, int 
*exact_flag)
-{
-    double m1_0 = P[X] - TP[X];
-    double m1_1 = P[Y] - TP[Y];
-    double m2_0 = Q[X] - TP[X];
-    double m2_1 = Q[Y] - TP[Y];
-    double m3_0 = R[X] - TP[X];
-    double m3_1 = R[Y] - TP[Y];
-
-    int r = ptm_sign(
-           (m1_0 * m2_1 - m1_1 * m2_0) * (R[Z] - TP[Z]) +
-           (m2_0 * m3_1 - m2_1 * m3_0) * (P[Z] - TP[Z]) +
-           (m3_0 * m1_1 - m3_1 * m1_0) * (Q[Z] - TP[Z]));
-
-    if (!r) {
-       (*exact_flag) = 1;
-       /*bu_log("vertices coplanar with origin\n");*/
-    }
-    return r;
-}
-
-/* Return the contribution of this triangle to the winding number. */
-int
-bg_ptm_triangle_chain(point_t v1, point_t v2, point_t v3, point_t tp, int 
*exact_flag)
-{
-    int ef = 0;
-    int v1sign = ptm_vertex_sign(v1, tp, &ef);
-    int v2sign = ptm_vertex_sign(v2, tp, &ef);
-    int v3sign = ptm_vertex_sign(v3, tp, &ef);
-    int face_boundary = 0;
-    int tsign;
-
-    if (v1sign != v2sign) {
-       face_boundary += ptm_edge_sign(v1, v2, tp, &ef);
-    }
-    if (v2sign != v3sign) {
-       face_boundary += ptm_edge_sign(v2, v3, tp, &ef);
-    }
-    if (v3sign != v1sign) {
-       face_boundary += ptm_edge_sign(v3, v1, tp, &ef);
-    }
-    if (!face_boundary) {
-       if (ef) {
-           (*exact_flag) = 1;
-       }
-       return 0;
-    }
-
-    tsign = ptm_triangle_sign(v1, v2, v3, tp, &ef);
-    if (ef) {
-       (*exact_flag) = 1;
-    }
-    return tsign;
-}
-
-
-int
-bg_trimesh_pt_in(point_t tp, int num_faces, int *faces, int num_vertices, 
point_t *pts)
-{
-    int exact = 0;
-    int wn = 0;
-    int not_solid = bg_trimesh_solid2(num_vertices, num_faces, (fastf_t *)pts, 
faces, NULL);
-    if (not_solid) {
-       return -1;
-    }
-
-    for (int i = 0; i < num_faces; i++) {
-       point_t v1, v2, v3;
-       VMOVE(v1, pts[faces[3*i+0]]);
-       VMOVE(v2, pts[faces[3*i+1]]);
-       VMOVE(v3, pts[faces[3*i+2]]);
-       wn += bg_ptm_triangle_chain(v1, v2, v3, tp, &exact);
-       if (exact) return 2;
-    }
-
-    return wn;
-}
-
-
-
-/*
- * Local Variables:
- * tab-width: 8
- * mode: C
- * indent-tabs-mode: t
- * c-file-style: "stroustrup"
- * End:
- * ex: shiftwidth=4 tabstop=8
- */

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.



_______________________________________________
BRL-CAD Source Commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/brlcad-commits

Reply via email to