Contains functions and constants used in multiple classes. *
Пример #1
0
        private void acceleratedProgram(Vector2 velocity, ref Vector2 result)
        {
            //Debug.Log(velocity.ToString() + " " + result.ToString());
            float   speed      = RVOMath.abs(velocity);
            float   maxSpeed   = RVOMath.Min(speed + accelerated_, maxSpeed_);
            float   minSpeed   = RVOMath.Max(speed - accelerated_, 0.0f);
            Vector2 tempResult = result;

            //Debug.Log(speed);
            if (speed >= minSpeedToTurn_)
            {
                Vector2 leftVerticalVelocity  = new Vector2(-velocity.y_, velocity.x_);
                Vector2 rightVerticalVelocity = new Vector2(velocity.y_, -velocity.x_);
                leftVerticalVelocity  = RVOMath.normalize(leftVerticalVelocity) * speed * angularSpeed_;
                rightVerticalVelocity = RVOMath.normalize(rightVerticalVelocity) * speed * angularSpeed_;
                Vector2 leftMin      = RVOMath.normalize(velocity + leftVerticalVelocity) * minSpeed;
                Vector2 leftMax      = RVOMath.normalize(velocity + leftVerticalVelocity) * maxSpeed;
                Vector2 rightMin     = RVOMath.normalize(velocity + rightVerticalVelocity) * minSpeed;
                Vector2 rightMax     = RVOMath.normalize(velocity + rightVerticalVelocity) * maxSpeed;
                Vector2 leftVector2  = leftMax - leftMin;
                Vector2 rightVector2 = rightMax - rightMin;
                if (RVOMath.det(leftVector2, result) < 0.0f && RVOMath.det(rightVector2, result) > 0.0f) //middle
                {
                    float resultSpeed = RVOMath.abs(result);
                    if (resultSpeed > maxSpeed)
                    {
                        tempResult = RVOMath.normalize(result) * maxSpeed;
                    }
                    if (resultSpeed < minSpeed)
                    {
                        tempResult = RVOMath.normalize(result) * minSpeed;
                    }
                }
                else
                {
                    if (RVOMath.det(leftVector2, result) > 0.0f) //left
                    {
                        float r = ((result - leftMin) * (leftMax - leftMin)) / RVOMath.absSq(leftMax - leftMin);
                        if (id_ == 2)
                        {
                            Debug.Log(r);
                        }
                        if (r < 0.0f)
                        {
                            tempResult = RVOMath.normalize(leftVector2) * minSpeed;
                        }
                        if (r > 1.0f)
                        {
                            tempResult = RVOMath.normalize(leftVector2) * maxSpeed;
                        }
                        if (r >= 0.0f && r <= 1.0f)
                        {
                            float resultSpeed = RVOMath.absSq(result) - RVOMath.distSqPointLineSegment(leftMin, leftMax, result);
                            resultSpeed = RVOMath.sqrt(resultSpeed);
                            if (resultSpeed > maxSpeed)
                            {
                                tempResult = RVOMath.normalize(leftVector2) * maxSpeed;
                            }
                            if (resultSpeed < minSpeed)
                            {
                                tempResult = RVOMath.normalize(leftVector2) * minSpeed;
                            }
                            if (resultSpeed >= minSpeed && resultSpeed <= maxSpeed)
                            {
                                tempResult = RVOMath.normalize(leftVector2) * resultSpeed;
                            }
                        }
                    }
                    if (RVOMath.det(rightVector2, result) < 0.0f) //right
                    {
                        float r = ((result - rightMin) * (rightMax - rightMin)) / RVOMath.absSq(rightMax - rightMin);
                        if (r < 0.0f)
                        {
                            tempResult = RVOMath.normalize(rightVector2) * minSpeed;
                        }
                        if (r > 1.0f)
                        {
                            tempResult = RVOMath.normalize(rightVector2) * maxSpeed;
                        }
                        if (r >= 0.0f && r <= 1.0f)
                        {
                            float resultSpeed = RVOMath.absSq(result) - RVOMath.distSqPointLineSegment(rightMin, rightMax, result);
                            resultSpeed = RVOMath.sqrt(resultSpeed);
                            if (resultSpeed > maxSpeed)
                            {
                                tempResult = RVOMath.normalize(rightVector2) * maxSpeed;
                            }
                            if (resultSpeed < minSpeed)
                            {
                                tempResult = RVOMath.normalize(rightVector2) * minSpeed;
                            }
                            if (resultSpeed >= minSpeed && resultSpeed <= maxSpeed)
                            {
                                tempResult = RVOMath.normalize(rightVector2) * resultSpeed;
                            }
                        }
                    }
                }
            }
            else
            {
                float resultSpeed = RVOMath.abs(result);
                if (resultSpeed > maxSpeed)
                {
                    if (RVOMath.abs(velocity) < 1e-6f)
                    {
                        tempResult = RVOMath.normalize(prefVelocity_) * maxSpeed;
                    }
                    else
                    {
                        tempResult = RVOMath.normalize(velocity) * maxSpeed;
                    }
                }
                if (resultSpeed < minSpeed)
                {
                    tempResult = RVOMath.normalize(velocity) * minSpeed;
                }
            }
            result = tempResult;
        }
Пример #2
0
        /**
         * <summary>Computes the new velocity of this agent.</summary>
         */
        internal void computeNewVelocity()
        {
            orcaLines_.Clear();

            float invTimeHorizonObst = 1.0f / timeHorizonObst_;

            /* Create obstacle ORCA lines. */
            for (int i = 0; i < obstacleNeighbors_.Count; ++i)
            {
                Obstacle obstacle1 = obstacleNeighbors_[i].Value;
                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 (RVOMath.det(invTimeHorizonObst * relativePosition1 - orcaLines_[j].point, orcaLines_[j].direction) - invTimeHorizonObst * radius_ >= -RVOMath.RVO_EPSILON && RVOMath.det(invTimeHorizonObst * relativePosition2 - orcaLines_[j].point, orcaLines_[j].direction) - invTimeHorizonObst * radius_ >= -RVOMath.RVO_EPSILON)
                    {
                        alreadyCovered = true;

                        break;
                    }
                }

                if (alreadyCovered)
                {
                    continue;
                }

                /* Not yet covered. Check for collisions. */
                float distSq1 = RVOMath.absSq(relativePosition1);
                float distSq2 = RVOMath.absSq(relativePosition2);

                float radiusSq = RVOMath.sqr(radius_);

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

                Line line;

                if (s < 0.0f && distSq1 <= radiusSq)
                {
                    /* Collision with left vertex. Ignore if non-convex. */
                    if (obstacle1.convex_)
                    {
                        line.point     = new Vector2(0.0f, 0.0f);
                        line.direction = RVOMath.normalize(new Vector2(-relativePosition1.y(), relativePosition1.x()));
                        orcaLines_.Add(line);
                    }

                    continue;
                }
                else if (s > 1.0f && distSq2 <= radiusSq)
                {
                    /*
                     * Collision with right vertex. Ignore if non-convex or if
                     * it will be taken care of by neighboring obstacle.
                     */
                    if (obstacle2.convex_ && RVOMath.det(relativePosition2, obstacle2.direction_) >= 0.0f)
                    {
                        line.point     = new Vector2(0.0f, 0.0f);
                        line.direction = RVOMath.normalize(new Vector2(-relativePosition2.y(), relativePosition2.x()));
                        orcaLines_.Add(line);
                    }

                    continue;
                }
                else if (s >= 0.0f && s < 1.0f && distSqLine <= radiusSq)
                {
                    /* Collision with obstacle segment. */
                    line.point     = new Vector2(0.0f, 0.0f);
                    line.direction = -obstacle1.direction_;
                    orcaLines_.Add(line);

                    continue;
                }

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

                Vector2 leftLegDirection, rightLegDirection;

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

                    obstacle2 = obstacle1;

                    float leg1 = RVOMath.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.0f && distSqLine <= radiusSq)
                {
                    /*
                     * Obstacle viewed obliquely so that
                     * right vertex defines velocity obstacle.
                     */
                    if (!obstacle2.convex_)
                    {
                        /* Ignore obstacle. */
                        continue;
                    }

                    obstacle1 = obstacle2;

                    float leg2 = RVOMath.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 = RVOMath.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 = RVOMath.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 (obstacle1.convex_ && RVOMath.det(leftLegDirection, -leftNeighbor.direction_) >= 0.0f)
                {
                    /* Left leg points into obstacle. */
                    leftLegDirection = -leftNeighbor.direction_;
                    isLeftLegForeign = true;
                }

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

                /* Compute cut-off centers. */
                Vector2 leftCutOff   = invTimeHorizonObst * (obstacle1.point_ - position_);
                Vector2 rightCutOff  = invTimeHorizonObst * (obstacle2.point_ - position_);
                Vector2 cutOffVector = 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) * cutOffVector) / RVOMath.absSq(cutOffVector);
                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 = RVOMath.normalize(velocity_ - leftCutOff);

                    line.direction = new Vector2(unitW.y(), -unitW.x());
                    line.point     = leftCutOff + radius_ * invTimeHorizonObst * unitW;
                    orcaLines_.Add(line);

                    continue;
                }
                else if (t > 1.0f && tRight < 0.0f)
                {
                    /* Project on right cut-off circle. */
                    Vector2 unitW = RVOMath.normalize(velocity_ - rightCutOff);

                    line.direction = new Vector2(unitW.y(), -unitW.x());
                    line.point     = rightCutOff + radius_ * invTimeHorizonObst * unitW;
                    orcaLines_.Add(line);

                    continue;
                }

                /*
                 * 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) ? float.PositiveInfinity : RVOMath.absSq(velocity_ - (leftCutOff + t * cutOffVector));
                float distSqLeft   = tLeft < 0.0f ? float.PositiveInfinity : RVOMath.absSq(velocity_ - (leftCutOff + tLeft * leftLegDirection));
                float distSqRight  = tRight < 0.0f ? float.PositiveInfinity : RVOMath.absSq(velocity_ - (rightCutOff + tRight * rightLegDirection));

                if (distSqCutoff <= distSqLeft && distSqCutoff <= distSqRight)
                {
                    /* Project on cut-off line. */
                    line.direction = -obstacle1.direction_;
                    line.point     = leftCutOff + radius_ * invTimeHorizonObst * new Vector2(-line.direction.y(), line.direction.x());
                    orcaLines_.Add(line);

                    continue;
                }

                if (distSqLeft <= distSqRight)
                {
                    /* Project on left leg. */
                    if (isLeftLegForeign)
                    {
                        continue;
                    }

                    line.direction = leftLegDirection;
                    line.point     = leftCutOff + radius_ * invTimeHorizonObst * new Vector2(-line.direction.y(), line.direction.x());
                    orcaLines_.Add(line);

                    continue;
                }

                /* Project on right leg. */
                if (isRightLegForeign)
                {
                    continue;
                }

                line.direction = -rightLegDirection;
                line.point     = rightCutOff + radius_ * invTimeHorizonObst * new Vector2(-line.direction.y(), line.direction.x());
                orcaLines_.Add(line);
            }

            int numObstLines = orcaLines_.Count;

            float invTimeHorizon = 1.0f / timeHorizon_;

            /* Create agent ORCA lines. */
            for (int i = 0; i < agentNeighbors_.Count; ++i)
            {
                Agent other = agentNeighbors_[i].Value;

                Vector2 relativePosition = other.position_ - position_;
                Vector2 relativeVelocity = velocity_ - other.velocity_;
                float   distSq           = RVOMath.absSq(relativePosition);
                float   combinedRadius   = radius_ + other.radius_;
                float   combinedRadiusSq = RVOMath.sqr(combinedRadius);

                Line    line;
                Vector2 u;

                if (distSq > combinedRadiusSq)
                {
                    /* No collision. */
                    Vector2 w = relativeVelocity - invTimeHorizon * relativePosition;

                    /* Vector from cutoff center to relative velocity. */
                    float wLengthSq   = RVOMath.absSq(w);
                    float dotProduct1 = w * relativePosition;

                    if (dotProduct1 < 0.0f && RVOMath.sqr(dotProduct1) > combinedRadiusSq * wLengthSq)
                    {
                        /* Project on cut-off circle. */
                        float   wLength = RVOMath.sqrt(wLengthSq);
                        Vector2 unitW   = w / wLength;

                        line.direction = new Vector2(unitW.y(), -unitW.x());
                        u = (combinedRadius * invTimeHorizon - wLength) * unitW;
                    }
                    else
                    {
                        /* Project on legs. */
                        float leg = RVOMath.sqrt(distSq - combinedRadiusSq);

                        if (RVOMath.det(relativePosition, w) > 0.0f)
                        {
                            /* Project on left leg. */
                            line.direction = new Vector2(relativePosition.x() * leg - relativePosition.y() * combinedRadius, relativePosition.x() * combinedRadius + relativePosition.y() * leg) / distSq;
                        }
                        else
                        {
                            /* Project on right leg. */
                            line.direction = -new Vector2(relativePosition.x() * leg + relativePosition.y() * combinedRadius, -relativePosition.x() * combinedRadius + relativePosition.y() * leg) / distSq;
                        }

                        float dotProduct2 = relativeVelocity * line.direction;
                        u = dotProduct2 * line.direction - relativeVelocity;
                    }
                }
                else
                {
                    /* Collision. Project on cut-off circle of time timeStep. */
                    float invTimeStep = 1.0f / sim_.timeStep_;

                    /* Vector from cutoff center to relative velocity. */
                    Vector2 w = relativeVelocity - invTimeStep * relativePosition;

                    float   wLength = RVOMath.abs(w);
                    Vector2 unitW   = w / wLength;

                    line.direction = new Vector2(unitW.y(), -unitW.x());
                    u = (combinedRadius * invTimeStep - wLength) * unitW;
                }

                line.point = velocity_ + 0.5f * u;
                orcaLines_.Add(line);
            }

            int lineFail = linearProgram2(orcaLines_, maxSpeed_, prefVelocity_, false, ref newVelocity_);

            if (lineFail < orcaLines_.Count)
            {
                linearProgram3(orcaLines_, numObstLines, lineFail, maxSpeed_, ref newVelocity_);
            }
        }
