Пример #1
0
        new void linearProgram3(IList <Line> lines, int numObstLines, int beginLine, float radius, ref Vector2 result)
        {
            float distance = 0.0f;

            for (int i = beginLine; i < lines.Count; ++i)
            {
                if ((float)Math.Round(Vector2.det(lines[i].direction, lines[i].point - result), 3) > distance)
                {
                    /* Result does not satisfy constraint of line i. */
                    IList <Line> projLines = new List <Line>();
                    for (int k = 0; k < numObstLines; ++k)
                    {
                        projLines.Add(lines[k]);
                    }


                    for (int j = numObstLines; j < i; ++j)
                    {
                        Line line;

                        float determinant = Vector2.det(lines[i].direction, lines[j].direction);

                        if (Math.Abs(determinant) <= RVO_EPSILON)
                        {
                            /* Line i and line j are parallel. */
                            if (lines[i].direction * lines[j].direction > 0.0f)
                            {
                                /* Line i and line j point in the same direction. */
                                continue;
                            }
                            else
                            {
                                /* Line i and line j point in opposite direction. */
                                line.point = 0.5f * (lines[i].point + lines[j].point);
                            }
                        }
                        else
                        {
                            line.point = lines[i].point + (Vector2.det(lines[j].direction, lines[i].point - lines[j].point) / determinant) * lines[i].direction;
                        }

                        line.direction = Vector2.normalize(lines[j].direction - lines[i].direction);
                        projLines.Add(line);
                    }

                    Vector2 tempResult = result;
                    if (linearProgram2(projLines, radius, new Vector2(-lines[i].direction.y(), lines[i].direction.x()), true, ref result) < projLines.Count)
                    {
                        /* This should in principle not happen.  The result is by definition
                         * already in the feasible region of this linear program. If it fails,
                         * it is due to small floating point error, and the current result is
                         * kept.
                         */
                        result = tempResult;
                    }

                    distance = Vector2.det(lines[i].direction, lines[i].point - result);
                }
            }
        }
Пример #2
0
        public override void interactWith(SuperAgent agent)
        {
            Vector2 relative_position = agent.position_ - agent.position_;
            // w_phi enables to deal with elliptical forces
            float w_phi = 1;
            float test  = ((HelbingAgent)(agent)).motion_dir_ * Vector2.normalize(-relative_position);
            float test2 = ((1 + motion_dir_ * Vector2.normalize(-relative_position)) / 2);
            float A     = A_;

            if (id_ == 0)
            {
                A = A_ * 5;
            }
            if (type_ == 1)
            {
                //w_phi = lambda_ + (1 - lambda_)*((1+motion_dir_*normalize(-relative_position))/2);
                w_phi = (float)Math.Pow(test + 1, lambda_) / (float)Math.Pow(2f, lambda_);
            }
            // Compute force
            float   radius_m_dist = radius_ + agent.radius_ - Vector2.abs(relative_position);
            float   exp_term      = (radius_m_dist) / B_;
            Vector2 force         = w_phi * A * (float)Math.Exp(exp_term) * Vector2.normalize(relative_position);

            // Body force
            if (radius_m_dist > 0)
            {
                force += k_ * radius_m_dist * Vector2.normalize(relative_position);
            }
            acceleration_ += force;
        }
Пример #3
0
        public override void interactWith(Obstacle obstacle)
        {
            // Get vertex
            Obstacle obstacle2 = obstacle.next_;
            // Distance to the vertex
            Vector2 vector2Vertex = Vector2.vectorToSegment(obstacle.point_, obstacle2.point_, position_);
            // w_phi enables to deal with elliptical forces
            float w_phi = 1;
            float test  = motion_dir_ * Vector2.normalize(vector2Vertex);

            if (type_ == 1)
            {
                //w_phi = lambda_ + (1 - lambda_)*(1+motion_dir_*normalize(vector2Vertex)/2);
                w_phi = (float)(Math.Pow(test + 1, lambda_) / Math.Pow(2, lambda_));
            }
            // Compute force
            float   exp_term = (radius_ - Vector2.abs(vector2Vertex)) / B_;
            Vector2 force    = w_phi * A_ * (float)Math.Exp(exp_term) * -1 * Vector2.normalize(vector2Vertex) / m_;

            // Body force
            if (Vector2.abs(vector2Vertex) < radius_)
            {
                force += k_ * (radius_ - Vector2.abs(vector2Vertex)) * -1 * Vector2.normalize(vector2Vertex) / m_;
            }
            acceleration_ += force;
        }
