/** * <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) { float distance = 0.0f; 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; 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 (Vector2.Dot(lines[i].direction, lines[j].direction) > 0.0f) { /* Line i and line j point in the same direction. */ continue; } else { /* Line i and line j point in opposite direction. */ line.point = 0.5f * (lines[i].point + lines[j].point); } } else { line.point = lines[i].point + (RVOMath.det(lines[j].direction, lines[i].point - lines[j].point) / determinant) * lines[i].direction; } line.direction = RVOMath.normalize(lines[j].direction - lines[i].direction); projLines.Add(line); } Vector2 tempResult = result; if (linearProgram2(projLines, radius, new Vector2(-lines[i].direction.y, lines[i].direction.x), true, ref result) < projLines.Count) { /* * This should in principle not happen. The result is by * definition already in the feasible region of this * linear program. If it fails, it is due to small * floating point error, and the current result is kept. */ result = tempResult; } distance = RVOMath.det(lines[i].direction, lines[i].point - result); } } }
/** * <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 = Vector2.Dot(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 = Mathf.Min(tRight, t); } else { /* Line i bounds line lineNo on the left. */ tLeft = Mathf.Max(tLeft, t); } if (tLeft > tRight) { return(false); } } if (directionOpt) { /* Optimize direction. */ if (Vector2.Dot(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 = Vector2.Dot(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); }
/** * <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); } } }