Пример #3
0
        private void queryAgentTreeRecursive(Vector2 position, ref float rangeSq, ref int agentNo, int node)
        {
            if (agentTree_[node].end_ - agentTree_[node].begin_ <= MAX_LEAF_SIZE)
            {
                for (int i = agentTree_[node].begin_; i < agentTree_[node].end_; ++i)
                {
                    float distSq = RVOMath.absSq(position - agents_[i].position_);
                    if (distSq < rangeSq)
                    {
                        rangeSq = distSq;
                        agentNo = agents_[i].id_;
                    }
                }
            }
            else
            {
                float distSqLeft  = RVOMath.sqr(Math.Max(0.0f, agentTree_[agentTree_[node].left_].minX_ - position.x_)) + RVOMath.sqr(Math.Max(0.0f, position.x_ - agentTree_[agentTree_[node].left_].maxX_)) + RVOMath.sqr(Math.Max(0.0f, agentTree_[agentTree_[node].left_].minY_ - position.y_)) + RVOMath.sqr(Math.Max(0.0f, position.y_ - agentTree_[agentTree_[node].left_].maxY_));
                float distSqRight = RVOMath.sqr(Math.Max(0.0f, agentTree_[agentTree_[node].right_].minX_ - position.x_)) + RVOMath.sqr(Math.Max(0.0f, position.x_ - agentTree_[agentTree_[node].right_].maxX_)) + RVOMath.sqr(Math.Max(0.0f, agentTree_[agentTree_[node].right_].minY_ - position.y_)) + RVOMath.sqr(Math.Max(0.0f, position.y_ - agentTree_[agentTree_[node].right_].maxY_));

                if (distSqLeft < distSqRight)
                {
                    if (distSqLeft < rangeSq)
                    {
                        queryAgentTreeRecursive(position, ref rangeSq, ref agentNo, agentTree_[node].left_);

                        if (distSqRight < rangeSq)
                        {
                            queryAgentTreeRecursive(position, ref rangeSq, ref agentNo, agentTree_[node].right_);
                        }
                    }
                }
                else
                {
                    if (distSqRight < rangeSq)
                    {
                        queryAgentTreeRecursive(position, ref rangeSq, ref agentNo, agentTree_[node].right_);

                        if (distSqLeft < rangeSq)
                        {
                            queryAgentTreeRecursive(position, ref rangeSq, ref agentNo, agentTree_[node].left_);
                        }
                    }
                }
            }
        }
Пример #4
0
        /**
         * <summary>Solves a two-dimensional linear program subject to linear
         * constraints defined by lines and a circular constraint.</summary>
         *
         * <param name="lines">Lines defining the linear constraints.</param>
         * <param name="numObstLines">Count of obstacle lines.</param>
         * <param name="beginLine">The line on which the 2-d linear program
         * failed.</param>
         * <param name="radius">The radius of the circular constraint.</param>
         * <param name="result">A reference to the result of the linear program.
         * </param>
         */
        private void linearProgram3(IList <Line> lines, int numObstLines, int beginLine, float radius, ref Vector2 result)
        {
            if (mass_ != 1)
            {
                Debug.Log("linearProgram3 beginLine:" + beginLine);
            }

            float distance = 0.0f;

            // 遍历所有剩余ORCA线
            for (int i = beginLine; i < lines.Count; ++i)
            {
                // 每一条 ORCA 线都需要精确的做出处理,distance 为 最大违规的速度
                if (RVOMath.det(lines[i].direction, lines[i].point - result) > distance)
                {
                    /* Result does not satisfy constraint of line i. */
                    IList <Line> projLines = new List <Line>();
                    // 1.静态阻挡的orca线直接加到projLines中
                    for (int ii = 0; ii < numObstLines; ++ii)
                    {
                        projLines.Add(lines[ii]);
                    }
                    // 2.动态阻挡的orca线需要重新计算line,从第一个非静态阻挡到当前的orca线
                    for (int j = numObstLines; j < i; ++j)
                    {
                        Line line;

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

                        if (RVOMath.fabs(determinant) <= RVOMath.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. */
                                // 2-1 两条线平行且同向
                                continue;
                            }
                            else
                            {
                                /* Line i and line j point in opposite direction. */
                                // 2-2 两条线平行且反向
                                line.point = 0.5f * (lines[i].point + lines[j].point);
                            }
                        }
                        else
                        {
                            // 2-3 两条线不平行
                            line.point = lines[i].point + (RVOMath.det(lines[j].direction, lines[i].point - lines[j].point) / determinant) * lines[i].direction;
                        }
                        // 计算ORCA线的方向
                        line.direction = RVOMath.normalize(lines[j].direction - lines[i].direction);
                        projLines.Add(line);
                    }
                    // 3.再次计算最优速度
                    Vector2 tempResult = result;
                    // 注意这里的 new Vector2(-lines[i].direction.y(), lines[i].direction.x()) 是方向向量
                    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 = RVOMath.det(lines[i].direction, lines[i].point - result);
                }
            }
        }
Пример #5
0
        public void setPreferred()
        {
            goalDirection = new Vector2(0.0f, 0.0f);
            if (path != null && pathStatus < path.corners.Length)
            {
                goalDirection = new Vector2(path.corners[pathStatus].x, path.corners[pathStatus].z) - new Vector2(transform.position.x, transform.position.z);

                if (RVOMath.absSq(goalDirection) < goalOffset)
                {
                    pathStatus++;
                }
                if (RVOMath.absSq(goalDirection) > AgentReference.maxSpeed_ * 0.9)
                {
                    //Choose between two; max speed or less. (This provides somewhat smooth movement)
//                    float speed = userCoefficient * (float)((RVOMath.abs(RVOMath.normalize(goalDirection) / 1f) > 0.1) ? 0.1 : RVOMath.abs(RVOMath.normalize(goalDirection) / 1f));
                    float speed = (float)((RVOMath.abs(RVOMath.normalize(goalDirection)) > AgentReference.maxSpeed_ * 0.9) ? AgentReference.maxSpeed_ * 0.9 : RVOMath.abs(RVOMath.normalize(goalDirection)) * AgentReference.maxSpeed_);
                    goalDirection = new Vector2(RVOMath.normalize(goalDirection).x() * speed, RVOMath.normalize(goalDirection).y() * speed);
                }
            }
            else
            {
                pathStatus = -1;
                path       = null;
                //setDestination(transform.position);
            }

            AgentReference.prefVelocity_ = goalDirection * RVOMagnify.Magnify;
        }
