/* * Copyright (c) 2008 Hypertriton, Inc. * * 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. * * 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 AUTHOR 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. */ /* * Polygon routines. Note that unlike most other math library structures, * M_Polygon uses dynamic allocation. */ #include #include "m.h" void M_PolygonInit2(M_Polygon2 *poly) { poly->s = NULL; poly->n = 0; } void M_PolygonInit3(M_Polygon3 *poly) { poly->s = NULL; poly->n = 0; } void M_PolygonFree2(M_Polygon2 *poly) { Free(poly->s); poly->s = NULL; poly->n = 0; } void M_PolygonFree3(M_Polygon3 *poly) { Free(poly->s); poly->s = NULL; poly->n = 0; } M_Polygon2 M_PolygonRead2(AG_DataSource *ds) { M_Polygon2 P; Uint i; P.n = (Uint)AG_ReadUint32(ds); P.s = Malloc(P.n*sizeof(M_Line2)); for (i = 0; i < P.n; i++) { P.s[i] = M_LineRead2(ds); } return (P); } M_Polygon3 M_PolygonRead3(AG_DataSource *ds) { M_Polygon3 P; Uint i; P.n = (Uint)AG_ReadUint32(ds); P.s = Malloc(P.n*sizeof(M_Line3)); for (i = 0; i < P.n; i++) { P.s[i] = M_LineRead3(ds); } return (P); } void M_PolygonWrite2(AG_DataSource *ds, M_Polygon2 *P) { Uint i; AG_WriteUint32(ds, (Uint32)P->n); for (i = 0; i < P->n; i++) M_LineWrite2(ds, &P->s[i]); } void M_PolygonWrite3(AG_DataSource *ds, M_Polygon3 *P) { Uint i; AG_WriteUint32(ds, (Uint32)P->n); for (i = 0; i < P->n; i++) M_LineWrite3(ds, &P->s[i]); } M_Polygon2 M_PolygonFromLines2(Uint n, M_Line2 *lines) { M_Polygon2 P; Uint i; P.s = Malloc(n*sizeof(M_Line2)); P.n = n; for (i = 0; i < n; i++) { P.s[i] = lines[i]; } return (P); } M_Polygon3 M_PolygonFromLines3(Uint n, M_Line3 *lines) { M_Polygon3 P; Uint i; P.s = Malloc(n*sizeof(M_Line3)); P.n = n; for (i = 0; i < n; i++) { P.s[i] = lines[i]; } return (P); } /* Test whether the given point lies inside the polygon. */ int M_PointInPolygon2(M_Polygon2 *poly, M_Vector2 p) { int i, count = 0; M_Real ix; M_Vector2 p1, p2; p1 = poly->s[0].p; for (i = 1; i <= poly->n; i++) { p2 = poly->s[i % poly->n].p; if (p.y > MIN(p1.y, p2.y) && p.y <= MAX(p1.y, p2.y) && p.x <= MAX(p1.x, p2.x)) { if (p1.y != p2.y) { /* * Compute the intersection of the X axis * with this line segment. */ ix = (p.y - p1.y)*(p2.x - p1.x) / (p2.y - p1.y) + p1.x; if (p1.x == p2.x || p.x <= ix) count++; } } p1 = p2; } if (count%2 == 0) { return (0); } else { return (1); } } /* Test whether the given polygon is convex (1) or concave (0). */ /* XXX test; assumes no self-intersections */ int M_PolygonIsConvex2(M_Polygon2 *poly) { int i, flag = 0; if (poly->n < 3) { AG_SetError("<3 vertices"); return (-1); } for (i = 0; i < poly->n; i++) { M_Vector2 pi = poly->s[(i) % poly->n].p; M_Vector2 pj = poly->s[(i+1) % poly->n].p; M_Vector2 pk = poly->s[(i+2) % poly->n].p; M_Vector2 pji = M_VecSub2p(&pj, &pi); M_Vector2 pkj = M_VecSub2p(&pk, &pj); M_Real dot; dot = M_VecPerpDot2p(&pji, &pkj); if (dot < 0.0) { flag |= 1; } else if (dot >= 0.0) { flag |= 2; } if (flag == 3) { return (0); } } if (flag != 0) { return (1); } return (0); } /* Test whether the given polygon is planar to machine precision. */ int M_PolygonIsPlanar3(M_Polygon3 *poly) { M_Plane3 P; Uint i; if (poly->n < 3) { AG_SetError("<3 vertices"); return (-1); } if (poly->n == 3) return (1); P = M_PlaneFromPts3(poly->s[0].p, poly->s[1].p, poly->s[2].p); for (i = 3; i < poly->n; i++) { M_Vector3 p = poly->s[i].p; if ((P.a*p.x + P.b*p.y + P.c*p.z + P.d) > M_MACHEP) return (0); } return (1); }