/// <summary> Gets the closest point to a given point on the indefinately extended line.
        /// TODO: Move this somewhere in math package
        /// 
        /// </summary>
        /// <param name="startA">Starting point of the line
        /// </param>
        /// <param name="endA">End point of the line
        /// </param>
        /// <param name="point">The point to get a closes point on the line for
        /// </param>
        /// <returns> the closest point on the line or null if the lines are parallel
        /// </returns>
        public static Vector2f GetClosestPoint(Vector2f startA, Vector2f endA, Vector2f point)
        {
            Vector2f startB = point;
            Vector2f endB = new Vector2f(endA);
            endB.Sub(startA);
            endB.Reconfigure(endB.y, - endB.x);

            float d = endB.y * (endA.x - startA.x);
            d -= endB.x * (endA.y - startA.y);

            if (d == 0)
                return null;

            float uA = endB.x * (startA.y - startB.Y);
            uA -= endB.y * (startA.x - startB.X);
            uA /= d;

            return new Vector2f(startA.x + uA * (endA.x - startA.x), startA.y + uA * (endA.y - startA.y));
        }
        /// <seealso cref="Silver.Weight.Raw.Collide.Collider.Collide(Silver.Weight.Raw.Contact[], Silver.Weight.Raw.Body, Silver.Weight.Raw.Body)">
        /// </seealso>
        public override int Collide(Contact[] contacts, Body bodyA, Body bodyB)
        {
            Line line = (Line) bodyA.Shape;
            Polygon poly = (Polygon) bodyB.Shape;

            // TODO: this can be optimized using matrix multiplications and moving only one shape
            // specifically the line, because it has only two vertices
            Vector2f[] vertsA = line.getVertices(bodyA.GetPosition(), bodyA.Rotation);
            Vector2f[] vertsB = poly.GetVertices(bodyB.GetPosition(), bodyB.Rotation);

            Vector2f pos = poly.GetCentroid(bodyB.GetPosition(), bodyB.Rotation);

            // using the z axis of a 3d Cross product we determine on what side B is
            bool isLeftOf = 0 > (pos.x - vertsA[0].x) * (vertsA[1].y - vertsA[0].y) - (vertsA[1].x - vertsA[0].x) * (pos.y - vertsA[0].y);

            // to get the proper intersection pairs we make sure
            // the line's normal is pointing towards the polygon
            // TODO: verify that it's not actually pointing in the opposite direction
            if (isLeftOf)
            {
                Vector2f tmp = vertsA[0];
                vertsA[0] = vertsA[1];
                vertsA[1] = tmp;
            }

            // we use the line's normal for our sweepline projection
            Vector2f normal = new Vector2f(vertsA[1]);
            normal.Sub(vertsA[0]);
            normal.Reconfigure(normal.y, - normal.x);
            EdgeSweep sweep = new EdgeSweep(normal);
            sweep.Insert(0, true, vertsA[0].Dot(normal));
            sweep.Insert(0, true, vertsA[1].Dot(normal));
            sweep.AddVerticesToSweep(false, vertsB);
            int[][] collEdgeCands = sweep.OverlappingEdges;

            IntersectionGatherer intGath = new IntersectionGatherer(vertsA, vertsB);
            for (int i = 0; i < collEdgeCands.Length; i++)
                intGath.Intersect(collEdgeCands[i][0], collEdgeCands[i][1]);

            Intersection[] intersections = intGath.Intersections;

            return PopulateContacts(contacts, vertsA, vertsB, intersections);
        }
示例#3
0
        /// <summary> Get the closest point on the line to a given point
        /// 
        /// </summary>
        /// <param name="point">The point which we want to project
        /// </param>
        /// <param name="result">The point on the line closest to the given point
        /// </param>
        public virtual void getClosestPoint(ROVector2f point, Vector2f result)
        {
            loc.Reconfigure(point);
            loc.Sub(start);

            v.Reconfigure(vec);
            v2.Reconfigure(vec);
            v2.Scale(- 1);

            v.Normalise();
            loc.ProjectOntoUnit(v, proj);
            if (proj.LengthSquared() > vec.LengthSquared())
            {
                result.Reconfigure(end);
                return ;
            }
            proj.Add(start);

            other.Reconfigure(proj);
            other.Sub(end);
            if (other.LengthSquared() > vec.LengthSquared())
            {
                result.Reconfigure(start);
                return ;
            }

            result.Reconfigure(proj);
            return ;
        }