Пример #4
0
        internal Pair <Vector2, Vector2> computeTangentsPoints(Agent observer, Agent agent)
        {
            // First element of the pair = left tangent
            // Second element of the pair = right tangent
            Pair <Vector2, Vector2> toReturn = new Pair <Vector2, Vector2>();
            Vector2 centers = agent.position_ - observer.position_;
            Vector2 r1a     = Vector2.normalize(Vector2.rotation(centers, (float)-Math.PI / 2)) * observer.radius_;
            Vector2 r1b     = Vector2.normalize(Vector2.rotation(centers, (float)Math.PI / 2)) * observer.radius_;
            // Compute intersection points between radius and circle
            // Right one
            Vector2 h1a = observer.position_ + r1a;
            // Left one
            Vector2 h1b = observer.position_ + r1b;

            // If the radius is the same, tangents points are perpendicular to centers vector
            if (Math.Abs(observer.radius_ - agent.radius_) < RVO_EPSILON)
            {
                toReturn.First  = h1a;
                toReturn.Second = h1b;
            }
            else
            {
                Vector2 r2a = Vector2.normalize(Vector2.rotation(centers, (float)-Math.PI / 2)) * agent.radius_;
                Vector2 r2b = Vector2.normalize(Vector2.rotation(centers, (float)Math.PI / 2)) * agent.radius_;
                Vector2 h2a = agent.position_ + r2a;
                Vector2 h2b = agent.position_ + r2b;
                // If tangents are parallel, radius are the same, i.e. there is no intersection point.
                if (Math.Abs(Vector2.det(h1a - h2a, h1b - h2b)) < RVO_EPSILON)
                {
                    Console.Write("Problem while computing tangent points\n SHALL NOT HAPPEN !!! \n");
                    toReturn.First  = h1a;
                    toReturn.Second = h1b;
                }
                else
                {
                    Vector2 intersectionPoint = Vector2.intersectOf2Lines(h1a, h2a, h1b, h2b);
                    // Equivalent to :
                    Vector2 circleCenter = (intersectionPoint + observer.position_) / 2;
                    toReturn = Vector2.intersectOf2Circles(circleCenter, Vector2.abs(circleCenter - observer.position_), observer.position_, observer.radius_);
                    // Test angles to know which one is right &  which one is left
                    if (Vector2.isOnTheLeftSide(toReturn.First - observer.position_, centers))
                    {
                        Vector2 temp = toReturn.First;
                        toReturn.First  = toReturn.Second;
                        toReturn.Second = temp;
                    }
                }
            }
            return(toReturn);
        }
Пример #5
0
        public int addObstacle(IList <Vector2> vertices)
        {
            if (vertices.Count < 2)
            {
                return(RVO_ERROR);
            }

            int obstacleNo = obstacles_.Count;

            for (int i = 0; i < vertices.Count; ++i)
            {
                Obstacle obstacle = new Obstacle();
                obstacle.point_ = vertices[i];
                if (i > 0)
                {
                    obstacle.previous_       = obstacles_[obstacleNo - 1];
                    obstacle.previous_.next_ = obstacle;
                }
                if (i == vertices.Count - 1)
                {
                    obstacle.next_           = obstacles_[obstacleNo - 1];
                    obstacle.next_.previous_ = obstacle;
                }
                obstacle.direction_ = Vector2.normalize(vertices[(i == vertices.Count - 1 ? 0 : i + 1)] - vertices[i]);

                if (vertices.Count == 2)
                {
                    obstacle.convex_ = true;
                }
                else
                {
                    obstacle.convex_ = (RVOMath.leftOf(vertices[(i == 0 ? vertices.Count - 1 : i - 1)], vertices[(i == vertices.Count - 1 ? 0 : i + 1)], vertices[i]) >= 0);
                }                                    // TO DO - Fix leftOf(dunno what is do)

                obstacle.id_ = obstacles_.Count;


                obstacles_.Add(obstacle);
                obstacleNo = obstacles_.Count;
            }

            return(obstacleNo);
        }
