public void AddRange(IList <TriangulationPoint> points, WindingOrderType windingOrder) { if (points == null || points.Count < 1) { return; } if (WindingOrder == WindingOrderType.Unknown && Count == 0) { WindingOrder = 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 = points.Count - i - 1; } Add(points[idx], -1, false); } if (WindingOrder == WindingOrderType.Unknown) { WindingOrder = CalculateWindingOrder(); } Epsilon = CalculateEpsilon(); }
public void Clear() { mPoints.Clear(); mBoundingBox.Clear(); mEpsilon = MathUtil.EPSILON; mWindingOrder = WindingOrderType.Unknown; }
public void Clear() { MPoints.Clear(); _boundingBox = new Rect2D(); Epsilon = MathUtil.EPSILON; _windingOrder = WindingOrderType.Unknown; }
public Point2DList(Point2DList l) { int numPoints = l.Count; for (int i = 0; i < numPoints; ++i) { mPoints.Add(l [i]); } mBoundingBox.Set(l.BoundingBox); mEpsilon = l.Epsilon; mWindingOrder = l.WindingOrder; }
public override void AddRange(IEnumerator <Point2D> iter, WindingOrderType windingOrder) { if (iter == null) { return; } iter.Reset(); while (iter.MoveNext()) { Add(iter.Current); } }
public Point2DList(Point2DList l) : this() { int numPoints = l.Count; for (int i = 0; i < numPoints; ++i) { MPoints.Add(l[i]); } _boundingBox = l.BoundingBox; Epsilon = l.Epsilon; _windingOrder = l.WindingOrder; }
public override void AddRange(IEnumerator <Point2D> iter, WindingOrderType windingOrder) { if (iter == null) { return; } if (mWindingOrder == WindingOrderType.Unknown && Count == 0) { mWindingOrder = windingOrder; } bool bReverseReadOrder = (WindingOrder != WindingOrderType.Unknown) && (windingOrder != WindingOrderType.Unknown) && (WindingOrder != windingOrder); bool bAddedFirst = true; int startCount = mPoints.Count; iter.Reset(); while (iter.MoveNext()) { TriangulationPoint pt = null; if (iter.Current is TriangulationPoint) { pt = iter.Current as TriangulationPoint; } else { pt = new TriangulationPoint(iter.Current.X, iter.Current.Y); } if (!bAddedFirst) { bAddedFirst = true; mPoints.Add(pt); } else if (bReverseReadOrder) { mPoints.Insert(startCount, pt); } else { mPoints.Add(pt); } mBoundingBox.AddPoint(iter.Current); } if (mWindingOrder == WindingOrderType.Unknown && windingOrder == WindingOrderType.Unknown) { mWindingOrder = CalculateWindingOrder(); } mEpsilon = CalculateEpsilon(); }
protected virtual void Add(Point2D p, int idx, bool bCalcWindingOrderAndEpsilon) { if (idx < 0) { mPoints.Add(p); } else { mPoints.Insert(idx, p); } mBoundingBox.AddPoint(p); if (bCalcWindingOrderAndEpsilon) { if (mWindingOrder == WindingOrderType.Unknown) { mWindingOrder = CalculateWindingOrder(); } mEpsilon = CalculateEpsilon(); } }
protected virtual void AddRange(IEnumerator <Point2D> iter, WindingOrderType windingOrder) { if (iter == null) { return; } if (_windingOrder == WindingOrderType.Unknown && Count == 0) { _windingOrder = windingOrder; } bool bReverseReadOrder = (WindingOrder != WindingOrderType.Unknown) && (windingOrder != WindingOrderType.Unknown) && (WindingOrder != windingOrder); bool bAddedFirst = true; int startCount = MPoints.Count; iter.Reset(); while (iter.MoveNext()) { if (!bAddedFirst) { bAddedFirst = true; MPoints.Add(iter.Current); } else if (bReverseReadOrder) { MPoints.Insert(startCount, iter.Current); } else { MPoints.Add(iter.Current); } BoundingBox = BoundingBox.AddPoint(iter.Current); } if (_windingOrder == WindingOrderType.Unknown && windingOrder == WindingOrderType.Unknown) { _windingOrder = CalculateWindingOrder(); } Epsilon = CalculateEpsilon(); }
// From Eric Jordan's convex decomposition library /// <summary> /// Merges all parallel edges in the list of vertices /// </summary> /// <param name="tolerance"></param> public void MergeParallelEdges(double tolerance) { if (Count <= 3) { // Can't do anything useful here to a triangle return; } bool[] mergeMe = new bool[Count]; int newNVertices = Count; //Gather points to process for (int i = 0; i < Count; ++i) { int lower = (i == 0) ? (Count - 1) : (i - 1); int middle = i; int upper = (i == Count - 1) ? (0) : (i + 1); double dx0 = this [middle].X - this [lower].X; double dy0 = this [middle].Y - this [lower].Y; double dx1 = this [upper].Y - this [middle].X; double dy1 = this [upper].Y - this [middle].Y; double norm0 = Math.Sqrt(dx0 * dx0 + dy0 * dy0); double norm1 = Math.Sqrt(dx1 * dx1 + dy1 * dy1); if (!(norm0 > 0.0 && norm1 > 0.0) && newNVertices > 3) { //Merge identical points mergeMe [i] = true; --newNVertices; } dx0 /= norm0; dy0 /= norm0; dx1 /= norm1; dy1 /= norm1; double cross = dx0 * dy1 - dx1 * dy0; double dot = dx0 * dx1 + dy0 * dy1; if (Math.Abs(cross) < tolerance && dot > 0 && newNVertices > 3) { mergeMe [i] = true; --newNVertices; } else { mergeMe [i] = false; } } if (newNVertices == Count || newNVertices == 0) { return; } int currIndex = 0; // Copy the vertices to a new list and clear the old Point2DList oldVertices = new Point2DList(this); Clear(); for (int i = 0; i < oldVertices.Count; ++i) { if (mergeMe [i] || newNVertices == 0 || currIndex == newNVertices) { continue; } if (currIndex >= newNVertices) { throw new Exception("Point2DList::MergeParallelEdges - currIndex[ " + currIndex.ToString() + "] >= newNVertices[" + newNVertices + "]"); } mPoints.Add(oldVertices [i]); mBoundingBox.AddPoint(oldVertices [i]); ++currIndex; } mWindingOrder = CalculateWindingOrder(); mEpsilon = CalculateEpsilon(); }
/// <summary> /// Checks if polygon is valid for use in Box2d engine. /// Last ditch effort to ensure no invalid polygons are /// added to world geometry. /// /// Performs a full check, for simplicity, convexity, /// orientation, minimum angle, and volume. This won't /// be very efficient, and a lot of it is redundant when /// other tools in this section are used. /// /// From Eric Jordan's convex decomposition library /// </summary> /// <param name="printErrors"></param> /// <returns></returns> public PolygonError CheckPolygon() { PolygonError error = PolygonError.None; if (Count < 3 || Count > Point2DList.kMaxPolygonVertices) { error |= PolygonError.NotEnoughVertices; // no other tests will be valid at this point, so just return return(error); } if (IsDegenerate()) { error |= PolygonError.Degenerate; } //bool bIsConvex = IsConvex(); //if (!IsConvex()) //{ // error |= PolygonError.NotConvex; //} if (!IsSimple()) { error |= PolygonError.NotSimple; } if (GetArea() < MathUtil.EPSILON) { error |= PolygonError.AreaTooSmall; } // the following tests don't make sense if the polygon is not simple if ((error & PolygonError.NotSimple) != PolygonError.NotSimple) { bool bReversed = false; WindingOrderType expectedWindingOrder = WindingOrderType.CCW; WindingOrderType reverseWindingOrder = WindingOrderType.CW; if (WindingOrder == reverseWindingOrder) { WindingOrder = expectedWindingOrder; bReversed = true; } //Compute normals Point2D[] normals = new Point2D[Count]; Point2DList vertices = new Point2DList(Count); for (int i = 0; i < Count; ++i) { vertices.Add(new Point2D(this [i].X, this [i].Y)); int i1 = i; int i2 = NextIndex(i); Point2D edge = new Point2D(this [i2].X - this [i1].X, this [i2].Y - this [i1].Y); normals [i] = Point2D.Perpendicular(edge, 1.0); normals [i].Normalize(); } //Required side checks for (int i = 0; i < Count; ++i) { int iminus = PreviousIndex(i); //Parallel sides check double cross = Point2D.Cross(normals [iminus], normals [i]); cross = MathUtil.Clamp(cross, -1.0f, 1.0f); float angle = (float)Math.Asin(cross); if (Math.Abs(angle) <= Point2DList.kAngularSlop) { error |= PolygonError.SidesTooCloseToParallel; break; } // For some reason, the following checks do not seem to work // correctly in all cases - they return false positives. // //Too skinny check - only valid for convex polygons // if (bIsConvex) // { // for (int j = 0; j < Count; ++j) // { // if (j == i || j == NextIndex(i)) // { // continue; // } // Point2D testVector = vertices[j] - vertices[i]; // testVector.Normalize(); // double s = Point2D.Dot(testVector, normals[i]); // if (s >= -Point2DList.kLinearSlop) // { // error |= PolygonError.TooThin; // } // } // Point2D centroid = vertices.GetCentroid(); // Point2D n1 = normals[iminus]; // Point2D n2 = normals[i]; // Point2D v = vertices[i] - centroid; // Point2D d = new Point2D(); // d.X = Point2D.Dot(n1, v); // - toiSlop; // d.Y = Point2D.Dot(n2, v); // - toiSlop; // // Shifting the edge inward by toiSlop should // // not cause the plane to pass the centroid. // if ((d.X < 0.0f) || (d.Y < 0.0f)) // { // error |= PolygonError.TooThin; // } // } } if (bReversed) { WindingOrder = reverseWindingOrder; } } //if (error != PolygonError.None) //{ // Console.WriteLine("Found invalid polygon: {0} {1}\n", Point2DList.GetErrorString(error), this.ToString()); //} return(error); }
public PolygonError CheckPolygon() { PolygonError error = PolygonError.None; if (Count < 3 || Count > Point2DList.kMaxPolygonVertices) { error |= PolygonError.NotEnoughVertices; return(error); } if (IsDegenerate()) { error |= PolygonError.Degenerate; } if (!IsSimple()) { error |= PolygonError.NotSimple; } if (GetArea() < MathUtil.EPSILON) { error |= PolygonError.AreaTooSmall; } if ((error & PolygonError.NotSimple) != PolygonError.NotSimple) { bool bReversed = false; WindingOrderType expectedWindingOrder = WindingOrderType.CCW; WindingOrderType reverseWindingOrder = WindingOrderType.CW; if (WindingOrder == reverseWindingOrder) { WindingOrder = expectedWindingOrder; bReversed = true; } Point2D[] normals = new Point2D[Count]; Point2DList vertices = new Point2DList(Count); for (int i = 0; i < Count; ++i) { vertices.Add(new Point2D(this[i].X, this[i].Y)); int i1 = i; int i2 = NextIndex(i); Point2D edge = new Point2D(this[i2].X - this[i1].X, this[i2].Y - this[i1].Y); normals[i] = Point2D.Perpendicular(edge, 1.0); normals[i].Normalize(); } for (int i = 0; i < Count; ++i) { int iminus = PreviousIndex(i); double cross = Point2D.Cross(normals[iminus], normals[i]); cross = MathUtil.Clamp(cross, -1.0f, 1.0f); float angle = (float)Math.Asin(cross); if (Math.Abs(angle) <= Point2DList.kAngularSlop) { error |= PolygonError.SidesTooCloseToParallel; break; } } if (bReversed) { WindingOrder = reverseWindingOrder; } } return(error); }
public Contour(ITriangulatable parent, IList <TriangulationPoint> points, WindingOrderType windingOrder) { // Currently assumes that input is pre-checked for validity _parent = parent; AddRange(points, windingOrder); }