/** * @brief Returns the first {@link TSCollider2D} within a rectangular area. Returns null if there is none. * * @param pointA Top-left corner of the rectangle. * @param radius Bottom-right corner of the rectangle. **/ public static object _OverlapArea(TSVector2 pointA, TSVector2 pointB, Physics2D.BodySpecialSensor sensorType) { TSVector2 center; center.x = (pointA.x + pointB.x) * FP.Half; center.y = (pointA.y + pointB.y) * FP.Half; Physics2D.Vertices vertices = new Physics2D.Vertices(4); vertices.Add(new TSVector2(pointA.x, pointA.y) - center); vertices.Add(new TSVector2(pointB.x, pointA.y) - center); vertices.Add(new TSVector2(pointB.x, pointB.y) - center); vertices.Add(new TSVector2(pointA.x, pointB.y) - center); return(OverlapGeneric(new Physics2D.PolygonShape(vertices, 1), center, sensorType)); }
public static object _OverlapArea(TSVector2 i_PointA, TSVector2 i_PointB, Physics2D.BodySpecialSensor i_SensorType, int i_Mask) { TSVector2 center; center.x = (i_PointA.x + i_PointB.x) * FP.Half; center.y = (i_PointA.y + i_PointB.y) * FP.Half; Physics2D.Vertices vertices = new Physics2D.Vertices(4); vertices.Add(new TSVector2(i_PointA.x, i_PointA.y) - center); vertices.Add(new TSVector2(i_PointB.x, i_PointA.y) - center); vertices.Add(new TSVector2(i_PointB.x, i_PointB.y) - center); vertices.Add(new TSVector2(i_PointA.x, i_PointB.y) - center); return(OverlapGeneric(new Physics2D.PolygonShape(vertices, 1), center, i_SensorType, i_Mask)); }
/** * @brief Returns the first {@link TSCollider2D} within a rectangular area. Returns null if there is none. * * @param pointA Top-left corner of the rectangle. * @param radius Bottom-right corner of the rectangle. * @param layerMask Unity's layer mask to filter objects. **/ public static object _OverlapArea(TSVector2 pointA, TSVector2 pointB, Physics2D.BodySpecialSensor sensorType, int layerMask = UnityEngine.Physics.DefaultRaycastLayers) { TSVector2 center; center.x = (pointA.x + pointB.x) * FP.Half; center.y = (pointA.y + pointB.y) * FP.Half; Physics2D.Vertices vertices = new Physics2D.Vertices(4); vertices.Add(new TSVector2(pointA.x, pointA.y) - center); vertices.Add(new TSVector2(pointB.x, pointA.y) - center); vertices.Add(new TSVector2(pointB.x, pointB.y) - center); vertices.Add(new TSVector2(pointA.x, pointB.y) - center); return(OverlapGeneric(new Physics2D.PolygonShape(vertices, 1), center, sensorType, layerMask)); }
/** * @brief Create the internal shape used to represent a PolygonCollider. **/ public override TrueSync.Physics2D.Shape[] CreateShapes() { if (_points == null || _points.Length == 0) { return(null); } TSVector2 lossy2D = new TSVector2(lossyScale.x, lossyScale.y); TrueSync.Physics2D.Vertices v = new Physics2D.Vertices(); for (int index = 0, length = _points.Length; index < length; index++) { v.Add(TSVector2.Scale(_points[index], lossy2D)); } List <TrueSync.Physics2D.Vertices> convexShapeVs = TrueSync.Physics2D.BayazitDecomposer.ConvexPartition(v); TrueSync.Physics2D.Shape[] result = new Physics2D.Shape[convexShapeVs.Count]; for (int index = 0, length = result.Length; index < length; index++) { result[index] = new TrueSync.Physics2D.PolygonShape(convexShapeVs[index], 1); } return(result); }
/** * @brief Create the internal shape used to represent a TSBoxCollider. **/ public override TrueSync.Physics2D.Shape CreateShape() { if (_points == null || _points.Length == 0) { return(null); } TSVector2 lossy2D = new TSVector2(lossyScale.x, lossyScale.y); TrueSync.Physics2D.Vertices v = new Physics2D.Vertices(); for (int index = 0, length = _points.Length; index < length; index++) { v.Add(TSVector2.Scale(_points[index], lossy2D)); } return(new TrueSync.Physics2D.PolygonShape(v, 1)); }
/** * @brief Create the internal shape used to represent a TSBoxCollider. **/ public override Physics2D.Shape[] CreateShapes() { if (m_Points == null || m_Points.Length == 0) { return(null); } Physics2D.Vertices v = new Physics2D.Vertices(); for (int index = 0, length = m_Points.Length; index < length; index++) { v.Add(m_Points[index]); } List <Physics2D.Vertices> convexShapeVs = Physics2D.BayazitDecomposer.ConvexPartition(v); Physics2D.Shape[] result = new Physics2D.Shape[convexShapeVs.Count]; for (int index = 0, length = result.Length; index < length; index++) { result[index] = new Physics2D.PolygonShape(convexShapeVs[index], 1); } return(result); }
public Dictionary <Fixture, TSVector2> Activate(TSVector2 pos, FP radius, FP maxForce) { AABB aABB; aABB.LowerBound = pos + new TSVector2(-radius, -radius); aABB.UpperBound = pos + new TSVector2(radius, radius); Fixture[] shapes = new Fixture[this.MaxShapes]; Fixture[] containedShapes = new Fixture[5]; bool exit = false; int shapeCount = 0; int containedShapeCount = 0; this.World.QueryAABB(delegate(Fixture fixture) { bool flag22 = fixture.TestPoint(ref pos); bool result2; if (flag22) { bool ignoreWhenInsideShape = this.IgnoreWhenInsideShape; if (ignoreWhenInsideShape) { exit = true; result2 = false; return(result2); } Fixture[] arg_45_0 = containedShapes; int num4 = containedShapeCount; containedShapeCount = num4 + 1; arg_45_0[num4] = fixture; } else { Fixture[] arg_62_0 = shapes; int num4 = shapeCount; shapeCount = num4 + 1; arg_62_0[num4] = fixture; } result2 = true; return(result2); }, ref aABB); bool exit2 = exit; Dictionary <Fixture, TSVector2> result; if (exit2) { result = new Dictionary <Fixture, TSVector2>(); } else { Dictionary <Fixture, TSVector2> dictionary = new Dictionary <Fixture, TSVector2>(shapeCount + containedShapeCount); FP[] array = new FP[shapeCount * 2]; int num = 0; for (int i = 0; i < shapeCount; i++) { CircleShape circleShape = shapes[i].Shape as CircleShape; bool flag = circleShape != null; PolygonShape polygonShape; if (flag) { Vertices vertices = new Vertices(); TSVector2 item = TSVector2.zero + new TSVector2(circleShape.Radius, 0); vertices.Add(item); item = TSVector2.zero + new TSVector2(0, circleShape.Radius); vertices.Add(item); item = TSVector2.zero + new TSVector2(-circleShape.Radius, circleShape.Radius); vertices.Add(item); item = TSVector2.zero + new TSVector2(0, -circleShape.Radius); vertices.Add(item); polygonShape = new PolygonShape(vertices, 0); } else { polygonShape = (shapes[i].Shape as PolygonShape); } bool flag2 = shapes[i].Body.BodyType == BodyType.Dynamic && polygonShape != null; if (flag2) { TSVector2 tSVector = shapes[i].Body.GetWorldPoint(polygonShape.MassData.Centroid) - pos; FP y = FP.Atan2(tSVector.y, tSVector.x); FP y2 = FP.MaxValue; FP y3 = FP.MinValue; FP fP = 0f; FP fP2 = 0f; for (int j = 0; j < polygonShape.Vertices.Count; j++) { TSVector2 tSVector2 = shapes[i].Body.GetWorldPoint(polygonShape.Vertices[j]) - pos; FP fP3 = FP.Atan2(tSVector2.y, tSVector2.x); FP fP4 = fP3 - y; fP4 = (fP4 - MathHelper.Pi) % (2 * MathHelper.Pi); bool flag3 = fP4 < 0f; if (flag3) { fP4 += 2 * MathHelper.Pi; } fP4 -= MathHelper.Pi; bool flag4 = FP.Abs(fP4) > MathHelper.Pi; if (!flag4) { bool flag5 = fP4 > y3; if (flag5) { y3 = fP4; fP2 = fP3; } bool flag6 = fP4 < y2; if (flag6) { y2 = fP4; fP = fP3; } } } array[num] = fP; num++; array[num] = fP2; num++; } } Array.Sort <FP>(array, 0, num, this._rdc); this._data.Clear(); bool flag7 = true; for (int k = 0; k < num; k++) { Fixture fixture = null; int num2 = (k == num - 1) ? 0 : (k + 1); bool flag8 = array[k] == array[num2]; if (!flag8) { bool flag9 = k == num - 1; FP x; if (flag9) { x = array[0] + MathHelper.Pi * 2 + array[k]; } else { x = array[k + 1] + array[k]; } x /= 2; TSVector2 pos2 = pos; TSVector2 point = radius * new TSVector2(FP.Cos(x), FP.Sin(x)) + pos; bool hitClosest = false; this.World.RayCast(delegate(Fixture f, TSVector2 p, TSVector2 n, FP fr) { Body body = f.Body; bool flag22 = !this.IsActiveOn(body); FP result2; if (flag22) { result2 = 0; } else { hitClosest = true; fixture = f; result2 = fr; } return(result2); }, pos2, point); bool flag10 = hitClosest && fixture.Body.BodyType == BodyType.Dynamic; if (flag10) { bool flag11 = this._data.Any <ShapeData>() && this._data.Last <ShapeData>().Body == fixture.Body && !flag7; if (flag11) { int index = this._data.Count - 1; ShapeData value = this._data[index]; value.Max = array[num2]; this._data[index] = value; } else { ShapeData item2; item2.Body = fixture.Body; item2.Min = array[k]; item2.Max = array[num2]; this._data.Add(item2); } bool flag12 = this._data.Count > 1 && k == num - 1 && this._data.Last <ShapeData>().Body == this._data.First <ShapeData>().Body&& this._data.Last <ShapeData>().Max == this._data.First <ShapeData>().Min; if (flag12) { ShapeData value2 = this._data[0]; value2.Min = this._data.Last <ShapeData>().Min; this._data.RemoveAt(this._data.Count - 1); this._data[0] = value2; while (this._data.First <ShapeData>().Min >= this._data.First <ShapeData>().Max) { value2.Min -= MathHelper.Pi * 2; this._data[0] = value2; } } int index2 = this._data.Count - 1; ShapeData value3 = this._data[index2]; while (this._data.Count > 0 && this._data.Last <ShapeData>().Min >= this._data.Last <ShapeData>().Max) { value3.Min = this._data.Last <ShapeData>().Min - 2 * MathHelper.Pi; this._data[index2] = value3; } flag7 = false; } else { flag7 = true; } } } for (int l = 0; l < this._data.Count; l++) { bool flag13 = !this.IsActiveOn(this._data[l].Body); if (!flag13) { FP fP5 = this._data[l].Max - this._data[l].Min; FP fP6 = MathHelper.Min(RealExplosion.MaxEdgeOffset, this.EdgeRatio * fP5); int num3 = FP.Ceiling((fP5 - 2f * fP6 - (this.MinRays - 1) * this.MaxAngle) / this.MaxAngle).AsInt(); bool flag14 = num3 < 0; if (flag14) { num3 = 0; } FP y4 = (fP5 - fP6 * 2f) / (this.MinRays + num3 - 1); FP fP7 = this._data[l].Min + fP6; while (fP7 < this._data[l].Max || MathUtils.FPEquals(fP7, this._data[l].Max, 0.0001f)) { TSVector2 pos3 = pos; TSVector2 tSVector3 = pos + radius * new TSVector2(FP.Cos(fP7), FP.Sin(fP7)); TSVector2 tSVector4 = TSVector2.zero; FP fP8 = FP.MaxValue; List <Fixture> fixtureList = this._data[l].Body.FixtureList; for (int m = 0; m < fixtureList.Count; m++) { Fixture fixture3 = fixtureList[m]; RayCastInput rayCastInput; rayCastInput.Point1 = pos3; rayCastInput.Point2 = tSVector3; rayCastInput.MaxFraction = 50f; RayCastOutput rayCastOutput; bool flag15 = fixture3.RayCast(out rayCastOutput, ref rayCastInput, 0); if (flag15) { bool flag16 = fP8 > rayCastOutput.Fraction; if (flag16) { fP8 = rayCastOutput.Fraction; tSVector4 = rayCastOutput.Fraction * tSVector3 + (1 - rayCastOutput.Fraction) * pos3; } } FP scaleFactor = fP5 / (this.MinRays + num3) * maxForce * 180f / MathHelper.Pi * (1f - TSMath.Min(FP.One, fP8)); TSVector2 tSVector5 = TSVector2.Dot(scaleFactor * new TSVector2(FP.Cos(fP7), FP.Sin(fP7)), -rayCastOutput.Normal) * new TSVector2(FP.Cos(fP7), FP.Sin(fP7)); this._data[l].Body.ApplyLinearImpulse(ref tSVector5, ref tSVector4); bool flag17 = dictionary.ContainsKey(fixture3); if (flag17) { Dictionary <Fixture, TSVector2> dictionary2 = dictionary; Fixture key = fixture3; dictionary2[key] += tSVector5; } else { dictionary.Add(fixture3, tSVector5); } bool flag18 = fP8 > 1f; if (flag18) { tSVector4 = tSVector3; } } fP7 += y4; } } } for (int n2 = 0; n2 < containedShapeCount; n2++) { Fixture fixture2 = containedShapes[n2]; bool flag19 = !this.IsActiveOn(fixture2.Body); if (!flag19) { FP scaleFactor2 = this.MinRays * maxForce * 180f / MathHelper.Pi; CircleShape circleShape2 = fixture2.Shape as CircleShape; bool flag20 = circleShape2 != null; TSVector2 worldPoint; if (flag20) { worldPoint = fixture2.Body.GetWorldPoint(circleShape2.Position); } else { PolygonShape polygonShape2 = fixture2.Shape as PolygonShape; worldPoint = fixture2.Body.GetWorldPoint(polygonShape2.MassData.Centroid); } TSVector2 value4 = scaleFactor2 * (worldPoint - pos); fixture2.Body.ApplyLinearImpulse(ref value4, ref worldPoint); bool flag21 = !dictionary.ContainsKey(fixture2); if (flag21) { dictionary.Add(fixture2, value4); } } } result = dictionary; } return(result); }
/// <summary> /// Merges all parallel edges in the list of vertices /// </summary> /// <param name="vertices">The vertices.</param> /// <param name="tolerance">The tolerance.</param> public static Vertices MergeParallelEdges(Vertices vertices, FP tolerance) { //From Eric Jordan's convex decomposition library if (vertices.Count <= 3) { return(vertices); //Can't do anything useful here to a triangle } bool[] mergeMe = new bool[vertices.Count]; int newNVertices = vertices.Count; //Gather points to process for (int i = 0; i < vertices.Count; ++i) { int lower = (i == 0) ? (vertices.Count - 1) : (i - 1); int middle = i; int upper = (i == vertices.Count - 1) ? (0) : (i + 1); FP dx0 = vertices[middle].x - vertices[lower].x; FP dy0 = vertices[middle].y - vertices[lower].y; FP dx1 = vertices[upper].y - vertices[middle].x; FP dy1 = vertices[upper].y - vertices[middle].y; FP norm0 = FP.Sqrt(dx0 * dx0 + dy0 * dy0); FP norm1 = FP.Sqrt(dx1 * dx1 + dy1 * dy1); if (!(norm0 > 0.0f && norm1 > 0.0f) && newNVertices > 3) { //Merge identical points mergeMe[i] = true; --newNVertices; } dx0 /= norm0; dy0 /= norm0; dx1 /= norm1; dy1 /= norm1; FP cross = dx0 * dy1 - dx1 * dy0; FP dot = dx0 * dx1 + dy0 * dy1; if (FP.Abs(cross) < tolerance && dot > 0 && newNVertices > 3) { mergeMe[i] = true; --newNVertices; } else { mergeMe[i] = false; } } if (newNVertices == vertices.Count || newNVertices == 0) { return(vertices); } int currIndex = 0; //Copy the vertices to a new list and clear the old Vertices newVertices = new Vertices(newNVertices); for (int i = 0; i < vertices.Count; ++i) { if (mergeMe[i] || newNVertices == 0 || currIndex == newNVertices) { continue; } Debug.Assert(currIndex < newNVertices); newVertices.Add(vertices[i]); ++currIndex; } return(newVertices); }
//Rounded rectangle contributed by Jonathan Smars - [email protected] /// <summary> /// Creates a rounded rectangle with the specified width and height. /// </summary> /// <param name="width">The width.</param> /// <param name="height">The height.</param> /// <param name="xRadius">The rounding X radius.</param> /// <param name="yRadius">The rounding Y radius.</param> /// <param name="segments">The number of segments to subdivide the edges.</param> /// <returns></returns> public static Vertices CreateRoundedRectangle(FP width, FP height, FP xRadius, FP yRadius, int segments) { if (yRadius > height / 2 || xRadius > width / 2) { throw new Exception("Rounding amount can't be more than half the height and width respectively."); } if (segments < 0) { throw new Exception("Segments must be zero or more."); } //We need at least 8 vertices to create a rounded rectangle Debug.Assert(Settings.MaxPolygonVertices >= 8); Vertices vertices = new Vertices(); if (segments == 0) { vertices.Add(new TSVector2(width * .5f - xRadius, -height * .5f)); vertices.Add(new TSVector2(width * .5f, -height * .5f + yRadius)); vertices.Add(new TSVector2(width * .5f, height * .5f - yRadius)); vertices.Add(new TSVector2(width * .5f - xRadius, height * .5f)); vertices.Add(new TSVector2(-width * .5f + xRadius, height * .5f)); vertices.Add(new TSVector2(-width * .5f, height * .5f - yRadius)); vertices.Add(new TSVector2(-width * .5f, -height * .5f + yRadius)); vertices.Add(new TSVector2(-width * .5f + xRadius, -height * .5f)); } else { int numberOfEdges = (segments * 4 + 8); FP stepSize = FP.PiTimes2 / (numberOfEdges - 4); int perPhase = numberOfEdges / 4; TSVector2 posOffset = new TSVector2(width / 2 - xRadius, height / 2 - yRadius); vertices.Add(posOffset + new TSVector2(xRadius, -yRadius + yRadius)); short phase = 0; for (int i = 1; i < numberOfEdges; i++) { if (i - perPhase == 0 || i - perPhase * 3 == 0) { posOffset.x *= -1; phase--; } else if (i - perPhase * 2 == 0) { posOffset.y *= -1; phase--; } vertices.Add(posOffset + new TSVector2(xRadius * FP.Cos(stepSize * -(i + phase)), -yRadius * FP.Sin(stepSize * -(i + phase)))); } } return(vertices); }
/// <summary> /// Creates an capsule with the specified height, radius and number of edges. /// A capsule has the same form as a pill capsule. /// </summary> /// <param name="height">Height (inner height + radii) of the capsule.</param> /// <param name="topRadius">Radius of the top.</param> /// <param name="topEdges">The number of edges of the top. The more edges, the more it resembles an capsule</param> /// <param name="bottomRadius">Radius of bottom.</param> /// <param name="bottomEdges">The number of edges of the bottom. The more edges, the more it resembles an capsule</param> /// <returns></returns> public static Vertices CreateCapsule(FP height, FP topRadius, int topEdges, FP bottomRadius, int bottomEdges) { if (height <= 0) { throw new ArgumentException("Height must be longer than 0", "height"); } if (topRadius <= 0) { throw new ArgumentException("The top radius must be more than 0", "topRadius"); } if (topEdges <= 0) { throw new ArgumentException("Top edges must be more than 0", "topEdges"); } if (bottomRadius <= 0) { throw new ArgumentException("The bottom radius must be more than 0", "bottomRadius"); } if (bottomEdges <= 0) { throw new ArgumentException("Bottom edges must be more than 0", "bottomEdges"); } if (topRadius >= height / 2) { throw new ArgumentException( "The top radius must be lower than height / 2. Higher values of top radius would create a circle, and not a half circle.", "topRadius"); } if (bottomRadius >= height / 2) { throw new ArgumentException( "The bottom radius must be lower than height / 2. Higher values of bottom radius would create a circle, and not a half circle.", "bottomRadius"); } Vertices vertices = new Vertices(); FP newHeight = (height - topRadius - bottomRadius) * 0.5f; // top vertices.Add(new TSVector2(topRadius, newHeight)); FP stepSize = FP.Pi / topEdges; for (int i = 1; i < topEdges; i++) { vertices.Add(new TSVector2(topRadius * FP.Cos(stepSize * i), topRadius * FP.Sin(stepSize * i) + newHeight)); } vertices.Add(new TSVector2(-topRadius, newHeight)); // bottom vertices.Add(new TSVector2(-bottomRadius, -newHeight)); stepSize = FP.Pi / bottomEdges; for (int i = 1; i < bottomEdges; i++) { vertices.Add(new TSVector2(-bottomRadius * FP.Cos(stepSize * i), -bottomRadius * FP.Sin(stepSize * i) - newHeight)); } vertices.Add(new TSVector2(bottomRadius, -newHeight)); return(vertices); }
public static Vertices GetConvexHull(Vertices vertices) { bool flag = vertices.Count <= 3; Vertices result; if (flag) { result = vertices; } else { int num = 0; FP y = vertices[0].x; for (int i = 1; i < vertices.Count; i++) { FP x = vertices[i].x; bool flag2 = x > y || (x == y && vertices[i].y < vertices[num].y); if (flag2) { num = i; y = x; } } int[] array = new int[vertices.Count]; int num2 = 0; int num3 = num; bool flag6; do { array[num2] = num3; int num4 = 0; for (int j = 1; j < vertices.Count; j++) { bool flag3 = num4 == num3; if (flag3) { num4 = j; } else { TSVector2 tSVector = vertices[num4] - vertices[array[num2]]; TSVector2 tSVector2 = vertices[j] - vertices[array[num2]]; FP x2 = MathUtils.Cross(ref tSVector, ref tSVector2); bool flag4 = x2 < 0f; if (flag4) { num4 = j; } bool flag5 = x2 == 0f && tSVector2.LengthSquared() > tSVector.LengthSquared(); if (flag5) { num4 = j; } } } num2++; num3 = num4; flag6 = (num4 == num); }while (!flag6); Vertices vertices2 = new Vertices(num2); for (int k = 0; k < num2; k++) { vertices2.Add(vertices[array[k]]); } result = vertices2; } return(result); }
private static bool ResolvePinchPoint(Vertices pin, out Vertices poutA, out Vertices poutB, FP tolerance) { poutA = new Vertices(); poutB = new Vertices(); bool flag = pin.Count < 3; bool result; if (flag) { result = false; } else { bool flag2 = false; int num = -1; int num2 = -1; for (int i = 0; i < pin.Count; i++) { for (int j = i + 1; j < pin.Count; j++) { bool flag3 = FP.Abs(pin[i].x - pin[j].x) < tolerance && FP.Abs(pin[i].y - pin[j].y) < tolerance && j != i + 1; if (flag3) { num = i; num2 = j; flag2 = true; break; } } bool flag4 = flag2; if (flag4) { break; } } bool flag5 = flag2; if (flag5) { int num3 = num2 - num; bool flag6 = num3 == pin.Count; if (flag6) { result = false; return(result); } for (int k = 0; k < num3; k++) { int index = EarclipDecomposer.Remainder(num + k, pin.Count); poutA.Add(pin[index]); } int num4 = pin.Count - num3; for (int l = 0; l < num4; l++) { int index2 = EarclipDecomposer.Remainder(num2 + l, pin.Count); poutB.Add(pin[index2]); } } result = flag2; } return(result); }
private static Vertices AddTriangle(Vertices t, Vertices vertices) { int num = -1; int num2 = -1; int num3 = -1; int num4 = -1; for (int i = 0; i < vertices.Count; i++) { bool flag = t[0].x == vertices[i].x && t[0].y == vertices[i].y; if (flag) { bool flag2 = num == -1; if (flag2) { num = i; num2 = 0; } else { num3 = i; num4 = 0; } } else { bool flag3 = t[1].x == vertices[i].x && t[1].y == vertices[i].y; if (flag3) { bool flag4 = num == -1; if (flag4) { num = i; num2 = 1; } else { num3 = i; num4 = 1; } } else { bool flag5 = t[2].x == vertices[i].x && t[2].y == vertices[i].y; if (flag5) { bool flag6 = num == -1; if (flag6) { num = i; num2 = 2; } else { num3 = i; num4 = 2; } } } } } bool flag7 = num == 0 && num3 == vertices.Count - 1; if (flag7) { num = vertices.Count - 1; num3 = 0; } bool flag8 = num3 == -1; Vertices result; if (flag8) { result = null; } else { int num5 = 0; bool flag9 = num5 == num2 || num5 == num4; if (flag9) { num5 = 1; } bool flag10 = num5 == num2 || num5 == num4; if (flag10) { num5 = 2; } Vertices vertices2 = new Vertices(vertices.Count + 1); for (int j = 0; j < vertices.Count; j++) { vertices2.Add(vertices[j]); bool flag11 = j == num; if (flag11) { vertices2.Add(t[num5]); } } result = vertices2; } return(result); }
/// <summary> /// Decompose the polygon into triangles. /// /// Properties: /// - Only works on counter clockwise polygons /// /// </summary> /// <param name="vertices">The list of points describing the polygon</param> public static List <Vertices> ConvexPartition(Vertices vertices) { Debug.Assert(vertices.Count > 3); Debug.Assert(vertices.IsCounterClockWise()); int[] polygon = new int[vertices.Count]; for (int v = 0; v < vertices.Count; v++) { polygon[v] = v; } int nv = vertices.Count; // Remove nv-2 Vertices, creating 1 triangle every time int count = 2 * nv; /* error detection */ List <Vertices> result = new List <Vertices>(); for (int v = nv - 1; nv > 2;) { // If we loop, it is probably a non-simple polygon if (0 >= (count--)) { // Triangulate: ERROR - probable bad polygon! return(new List <Vertices>()); } // Three consecutive vertices in current polygon, <u,v,w> int u = v; if (nv <= u) { u = 0; // Previous } v = u + 1; if (nv <= v) { v = 0; // New v } int w = v + 1; if (nv <= w) { w = 0; // Next } _tmpA = vertices[polygon[u]]; _tmpB = vertices[polygon[v]]; _tmpC = vertices[polygon[w]]; if (Snip(vertices, u, v, w, nv, polygon)) { int s, t; // Output Triangle Vertices triangle = new Vertices(3); triangle.Add(_tmpA); triangle.Add(_tmpB); triangle.Add(_tmpC); result.Add(triangle); // Remove v from remaining polygon for (s = v, t = v + 1; t < nv; s++, t++) { polygon[s] = polygon[t]; } nv--; // Reset error detection counter count = 2 * nv; } } return(result); }
public static Vertices MergeParallelEdges(Vertices vertices, FP tolerance) { bool flag = vertices.Count <= 3; Vertices result; if (flag) { result = vertices; } else { bool[] array = new bool[vertices.Count]; int num = vertices.Count; for (int i = 0; i < vertices.Count; i++) { int index = (i == 0) ? (vertices.Count - 1) : (i - 1); int index2 = i; int index3 = (i == vertices.Count - 1) ? 0 : (i + 1); FP fP = vertices[index2].x - vertices[index].x; FP fP2 = vertices[index2].y - vertices[index].y; FP fP3 = vertices[index3].y - vertices[index2].x; FP fP4 = vertices[index3].y - vertices[index2].y; FP fP5 = FP.Sqrt(fP * fP + fP2 * fP2); FP fP6 = FP.Sqrt(fP3 * fP3 + fP4 * fP4); bool flag2 = (!(fP5 > 0f) || !(fP6 > 0f)) && num > 3; if (flag2) { array[i] = true; num--; } fP /= fP5; fP2 /= fP5; fP3 /= fP6; fP4 /= fP6; FP value = fP * fP4 - fP3 * fP2; FP x = fP * fP3 + fP2 * fP4; bool flag3 = FP.Abs(value) < tolerance && x > 0 && num > 3; if (flag3) { array[i] = true; num--; } else { array[i] = false; } } bool flag4 = num == vertices.Count || num == 0; if (flag4) { result = vertices; } else { int num2 = 0; Vertices vertices2 = new Vertices(num); for (int j = 0; j < vertices.Count; j++) { bool flag5 = array[j] || num == 0 || num2 == num; if (!flag5) { Debug.Assert(num2 < num); vertices2.Add(vertices[j]); num2++; } } result = vertices2; } } return(result); }
private static PolyClipError BuildPolygonsFromChain(List <YuPengClipper.Edge> simplicies, out List <Vertices> result) { result = new List <Vertices>(); PolyClipError polyClipError = PolyClipError.None; PolyClipError result2; while (simplicies.Count > 0) { Vertices vertices = new Vertices(); vertices.Add(simplicies[0].EdgeStart); vertices.Add(simplicies[0].EdgeEnd); simplicies.RemoveAt(0); bool flag = false; int num = 0; int count = simplicies.Count; while (!flag && simplicies.Count > 0) { bool flag2 = YuPengClipper.VectorEqual(vertices[vertices.Count - 1], simplicies[num].EdgeStart); if (flag2) { bool flag3 = YuPengClipper.VectorEqual(simplicies[num].EdgeEnd, vertices[0]); if (flag3) { flag = true; } else { vertices.Add(simplicies[num].EdgeEnd); } simplicies.RemoveAt(num); num--; } else { bool flag4 = YuPengClipper.VectorEqual(vertices[vertices.Count - 1], simplicies[num].EdgeEnd); if (flag4) { bool flag5 = YuPengClipper.VectorEqual(simplicies[num].EdgeStart, vertices[0]); if (flag5) { flag = true; } else { vertices.Add(simplicies[num].EdgeStart); } simplicies.RemoveAt(num); num--; } } bool flag6 = !flag; if (flag6) { bool flag7 = ++num == simplicies.Count; if (flag7) { bool flag8 = count == simplicies.Count; if (flag8) { result = new List <Vertices>(); Debug.WriteLine("Undefined error while building result polygon(s)."); result2 = PolyClipError.BrokenResult; return(result2); } num = 0; count = simplicies.Count; } } } bool flag9 = vertices.Count < 3; if (flag9) { polyClipError = PolyClipError.DegeneratedOutput; Debug.WriteLine("Degenerated output polygon produced (vertices < 3)."); } result.Add(vertices); } result2 = polyClipError; return(result2); }
/// <summary> /// Returns the convex hull from the given vertices.. /// </summary> public static Vertices GetConvexHull(Vertices vertices) { if (vertices.Count <= 3) { return(vertices); } Vertices pointSet = new Vertices(vertices); //Sort by X-axis pointSet.Sort(_pointComparer); TSVector2[] h = new TSVector2[pointSet.Count]; Vertices res; int top = -1; // indices for bottom and top of the stack int i; // array scan index // Get the indices of points with min x-coord and min|max y-coord const int minmin = 0; FP xmin = pointSet[0].x; for (i = 1; i < pointSet.Count; i++) { if (pointSet[i].x != xmin) { break; } } // degenerate case: all x-coords == xmin int minmax = i - 1; if (minmax == pointSet.Count - 1) { h[++top] = pointSet[minmin]; if (pointSet[minmax].y != pointSet[minmin].y) // a nontrivial segment { h[++top] = pointSet[minmax]; } h[++top] = pointSet[minmin]; // add polygon endpoint res = new Vertices(top + 1); for (int j = 0; j < top + 1; j++) { res.Add(h[j]); } return(res); } top = -1; // Get the indices of points with max x-coord and min|max y-coord int maxmax = pointSet.Count - 1; FP xmax = pointSet[pointSet.Count - 1].x; for (i = pointSet.Count - 2; i >= 0; i--) { if (pointSet[i].x != xmax) { break; } } int maxmin = i + 1; // Compute the lower hull on the stack H h[++top] = pointSet[minmin]; // push minmin point onto stack i = minmax; while (++i <= maxmin) { // the lower line joins P[minmin] with P[maxmin] if (MathUtils.Area(pointSet[minmin], pointSet[maxmin], pointSet[i]) >= 0 && i < maxmin) { continue; // ignore P[i] above or on the lower line } while (top > 0) // there are at least 2 points on the stack { // test if P[i] is left of the line at the stack top if (MathUtils.Area(h[top - 1], h[top], pointSet[i]) > 0) { break; // P[i] is a new hull vertex } top--; // pop top point off stack } h[++top] = pointSet[i]; // push P[i] onto stack } // Next, compute the upper hull on the stack H above the bottom hull if (maxmax != maxmin) // if distinct xmax points { h[++top] = pointSet[maxmax]; // push maxmax point onto stack } int bot = top; i = maxmin; while (--i >= minmax) { // the upper line joins P[maxmax] with P[minmax] if (MathUtils.Area(pointSet[maxmax], pointSet[minmax], pointSet[i]) >= 0 && i > minmax) { continue; // ignore P[i] below or on the upper line } while (top > bot) // at least 2 points on the upper stack { // test if P[i] is left of the line at the stack top if (MathUtils.Area(h[top - 1], h[top], pointSet[i]) > 0) { break; // P[i] is a new hull vertex } top--; // pop top point off stack } h[++top] = pointSet[i]; // push P[i] onto stack } if (minmax != minmin) { h[++top] = pointSet[minmin]; // push joining endpoint onto stack } res = new Vertices(top + 1); for (int j = 0; j < top + 1; j++) { res.Add(h[j]); } return(res); }
public static List <Vertices> PolygonizeTriangles(List <Vertices> triangles, int maxPolys = 2147483647, float tolerance = 0.001f) { bool flag = triangles.Count <= 0; List <Vertices> result; if (flag) { result = triangles; } else { List <Vertices> list = new List <Vertices>(); bool[] array = new bool[triangles.Count]; for (int i = 0; i < triangles.Count; i++) { array[i] = false; Vertices vertices = triangles[i]; TSVector2 tSVector = vertices[0]; TSVector2 tSVector2 = vertices[1]; TSVector2 tSVector3 = vertices[2]; bool flag2 = (tSVector.x == tSVector2.x && tSVector.y == tSVector2.y) || (tSVector2.x == tSVector3.x && tSVector2.y == tSVector3.y) || (tSVector.x == tSVector3.x && tSVector.y == tSVector3.y); if (flag2) { array[i] = true; } } int num = 0; bool flag3 = true; while (flag3) { int num2 = -1; for (int j = 0; j < triangles.Count; j++) { bool flag4 = array[j]; if (!flag4) { num2 = j; break; } } bool flag5 = num2 == -1; if (flag5) { flag3 = false; } else { Vertices vertices2 = new Vertices(3); for (int k = 0; k < 3; k++) { vertices2.Add(triangles[num2][k]); } array[num2] = true; int l = 0; int m = 0; while (m < 2 * triangles.Count) { while (l >= triangles.Count) { l -= triangles.Count; } bool flag6 = array[l]; if (!flag6) { Vertices vertices3 = SimpleCombiner.AddTriangle(triangles[l], vertices2); bool flag7 = vertices3 == null; if (!flag7) { bool flag8 = vertices3.Count > Settings.MaxPolygonVertices; if (!flag8) { bool flag9 = vertices3.IsConvex(); if (flag9) { vertices2 = new Vertices(vertices3); array[l] = true; } } } } m++; l++; } bool flag10 = num < maxPolys; if (flag10) { SimplifyTools.MergeParallelEdges(vertices2, tolerance); bool flag11 = vertices2.Count >= 3; if (flag11) { list.Add(new Vertices(vertices2)); } else { Debug.WriteLine("Skipping corrupt poly."); } } bool flag12 = vertices2.Count >= 3; if (flag12) { num++; } } } for (int n = list.Count - 1; n >= 0; n--) { bool flag13 = list[n].Count == 0; if (flag13) { list.RemoveAt(n); } } result = list; } return(result); }
/// <summary> /// Calculates the polygon(s) from the result simplical chain. /// </summary> /// <remarks>Used by method <c>Execute()</c>.</remarks> private static PolyClipError BuildPolygonsFromChain(List <Edge> simplicies, out List <Vertices> result) { result = new List <Vertices>(); PolyClipError errVal = PolyClipError.None; while (simplicies.Count > 0) { Vertices output = new Vertices(); output.Add(simplicies[0].EdgeStart); output.Add(simplicies[0].EdgeEnd); simplicies.RemoveAt(0); bool closed = false; int index = 0; int count = simplicies.Count; // Needed to catch infinite loops while (!closed && simplicies.Count > 0) { if (VectorEqual(output[output.Count - 1], simplicies[index].EdgeStart)) { if (VectorEqual(simplicies[index].EdgeEnd, output[0])) { closed = true; } else { output.Add(simplicies[index].EdgeEnd); } simplicies.RemoveAt(index); --index; } else if (VectorEqual(output[output.Count - 1], simplicies[index].EdgeEnd)) { if (VectorEqual(simplicies[index].EdgeStart, output[0])) { closed = true; } else { output.Add(simplicies[index].EdgeStart); } simplicies.RemoveAt(index); --index; } if (!closed) { if (++index == simplicies.Count) { if (count == simplicies.Count) { result = new List <Vertices>(); Debug.WriteLine("Undefined error while building result polygon(s)."); return(PolyClipError.BrokenResult); } index = 0; count = simplicies.Count; } } } if (output.Count < 3) { errVal = PolyClipError.DegeneratedOutput; Debug.WriteLine("Degenerated output polygon produced (vertices < 3)."); } result.Add(output); } return(errVal); }
public static Vertices CreateCapsule(FP height, FP topRadius, int topEdges, FP bottomRadius, int bottomEdges) { bool flag = height <= 0; if (flag) { throw new ArgumentException("Height must be longer than 0", "height"); } bool flag2 = topRadius <= 0; if (flag2) { throw new ArgumentException("The top radius must be more than 0", "topRadius"); } bool flag3 = topEdges <= 0; if (flag3) { throw new ArgumentException("Top edges must be more than 0", "topEdges"); } bool flag4 = bottomRadius <= 0; if (flag4) { throw new ArgumentException("The bottom radius must be more than 0", "bottomRadius"); } bool flag5 = bottomEdges <= 0; if (flag5) { throw new ArgumentException("Bottom edges must be more than 0", "bottomEdges"); } bool flag6 = topRadius >= height / 2; if (flag6) { throw new ArgumentException("The top radius must be lower than height / 2. Higher values of top radius would create a circle, and not a half circle.", "topRadius"); } bool flag7 = bottomRadius >= height / 2; if (flag7) { throw new ArgumentException("The bottom radius must be lower than height / 2. Higher values of bottom radius would create a circle, and not a half circle.", "bottomRadius"); } Vertices vertices = new Vertices(); FP fP = (height - topRadius - bottomRadius) * 0.5f; vertices.Add(new TSVector2(topRadius, fP)); FP x = MathHelper.Pi / topEdges; for (int i = 1; i < topEdges; i++) { vertices.Add(new TSVector2(topRadius * FP.Cos(x * i), topRadius * FP.Sin(x * i) + fP)); } vertices.Add(new TSVector2(-topRadius, fP)); vertices.Add(new TSVector2(-bottomRadius, -fP)); x = MathHelper.Pi / bottomEdges; for (int j = 1; j < bottomEdges; j++) { vertices.Add(new TSVector2(-bottomRadius * FP.Cos(x * j), -bottomRadius * FP.Sin(x * j) - fP)); } vertices.Add(new TSVector2(bottomRadius, -fP)); return(vertices); }
/// <summary> /// Activate the explosion at the specified position. /// </summary> /// <param name="pos">The position where the explosion happens </param> /// <param name="radius">The explosion radius </param> /// <param name="maxForce">The explosion force at the explosion point (then is inversely proportional to the square of the distance)</param> /// <returns>A list of bodies and the amount of force that was applied to them.</returns> public Dictionary <Fixture, TSVector2> Activate(TSVector2 pos, FP radius, FP maxForce) { AABB aabb; aabb.LowerBound = pos + new TSVector2(-radius, -radius); aabb.UpperBound = pos + new TSVector2(radius, radius); Fixture[] shapes = new Fixture[MaxShapes]; // More than 5 shapes in an explosion could be possible, but still strange. Fixture[] containedShapes = new Fixture[5]; bool exit = false; int shapeCount = 0; int containedShapeCount = 0; // Query the world for overlapping shapes. World.QueryAABB( fixture => { if (fixture.TestPoint(ref pos)) { if (IgnoreWhenInsideShape) { exit = true; return(false); } containedShapes[containedShapeCount++] = fixture; } else { shapes[shapeCount++] = fixture; } // Continue the query. return(true); }, ref aabb); if (exit) { return(new Dictionary <Fixture, TSVector2>()); } Dictionary <Fixture, TSVector2> exploded = new Dictionary <Fixture, TSVector2>(shapeCount + containedShapeCount); // Per shape max/min angles for now. FP[] vals = new FP[shapeCount * 2]; int valIndex = 0; for (int i = 0; i < shapeCount; ++i) { PolygonShape ps; CircleShape cs = shapes[i].Shape as CircleShape; if (cs != null) { // We create a "diamond" approximation of the circle Vertices v = new Vertices(); TSVector2 vec = TSVector2.zero + new TSVector2(cs.Radius, 0); v.Add(vec); vec = TSVector2.zero + new TSVector2(0, cs.Radius); v.Add(vec); vec = TSVector2.zero + new TSVector2(-cs.Radius, cs.Radius); v.Add(vec); vec = TSVector2.zero + new TSVector2(0, -cs.Radius); v.Add(vec); ps = new PolygonShape(v, 0); } else { ps = shapes[i].Shape as PolygonShape; } if ((shapes[i].Body.BodyType == BodyType.Dynamic) && ps != null) { TSVector2 toCentroid = shapes[i].Body.GetWorldPoint(ps.MassData.Centroid) - pos; FP angleToCentroid = FP.Atan2(toCentroid.y, toCentroid.x); FP min = FP.MaxValue; FP max = FP.MinValue; FP minAbsolute = 0.0f; FP maxAbsolute = 0.0f; for (int j = 0; j < ps.Vertices.Count; ++j) { TSVector2 toVertex = (shapes[i].Body.GetWorldPoint(ps.Vertices[j]) - pos); FP newAngle = FP.Atan2(toVertex.y, toVertex.x); FP diff = (newAngle - angleToCentroid); diff = (diff - FP.Pi) % (2 * FP.Pi); // the minus pi is important. It means cutoff for going other direction is at 180 deg where it needs to be if (diff < 0.0f) { diff += 2 * FP.Pi; // correction for not handling negs } diff -= FP.Pi; if (FP.Abs(diff) > FP.Pi) { continue; // Something's wrong, point not in shape but exists angle diff > 180 } if (diff > max) { max = diff; maxAbsolute = newAngle; } if (diff < min) { min = diff; minAbsolute = newAngle; } } vals[valIndex] = minAbsolute; ++valIndex; vals[valIndex] = maxAbsolute; ++valIndex; } } Array.Sort(vals, 0, valIndex, _rdc); _data.Clear(); bool rayMissed = true; for (int i = 0; i < valIndex; ++i) { Fixture fixture = null; FP midpt; int iplus = (i == valIndex - 1 ? 0 : i + 1); if (vals[i] == vals[iplus]) { continue; } if (i == valIndex - 1) { // the single edgecase midpt = (vals[0] + FP.PiTimes2 + vals[i]); } else { midpt = (vals[i + 1] + vals[i]); } midpt = midpt / 2; TSVector2 p1 = pos; TSVector2 p2 = radius * new TSVector2(FP.Cos(midpt), FP.Sin(midpt)) + pos; // RaycastOne bool hitClosest = false; World.RayCast((f, p, n, fr) => { Body body = f.Body; if (!IsActiveOn(body)) { return(0); } hitClosest = true; fixture = f; return(fr); }, p1, p2); //draws radius points if ((hitClosest) && (fixture.Body.BodyType == BodyType.Dynamic)) { if ((_data.Any()) && (_data.Last().Body == fixture.Body) && (!rayMissed)) { int laPos = _data.Count - 1; ShapeData la = _data[laPos]; la.Max = vals[iplus]; _data[laPos] = la; } else { // make new ShapeData d; d.Body = fixture.Body; d.Min = vals[i]; d.Max = vals[iplus]; _data.Add(d); } if ((_data.Count > 1) && (i == valIndex - 1) && (_data.Last().Body == _data.First().Body) && (_data.Last().Max == _data.First().Min)) { ShapeData fi = _data[0]; fi.Min = _data.Last().Min; _data.RemoveAt(_data.Count - 1); _data[0] = fi; while (_data.First().Min >= _data.First().Max) { fi.Min -= FP.PiTimes2; _data[0] = fi; } } int lastPos = _data.Count - 1; ShapeData last = _data[lastPos]; while ((_data.Count > 0) && (_data.Last().Min >= _data.Last().Max)) // just making sure min<max { last.Min = _data.Last().Min - FP.PiTimes2; _data[lastPos] = last; } rayMissed = false; } else { rayMissed = true; // raycast did not find a shape } } for (int i = 0; i < _data.Count; ++i) { if (!IsActiveOn(_data[i].Body)) { continue; } FP arclen = _data[i].Max - _data[i].Min; FP first = TSMath.Min(MaxEdgeOffset, EdgeRatio * arclen); int insertedRays = FP.Ceiling((((arclen - 2.0f * first) - (MinRays - 1) * MaxAngle) / MaxAngle)).AsInt(); if (insertedRays < 0) { insertedRays = 0; } FP offset = (arclen - first * 2.0f) / ((FP)MinRays + insertedRays - 1); //Note: This loop can go into infinite as it operates on FPs. //Added FPEquals with a large epsilon. for (FP j = _data[i].Min + first; j < _data[i].Max || MathUtils.FPEquals(j, _data[i].Max, 0.0001f); j += offset) { TSVector2 p1 = pos; TSVector2 p2 = pos + radius * new TSVector2(FP.Cos(j), FP.Sin(j)); TSVector2 hitpoint = TSVector2.zero; FP minlambda = FP.MaxValue; List <Fixture> fl = _data[i].Body.FixtureList; for (int x = 0; x < fl.Count; x++) { Fixture f = fl[x]; RayCastInput ri; ri.Point1 = p1; ri.Point2 = p2; ri.MaxFraction = 50f; RayCastOutput ro; if (f.RayCast(out ro, ref ri, 0)) { if (minlambda > ro.Fraction) { minlambda = ro.Fraction; hitpoint = ro.Fraction * p2 + (1 - ro.Fraction) * p1; } } // the force that is to be applied for this particular ray. // offset is angular coverage. lambda*length of segment is distance. FP impulse = (arclen / (MinRays + insertedRays)) * maxForce * 180.0f / FP.Pi * (1.0f - TrueSync.TSMath.Min(FP.One, minlambda)); // We Apply the impulse!!! TSVector2 vectImp = TSVector2.Dot(impulse * new TSVector2(FP.Cos(j), FP.Sin(j)), -ro.Normal) * new TSVector2(FP.Cos(j), FP.Sin(j)); _data[i].Body.ApplyLinearImpulse(ref vectImp, ref hitpoint); // We gather the fixtures for returning them if (exploded.ContainsKey(f)) { exploded[f] += vectImp; } else { exploded.Add(f, vectImp); } if (minlambda > 1.0f) { hitpoint = p2; } } } } // We check contained shapes for (int i = 0; i < containedShapeCount; ++i) { Fixture fix = containedShapes[i]; if (!IsActiveOn(fix.Body)) { continue; } FP impulse = MinRays * maxForce * 180.0f / FP.Pi; TSVector2 hitPoint; CircleShape circShape = fix.Shape as CircleShape; if (circShape != null) { hitPoint = fix.Body.GetWorldPoint(circShape.Position); } else { PolygonShape shape = fix.Shape as PolygonShape; hitPoint = fix.Body.GetWorldPoint(shape.MassData.Centroid); } TSVector2 vectImp = impulse * (hitPoint - pos); fix.Body.ApplyLinearImpulse(ref vectImp, ref hitPoint); if (!exploded.ContainsKey(fix)) { exploded.Add(fix, vectImp); } } return(exploded); }