Пример #6
0
        public override void computeNewVelocity()
        {
            acceleration_ = new Vector2(0, 0);

            // Compute goal's force
            Vector2 toto       = Vector2.normalize(goal_ - position_);
            Vector2 toto2      = Vector2.normalize(goal_ - position_) - velocity_;
            Vector2 goal_force = (maxSpeed_ * Vector2.normalize(goal_ - position_) - velocity_) / tau_;

            acceleration_ = goal_force;

            // Direction of motion
            if (velocity_ != new Vector2(0, 0))
            {
                motion_dir_ = Vector2.normalize(velocity_);
            }
            else
            {
                motion_dir_ = Vector2.normalize(goal_ - position_);
            }

            // Compute obstacles' forces
            for (int i = 0; i < obstacleNeighbors_.Count; ++i)
            {
                interactWith(obstacleNeighbors_[i].Value);
            }

            // Compute neighbors' forces
            interactWithAgents();

            // Limit acceleration
            if (Vector2.abs(acceleration_) > 5)
            {
                acceleration_ = 5 * Vector2.normalize(acceleration_);
            }

            newVelocity_ = velocity_ + acceleration_ * sim_.getTimeStep();

            if (Vector2.abs(newVelocity_) > maxSpeed_)
            {
                newVelocity_ = Vector2.normalize(newVelocity_) * maxSpeed_;
            }
        }
Пример #7
0
        new int linearProgram2(IList <Line> lines, float radius, Vector2 optVelocity, bool directionOpt, ref Vector2 result)
        {
            if (!directionOpt)
            {
                /*
                 * Optimize direction. Note that the optimization velocity is of unit
                 * length in this case.
                 */
                result = optVelocity * radius;
            }
            else if (Vector2.absSq(optVelocity) > Vector2.sqr(radius))
            {
                /* Optimize closest point and outside circle. */
                result = Vector2.normalize(optVelocity) * radius;
            }
            else
            {
                /* Optimize closest point and inside circle. */
                result = optVelocity;
            }



            for (int i = 0; i < lines.Count; ++i)
            {
                if (Vector2.det(lines[i].direction, lines[i].point - result) > 0.0f)
                {
                    /* Result does not satisfy constraint i. Compute new optimal result. */
                    Vector2 tempResult = result;
                    if (!linearProgram1(lines, i, radius, optVelocity, directionOpt, ref result))
                    {
                        result = tempResult;

                        return(i);
                    }
                }
            }

            return(lines.Count);
        }
