protected void OnInit( ) { var polyObj = new GameObject(); var polyView = polyObj.AddComponent <PolygonView>(); polyObj.transform.parent = contextView.transform; polyObj.name = "Drawing Path"; polyView.glUtils = polyObj.AddComponent <_GLUtils>(); var lineParentObj = new GameObject("LineGroup"); lineParentObj.transform.parent = polyObj.transform; polyView.lineParent = lineParentObj.transform; var pointParentObj = new GameObject("PointGroup"); pointParentObj.transform.parent = polyObj.transform; polyView.pointParent = pointParentObj.transform; polyView.points = new List <PointView> ( ); polyView.lines = new List <LineView> ( ); pathView = polyView; pathEntity = new PolygonEntity( ); }
/// <summary> /// Given 2 PolygonEntitites, finds the edge with the least penetration /// </summary> /// <param name="A"></param> /// <param name="B"></param> /// <param name="PolygonIndex"> An out parameter giving the index where the Axis of least penetration was found </param> /// <returns>returns the value of the axis of least penetration </returns> public static float FindAxisLeastPenetration(PolygonEntity A, PolygonEntity B, ref int PolygonIndex) { float greatestProjection = -100000; int faceIndex = 0; for (int i = 0; i < A.GetVertices().Length; i++) { Vector Normal = A.GetFaceNormal(i).Normalized(); Vector verticePosition = A.GetVertices()[i]; Vector verticeIndex = B.GetSupportPoint(Normal * -1); verticeIndex += B.position; Vector DistanceToVertice = verticeIndex - verticePosition; float projection = Vector.Dot(DistanceToVertice, Normal); if (projection > greatestProjection) { greatestProjection = projection; faceIndex = i; } } PolygonIndex = faceIndex; return(greatestProjection); }
/// <summary> /// Given a CircleEntity and a PolygonEntity, checks if their bounding volumes overlap each other /// </summary> /// <returns></returns> public static bool DetectBoundingVolumeCollision(CircleEntity A, PolygonEntity B) { float CollisionDistance = A.Radius + B.GetVolumeRadius(); float dx = A.x - B.x; float dy = A.y - B.y; return(CollisionDistance * CollisionDistance >= (dx * dx) + (dy * dy)); }
/// <summary> /// Given 2 PolygonEntities, checks if their bounding volumes are colliding /// </summary> /// <returns></returns> public static bool DetectBoundingVolumeCollision(PolygonEntity A, PolygonEntity B) { if (Utils.IsNearEqual(A.GetInvMass(), 0, 0.0001f) && Utils.IsNearEqual(B.GetInvMass(), 0, 0.0001f)) { return(false); } float CollisionDistance = A.GetVolumeRadius() + B.GetVolumeRadius(); float dx = A.x - B.x; float dy = A.y - B.y; return(CollisionDistance * CollisionDistance >= (dx * dx) + (dy * dy)); }
/// <summary> /// Returns trimmed polygon after trimming this polygon using the /// given array of planes as half spaces. /// </summary> /// <param name="halfSpaces">Trimming planes.</param> /// <returns>Trimmed Polygon</returns> public Polygon Trim(Plane[] halfSpaces) { IPlaneEntity[] hosts = halfSpaces.ConvertAll(GeometryExtension.ToEntity <Plane, IPlaneEntity>); IPolygonEntity entity = PolygonEntity.Trim(hosts); if (null == entity) { return(null); } Hide(this); Hide(halfSpaces); return(new Polygon(entity, true)); }
/// <summary> /// Vytvoří polygon /// </summary> /// <param name="points">Kolekce bodů polygonu</param> /// <returns>Polygon</returns> private void drawPolygonEntity(PointCollection points) { Point startPosition = new Point(double.NaN, double.NaN); Point endPosition = new Point(double.NaN, double.NaN); foreach (Point vertex in points) { if (double.IsNaN(startPosition.X) || vertex.X < startPosition.X) { startPosition.X = vertex.X; } if (double.IsNaN(startPosition.Y) || vertex.Y < startPosition.Y) { startPosition.Y = vertex.Y; } if (double.IsNaN(endPosition.X) || vertex.X > endPosition.X) { endPosition.X = vertex.X; } if (double.IsNaN(endPosition.Y) || vertex.Y > endPosition.Y) { endPosition.Y = vertex.Y; } } PolygonEntity entity = Document.AddNewEntity <PolygonEntity>(); entity.Move(startPosition); double width = entity.Width = endPosition.X - startPosition.X; double height = entity.Height = endPosition.Y - startPosition.Y; foreach (Point vertex in points) { entity.AddPoint(new Point((vertex.X - startPosition.X) / width, (vertex.Y - startPosition.Y) / height)); } this.drawEntity(entity); this.selection.SelectWithoutBorder(entity); }
/// <summary> /// Finds the polygon generated by the overlap between 2 PolygonEntitites /// </summary> /// <param name="referencePolygon"> The polygon that will be used as a base for trimming </param> /// <param name="polygonToBeTrimmed"> The polygon that will be trimmed s</param> /// <returns></returns> public static List <Vector> SutherlandHodgmanClipping(PolygonEntity referencePolygon, PolygonEntity polygonToBeTrimmed) { List <Vector> outputList = polygonToBeTrimmed.GetVerticeList(); //for each face in reference poly for (int i = 0; i < referencePolygon.GetVertices().Length; i++) { //use output from previous iteration as new input List <Vector> inputList = new List <Vector>(outputList); //start with an empty output list outputList.Clear(); int secondIndex = i + 1 >= referencePolygon.GetVertices().Length ? 0 : i + 1; //get reflected face normal Vector StartPoint = referencePolygon.GetVertices()[i]; Vector Endpoint = referencePolygon.GetVertices()[secondIndex]; //for every point in incident poly for (int j = 0; j < inputList.Count; j++) { //get v1 Vector v1 = inputList[j]; int secondIncIndex = j + 1 >= inputList.Count ? 0 : j + 1; Vector v2 = inputList[secondIncIndex]; //get v2 float v1DisToLine = DistancePointToLine(Endpoint, StartPoint, v1); float v2DisToLine = DistancePointToLine(Endpoint, StartPoint, v2); //entered end point first to get the normal facing towards the polygon bool v1IsFront = v1DisToLine > 0; bool v2IsFront = v2DisToLine > 0; //if v1 + v2 in front if (v1IsFront && v2IsFront) { //save v2 outputList.Add(v2); } //if v1 in front and v2 in the back else if (v1IsFront && !v2IsFront) { //save intersection outputList.Add(CollisionDetection.FindLineIntersection(StartPoint, Endpoint, v1, v2)); } //if v1 in back and v2 in the front else if (!v1IsFront && v2IsFront) { //save intersection and v2 outputList.Add(CollisionDetection.FindLineIntersection(StartPoint, Endpoint, v1, v2)); outputList.Add(v2); } //if both are on the back //save none } } return(outputList); }
/// <summary> /// Given 2 PolygonEntities generates a Manifold , generates a manifold containing the information required to /// resolve the collision (if there was one to begin with). /// </summary> public static Manifold GenerateManifold(PolygonEntity A, PolygonEntity B) { Manifold Result; int FaceA = 0; int FaceB = 0; //find reference face float AtBPenetration = CollisionDetection.FindAxisLeastPenetration(A, B, ref FaceA); if (AtBPenetration > 0) { return(GenerateEmptyManifold()); } float BtAPenetration = CollisionDetection.FindAxisLeastPenetration(B, A, ref FaceB); if (BtAPenetration > 0) { return(GenerateEmptyManifold()); } PolygonEntity refPol; PolygonEntity IncPol; bool flip = false; int refFace = -1234; if (BiasGreaterThan(AtBPenetration, BtAPenetration)) { refPol = A; IncPol = B; flip = false; refFace = FaceA; } else { refPol = B; IncPol = A; refFace = FaceB; flip = true; } if (refFace == -1234) { Console.WriteLine("ERROR"); } Vector Normal = refPol.GetFaceNormal(refFace).Normalized(); //SUTHERLAND HODGEMAN List <Vector> ClippedPolygon = SutherlandHodgmanClipping(A, B); Vector Max = Utils.GetSupportPoint(Normal, ClippedPolygon); Vector Min = Utils.GetSupportPoint(Normal * -1, ClippedPolygon); Vector PenetrationVector = Max - Min; float Penertration = Mathf.Abs(Vector.Dot(PenetrationVector, Normal)); //Find points in polygon that are in the reference face Vector v1 = A.GetVertices()[FaceA]; int nextIndex = FaceA + 1 >= A.GetVertices().Length ? 0 : FaceA + 1; Vector v2 = A.GetVertices()[nextIndex]; //Console.WriteLine("V1 " + v1); // Console.WriteLine("V2 : " + v2); Vector faceDirection = v2 - v1; //Console.WriteLine("START "); //PointInFace.RemoveRange(2, PointInFace.Count - 2); List <Vector> ContactPoint = new List <Vector>(); foreach (Vector Point in ClippedPolygon) { //Console.WriteLine("Point " + Point); if (Point.IsEqualTo(v1, 0.01f) || Point.IsEqualTo(v2, 0.01f)) { //Console.WriteLine("Inline v1/v2"); continue; } float Distance = DistancePointToLine(v2, v1, Point); //Console.WriteLine("DIst " + Distance); if (Distance > 0) { ContactPoint.Add(Point); } } if (ContactPoint.Count >= 2) { if (ContactPoint[0].IsEqualTo(ContactPoint[1], 0.01f)) { ContactPoint.RemoveAt(1); } } Penertration /= ContactPoint.Count; if (flip) { Normal = -1 * Normal; } Result.A = A; Result.B = B; Result.PenetrationDepth = Penertration; Result.Normal = Normal; Result.ContactPoint = ContactPoint; //Console.WriteLine("POF C" + ContactPoint.Count); Result.IsEmpty = false; return(Result); }
/// <summary> /// Given a PolygonEntitiy and a Circle Entity, generates a manifold containing the information required to /// resolve the collision (if there was one to begin with). /// </summary> public static Manifold GenerateManifold(PolygonEntity poly, CircleEntity circle) { Manifold Result; Result.A = poly; Result.B = circle; Result.IsEmpty = false; Result.ContactPoint = new List <Vector>(); Vector relativeCirclePos = circle.position - poly.position; float seperation = -10000; int face = -1234; for (int i = 0; i < poly.GetVertices().Length; i++) { //get the normal Vector normal = poly.GetFaceNormal(i).Normalized(); Vector circleToPoint = relativeCirclePos - poly.GetLocalSpaceVertices()[i]; //dot the normal with the circle position float currentSeperation = Vector.Dot(normal, circleToPoint); //if result of dot is bigger than radius if (currentSeperation > circle.Radius) { return(GenerateEmptyManifold()); } //return //if its bigger than stored penetration if (currentSeperation > seperation) { face = i; seperation = currentSeperation; } } Vector v1 = poly.GetVertices()[face]; int secondIndex = face + 1 >= poly.GetVertices().Length ? 0 : face + 1; Vector v2 = poly.GetVertices()[secondIndex]; //if point is inside polygon if (seperation < EPSILON) { //normal is negative face normal Result.Normal = poly.GetFaceNormal(face).Normalized() * -1f; Result.PenetrationDepth = circle.Radius; Result.ContactPoint.Add(Result.Normal * circle.Radius + circle.position); //penetration depth is radius //contact point is -normal*radius + position } //determine which voronoi region the circle lies in //dot with first point float v1Dot = Vector.Dot(circle.position - v1, v2 - v1); float v2Dot = Vector.Dot(circle.position - v2, v1 - v2); Result.PenetrationDepth = circle.Radius - seperation; //dot with second point //penetration depth is radius-seperation //if dot with first point is negative if (v1Dot <= 0) { if (Mathf.DistanceSquared(v1.x, v1.y, circle.position.x, circle.position.y) > circle.Radius * circle.Radius) { return(GenerateEmptyManifold()); } Result.Normal = (v1 - poly.position).Normalized(); Result.ContactPoint.Add(v1); //normal is point-center //contact point is point } else if (v2Dot <= 0) { if (Mathf.DistanceSquared(v2.x, v2.y, circle.position.x, circle.position.y) > circle.Radius * circle.Radius) { return(GenerateEmptyManifold()); } Result.Normal = (v2 - poly.position).Normalized(); Result.ContactPoint.Add(v2); } else { Result.Normal = poly.GetFaceNormal(face).Normalized(); Result.ContactPoint.Add(Result.Normal * circle.Radius + circle.position); } return(Result); }
public override bool CheckCollision(PolygonEntity other) { return(CollisionDetection.DetectBoundingVolumeCollision(this, other));; }
public override Manifold GenerateManifold(PolygonEntity other) { return(CollisionResolution.GenerateManifold(other, this)); }
public abstract Manifold GenerateManifold(PolygonEntity other);
public abstract bool CheckCollision(PolygonEntity other);