Пример #6
0
        void queryAgentTreeRecursive(Agent agent, ref float rangeSq, int node)
        {
            if (agentTree_[node].end - agentTree_[node].begin <= MAX_LEAF_SIZE)
            {
                for (int i = agentTree_[node].begin; i < agentTree_[node].end; ++i)
                {
                    agent.insertAgentNeighbor(agents_[i], ref rangeSq);
                }
            }
            else
            {
                float distSqLeft = RVOMath.sqr(Math.Max(0.0f, agentTree_[agentTree_[node].left].minX - agent.position_.x_)) + RVOMath.sqr(Math.Max(0.0f, agent.position_.x_ - agentTree_[agentTree_[node].left].maxX)) + RVOMath.sqr(Math.Max(0.0f, agentTree_[agentTree_[node].left].minY - agent.position_.y_)) + RVOMath.sqr(Math.Max(0.0f, agent.position_.y_ - agentTree_[agentTree_[node].left].maxY));

                float distSqRight = RVOMath.sqr(Math.Max(0.0f, agentTree_[agentTree_[node].right].minX - agent.position_.x_)) + RVOMath.sqr(Math.Max(0.0f, agent.position_.x_ - agentTree_[agentTree_[node].right].maxX)) + RVOMath.sqr(Math.Max(0.0f, agentTree_[agentTree_[node].right].minY - agent.position_.y_)) + RVOMath.sqr(Math.Max(0.0f, agent.position_.y_ - agentTree_[agentTree_[node].right].maxY));

                if (distSqLeft < distSqRight)
                {
                    if (distSqLeft < rangeSq)
                    {
                        queryAgentTreeRecursive(agent, ref rangeSq, agentTree_[node].left);

                        if (distSqRight < rangeSq)
                        {
                            queryAgentTreeRecursive(agent, ref rangeSq, agentTree_[node].right);
                        }
                    }
                }
                else
                {
                    if (distSqRight < rangeSq)
                    {
                        queryAgentTreeRecursive(agent, ref rangeSq, agentTree_[node].right);

                        if (distSqLeft < rangeSq)
                        {
                            queryAgentTreeRecursive(agent, ref rangeSq, agentTree_[node].left);
                        }
                    }
                }
            }
        }