Пример #8
0
        public override void interactWith(Obstacle obstacle)

        {
            Obstacle obstacle1 = obstacle;
            Obstacle obstacle2 = obstacle1.next_;

            Vector2 relativePosition1 = obstacle1.point_ - position_;
            Vector2 relativePosition2 = obstacle2.point_ - position_;

            /*
             * Check if velocity obstacle of obstacle is already taken care of by
             * previously constructed obstacle ORCA lines.
             */
            bool alreadyCovered = false;

            for (int j = 0; j < orcaLines_.Count; ++j)
            {
                if (Vector2.det((1.0f / timeHorizonObst_) * relativePosition1 - orcaLines_[j].point, orcaLines_[j].direction) - (1.0f / timeHorizonObst_) * radius_ >= -RVO_EPSILON &&
                    Vector2.det((1.0f / timeHorizonObst_) * relativePosition2 - orcaLines_[j].point, orcaLines_[j].direction) - (1.0f / timeHorizonObst_) * radius_ >= -RVO_EPSILON)
                {
                    alreadyCovered = true;
                    break;
                }
            }

            if (alreadyCovered)
            {
                return;
            }

            /* Not yet covered. Check for collisions. */

            float distSq1 = Vector2.absSq(relativePosition1);
            float distSq2 = Vector2.absSq(relativePosition2);

            float radiusSq = Vector2.sqr(radius_);

            Vector2 obstacleVector = obstacle2.point_ - obstacle1.point_;
            float   s          = (-relativePosition1 * obstacleVector) / Vector2.absSq(obstacleVector);
            float   distSqLine = Vector2.absSq(-relativePosition1 - s * obstacleVector);

            Line line;

            if (s < 0 && distSq1 <= radiusSq)
            {
                /* Collision with left vertex. Ignore if non-convex. */
                if (obstacle1.convex_)
                {
                    line.point     = new Vector2(0, 0);
                    line.direction = Vector2.normalize(new Vector2(-relativePosition1.y(), relativePosition1.x()));
                    orcaLines_.Add(line);
                }
                return;
            }
            else if (s > 1 && distSq2 <= radiusSq)
            {
                /* Collision with right vertex. Ignore if non-convex
                 * or if it will be taken care of by neighoring obstace */
                if (obstacle2.convex_ && Vector2.det(relativePosition2, obstacle2.direction_) >= 0)
                {
                    line.point     = new Vector2(0, 0);
                    line.direction = Vector2.normalize(new Vector2(-relativePosition2.y(), relativePosition2.x()));
                    orcaLines_.Add(line);
                }
                return;
            }
            else if (s >= 0 && s < 1 && distSqLine <= radiusSq)
            {
                /* Collision with obstacle segment. */
                line.point     = new Vector2(0, 0);
                line.direction = -obstacle1.direction_;
                orcaLines_.Add(line);
                return;
            }

            /*
             * No collision.
             * Compute legs. When obliquely viewed, both legs can come from a single
             * vertex. Legs extend cut-off line when nonconvex vertex.
             */

            Vector2 leftLegDirection, rightLegDirection;

            if (s < 0 && distSqLine <= radiusSq)
            {
                /*
                 * Obstacle viewed obliquely so that left vertex
                 * defines velocity obstacle.
                 */
                if (!obstacle1.convex_)
                {
                    /* Ignore obstacle. */
                    return;
                }

                obstacle2 = obstacle1;

                float leg1 = (float)Math.Sqrt(distSq1 - radiusSq);
                leftLegDirection  = new Vector2(relativePosition1.x() * leg1 - relativePosition1.y() * radius_, relativePosition1.x() * radius_ + relativePosition1.y() * leg1) / distSq1;
                rightLegDirection = new Vector2(relativePosition1.x() * leg1 + relativePosition1.y() * radius_, -relativePosition1.x() * radius_ + relativePosition1.y() * leg1) / distSq1;
            }
            else if (s > 1 && distSqLine <= radiusSq)
            {
                /*
                 * Obstacle viewed obliquely so that
                 * right vertex defines velocity obstacle.
                 */
                if (!obstacle2.convex_)
                {
                    /* Ignore obstacle. */
                    return;
                }

                obstacle1 = obstacle2;

                float leg2 = (float)Math.Sqrt(distSq2 - radiusSq);
                leftLegDirection  = new Vector2(relativePosition2.x() * leg2 - relativePosition2.y() * radius_, relativePosition2.x() * radius_ + relativePosition2.y() * leg2) / distSq2;
                rightLegDirection = new Vector2(relativePosition2.x() * leg2 + relativePosition2.y() * radius_, -relativePosition2.x() * radius_ + relativePosition2.y() * leg2) / distSq2;
            }
            else
            {
                /* Usual situation. */
                if (obstacle1.convex_)
                {
                    float leg1 = (float)Math.Sqrt(distSq1 - radiusSq);
                    leftLegDirection = new Vector2(relativePosition1.x() * leg1 - relativePosition1.y() * radius_, relativePosition1.x() * radius_ + relativePosition1.y() * leg1) / distSq1;
                }
                else
                {
                    /* Left vertex non-convex; left leg extends cut-off line. */
                    leftLegDirection = -obstacle1.direction_;
                }

                if (obstacle2.convex_)
                {
                    float leg2 = (float)Math.Sqrt(distSq2 - radiusSq);
                    rightLegDirection = new Vector2(relativePosition2.x() * leg2 + relativePosition2.y() * radius_, -relativePosition2.x() * radius_ + relativePosition2.y() * leg2) / distSq2;
                }
                else
                {
                    /* Right vertex non-convex; right leg extends cut-off line. */
                    rightLegDirection = obstacle1.direction_;
                }
            }

            /*
             * Legs can never point into neighboring edge when convex vertex,
             * take cutoff-line of neighboring edge instead. If velocity projected on
             * "foreign" leg, no constraint is added.
             */

            Obstacle leftNeighbor = obstacle1.previous_;

            bool isLeftLegForeign  = false;
            bool isRightLegForeign = false;


            if (obstacle.convex_ && Vector2.det(leftLegDirection, -leftNeighbor.direction_) >= 0.0f)
            {
                /* Left leg points into obstacle. */
                leftLegDirection = -leftNeighbor.direction_;
                isLeftLegForeign = true;
            }

            if (obstacle2.convex_ && Vector2.det(rightLegDirection, obstacle2.direction_) <= 0.0f)
            {
                /* Right leg points into obstacle. */
                rightLegDirection = obstacle2.direction_;
                isRightLegForeign = true;
            }

            /* Compute cut-off centers. */
            Vector2 leftCutoff  = (1.0f / timeHorizonObst_) * (obstacle1.point_ - position_);
            Vector2 rightCutoff = (1.0f / timeHorizonObst_) * (obstacle2.point_ - position_);
            Vector2 cutoffVec   = rightCutoff - leftCutoff;

            /* Project current velocity on velocity obstacle. */

            /* Check if current velocity is projected on cutoff circles. */
            float t      = (obstacle1 == obstacle2 ? 0.5f : ((velocity_ - leftCutoff) * cutoffVec) / Vector2.absSq(cutoffVec));
            float tLeft  = ((velocity_ - leftCutoff) * leftLegDirection);
            float tRight = ((velocity_ - rightCutoff) * rightLegDirection);

            if ((t < 0.0f && tLeft < 0.0f) || (obstacle1 == obstacle2 && tLeft < 0.0f && tRight < 0.0f))
            {
                /* Project on left cut-off circle. */
                Vector2 unitW = Vector2.normalize(velocity_ - leftCutoff);

                line.direction = new Vector2(unitW.y(), -unitW.x());
                line.point     = leftCutoff + radius_ * (1.0f / timeHorizonObst_) * unitW;
                orcaLines_.Add(line);
                return;
            }
            else if (t > 1.0f && tRight < 0.0f)
            {
                /* Project on right cut-off circle. */
                Vector2 unitW = Vector2.normalize(velocity_ - rightCutoff);

                line.direction = new Vector2(unitW.y(), -unitW.x());
                line.point     = rightCutoff + radius_ * (1.0f / timeHorizonObst_) * unitW;
                orcaLines_.Add(line);
                return;
            }

            /*
             * Project on left leg, right leg, or cut-off line, whichever is closest
             * to velocity.
             */
            float distSqCutoff = ((t <0.0f || t> 1.0f || obstacle1 == obstacle2) ? Single.PositiveInfinity : Vector2.absSq(velocity_ - (leftCutoff + t * cutoffVec)));
            float distSqLeft   = ((tLeft < 0.0f) ? Single.PositiveInfinity : Vector2.absSq(velocity_ - (leftCutoff + tLeft * leftLegDirection)));
            float distSqRight  = ((tRight < 0.0f) ? Single.PositiveInfinity : Vector2.absSq(velocity_ - (rightCutoff + tRight * rightLegDirection)));

            if (distSqCutoff <= distSqLeft && distSqCutoff <= distSqRight)
            {
                /* Project on cut-off line. */
                line.direction = -obstacle1.direction_;
                line.point     = leftCutoff + radius_ * (1.0f / timeHorizonObst_) * new Vector2(-line.direction.y(), line.direction.x());
                orcaLines_.Add(line);
                return;
            }
            else if (distSqLeft <= distSqRight)
            {
                /* Project on left leg. */
                if (isLeftLegForeign)
                {
                    return;
                }

                line.direction = leftLegDirection;
                line.point     = leftCutoff + radius_ * (1.0f / timeHorizonObst_) * new Vector2(-line.direction.y(), line.direction.x());
                orcaLines_.Add(line);
                return;
            }
            else
            {
                /* Project on right leg. */
                if (isRightLegForeign)
                {
                    return;
                }

                line.direction = -rightLegDirection;
                line.point     = rightCutoff + radius_ * (1.0f / timeHorizonObst_) * new Vector2(-line.direction.y(), line.direction.x());
                orcaLines_.Add(line);
                return;
            }
        }