示例#4
0
        //    private static Vector2f r1 = new Vector2f();
        //    private static Vector2f r2 = new Vector2f();
        //    private static Vector2f relativeVelocity = new Vector2f();
        //    private static Vector2f impulse = new Vector2f();
        //    private static Vector2f Pb = new Vector2f();
        //    private static Vector2f tmp = new Vector2f();
        //    
        //    /**
        //     * Apply the impulse accumlated at the contact points maintained
        //     * by this arbiter.
        //     */
        //    void ApplyImpulse() {
        //        Body b1 = body1;
        //        Body b2 = body2;
        //        
        //        for (int i = 0; i < numContacts; ++i)
        //        {
        //            Contact c = contacts[i];
        //            
        //            r1.set(c.position);
        //            r1.Sub(b1.GetPosition());
        //            r2.set(c.position);
        //            r2.Sub(b2.GetPosition());
        //
        //            // Relative velocity at contact
        //            relativeVelocity.set(b2.getVelocity());
        //            relativeVelocity.Add(MathUtil.Cross(b2.getAngularVelocity(), r2));
        //            relativeVelocity.Sub(b1.getVelocity());
        //            relativeVelocity.Sub(MathUtil.Cross(b1.getAngularVelocity(), r1));
        //            
        //            // Compute normal impulse with bias.
        //            float vn = relativeVelocity.Dot(c.normal);
        //            
        //            // bias caculations are now handled seperately hence we only
        //            // handle the real impulse caculations here
        //            //float normalImpulse = c.massNormal * ((c.restitution - vn) + c.bias);
        //            float normalImpulse = c.massNormal * (c.restitution - vn);
        //            
        //            // Clamp the accumulated impulse
        //            float oldNormalImpulse = c.accumulatedNormalImpulse;
        //            c.accumulatedNormalImpulse = Math.max(oldNormalImpulse + normalImpulse, 0.0f);
        //            normalImpulse = c.accumulatedNormalImpulse - oldNormalImpulse;
        //            
        //            if (normalImpulse != 0) {
        //                // Apply contact impulse
        //                impulse.set(c.normal);
        //                impulse.Scale(normalImpulse);
        //                
        //                tmp.set(impulse);
        //                tmp.Scale(-b1.getInvMass());
        //                b1.AdjustVelocity(tmp);
        //                b1.AdjustAngularVelocity(-(b1.getInvI() * MathUtil.Cross(r1, impulse)));
        //    
        //                tmp.set(impulse);
        //                tmp.Scale(b2.getInvMass());
        //                b2.AdjustVelocity(tmp);
        //                b2.AdjustAngularVelocity(b2.getInvI() * MathUtil.Cross(r2, impulse));
        //            }
        //            
        //            // Compute bias impulse
        //            // NEW STUFF FOR SEPERATING BIAS
        //            relativeVelocity.set(b2.getBiasedVelocity());
        //            relativeVelocity.Add(MathUtil.Cross(b2.getBiasedAngularVelocity(), r2));
        //            relativeVelocity.Sub(b1.getBiasedVelocity());
        //            relativeVelocity.Sub(MathUtil.Cross(b1.getBiasedAngularVelocity(), r1));
        //            float vnb = relativeVelocity.Dot(c.normal);
        //
        //            float biasImpulse = c.massNormal * (-vnb + c.bias);
        //            float oldBiasImpulse = c.biasImpulse;
        //            c.biasImpulse = Math.max(oldBiasImpulse + biasImpulse, 0.0f);
        //            biasImpulse = c.biasImpulse - oldBiasImpulse;
        //
        //            if (biasImpulse != 0) {
        //                Pb.set(c.normal);
        //                Pb.Scale(biasImpulse);
        //                
        //                tmp.set(Pb);
        //                tmp.Scale(-b1.getInvMass());
        //                b1.AdjustBiasedVelocity(tmp);
        //                b1.AdjustBiasedAngularVelocity(-(b1.getInvI() * MathUtil.Cross(r1, Pb)));
        //    
        //                tmp.set(Pb);
        //                tmp.Scale(b2.getInvMass());
        //                b2.AdjustBiasedVelocity(tmp);
        //                b2.AdjustBiasedAngularVelocity((b2.getInvI() * MathUtil.Cross(r2, Pb)));
        //            }
        //            // END NEW STUFF
        //            
        //            //
        //            // Compute friction (tangent) impulse
        //            //
        //            float maxTangentImpulse = friction * c.accumulatedNormalImpulse;
        //
        //            // Relative velocity at contact
        //            relativeVelocity.set(b2.getVelocity());
        //            relativeVelocity.Add(MathUtil.Cross(b2.getAngularVelocity(), r2));
        //            relativeVelocity.Sub(b1.getVelocity());
        //            relativeVelocity.Sub(MathUtil.Cross(b1.getAngularVelocity(), r1));
        //            
        //            Vector2f tangent = MathUtil.Cross(c.normal, 1.0f);
        //            float vt = relativeVelocity.Dot(tangent);
        //            float tangentImpulse = c.massTangent * (-vt);
        //
        //            // Clamp friction
        //            float oldTangentImpulse = c.accumulatedTangentImpulse;
        //            c.accumulatedTangentImpulse = MathUtil.Clamp(oldTangentImpulse + tangentImpulse, -maxTangentImpulse, maxTangentImpulse);
        //            tangentImpulse = c.accumulatedTangentImpulse - oldTangentImpulse;
        //
        //            // Apply contact impulse
        //            if ((tangentImpulse > 0.1f) || (tangentImpulse < -0.1f)) {
        //                impulse = MathUtil.Scale(tangent, tangentImpulse);
        //    
        //                tmp.set(impulse);
        //                tmp.Scale(-b1.getInvMass());
        //                b1.AdjustVelocity(tmp);
        //                b1.AdjustAngularVelocity(-b1.getInvI() * MathUtil.Cross(r1, impulse));
        //    
        //                tmp.set(impulse);
        //                tmp.Scale(b2.getInvMass());
        //                b2.AdjustVelocity(tmp);
        //                b2.AdjustAngularVelocity(b2.getInvI() * MathUtil.Cross(r2, impulse));
        //            }
        //        }
        //    }
        /// <summary> Apply the impulse accumlated at the contact points maintained
        /// by this arbiter.
        /// </summary>
        internal virtual void ApplyImpulse()
        {
            Body b1 = body1;
            Body b2 = body2;

            for (int i = 0; i < numContacts; ++i)
            {
                Contact c = contacts[i];

                Vector2f r1 = new Vector2f(c.position);
                r1.Sub(b1.GetPosition());
                Vector2f r2 = new Vector2f(c.position);
                r2.Sub(b2.GetPosition());

                // Relative velocity at contact
                Vector2f relativeVelocity = new Vector2f(b2.Velocity);
                relativeVelocity.Add(MathUtil.Cross(b2.AngularVelocity, r2));
                relativeVelocity.Sub(b1.Velocity);
                relativeVelocity.Sub(MathUtil.Cross(b1.AngularVelocity, r1));

                // Compute normal impulse with bias.
                float vn = relativeVelocity.Dot(c.normal);

                // bias caculations are now handled seperately hence we only
                // handle the real impulse caculations here
                //float normalImpulse = c.massNormal * ((c.restitution - vn) + c.bias);
                float normalImpulse = c.massNormal * (c.restitution - vn);

                // Clamp the accumulated impulse
                float oldNormalImpulse = c.accumulatedNormalImpulse;
                c.accumulatedNormalImpulse = System.Math.Max(oldNormalImpulse + normalImpulse, 0.0f);
                normalImpulse = c.accumulatedNormalImpulse - oldNormalImpulse;

                // Apply contact impulse
                Vector2f impulse = MathUtil.Scale(c.normal, normalImpulse);

                b1.AdjustVelocity(MathUtil.Scale(impulse, - b1.InvMass));
                b1.AdjustAngularVelocity(- (b1.InvI * MathUtil.Cross(r1, impulse)));

                b2.AdjustVelocity(MathUtil.Scale(impulse, b2.InvMass));
                b2.AdjustAngularVelocity(b2.InvI * MathUtil.Cross(r2, impulse));

                // Compute bias impulse
                // NEW STUFF FOR SEPERATING BIAS
                relativeVelocity.Reconfigure(b2.BiasedVelocity);
                relativeVelocity.Add(MathUtil.Cross(b2.BiasedAngularVelocity, r2));
                relativeVelocity.Sub(b1.BiasedVelocity);
                relativeVelocity.Sub(MathUtil.Cross(b1.BiasedAngularVelocity, r1));
                float vnb = relativeVelocity.Dot(c.normal);

                float biasImpulse = c.massNormal * (- vnb + c.bias);
                float oldBiasImpulse = c.biasImpulse;
                c.biasImpulse = System.Math.Max(oldBiasImpulse + biasImpulse, 0.0f);
                biasImpulse = c.biasImpulse - oldBiasImpulse;

                Vector2f Pb = MathUtil.Scale(c.normal, biasImpulse);

                b1.AdjustBiasedVelocity(MathUtil.Scale(Pb, - b1.InvMass));
                b1.AdjustBiasedAngularVelocity(- (b1.InvI * MathUtil.Cross(r1, Pb)));

                b2.AdjustBiasedVelocity(MathUtil.Scale(Pb, b2.InvMass));
                b2.AdjustBiasedAngularVelocity((b2.InvI * MathUtil.Cross(r2, Pb)));

                // END NEW STUFF

                //
                // Compute friction (tangent) impulse
                //
                float maxTangentImpulse = friction * c.accumulatedNormalImpulse;

                // Relative velocity at contact
                relativeVelocity.Reconfigure(b2.Velocity);
                relativeVelocity.Add(MathUtil.Cross(b2.AngularVelocity, r2));
                relativeVelocity.Sub(b1.Velocity);
                relativeVelocity.Sub(MathUtil.Cross(b1.AngularVelocity, r1));

                Vector2f tangent = MathUtil.Cross(c.normal, 1.0f);
                float vt = relativeVelocity.Dot(tangent);
                float tangentImpulse = c.massTangent * (- vt);

                // Clamp friction
                float oldTangentImpulse = c.accumulatedTangentImpulse;
                c.accumulatedTangentImpulse = MathUtil.Clamp(oldTangentImpulse + tangentImpulse, - maxTangentImpulse, maxTangentImpulse);
                tangentImpulse = c.accumulatedTangentImpulse - oldTangentImpulse;

                // Apply contact impulse
                impulse = MathUtil.Scale(tangent, tangentImpulse);

                b1.AdjustVelocity(MathUtil.Scale(impulse, - b1.InvMass));
                b1.AdjustAngularVelocity((- b1.InvI) * MathUtil.Cross(r1, impulse));

                b2.AdjustVelocity(MathUtil.Scale(impulse, b2.InvMass));
                b2.AdjustAngularVelocity(b2.InvI * MathUtil.Cross(r2, impulse));
            }
        }
        /// <seealso cref="Silver.Weight.Raw.Collide.Collider.Collide(Silver.Weight.Raw.Contact[], Silver.Weight.Raw.Body, Silver.Weight.Raw.Body)">
        /// </seealso>
        public virtual int Collide(Contact[] contacts, Body bodyA, Body bodyB)
        {
            Line line = (Line) bodyA.Shape;
            Circle circle = (Circle) bodyB.Shape;

            Vector2f[] vertsA = line.getVertices(bodyA.GetPosition(), bodyA.Rotation);

            // compute intersection of the line A and a line parallel to
            // the line A's normal passing through the origin of B
            Vector2f startA = vertsA[0];
            Vector2f endA = vertsA[1];
            ROVector2f startB = bodyB.GetPosition();
            Vector2f endB = new Vector2f(endA);
            endB.Sub(startA);
            endB.Reconfigure(endB.y, - endB.x);
            //		endB.Add(startB);// TODO: inline endB into equations below, this last operation will be useless..

            //TODO: reuse mathutil.Intersect
            //		float d = (endB.y - startB.getY()) * (endA.x - startA.x);
            //		d -= (endB.x - startB.getX()) * (endA.y - startA.y);
            //
            //		float uA = (endB.x - startB.getX()) * (startA.y - startB.getY());
            //		uA -= (endB.y - startB.getY()) * (startA.x - startB.getX());
            //		uA /= d;
            float d = endB.y * (endA.x - startA.x);
            d -= endB.x * (endA.y - startA.y);

            float uA = endB.x * (startA.y - startB.Y);
            uA -= endB.y * (startA.x - startB.X);
            uA /= d;

            Vector2f position = null;

            if (uA < 0)
            {
                // the intersection is somewhere before startA
                position = startA;
            }
            else if (uA > 1)
            {
                // the intersection is somewhere after endA
                position = endA;
            }
            else
            {
                position = new Vector2f(startA.x + uA * (endA.x - startA.x), startA.y + uA * (endA.y - startA.y));
            }

            Vector2f normal = endB; // reuse of vector object
            normal.Reconfigure(startB);
            normal.Sub(position);
            float distSquared = normal.LengthSquared();
            float radiusSquared = circle.Radius * circle.Radius;

            if (distSquared < radiusSquared)
            {
                contacts[0].Position = position;
                contacts[0].Feature = new FeaturePair();

                normal.Normalise();
                contacts[0].Normal = normal;

                float separation = (float) System.Math.Sqrt(distSquared) - circle.Radius;
                contacts[0].Separation = separation;

                return 1;
            }

            return 0;
        }