Пример #7
0
        /**
         * <summary>Computes the new velocity of this agent.</summary>
         */
        internal void computeNewVelocity()
        {
            orcaLines_.Clear();

            Fix64 invTimeHorizonObst = Fix64.One / timeHorizonObst_;

            /* Create obstacle ORCA lines. */
            for (int i = 0; i < obstacleNeighbors_.Count; ++i)
            {
                Obstacle obstacle1 = obstacleNeighbors_[i].Value;
                Obstacle obstacle2 = obstacle1.next_;

                Vec2 relativePosition1 = obstacle1.point_ - position_;
                Vec2 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 (RVOMath.det(invTimeHorizonObst * relativePosition1 - orcaLines_[j].point, orcaLines_[j].direction) - invTimeHorizonObst * radius_ >= -RVOMath.RVO_EPSILON && RVOMath.det(invTimeHorizonObst * relativePosition2 - orcaLines_[j].point, orcaLines_[j].direction) - invTimeHorizonObst * radius_ >= -RVOMath.RVO_EPSILON)
                    {
                        alreadyCovered = true;

                        break;
                    }
                }

                if (alreadyCovered)
                {
                    continue;
                }

                /* Not yet covered. Check for collisions. */
                Fix64 distSq1 = RVOMath.absSq(relativePosition1);
                Fix64 distSq2 = RVOMath.absSq(relativePosition2);

                Fix64 radiusSq = RVOMath.sqr(radius_);

                Vec2  obstacleVector   = obstacle2.point_ - obstacle1.point_;
                Fix64 obstacleVectorSq = RVOMath.absSq(obstacleVector);
                Fix64 s          = obstacleVectorSq == Fix64.Zero ? Fix64.One : (-relativePosition1 * obstacleVector) / obstacleVectorSq;
                Fix64 distSqLine = RVOMath.absSq(-relativePosition1 - s * obstacleVector);

                Line line;

                if (s < Fix64.Zero && distSq1 <= radiusSq)
                {
                    /* Collision with left vertex. Ignore if non-convex. */
                    if (obstacle1.convex_)
                    {
                        line.point     = Vec2.Zero;
                        line.direction = RVOMath.normalize(new Vec2(-relativePosition1.y, relativePosition1.x));
                        orcaLines_.Add(line);
                    }

                    continue;
                }
                else if (s > Fix64.One && distSq2 <= radiusSq)
                {
                    /*
                     * Collision with right vertex. Ignore if non-convex or if
                     * it will be taken care of by neighboring obstacle.
                     */
                    if (obstacle2.convex_ && RVOMath.det(relativePosition2, obstacle2.direction_) >= Fix64.Zero)
                    {
                        line.point     = Vec2.Zero;
                        line.direction = RVOMath.normalize(new Vec2(-relativePosition2.y, relativePosition2.x));
                        orcaLines_.Add(line);
                    }

                    continue;
                }
                else if (s >= Fix64.Zero && s < Fix64.One && distSqLine <= radiusSq)
                {
                    /* Collision with obstacle segment. */
                    line.point     = Vec2.Zero;
                    line.direction = -obstacle1.direction_;
                    orcaLines_.Add(line);

                    continue;
                }

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

                Vec2 leftLegDirection, rightLegDirection;

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

                    obstacle2 = obstacle1;

                    Fix64 leg1 = RVOMath.sqrt((distSq1 - radiusSq).Clamp(Fix64.Zero, Fix64.MaxValue));
                    leftLegDirection  = new Vec2(relativePosition1.x * leg1 - relativePosition1.y * radius_, relativePosition1.x * radius_ + relativePosition1.y * leg1) / distSq1;
                    rightLegDirection = new Vec2(relativePosition1.x * leg1 + relativePosition1.y * radius_, -relativePosition1.x * radius_ + relativePosition1.y * leg1) / distSq1;
                }
                else if (s > Fix64.One && distSqLine <= radiusSq)
                {
                    /*
                     * Obstacle viewed obliquely so that
                     * right vertex defines velocity obstacle.
                     */
                    if (!obstacle2.convex_)
                    {
                        /* Ignore obstacle. */
                        continue;
                    }

                    obstacle1 = obstacle2;

                    Fix64 leg2 = RVOMath.sqrt((distSq2 - radiusSq).Clamp(Fix64.Zero, Fix64.MaxValue));
                    leftLegDirection  = new Vec2(relativePosition2.x * leg2 - relativePosition2.y * radius_, relativePosition2.x * radius_ + relativePosition2.y * leg2) / distSq2;
                    rightLegDirection = new Vec2(relativePosition2.x * leg2 + relativePosition2.y * radius_, -relativePosition2.x * radius_ + relativePosition2.y * leg2) / distSq2;
                }
                else
                {
                    /* Usual situation. */
                    if (obstacle1.convex_)
                    {
                        Fix64 leg1 = RVOMath.sqrt((distSq1 - radiusSq).Clamp(Fix64.Zero, Fix64.MaxValue));
                        leftLegDirection = new Vec2(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_)
                    {
                        Fix64 leg2 = RVOMath.sqrt((distSq2 - radiusSq).Clamp(Fix64.Zero, Fix64.MaxValue));
                        rightLegDirection = new Vec2(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 (obstacle1.convex_ && RVOMath.det(leftLegDirection, -leftNeighbor.direction_) >= Fix64.Zero)
                {
                    /* Left leg points into obstacle. */
                    leftLegDirection = -leftNeighbor.direction_;
                    isLeftLegForeign = true;
                }

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

                /* Compute cut-off centers. */
                Vec2 leftCutOff   = invTimeHorizonObst * (obstacle1.point_ - position_);
                Vec2 rightCutOff  = invTimeHorizonObst * (obstacle2.point_ - position_);
                Vec2 cutOffVector = rightCutOff - leftCutOff;

                /* Project current velocity on velocity obstacle. */

                /* Check if current velocity is projected on cutoff circles. */
                Fix64 cutOffVectorSq = RVOMath.absSq(cutOffVector);
                Fix64 t      = obstacle1 == obstacle2 || cutOffVectorSq == Fix64.Zero ? 0.5f : ((velocity_ - leftCutOff) * cutOffVector) / cutOffVectorSq;
                Fix64 tLeft  = (velocity_ - leftCutOff) * leftLegDirection;
                Fix64 tRight = (velocity_ - rightCutOff) * rightLegDirection;

                if ((t < Fix64.Zero && tLeft < Fix64.Zero) || (obstacle1 == obstacle2 && tLeft < Fix64.Zero && tRight < Fix64.Zero))
                {
                    /* Project on left cut-off circle. */
                    Vec2 unitW = RVOMath.normalize(velocity_ - leftCutOff);

                    line.direction = new Vec2(unitW.y, -unitW.x);
                    line.point     = leftCutOff + radius_ * invTimeHorizonObst * unitW;
                    orcaLines_.Add(line);

                    continue;
                }
                else if (t > Fix64.One && tRight < Fix64.Zero)
                {
                    /* Project on right cut-off circle. */
                    Vec2 unitW = RVOMath.normalize(velocity_ - rightCutOff);

                    line.direction = new Vec2(unitW.y, -unitW.x);
                    line.point     = rightCutOff + radius_ * invTimeHorizonObst * unitW;
                    orcaLines_.Add(line);

                    continue;
                }

                /*
                 * Project on left leg, right leg, or cut-off line, whichever is
                 * closest to velocity.
                 */
                Fix64 distSqCutoff = (t <Fix64.Zero || t> Fix64.One || obstacle1 == obstacle2) ? Fix64.MaxValue : RVOMath.absSq(velocity_ - (leftCutOff + t * cutOffVector));
                Fix64 distSqLeft   = tLeft < Fix64.Zero ? Fix64.MaxValue : RVOMath.absSq(velocity_ - (leftCutOff + tLeft * leftLegDirection));
                Fix64 distSqRight  = tRight < Fix64.Zero ? Fix64.MaxValue : RVOMath.absSq(velocity_ - (rightCutOff + tRight * rightLegDirection));

                if (distSqCutoff <= distSqLeft && distSqCutoff <= distSqRight)
                {
                    /* Project on cut-off line. */
                    line.direction = -obstacle1.direction_;
                    line.point     = leftCutOff + radius_ * invTimeHorizonObst * new Vec2(-line.direction.y, line.direction.x);
                    orcaLines_.Add(line);

                    continue;
                }

                if (distSqLeft <= distSqRight)
                {
                    /* Project on left leg. */
                    if (isLeftLegForeign)
                    {
                        continue;
                    }

                    line.direction = leftLegDirection;
                    line.point     = leftCutOff + radius_ * invTimeHorizonObst * new Vec2(-line.direction.y, line.direction.x);
                    orcaLines_.Add(line);

                    continue;
                }

                /* Project on right leg. */
                if (isRightLegForeign)
                {
                    continue;
                }

                line.direction = -rightLegDirection;
                line.point     = rightCutOff + radius_ * invTimeHorizonObst * new Vec2(-line.direction.y, line.direction.x);
                orcaLines_.Add(line);
            }

            int numObstLines = orcaLines_.Count;

            Fix64 invTimeHorizon = Fix64.One / timeHorizon_;

            /* Create agent ORCA lines. */
            for (int i = 0; i < agentNeighbors_.Count; ++i)
            {
                Agent other = agentNeighbors_[i].Value;

                Vec2  relativePosition = other.position_ - position_;
                Vec2  relativeVelocity = velocity_ - other.velocity_;
                Fix64 distSq           = RVOMath.absSq(relativePosition);
                Fix64 combinedRadius   = radius_ + other.radius_;
                Fix64 combinedRadiusSq = RVOMath.sqr(combinedRadius);

                Line line;
                Vec2 u;

                if (distSq > combinedRadiusSq)
                {
                    /* No collision. */
                    Vec2 w = relativeVelocity - invTimeHorizon * relativePosition;

                    /*  the w has a change to be zero exactly.
                     *  for example: the two objects are at the exactly same position and with the exactly same velocity
                     *  so we have to make some perturbation to separate them */
                    if (w == Vec2.Zero)
                    {
                        w = id_ > other.id_ ? Vec2.Left : Vec2.Right;
                    }

                    /* Vector from cutoff center to relative velocity. */
                    Fix64 wLengthSq   = RVOMath.absSq(w);
                    Fix64 dotProduct1 = w * relativePosition;

                    if (dotProduct1 < Fix64.Zero && RVOMath.sqr(dotProduct1) > combinedRadiusSq * wLengthSq)
                    {
                        /* Project on cut-off circle. */
                        Fix64 wLength = RVOMath.sqrt(wLengthSq);
                        Vec2  unitW   = w / wLength;

                        line.direction = new Vec2(unitW.y, -unitW.x);
                        u = (combinedRadius * invTimeHorizon - wLength) * unitW;
                    }
                    else
                    {
                        /* Project on legs. */
                        Fix64 leg = RVOMath.sqrt(distSq - combinedRadiusSq);

                        if (RVOMath.det(relativePosition, w) > Fix64.Zero)
                        {
                            /* Project on left leg. */
                            line.direction = new Vec2(relativePosition.x * leg - relativePosition.y * combinedRadius, relativePosition.x * combinedRadius + relativePosition.y * leg) / distSq;
                        }
                        else
                        {
                            /* Project on right leg. */
                            line.direction = -new Vec2(relativePosition.x * leg + relativePosition.y * combinedRadius, -relativePosition.x * combinedRadius + relativePosition.y * leg) / distSq;
                        }

                        Fix64 dotProduct2 = relativeVelocity * line.direction;
                        u = dotProduct2 * line.direction - relativeVelocity;
                    }
                }
                else
                {
                    /* Collision. Project on cut-off circle of time timeStep. */
                    Fix64 invTimeStep = Fix64.One / simulator_.timeStep_;

                    /* Vector from cutoff center to relative velocity. */
                    Vec2 w = relativeVelocity - invTimeStep * relativePosition;

                    /*  the w has a change to be zero exactly.
                     *  for example: the two objects are at the exactly same position and with the exactly same velocity
                     *  so we have to make some perturbation to separate them */
                    if (w == Vec2.Zero)
                    {
                        w = id_ > other.id_ ? Vec2.Left : Vec2.Right;
                    }

                    Fix64 wLength = RVOMath.abs(w);
                    Vec2  unitW   = wLength == Fix64.Zero ? Vec2.Zero : w / wLength;

                    line.direction = new Vec2(unitW.y, -unitW.x);
                    u = (combinedRadius * invTimeStep - wLength) * unitW;
                }

                line.point = velocity_ + 0.5f * u;
                orcaLines_.Add(line);
            }

            int lineFail = linearProgram2(orcaLines_, maxSpeed_, prefVelocity_, false, ref newVelocity_);

            if (lineFail < orcaLines_.Count)
            {
                linearProgram3(orcaLines_, numObstLines, lineFail, maxSpeed_, ref newVelocity_);
            }
        }
Пример #8
0
        /**
         * <summary>Recursive method for querying the visibility between two
         * points within a specified radius.</summary>
         *
         * <returns>True if q1 and q2 are mutually visible within the radius;
         * false otherwise.</returns>
         *
         * <param name="q1">The first point between which visibility is to be
         * tested.</param>
         * <param name="q2">The second point between which visibility is to be
         * tested.</param>
         * <param name="radius">The radius within which visibility is to be
         * tested.</param>
         * <param name="node">The current obstacle k-D node.</param>
         */
        private bool queryVisibilityRecursive(Vector2 q1, Vector2 q2, float radius, ObstacleTreeNode node)
        {
            if (node == null)
            {
                return(true);
            }

            Obstacle obstacle1 = node.obstacle_;
            Obstacle obstacle2 = obstacle1.next_;

            float q1LeftOfI  = RVOMath.leftOf(obstacle1.point_, obstacle2.point_, q1);
            float q2LeftOfI  = RVOMath.leftOf(obstacle1.point_, obstacle2.point_, q2);
            float invLengthI = 1.0f / RVOMath.absSq(obstacle2.point_ - obstacle1.point_);

            if (q1LeftOfI >= 0.0f && q2LeftOfI >= 0.0f)
            {
                return(queryVisibilityRecursive(q1, q2, radius, node.left_) && ((RVOMath.sqr(q1LeftOfI) * invLengthI >= RVOMath.sqr(radius) && RVOMath.sqr(q2LeftOfI) * invLengthI >= RVOMath.sqr(radius)) || queryVisibilityRecursive(q1, q2, radius, node.right_)));
            }

            if (q1LeftOfI <= 0.0f && q2LeftOfI <= 0.0f)
            {
                return(queryVisibilityRecursive(q1, q2, radius, node.right_) && ((RVOMath.sqr(q1LeftOfI) * invLengthI >= RVOMath.sqr(radius) && RVOMath.sqr(q2LeftOfI) * invLengthI >= RVOMath.sqr(radius)) || queryVisibilityRecursive(q1, q2, radius, node.left_)));
            }

            if (q1LeftOfI >= 0.0f && q2LeftOfI <= 0.0f)
            {
                /* One can see through obstacle from left to right. */
                return(queryVisibilityRecursive(q1, q2, radius, node.left_) && queryVisibilityRecursive(q1, q2, radius, node.right_));
            }

            float point1LeftOfQ = RVOMath.leftOf(q1, q2, obstacle1.point_);
            float point2LeftOfQ = RVOMath.leftOf(q1, q2, obstacle2.point_);
            float invLengthQ    = 1.0f / RVOMath.absSq(q2 - q1);

            return(point1LeftOfQ * point2LeftOfQ >= 0.0f && RVOMath.sqr(point1LeftOfQ) * invLengthQ > RVOMath.sqr(radius) && RVOMath.sqr(point2LeftOfQ) * invLengthQ > RVOMath.sqr(radius) && queryVisibilityRecursive(q1, q2, radius, node.left_) && queryVisibilityRecursive(q1, q2, radius, node.right_));
        }
Пример #9
0
        /**
         * <summary>Computes the new velocity of this agent.</summary>
         */
        internal void computeNewVelocity()
        {
            orcaLines_.Clear();

            //KInt invTimeHorizonObst = 1 / timeHorizonObst_;

            KInt tempradius = radius_ / timeHorizonObst_;

            /* Create obstacle ORCA lines. */
            for (int i = 0; i < obstacleNeighbors_.Count; ++i)
            {
                Obstacle obstacle1 = obstacleNeighbors_[i].Value;
                Obstacle obstacle2 = obstacle1.next_;

                KInt2 relativePosition1 = obstacle1.point_ - position_;
                KInt2 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 (RVOMath.det(relativePosition1 / timeHorizonObst_ - orcaLines_[j].point, orcaLines_[j].direction) - tempradius >= 0 && RVOMath.det(relativePosition2 / timeHorizonObst_ - orcaLines_[j].point, orcaLines_[j].direction) - tempradius >= 0)
                    {
                        alreadyCovered = true;

                        break;
                    }
                }

                if (alreadyCovered)
                {
                    continue;
                }

                /* Not yet covered. Check for collisions. */
                KInt distSq1 = RVOMath.absSq(relativePosition1);
                KInt distSq2 = RVOMath.absSq(relativePosition2);

                KInt radiusSq = RVOMath.sqr(radius_);

                KInt2 obstacleVector = obstacle2.point_ - obstacle1.point_;
                KInt  s          = (-RVOMath.Dot(relativePosition1, obstacleVector)) / RVOMath.absSq(obstacleVector);
                KInt  distSqLine = RVOMath.absSq(-relativePosition1 - s * obstacleVector);

                Line line = new Line();

                if (s < 0 && distSq1 <= radiusSq)
                {
                    /* Collision with left vertex. Ignore if non-convex. */
                    if (obstacle1.convex_)
                    {
                        line.point     = KInt2.zero;
                        line.direction = RVOMath.normalize(KInt2.ToInt2(-relativePosition1.IntY, relativePosition1.IntX));
                        orcaLines_.Add(line);
                    }

                    continue;
                }
                else if (s > 1 && distSq2 <= radiusSq)
                {
                    /*
                     * Collision with right vertex. Ignore if non-convex or if
                     * it will be taken care of by neighboring obstacle.
                     */
                    if (obstacle2.convex_ && RVOMath.det(relativePosition2, obstacle2.direction_) >= 0)
                    {
                        line.point     = KInt2.zero;
                        line.direction = RVOMath.normalize(KInt2.ToInt2(-relativePosition2.IntY, relativePosition2.IntX));
                        orcaLines_.Add(line);
                    }

                    continue;
                }
                else if (s >= 0 && s < 1 && distSqLine <= radiusSq)
                {
                    /* Collision with obstacle segment. */
                    line.point     = KInt2.zero;
                    line.direction = -obstacle1.direction_;
                    orcaLines_.Add(line);

                    continue;
                }

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

                KInt2 leftLegDirection, rightLegDirection;

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

                    obstacle2 = obstacle1;

                    KInt leg1 = RVOMath.sqrt(distSq1 - radiusSq);
                    leftLegDirection  = KInt2.ToInt2(relativePosition1.IntX * leg1 - relativePosition1.IntY * radius_, relativePosition1.IntX * radius_ + relativePosition1.IntY * leg1) / distSq1;
                    rightLegDirection = KInt2.ToInt2(relativePosition1.IntX * leg1 + relativePosition1.IntY * radius_, -relativePosition1.IntX * radius_ + relativePosition1.IntY * leg1) / distSq1;
                    if (isover(leftLegDirection) || isover(rightLegDirection))
                    {
                        LogMgr.LogError("!!!");
                    }
                }
                else if (s > 1 && distSqLine <= radiusSq)
                {
                    /*
                     * Obstacle viewed obliquely so that
                     * right vertex defines velocity obstacle.
                     */
                    if (!obstacle2.convex_)
                    {
                        /* Ignore obstacle. */
                        continue;
                    }

                    obstacle1 = obstacle2;

                    KInt leg2 = RVOMath.sqrt(distSq2 - radiusSq);
                    leftLegDirection  = KInt2.ToInt2(relativePosition2.IntX * leg2 - relativePosition2.IntY * radius_, relativePosition2.IntX * radius_ + relativePosition2.IntY * leg2) / distSq2;
                    rightLegDirection = KInt2.ToInt2(relativePosition2.IntX * leg2 + relativePosition2.IntY * radius_, -relativePosition2.IntX * radius_ + relativePosition2.IntY * leg2) / distSq2;
                    if (isover(leftLegDirection) || isover(rightLegDirection))
                    {
                        LogMgr.LogError("!!!");
                    }
                }
                else
                {
                    /* Usual situation. */
                    if (obstacle1.convex_)
                    {
                        KInt leg1 = RVOMath.sqrt(distSq1 - radiusSq);
                        leftLegDirection = KInt2.ToInt2(relativePosition1.IntX * leg1 - relativePosition1.IntY * radius_, relativePosition1.IntX * radius_ + relativePosition1.IntY * leg1) / distSq1;
                        if (isover(leftLegDirection))
                        {
                            LogMgr.LogError("!!!");
                        }
                    }
                    else
                    {
                        /* Left vertex non-convex; left leg extends cut-off line. */
                        leftLegDirection = -obstacle1.direction_;
                        if (isover(leftLegDirection))
                        {
                            LogMgr.LogError("!!!");
                        }
                    }

                    if (obstacle2.convex_)
                    {
                        KInt leg2 = RVOMath.sqrt(distSq2 - radiusSq);

                        rightLegDirection = KInt2.ToInt2(relativePosition2.IntX * leg2 + relativePosition2.IntY * radius_, -relativePosition2.IntX * radius_ + relativePosition2.IntY * leg2) / distSq2;
                        if (isover(rightLegDirection))
                        {
                            LogMgr.LogError("!!!");
                        }
                    }
                    else
                    {
                        /* Right vertex non-convex; right leg extends cut-off line. */
                        rightLegDirection = obstacle1.direction_;
                        if (isover(rightLegDirection))
                        {
                            LogMgr.LogError("!!!");
                        }
                    }
                }

                /*
                 * 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 (obstacle1.convex_ && RVOMath.det(leftLegDirection, -leftNeighbor.direction_) >= 0)
                {
                    /* Left leg points into obstacle. */
                    leftLegDirection = -leftNeighbor.direction_;
                    if (isover(leftLegDirection))
                    {
                        LogMgr.LogError("!!!");
                    }
                    isLeftLegForeign = true;
                }

                if (obstacle2.convex_ && RVOMath.det(rightLegDirection, obstacle2.direction_) <= 0)
                {
                    /* Right leg points into obstacle. */
                    rightLegDirection = obstacle2.direction_;
                    isRightLegForeign = true;
                    if (isover(rightLegDirection))
                    {
                        LogMgr.LogError("!!!");
                    }
                }

                /* Compute cut-off centers. */
                KInt2 leftCutOff   = (obstacle1.point_ - position_) / timeHorizonObst_;
                KInt2 rightCutOff  = (obstacle2.point_ - position_) / timeHorizonObst_;
                KInt2 cutOffVector = rightCutOff - leftCutOff;

                /* Project current velocity on velocity obstacle. */

                /* Check if current velocity is projected on cutoff circles. */
                KInt sqvalue = RVOMath.absSq(cutOffVector);
                KInt t       = KInt.ToInt(KInt.divscale / 2);
                if (obstacle1 != obstacle2)
                {
                    if (sqvalue == 0)
                    {
                        t = KInt.MaxValue;
                    }
                    else
                    {
                        t = RVOMath.Dot((velocity_ - leftCutOff), cutOffVector) / sqvalue;
                    }
                }

                KInt tLeft  = RVOMath.Dot((velocity_ - leftCutOff), leftLegDirection);
                KInt tRight = RVOMath.Dot((velocity_ - rightCutOff), rightLegDirection);

                if ((t < 0 && tLeft < 0) || (obstacle1 == obstacle2 && tLeft < 0 && tRight < 0))
                {
                    /* Project on left cut-off circle. */
                    KInt2 unitW = RVOMath.normalize((velocity_ - leftCutOff));

                    line.direction = KInt2.ToInt2(unitW.IntY, -unitW.IntX);
                    line.point     = leftCutOff + radius_ * unitW / timeHorizonObst_;
                    orcaLines_.Add(line);

                    continue;
                }
                else if (t > 1 && tRight < 0)
                {
                    /* Project on right cut-off circle. */
                    KInt2 unitW = RVOMath.normalize((velocity_ - rightCutOff));

                    line.direction = KInt2.ToInt2(unitW.IntY, -unitW.IntX);
                    line.point     = rightCutOff + radius_ * unitW / timeHorizonObst_;
                    orcaLines_.Add(line);

                    continue;
                }

                /*
                 * Project on left leg, right leg, or cut-off line, whichever is
                 * closest to velocity.
                 */
                KInt distSqCutoff = (t < 0 || t > 1 || obstacle1 == obstacle2) ? KInt.MaxValue : RVOMath.absSq(velocity_ - (leftCutOff + t * cutOffVector));
                KInt distSqLeft   = tLeft < 0 ? KInt.MaxValue : RVOMath.absSq(velocity_ - (leftCutOff + tLeft * leftLegDirection));
                KInt distSqRight  = tRight < 0 ? KInt.MaxValue : RVOMath.absSq(velocity_ - (rightCutOff + tRight * rightLegDirection));

                if (distSqCutoff <= distSqLeft && distSqCutoff <= distSqRight)
                {
                    /* Project on cut-off line. */
                    line.direction = -obstacle1.direction_;
                    line.point     = leftCutOff + radius_ * KInt2.ToInt2(-line.direction.IntY, line.direction.IntX) / timeHorizonObst_;
                    orcaLines_.Add(line);

                    continue;
                }

                if (distSqLeft <= distSqRight)
                {
                    /* Project on left leg. */
                    if (isLeftLegForeign)
                    {
                        continue;
                    }

                    line.direction = leftLegDirection;
                    line.point     = leftCutOff + radius_ * KInt2.ToInt2(-line.direction.IntY, line.direction.IntX) / timeHorizonObst_;
                    orcaLines_.Add(line);

                    continue;
                }

                /* Project on right leg. */
                if (isRightLegForeign)
                {
                    continue;
                }

                line.direction = -rightLegDirection;
                line.point     = rightCutOff + radius_ * KInt2.ToInt2(-line.direction.IntY, line.direction.IntX) / timeHorizonObst_;
                orcaLines_.Add(line);
            }

            int numObstLines = orcaLines_.Count;

            //KInt invTimeHorizon = 1 / timeHorizon_;

            /* Create agent ORCA lines. */
            for (int i = 0; i < agentNeighbors_.Count; ++i)
            {
                Agent other = agentNeighbors_[i].Value;

                KInt2 relativePosition = other.position_ - position_;
                KInt2 relativeVelocity = velocity_ - other.velocity_;
                KInt  distSq           = RVOMath.absSq(relativePosition);
                KInt  combinedRadius   = radius_ + other.radius_;
                KInt  combinedRadiusSq = RVOMath.sqr(combinedRadius);

                Line  line = new Line();
                KInt2 u;

                if (distSq > combinedRadiusSq)
                {
                    /* No collision. */
                    KInt2 w = relativeVelocity - relativePosition / timeHorizon_;
                    /* Vector from cutoff center to relative velocity. */
                    KInt wLengthSq = RVOMath.absSq(w);

                    KInt dotProduct1 = RVOMath.Dot(w, relativePosition);

                    if (dotProduct1 < 0 && RVOMath.sqr(dotProduct1) > combinedRadiusSq * wLengthSq)
                    {
                        /* Project on cut-off circle. */
                        KInt wLength = RVOMath.sqrt(wLengthSq);
                        if (wLength == 0)
                        {
                            continue;
                        }
                        KInt2 unitW = w / wLength;

                        line.direction = KInt2.ToInt2(unitW.IntY, -unitW.IntX);
                        u = (combinedRadius / timeHorizon_ - wLength) * unitW;
                    }
                    else
                    {
                        /* Project on legs. */
                        KInt leg = RVOMath.sqrt(distSq - combinedRadiusSq);

                        if (RVOMath.det(relativePosition, w) > 0)
                        {
                            /* Project on left leg. */
                            line.direction = KInt2.ToInt2(relativePosition.IntX * leg - relativePosition.IntY * combinedRadius, relativePosition.IntX * combinedRadius + relativePosition.IntY * leg) / distSq;
                        }
                        else
                        {
                            /* Project on right leg. */
                            line.direction = -KInt2.ToInt2(relativePosition.IntX * leg + relativePosition.IntY * combinedRadius, -relativePosition.IntX * combinedRadius + relativePosition.IntY * leg) / distSq;
                        }

                        KInt dotProduct2 = RVOMath.Dot(relativeVelocity, line.direction);
                        u = dotProduct2 * line.direction - relativeVelocity;
                    }
                }
                else
                {
                    /* Collision. Project on cut-off circle of time timeStep. */
                    //KInt invTimeStep = 1 / Simulator.Instance.timeStep_;
                    /* Vector from cutoff center to relative velocity. */
                    KInt2 w       = relativeVelocity - relativePosition / Simulator.Instance.timeStep_;
                    KInt  wLength = RVOMath.abs(w);
                    if (wLength == 0)
                    {
                        continue;
                    }
                    KInt2 unitW = w / wLength;

                    line.direction = KInt2.ToInt2(unitW.IntY, -unitW.IntX);

                    u = (combinedRadius / Simulator.Instance.timeStep_ - wLength) * unitW;
                }

                line.point = velocity_ + u / 2;
                orcaLines_.Add(line);
            }

            int lineFail = linearProgram2(orcaLines_, maxSpeed_, prefVelocity_, false, ref newVelocity_);

            if (lineFail < orcaLines_.Count)
            {
                linearProgram3(orcaLines_, numObstLines, lineFail, maxSpeed_, ref newVelocity_);
            }
        }