Пример #9
0
        internal SuperAgent representGroup(Agent observer)
        {
            // Compute the left & right tangent points obtained for each agent of the group
            // First element of the pair = right tangent
            // Second element of the pair = left tangent
            IList <Pair <Vector2, Vector2> > tangents = new List <Pair <Vector2, Vector2> >();
            IList <Pair <Vector2, Vector2> > radii    = new List <Pair <Vector2, Vector2> >();

            for (int i = 0; i < agents_.Count; i++)
            {
                tangents.Add(computeTangentsPoints(observer, agents_[i]));
                Pair <Vector2, Vector2> rads = new Pair <Vector2, Vector2>();
                rads.First  = tangents[i].First - observer.position_;
                rads.Second = tangents[i].Second - observer.position_;
                radii.Add(rads);
            }
            // Compute the group tangent points (extrema)
            int rightExtremumId = 0;
            int leftExtremumId  = 0;

            for (int i = 1; i < tangents.Count; i++)
            {
                // Comparison
                if (Vector2.isOnTheLeftSide(radii[rightExtremumId].First, radii[i].First))
                {
                    rightExtremumId = i;
                }
                if (Vector2.isOnTheLeftSide(radii[i].Second, radii[leftExtremumId].Second))
                {
                    leftExtremumId = i;
                }
            }
            // If the tangent are taking more than 180°, cannot be considered as a group
            for (int i = 0; i < agents_.Count; i++)
            {
                if (Vector2.isOnTheLeftSide(radii[rightExtremumId].First, radii[i].First))
                {
                    //std::cout << "Problem representing groups : tangent angle > 180°\n";
                    return(new SuperAgent(null));
                }
                if (Vector2.isOnTheLeftSide(radii[i].Second, radii[leftExtremumId].Second))
                {
                    //std::cout << "Problem representing groups : tangent angle > 180°\n";
                    return(new SuperAgent(null));
                }
            }
            // Compute bisector
            Vector2 rightTangent      = Vector2.rotation(radii[rightExtremumId].First, (float)Math.PI / 2);
            Vector2 leftTangent       = Vector2.rotation(radii[leftExtremumId].Second, -(float)Math.PI / 2);
            Vector2 intersectionPoint = Vector2.intersectOf2Lines(tangents[rightExtremumId].First, tangents[rightExtremumId].First + rightTangent,
                                                                  tangents[leftExtremumId].Second, tangents[leftExtremumId].Second + leftTangent);
            // alpha/2 is more usefull than alpha
            float alpha2 = Vector2.angle(Vector2.rotation(tangents[leftExtremumId].Second - intersectionPoint, -Vector2.angle(tangents[rightExtremumId].First - intersectionPoint))) / 2;

            if (alpha2 < 0)
            {
                //std::cout << "Problem representing groups : angle computation\n SHALL NOT HAPPEN !!! \n";
                // But if radii are different or if
                return(new SuperAgent(null));
            }
            Vector2 bisector_normalize_vector = Vector2.normalize(observer.position_ - intersectionPoint);
            // Compute circle
            // The distance between the observer and the circle (along the bisector axis)
            float d = Single.PositiveInfinity;
            float a, b, c, delta, x;
            int   constrainingAgent = 0;

            for (int i = 0; i < agents_.Count; i++)
            {
                Vector2 ic1 = agents_[i].position_ - intersectionPoint;
                a     = 1 - Vector2.sqr((float)Math.Sin(alpha2));
                b     = 2 * (agents_[i].radius_ * (float)Math.Sin(alpha2) - ic1 * bisector_normalize_vector);
                c     = Vector2.absSq(ic1) - Vector2.sqr(agents_[i].radius_);
                delta = Vector2.sqr(b) - 4 * a * c;
                if (delta <= 0)
                {
                    if (delta < -4 * RVO_EPSILON * c)
                    {
                        return(new SuperAgent(null));
                    }
                    else
                    {
                        delta = 0;
                    }
                }
                x = (-b + (float)Math.Sqrt(delta)) / (2 * a);
                if (x < d)
                {
                    d = x;
                    constrainingAgent = i;
                }
            }
            if (d < Vector2.abs(observer.position_ - intersectionPoint) + observer.radius_ + d * Math.Sin(alpha2))
            {
                return(new SuperAgent(null));
            }
            SuperAgent toReturn     = new SuperAgent(sim_);

            toReturn.position_ = intersectionPoint + bisector_normalize_vector * d;
            toReturn.radius_   = d * (float)Math.Sin(alpha2);
            toReturn.velocity_ = agents_[constrainingAgent].velocity_;
            return(toReturn);
        }