/* 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. */ /// Changes from the Java version /// Polygon constructors sprused up, checks for 3+ polys /// Naming of everything /// getTriangulationMode() -> TriangulationMode { get; } /// Exceptions replaced /// Future possibilities /// We have a lot of Add/Clear methods -- we may prefer to just expose the container /// Some self-explanatory methods may deserve commenting anyways using UnityEngine; using System; using System.Collections.Generic; using System.Linq; namespace WPM.Poly2Tri { public class Polygon : Point2DList, ITriangulatable, IEnumerable, IList { // ITriangulatable Implementation protected Dictionary mPointMap = new Dictionary (); public IList Points { get { return this; } } protected List mTriangles; public IList Triangles { get { return mTriangles; } } public TriangulationMode TriangulationMode { get { return TriangulationMode.Polygon; } } public string FileName { get; set; } public bool DisplayFlipX { get; set; } public bool DisplayFlipY { get; set; } public float DisplayRotate { get; set; } private double mPrecision = TriangulationPoint.kVertexCodeDefaultPrecision; public double Precision { get { return mPrecision; } set { mPrecision = value; } } public double MinX { get { return mBoundingBox.MinX; } } public double MaxX { get { return mBoundingBox.MaxX; } } public double MinY { get { return mBoundingBox.MinY; } } public double MaxY { get { return mBoundingBox.MaxY; } } public Rect2D Bounds { get { return mBoundingBox; } } // Point2DList overrides public new TriangulationPoint this [int index] { get { return mPoints [index] as TriangulationPoint; } set { mPoints [index] = value; } } // Polygon Implementation protected List mHoles; public IList Holes { get { return mHoles; } } protected List mSteinerPoints; protected PolygonPoint _last; /// /// Create a polygon from a list of at least 3 points with no duplicates. /// /// A list of unique points public Polygon (IList points) { if (points.Count < 3) { Debug.Log ("Polygon has fewer than 3 points"); } AddRange (points, WindingOrderType.Unknown); } /// /// Create a polygon from a list of at least 3 points with no duplicates. /// /// A list of unique points public Polygon (IList points) { int pCount = points.Count; if (pCount < 3) { Debug.Log ("Polygon has fewer than 3 points"); } List pp = new List (pCount); for (int k = 0; k < pCount; k++) { pp.Add (new PolygonPoint (points [k].x, points [k].y)); } AddRange (pp, WindingOrderType.Unknown); } /// /// Create a polygon from a list of at least 3 points with no duplicates. /// /// A list of unique points. public Polygon (IEnumerable points) : this ((points as IList) ?? points.ToArray ()) { } /// /// Create a polygon from a list of at least 3 points with no duplicates. /// /// A list of unique points. public Polygon (params PolygonPoint[] points) : this ((IList)points) { } IEnumerator IEnumerable.GetEnumerator () { return new TriangulationPointEnumerator (mPoints); } public int IndexOf (TriangulationPoint p) { return mPoints.IndexOf (p); } public override void Add (Point2D p) { Add (p, -1, true); } public void Add (TriangulationPoint p) { Add (p, -1, true); } public void Add (PolygonPoint p) { Add (p, -1, true); } protected override void Add (Point2D p, int idx, bool bCalcWindingOrderAndEpsilon) { TriangulationPoint pt = p as TriangulationPoint; if (pt == null) { // we only store TriangulationPoints and PolygonPoints in this class return; } // do not insert duplicate points if (mPointMap.ContainsKey (pt.VertexCode)) { return; } mPointMap.Add (pt.VertexCode, pt); base.Add (p, idx, bCalcWindingOrderAndEpsilon); PolygonPoint pp = p as PolygonPoint; if (pp != null) { pp.Previous = _last; if (_last != null) { pp.Next = _last.Next; _last.Next = pp; } _last = pp; } return; } public void AddRange (IList points, Point2DList.WindingOrderType windingOrder) { if (points == null || points.Count < 1) { return; } if (mWindingOrder == Point2DList.WindingOrderType.Unknown && Count == 0) { mWindingOrder = windingOrder; } int numPoints = points.Count; bool bReverseReadOrder = (WindingOrder != WindingOrderType.Unknown) && (windingOrder != WindingOrderType.Unknown) && (WindingOrder != windingOrder); for (int i = 0; i < numPoints; ++i) { int idx = i; if (bReverseReadOrder) { idx = numPoints - i - 1; } Add (points [idx], -1, false); } if (mWindingOrder == WindingOrderType.Unknown) { mWindingOrder = CalculateWindingOrder (); } mEpsilon = CalculateEpsilon (); } public void AddRange (IList points, Point2DList.WindingOrderType windingOrder) { if (points == null || points.Count < 1) { return; } if (mWindingOrder == Point2DList.WindingOrderType.Unknown && Count == 0) { mWindingOrder = windingOrder; } int numPoints = points.Count; bool bReverseReadOrder = (WindingOrder != WindingOrderType.Unknown) && (windingOrder != WindingOrderType.Unknown) && (WindingOrder != windingOrder); for (int i = 0; i < numPoints; ++i) { int idx = i; if (bReverseReadOrder) { idx = numPoints - i - 1; } Add (points [idx], -1, false); } if (mWindingOrder == WindingOrderType.Unknown) { mWindingOrder = CalculateWindingOrder (); } mEpsilon = CalculateEpsilon (); } public void Insert (int idx, TriangulationPoint p) { Add (p, idx, true); } public bool Remove (TriangulationPoint p) { return base.Remove (p); } /// /// Removes a point from the polygon. Note this can be a somewhat expensive operation /// as it must recalculate the bounding area from scratch. /// /// public void RemovePoint (PolygonPoint p) { PolygonPoint next, prev; next = p.Next; prev = p.Previous; prev.Next = next; next.Previous = prev; mPoints.Remove (p); mBoundingBox.Clear (); foreach (PolygonPoint tmp in mPoints) { mBoundingBox.AddPoint (tmp); } } public bool Contains (TriangulationPoint p) { return mPoints.Contains (p); } public void CopyTo (TriangulationPoint[] array, int arrayIndex) { int numElementsToCopy = Math.Min (Count, array.Length - arrayIndex); for (int i = 0; i < numElementsToCopy; ++i) { array [arrayIndex + i] = mPoints [i] as TriangulationPoint; } } public void AddSteinerPoint (TriangulationPoint point) { if (mSteinerPoints == null) { mSteinerPoints = new List (); } mSteinerPoints.Add (point); } public void AddSteinerPoints (List points) { if (mSteinerPoints == null) { mSteinerPoints = new List (); } mSteinerPoints.AddRange (points); } public void ClearSteinerPoints () { if (mSteinerPoints != null) { mSteinerPoints.Clear (); } } /// /// Add a hole to the polygon. /// /// A subtraction polygon fully contained inside this polygon. public void AddHole (Polygon poly) { if (mHoles == null) { mHoles = new List (); } mHoles.Add (poly); // XXX: tests could be made here to be sure it is fully inside // addSubtraction( poly.getPoints() ); } public void AddTriangle (DelaunayTriangle t) { mTriangles.Add (t); } public void AddTriangles (IEnumerable list) { mTriangles.AddRange (list); } public void ClearTriangles () { if (mTriangles != null) { mTriangles.Clear (); } } public bool IsPointInside (TriangulationPoint p) { return PolygonUtil.PointInPolygon2D (this, p); } /// /// Creates constraints and populates the context with points /// /// The context public void Prepare (TriangulationContext tcx) { if (mTriangles == null) { mTriangles = new List (mPoints.Count); } else { mTriangles.Clear (); } // Outer constraints int pCount = mPoints.Count - 1; for (int i = 0; i < pCount; i++) { //tcx.NewConstraint(mPoints[i], mPoints[i + 1]); tcx.NewConstraint (this [i], this [i + 1]); } tcx.NewConstraint (this [Count - 1], this [0]); // Changed by Kronnect Games // tcx.NewConstraint (this [0], this [Count - 1]); tcx.Points.AddRange (this); // Hole constraints if (mHoles != null) { foreach (Polygon p in mHoles) { int mPointsCount = p.mPoints.Count - 1; for (int i = 0; i < mPointsCount; i++) { tcx.NewConstraint (p [i], p [i + 1]); } tcx.NewConstraint (p [p.Count - 1], p [0]); // Changed by Kronnect Games // tcx.NewConstraint (p [0], p [p.Count - 1]); tcx.Points.AddRange (p); } } if (mSteinerPoints != null) { tcx.Points.AddRange (mSteinerPoints); } } } }