Пример #10
0
        /**
         * <summary>Solves a two-dimensional linear program subject to linear
         * constraints defined by lines and a circular constraint.</summary>
         *
         * <param name="lines">Lines defining the linear constraints.</param>
         * <param name="numObstLines">Count of obstacle lines.</param>
         * <param name="beginLine">The line on which the 2-d linear program
         * failed.</param>
         * <param name="radius">The radius of the circular constraint.</param>
         * <param name="result">A reference to the result of the linear program.
         * </param>
         */
        private void linearProgram3(IList <Line> lines, int numObstLines, int beginLine, Fix64 radius, ref Vec2 result)
        {
            Fix64 distance = Fix64.Zero;

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

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

                        Fix64 determinant = RVOMath.det(lines[i].direction, lines[j].direction);

                        if (RVOMath.fabs(determinant) <= RVOMath.RVO_EPSILON)
                        {
                            /* Line i and line j are parallel. */
                            if (lines[i].direction * lines[j].direction > Fix64.Zero)
                            {
                                /* 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 + (RVOMath.det(lines[j].direction, lines[i].point - lines[j].point) / determinant) * lines[i].direction;
                        }

                        Vec2 dd = lines[j].direction - lines[i].direction;
                        if (dd.Length == Fix64.Zero)
                        {
                            line.direction = Vec2.Zero;
                        }
                        else
                        {
                            line.direction = RVOMath.normalize(dd);
                        }

                        projLines.Add(line);
                    }

                    Vec2 tempResult = result;
                    if (linearProgram2(projLines, radius, new Vec2(-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 = RVOMath.det(lines[i].direction, lines[i].point - result);
                }
            }
        }
Пример #11
0
        /**
         * <summary>Recursive method for querying the visibility between two
         * points within a specified radius.</summary>
         *
         * <returns>True if q1 and q2 are mutually visible within the radius;
         * false otherwise.</returns>
         *
         * <param name="q1">The first point between which visibility is to be
         * tested.</param>
         * <param name="q2">The second point between which visibility is to be
         * tested.</param>
         * <param name="radius">The radius within which visibility is to be
         * tested.</param>
         * <param name="node">The current obstacle k-D node.</param>
         */
        private bool queryVisibilityRecursive(Vec2 q1, Vec2 q2, Fix64 radius, ObstacleTreeNode node)
        {
            if (node == null)
            {
                return(true);
            }

            Obstacle obstacle1 = node.obstacle_;
            Obstacle obstacle2 = obstacle1.next_;

            Fix64 q1LeftOfI = RVOMath.leftOf(obstacle1.point_, obstacle2.point_, q1);
            Fix64 q2LeftOfI = RVOMath.leftOf(obstacle1.point_, obstacle2.point_, q2);
            Fix64 q12       = RVOMath.absSq(obstacle2.point_ - obstacle1.point_);

            if (q12 == Fix64.Zero)
            {
                return(true);
            }

            Fix64 invLengthI = Fix64.One / RVOMath.absSq(obstacle2.point_ - obstacle1.point_);

            if (q1LeftOfI >= Fix64.Zero && q2LeftOfI >= Fix64.Zero)
            {
                return(queryVisibilityRecursive(q1, q2, radius, node.left_) && ((RVOMath.sqr(q1LeftOfI) * invLengthI >= RVOMath.sqr(radius) && RVOMath.sqr(q2LeftOfI) * invLengthI >= RVOMath.sqr(radius)) || queryVisibilityRecursive(q1, q2, radius, node.right_)));
            }

            if (q1LeftOfI <= Fix64.Zero && q2LeftOfI <= Fix64.Zero)
            {
                return(queryVisibilityRecursive(q1, q2, radius, node.right_) && ((RVOMath.sqr(q1LeftOfI) * invLengthI >= RVOMath.sqr(radius) && RVOMath.sqr(q2LeftOfI) * invLengthI >= RVOMath.sqr(radius)) || queryVisibilityRecursive(q1, q2, radius, node.left_)));
            }

            if (q1LeftOfI >= Fix64.Zero && q2LeftOfI <= Fix64.Zero)
            {
                /* One can see through obstacle from left to right. */
                return(queryVisibilityRecursive(q1, q2, radius, node.left_) && queryVisibilityRecursive(q1, q2, radius, node.right_));
            }

            Fix64 point1LeftOfQ = RVOMath.leftOf(q1, q2, obstacle1.point_);
            Fix64 point2LeftOfQ = RVOMath.leftOf(q1, q2, obstacle2.point_);
            Fix64 sqp12         = RVOMath.absSq(q2 - q1);

            if (sqp12 == Fix64.Zero)
            {
                return(true);
            }

            Fix64 invLengthQ = Fix64.One / sqp12;

            return(point1LeftOfQ * point2LeftOfQ >= Fix64.Zero && RVOMath.sqr(point1LeftOfQ) * invLengthQ > RVOMath.sqr(radius) && RVOMath.sqr(point2LeftOfQ) * invLengthQ > RVOMath.sqr(radius) && queryVisibilityRecursive(q1, q2, radius, node.left_) && queryVisibilityRecursive(q1, q2, radius, node.right_));
        }
Пример #12
0
        private void queryGetNearestAgent(Agent agent, ref int _resultUid, double _minDistance, ref double _distance, int node, Func <int, bool> _callBack)
        {
            if (agentTree_[node].end_ - agentTree_[node].begin_ <= MAX_LEAF_SIZE)
            {
                for (int i = agentTree_[node].begin_; i < agentTree_[node].end_; ++i)
                {
                    Agent tmpAgent = agents_[i];

                    if (tmpAgent == agent || tmpAgent.type == AgentType.SkillPush || tmpAgent.type == AgentType.SkillObstacle || tmpAgent.type == AgentType.SkillUnit)
                    {
                        continue;
                    }

                    double dist = Vector2.Distance(tmpAgent.position_, agent.position_);

                    if (dist - tmpAgent.radius_ < _distance && dist + tmpAgent.radius_ > _minDistance)
                    {
                        if (_callBack(tmpAgent.uid))
                        {
                            _resultUid = tmpAgent.uid;

                            _distance = dist - tmpAgent.radius_;
                        }
                    }
                }
            }
            else
            {
                double distSqLeft  = RVOMath.sqr(Math.Max(0.0, agentTree_[agentTree_[node].left_].minX_ - agent.position_.x)) + RVOMath.sqr(Math.Max(0.0, agent.position_.x - agentTree_[agentTree_[node].left_].maxX_)) + RVOMath.sqr(Math.Max(0.0, agentTree_[agentTree_[node].left_].minY_ - agent.position_.y)) + RVOMath.sqr(Math.Max(0.0, agent.position_.y - agentTree_[agentTree_[node].left_].maxY_));
                double distSqRight = RVOMath.sqr(Math.Max(0.0, agentTree_[agentTree_[node].right_].minX_ - agent.position_.x)) + RVOMath.sqr(Math.Max(0.0, agent.position_.x - agentTree_[agentTree_[node].right_].maxX_)) + RVOMath.sqr(Math.Max(0.0, agentTree_[agentTree_[node].right_].minY_ - agent.position_.y)) + RVOMath.sqr(Math.Max(0.0, agent.position_.y - agentTree_[agentTree_[node].right_].maxY_));

                double distSq = (_distance + simulator.getMaxRadius()) * (_distance + simulator.getMaxRadius());

                if (distSqLeft < distSqRight)
                {
                    if (distSqLeft < distSq)
                    {
                        queryGetNearestAgent(agent, ref _resultUid, _minDistance, ref _distance, agentTree_[node].left_, _callBack);

                        if (distSqRight < distSq)
                        {
                            queryGetNearestAgent(agent, ref _resultUid, _minDistance, ref _distance, agentTree_[node].right_, _callBack);
                        }
                    }
                }
                else
                {
                    if (distSqRight < distSq)
                    {
                        queryGetNearestAgent(agent, ref _resultUid, _minDistance, ref _distance, agentTree_[node].right_, _callBack);

                        if (distSqLeft < distSq)
                        {
                            queryGetNearestAgent(agent, ref _resultUid, _minDistance, ref _distance, agentTree_[node].left_, _callBack);
                        }
                    }
                }
            }
        }
Пример #13
0
        private void queryPointTreeRecursive(Vector2 _pos, double _range, int node, List <int> list)
        {
            if (agentTree_[node].end_ - agentTree_[node].begin_ <= MAX_LEAF_SIZE)
            {
                for (int i = agentTree_[node].begin_; i < agentTree_[node].end_; ++i)
                {
                    Agent agent = agents_[i];

                    if (agent.type == AgentType.SkillPush || agent.type == AgentType.SkillObstacle || agent.type == AgentType.SkillUnit)
                    {
                        continue;
                    }

                    double dist = Vector2.Distance(agent.position_, _pos);

                    if (dist < _range + agent.radius_)
                    {
                        list.Add(agent.uid);
                    }
                }
            }
            else
            {
                double distSqLeft  = RVOMath.sqr(Math.Max(0.0, agentTree_[agentTree_[node].left_].minX_ - _pos.x)) + RVOMath.sqr(Math.Max(0.0, _pos.x - agentTree_[agentTree_[node].left_].maxX_)) + RVOMath.sqr(Math.Max(0.0, agentTree_[agentTree_[node].left_].minY_ - _pos.y)) + RVOMath.sqr(Math.Max(0.0, _pos.y - agentTree_[agentTree_[node].left_].maxY_));
                double distSqRight = RVOMath.sqr(Math.Max(0.0, agentTree_[agentTree_[node].right_].minX_ - _pos.x)) + RVOMath.sqr(Math.Max(0.0, _pos.x - agentTree_[agentTree_[node].right_].maxX_)) + RVOMath.sqr(Math.Max(0.0, agentTree_[agentTree_[node].right_].minY_ - _pos.y)) + RVOMath.sqr(Math.Max(0.0, _pos.y - agentTree_[agentTree_[node].right_].maxY_));

                double rangeSq = (_range + simulator.getMaxRadius()) * (_range + simulator.getMaxRadius());

                if (distSqLeft < distSqRight)
                {
                    if (distSqLeft < rangeSq)
                    {
                        queryPointTreeRecursive(_pos, _range, agentTree_[node].left_, list);

                        if (distSqRight < rangeSq)
                        {
                            queryPointTreeRecursive(_pos, _range, agentTree_[node].right_, list);
                        }
                    }
                }
                else
                {
                    if (distSqRight < rangeSq)
                    {
                        queryPointTreeRecursive(_pos, _range, agentTree_[node].right_, list);

                        if (distSqLeft < rangeSq)
                        {
                            queryPointTreeRecursive(_pos, _range, agentTree_[node].left_, list);
                        }
                    }
                }
            }
        }
Пример #14
0
        /**
         * <summary>Recursive method for building an obstacle k-D tree.
         * </summary>
         *
         * <returns>An obstacle k-D tree node.</returns>
         *
         * <param name="obstacles">A list of obstacles.</param>
         */
        private ObstacleTreeNode buildObstacleTreeRecursive(IList <Obstacle> obstacles)
        {
            if (obstacles.Count == 0)
            {
                return(null);
            }

            ObstacleTreeNode node = new ObstacleTreeNode();

            int optimalSplit = 0;
            int minLeft      = obstacles.Count;
            int minRight     = obstacles.Count;

            for (int i = 0; i < obstacles.Count; ++i)
            {
                int leftSize  = 0;
                int rightSize = 0;

                Obstacle obstacleI1 = obstacles[i];
                Obstacle obstacleI2 = obstacleI1.next_;

                /* Compute optimal split node. */
                for (int j = 0; j < obstacles.Count; ++j)
                {
                    if (i == j)
                    {
                        continue;
                    }

                    Obstacle obstacleJ1 = obstacles[j];
                    Obstacle obstacleJ2 = obstacleJ1.next_;

                    float j1LeftOfI = RVOMath.leftOf(obstacleI1.point_, obstacleI2.point_, obstacleJ1.point_);
                    float j2LeftOfI = RVOMath.leftOf(obstacleI1.point_, obstacleI2.point_, obstacleJ2.point_);

                    if (j1LeftOfI >= -RVOMath.RVO_EPSILON && j2LeftOfI >= -RVOMath.RVO_EPSILON)
                    {
                        ++leftSize;
                    }
                    else if (j1LeftOfI <= RVOMath.RVO_EPSILON && j2LeftOfI <= RVOMath.RVO_EPSILON)
                    {
                        ++rightSize;
                    }
                    else
                    {
                        ++leftSize;
                        ++rightSize;
                    }

                    if (new FloatPair(Mathf.Max(leftSize, rightSize), Mathf.Min(leftSize, rightSize)) >= new FloatPair(Mathf.Max(minLeft, minRight), Mathf.Min(minLeft, minRight)))
                    {
                        break;
                    }
                }

                if (new FloatPair(Mathf.Max(leftSize, rightSize), Mathf.Min(leftSize, rightSize)) < new FloatPair(Mathf.Max(minLeft, minRight), Mathf.Min(minLeft, minRight)))
                {
                    minLeft      = leftSize;
                    minRight     = rightSize;
                    optimalSplit = i;
                }
            }

            {
                /* Build split node. */
                IList <Obstacle> leftObstacles = new List <Obstacle>(minLeft);

                for (int n = 0; n < minLeft; ++n)
                {
                    leftObstacles.Add(null);
                }

                IList <Obstacle> rightObstacles = new List <Obstacle>(minRight);

                for (int n = 0; n < minRight; ++n)
                {
                    rightObstacles.Add(null);
                }

                int leftCounter  = 0;
                int rightCounter = 0;
                int i            = optimalSplit;

                Obstacle obstacleI1 = obstacles[i];
                Obstacle obstacleI2 = obstacleI1.next_;

                for (int j = 0; j < obstacles.Count; ++j)
                {
                    if (i == j)
                    {
                        continue;
                    }

                    Obstacle obstacleJ1 = obstacles[j];
                    Obstacle obstacleJ2 = obstacleJ1.next_;

                    float j1LeftOfI = RVOMath.leftOf(obstacleI1.point_, obstacleI2.point_, obstacleJ1.point_);
                    float j2LeftOfI = RVOMath.leftOf(obstacleI1.point_, obstacleI2.point_, obstacleJ2.point_);

                    if (j1LeftOfI >= -RVOMath.RVO_EPSILON && j2LeftOfI >= -RVOMath.RVO_EPSILON)
                    {
                        leftObstacles[leftCounter++] = obstacles[j];
                    }
                    else if (j1LeftOfI <= RVOMath.RVO_EPSILON && j2LeftOfI <= RVOMath.RVO_EPSILON)
                    {
                        rightObstacles[rightCounter++] = obstacles[j];
                    }
                    else
                    {
                        /* Split obstacle j. */
                        float t = RVOMath.det(obstacleI2.point_ - obstacleI1.point_, obstacleJ1.point_ - obstacleI1.point_) / RVOMath.det(obstacleI2.point_ - obstacleI1.point_, obstacleJ1.point_ - obstacleJ2.point_);

                        Vector2 splitPoint = obstacleJ1.point_ + t * (obstacleJ2.point_ - obstacleJ1.point_);

                        Obstacle newObstacle = new Obstacle();
                        newObstacle.point_     = splitPoint;
                        newObstacle.previous_  = obstacleJ1;
                        newObstacle.next_      = obstacleJ2;
                        newObstacle.convex_    = true;
                        newObstacle.direction_ = obstacleJ1.direction_;

                        newObstacle.id_ = Simulator.Instance.obstacles_.Count;

                        Simulator.Instance.obstacles_.Add(newObstacle);

                        obstacleJ1.next_     = newObstacle;
                        obstacleJ2.previous_ = newObstacle;

                        if (j1LeftOfI > 0.0f)
                        {
                            leftObstacles[leftCounter++]   = obstacleJ1;
                            rightObstacles[rightCounter++] = newObstacle;
                        }
                        else
                        {
                            rightObstacles[rightCounter++] = obstacleJ1;
                            leftObstacles[leftCounter++]   = newObstacle;
                        }
                    }
                }

                node.obstacle_ = obstacleI1;
                node.left_     = buildObstacleTreeRecursive(leftObstacles);
                node.right_    = buildObstacleTreeRecursive(rightObstacles);

                return(node);
            }
        }
Пример #15
0
        /**
         * <summary>Inserts an agent neighbor into the set of neighbors of this
         * agent.</summary>
         *
         * <param name="agent">A pointer to the agent to be inserted.</param>
         * <param name="rangeSq">The squared range around this agent.</param>
         */
        internal void insertAgentNeighbor(Agent agent, ref double rangeSq)
        {
            if (this != agent)
            {
                if (agent.type == AgentType.SkillPush || agent.type == AgentType.SkillObstacle || agent.type == AgentType.SkillUnit)
                {
                    if (agent.isMine == isMine || type == AgentType.SkillUnit)
                    {
                        return;
                    }
                }
                else if (agent.type == AgentType.Building)
                {
                    if (type == AgentType.AirUnit)
                    {
                        return;
                    }
                }
                else
                {
                    if (type == AgentType.SkillUnit)
                    {
                        return;
                    }

                    if ((type == AgentType.AirUnit) != (agent.type == AgentType.AirUnit))
                    {
                        return;
                    }

                    if (weight > agent.weight)
                    {
                        return;
                    }

                    //if (!prefVelocity_.Equals(Vector2.zero) && agent.isMine != isMine)
                    //{
                    //    return;
                    //}
                }

                double distSq = RVOMath.absSq(position_ - agent.position_);

                if (distSq < rangeSq)
                {
                    if (agent.type == AgentType.SkillPush || agent.type == AgentType.Building || agent.type == AgentType.SkillObstacle || agent.type == AgentType.SkillUnit)
                    {
                        double dis = Math.Sqrt(distSq);

                        double maxDis = radius_ + agent.radius_;

                        if (maxDis > dis)
                        {
                            double newSpeed = (maxDis - dis) / simulator.getTimeStep();

                            if (!bePush)
                            {
                                prefVelocity_ = Vector2.zero;

                                bePush = true;

                                beforePushSpeed = maxSpeed_;
                            }

                            if (newSpeed > maxSpeed_)
                            {
                                maxSpeed_ = newSpeed;
                            }
                        }
                    }

                    if (agentNeighbors_.Count < maxNeighbors_)
                    {
                        agentNeighbors_.Add(new KeyValuePair <double, Agent>(distSq, agent));
                    }

                    int i = agentNeighbors_.Count - 1;

                    while (i != 0 && distSq < agentNeighbors_[i - 1].Key)
                    {
                        agentNeighbors_[i] = agentNeighbors_[i - 1];
                        --i;
                    }

                    agentNeighbors_[i] = new KeyValuePair <double, Agent>(distSq, agent);

                    if (agentNeighbors_.Count == maxNeighbors_)
                    {
                        rangeSq = agentNeighbors_[agentNeighbors_.Count - 1].Key;
                    }
                }
            }
        }
Пример #16
0
        /**
         * <summary>Recursive method for computing the agent neighbors of the
         * specified agent.</summary>
         *
         * <param name="agent">The agent for which agent neighbors are to be
         * computed.</param>
         * <param name="rangeSq">The squared range around the agent.</param>
         * <param name="node">The current agent k-D tree node index.</param>
         */
        private void queryAgentTreeRecursive(Agent agent, ref float rangeSq, int node)
        {
            if (agentTree_[node].end_ - agentTree_[node].begin_ <= MAX_LEAF_SIZE)
            {
                for (int i = agentTree_[node].begin_; i < agentTree_[node].end_; ++i)
                {
                    agent.insertAgentNeighbor(agents_[i], ref rangeSq);
                }
            }
            else
            {
                float distSqLeft  = RVOMath.sqr(Mathf.Max(0.0f, agentTree_[agentTree_[node].left_].minX_ - agent.position_.x)) + RVOMath.sqr(Mathf.Max(0.0f, agent.position_.x - agentTree_[agentTree_[node].left_].maxX_)) + RVOMath.sqr(Mathf.Max(0.0f, agentTree_[agentTree_[node].left_].minY_ - agent.position_.y)) + RVOMath.sqr(Mathf.Max(0.0f, agent.position_.y - agentTree_[agentTree_[node].left_].maxY_));
                float distSqRight = RVOMath.sqr(Mathf.Max(0.0f, agentTree_[agentTree_[node].right_].minX_ - agent.position_.x)) + RVOMath.sqr(Mathf.Max(0.0f, agent.position_.x - agentTree_[agentTree_[node].right_].maxX_)) + RVOMath.sqr(Mathf.Max(0.0f, agentTree_[agentTree_[node].right_].minY_ - agent.position_.y)) + RVOMath.sqr(Mathf.Max(0.0f, agent.position_.y - agentTree_[agentTree_[node].right_].maxY_));

                if (distSqLeft < distSqRight)
                {
                    if (distSqLeft < rangeSq)
                    {
                        queryAgentTreeRecursive(agent, ref rangeSq, agentTree_[node].left_);

                        if (distSqRight < rangeSq)
                        {
                            queryAgentTreeRecursive(agent, ref rangeSq, agentTree_[node].right_);
                        }
                    }
                }
                else
                {
                    if (distSqRight < rangeSq)
                    {
                        queryAgentTreeRecursive(agent, ref rangeSq, agentTree_[node].right_);

                        if (distSqLeft < rangeSq)
                        {
                            queryAgentTreeRecursive(agent, ref rangeSq, agentTree_[node].left_);
                        }
                    }
                }
            }
        }
Пример #17
0
        /* Search for the best target velocity. */
        public void computeTargetVelocity()
        {
            orcaLines_.Clear();

            float invTimeHorizonObst = 1.0f / timeHorizonObst_;


            int numObstLines = orcaLines_.Count;

            float invTimeHorizon = 1.0f / timeHorizon_;

            /* Create agent ORCA lines. */
            for (int i = 0; i < agentNeighbors_.Count; ++i)
            {
                RVOAgent other            = agentNeighbors_[i].Value;
                Vector2  relativePosition = other.Position - Position;
                Vector2  relativeVelocity = TargetVelocity - other.TargetVelocity;
                float    distSq           = RVOMath.absSq(relativePosition);
                float    combinedRadius   = Radius + other.Radius;
                float    combinedRadiusSq = RVOMath.sqr(combinedRadius);

                Line    line;
                Vector2 u;

                if (distSq > combinedRadiusSq)
                {
                    /* No collision. */
                    Vector2 w = relativeVelocity - invTimeHorizon * relativePosition;
                    /* Vector from cutoff center to relative velocity. */
                    float wLengthSq = RVOMath.absSq(w);

                    float dotProduct1 = w * relativePosition;

                    if (dotProduct1 < 0.0f && RVOMath.sqr(dotProduct1) > combinedRadiusSq * wLengthSq)
                    {
                        /* Project on cut-off circle. */
                        float   wLength = RVOMath.sqrt(wLengthSq);
                        Vector2 unitW   = w / wLength;

                        line.direction = new Vector2(unitW.y(), -unitW.x());
                        u = (combinedRadius * invTimeHorizon - wLength) * unitW;
                    }
                    else
                    {
                        /* Project on legs. */
                        float leg = RVOMath.sqrt(distSq - combinedRadiusSq);

                        if (RVOMath.det(relativePosition, w) > 0.0f)
                        {
                            /* Project on left leg. */
                            line.direction = new Vector2(relativePosition.x() * leg - relativePosition.y() * combinedRadius, relativePosition.x() * combinedRadius + relativePosition.y() * leg) / distSq;
                        }
                        else
                        {
                            /* Project on right leg. */
                            line.direction = -new Vector2(relativePosition.x() * leg + relativePosition.y() * combinedRadius, -relativePosition.x() * combinedRadius + relativePosition.y() * leg) / distSq;
                        }

                        float dotProduct2 = relativeVelocity * line.direction;

                        u = dotProduct2 * line.direction - relativeVelocity;
                    }
                }
                else
                {
                    /* Collision. Project on cut-off circle of time timeStep. */
                    float invTimeStep = 1.0f / Simulator.Instance.timeStep_;

                    /* Vector from cutoff center to relative velocity. */
                    Vector2 w = relativeVelocity - invTimeStep * relativePosition;

                    float   wLength = RVOMath.abs(w);
                    Vector2 unitW   = w / wLength;

                    line.direction = new Vector2(unitW.y(), -unitW.x());
                    u = (combinedRadius * invTimeStep - wLength) * unitW;
                }

                line.point = TargetVelocity + 0.5f * u;
                orcaLines_.Add(line);
            }


            int lineFail = linearProgram2(orcaLines_, MaxSpeed, PreferredVelocity, false, ref TargetVelocity);

            if (lineFail < orcaLines_.Count)
            {
                linearProgram3(orcaLines_, numObstLines, lineFail, MaxSpeed, ref TargetVelocity);
            }
        }
Пример #18
0
        /**
         * <summary>Solves a one-dimensional linear program on a specified line
         * subject to linear constraints defined by lines and a circular
         * constraint.</summary>
         *
         * <returns>True if successful.</returns>
         *
         * <param name="lines">Lines defining the linear constraints.</param>
         * <param name="lineNo">The specified line constraint.</param>
         * <param name="radius">The radius of the circular constraint.</param>
         * <param name="optVelocity">The optimization velocity.</param>
         * <param name="directionOpt">True if the direction should be optimized.
         * </param>
         * <param name="result">A reference to the result of the linear program.
         * </param>
         */
        private bool linearProgram1(IList <Line> lines, int lineNo, float radius, Vector2 optVelocity, bool directionOpt, ref Vector2 result)
        {
            float dotProduct   = lines[lineNo].point * lines[lineNo].direction;
            float discriminant = RVOMath.sqr(dotProduct) + RVOMath.sqr(radius) - RVOMath.absSq(lines[lineNo].point);

            if (discriminant < 0.0f)
            {
                /* Max speed circle fully invalidates line lineNo. */
                return(false);
            }

            float sqrtDiscriminant = RVOMath.sqrt(discriminant);
            float tLeft            = -dotProduct - sqrtDiscriminant;
            float tRight           = -dotProduct + sqrtDiscriminant;

            for (int i = 0; i < lineNo; ++i)
            {
                float denominator = RVOMath.det(lines[lineNo].direction, lines[i].direction);
                float numerator   = RVOMath.det(lines[i].direction, lines[lineNo].point - lines[i].point);

                if (RVOMath.fabs(denominator) <= RVOMath.RVO_EPSILON)
                {
                    /* Lines lineNo and i are (almost) parallel. */
                    if (numerator < 0.0f)
                    {
                        return(false);
                    }

                    continue;
                }

                float t = numerator / denominator;

                if (denominator >= 0.0f)
                {
                    /* Line i bounds line lineNo on the right. */
                    tRight = Math.Min(tRight, t);
                }
                else
                {
                    /* Line i bounds line lineNo on the left. */
                    tLeft = Math.Max(tLeft, t);
                }

                if (tLeft > tRight)
                {
                    return(false);
                }
            }

            if (directionOpt)
            {
                /* Optimize direction. */
                if (optVelocity * lines[lineNo].direction > 0.0f)
                {
                    /* Take right extreme. */
                    result = lines[lineNo].point + tRight * lines[lineNo].direction;
                }
                else
                {
                    /* Take left extreme. */
                    result = lines[lineNo].point + tLeft * lines[lineNo].direction;
                }
            }
            else
            {
                /* Optimize closest point. */
                float t = lines[lineNo].direction * (optVelocity - lines[lineNo].point);

                if (t < tLeft)
                {
                    result = lines[lineNo].point + tLeft * lines[lineNo].direction;
                }
                else if (t > tRight)
                {
                    result = lines[lineNo].point + tRight * lines[lineNo].direction;
                }
                else
                {
                    result = lines[lineNo].point + t * lines[lineNo].direction;
                }
            }

            return(true);
        }
Пример #19
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)
            {
                Debug.Log("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 - RVOMath.sqr((float)Math.Sin(alpha2));
                b     = 2 * (agents_[i].radius_ * (float)Math.Sin(alpha2) - ic1 * bisector_normalize_vector);
                c     = Vector2.absSq(ic1) - RVOMath.sqr(agents_[i].radius_);
                delta = RVOMath.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);
        }