예제 #1
0
        public static Path PathTo(BoundParticle start, Point end, GeometryCollection geometry, float accel, float gravity)
        {
            // construct a new critical point
            Point newPoint = start.position();
            Line line1 = new Line(newPoint, start.boundTo.p1);
            Line line2 = new Line(newPoint, start.boundTo.p2);
            geometry.Add(line1);
            geometry.Add(line2);
            geometry.Remove(start.boundTo);

            Queue<PathCriticalPoint> bfs = new Queue<PathCriticalPoint>();
            // map time function for two attached points
            Dictionary<PathCriticalPoint, PointFunction> dict = new Dictionary<PathCriticalPoint, PointFunction>();
            PathCriticalPoint state1 = new PathCriticalPoint(line1, true);
            PathCriticalPoint state2 = new PathCriticalPoint(line2, true);
            dict[state1] = new PointFunction(0);
            dict[state2] = new PointFunction(0);
            bfs.Enqueue(state1);
            bfs.Enqueue(state2);
            // bfs will simply search through steps, and will not continue a branch if it doesn't improve anything
            while (bfs.Count > 0)
            {
                var head = bfs.Dequeue();
                // TODO: currently not going back to previously visited points, as the logic isn't correct for it
                var currPoint = head.firstPoint ? head.line.p1 : head.line.p2;
                foreach (var nextLine in geometry.LinesAttachedTo(currPoint).Where(l => !l.Equals(head.line)))
                {
                    var nextPoint = (nextLine.p1.Equals(currPoint)) ? nextLine.p2 : nextLine.p1;
                    var nextState = new PathCriticalPoint(nextLine, nextLine.p1.Equals(nextPoint));
                    PointFunction timings = new PointFunction(currPoint, nextPoint, dict[head], accel, gravity);
                    WorkWithTimings(end, geometry, bfs, dict, nextState, timings);
                    // also attempt to return along that path
                    var nextState2 = new PathCriticalPoint(nextLine, nextLine.p1.Equals(currPoint));
                    PointFunction timings2 = PointFunction.Return(currPoint, nextPoint, dict[head], accel, gravity);
                    WorkWithTimings(end, geometry, bfs, dict, nextState2, timings2);
                }
            }
            Path answer = null;
            if (ContainsAnyState(dict, end, geometry, 0))
            {
                answer = BestOfAnyState(dict, end, geometry, 0);
            }
            geometry.Remove(newPoint);
            geometry.Add(start.boundTo);
            return answer;
        }
예제 #2
0
 public PointFunction(Geometry.Point p1, Geometry.Point p2, PointFunction old, float accel, float gravity)
 {
     Vector2 path = ((Vector2)p2-(Vector2)p1);
     Vector2 normalized = path;
     normalized.Normalize();
     float g = gravity * path.Y / path.Length();
     // r and l have been specifically framed this way, and affect several equations
     float r = g + accel;
     float l = -g + accel;
     float d = path.Length();
     foreach(var pair in old.timings)
     {
         // is positive if it assists acceleration towards p2 (aka right)
         float b = FromKey(pair.Key);
         // collisions reduce speed
         Vector2 prevPath = (Vector2)p1 - pair.Value.posAt(0);
         if (prevPath != Vector2.Zero)
         {
             b *= Math.Abs(Vector2.Dot(path, prevPath)) / (path.Length() * prevPath.Length());
         }
         Parabola fullSpeedPath = new Parabola(r, b, 0);
         Parabola fullRetreatPath = new Parabola(-l, b, 0);
         Paraboloid speedThenRetreat = fullSpeedPath.FollowedBy(fullRetreatPath);
         int lowerBound = ToKey(fullRetreatPath.SpeedAt(d, 0));
         int upperBound = ToKey(fullSpeedPath.SpeedAt(d, 0));
         for (int i = lowerBound; i <= upperBound; i++)
         {
             float f = FromKey(i);
             float newPartialTime = speedThenRetreat.SpecialShit(d, f, -1);
             if (newPartialTime >= 0)
             {
                 float newT = newPartialTime + pair.Value.totalTime;
                 if (!timings.ContainsKey(i) || timings[i].totalTime > newT)
                 {
                     float rT = (l * newPartialTime + f - b) / (l + r);
                     float lT = newPartialTime - rT;
                     timings[i] = new Path(newT-lT, p1, b * normalized, r * normalized, pair.Value);
                     timings[i] = new Path(newT, timings[i].posAt(rT), timings[i].vAt(rT), -l * normalized, timings[i]);
                 }
             }
         }
     }
 }
예제 #3
0
 private static void WorkWithTimings(Point end, GeometryCollection geometry, Queue<PathCriticalPoint> bfs, Dictionary<PathCriticalPoint, PointFunction> dict, PathCriticalPoint nextState, PointFunction timings)
 {
     if (dict.ContainsKey(nextState))
     {
         double lowestChange = dict[nextState].improved(timings);
         if (!double.IsInfinity(lowestChange))
         {
             if (!ContainsAnyState(dict, end, geometry, 0) || lowestChange < BestOfAnyState(dict, end, geometry, 0).totalTime)
             {
                 bfs.Enqueue(nextState);
             }
         }
     }
     else
     {
         double lowestChange = (timings.timings.Count > 0) ? timings.timings.OrderBy(p => p.Value.totalTime).First().Value.totalTime : double.PositiveInfinity;
         dict[nextState] = timings;
         if (!ContainsAnyState(dict, end, geometry, 0) || lowestChange < BestOfAnyState(dict, end, geometry, 0).totalTime)
         {
             bfs.Enqueue(nextState);
         }
     }
 }
예제 #4
0
 internal static PointFunction Return(Geometry.Point p1, Geometry.Point p2, PointFunction old, float accel, float gravity)
 {
     // either you accelerate fully away and then return to get a higher speed, or you try to backpedel and then brace yourself to get a lower speed
     PointFunction answer = new PointFunction();
     Vector2 path = ((Vector2)p2 - (Vector2)p1);
     Vector2 normalized = path;
     normalized.Normalize();
     float g = gravity * path.Y / path.Length();
     // r and l have been specifically framed this way, and affect several equations
     float r = g + accel;
     float l = -g + accel;
     float d = (p1.v.Position - p2.v.Position).Length();
     foreach (var pair in old.timings)
     {
         // is positive if it assists acceleration towards p2 (aka right)
         float b = FromKey(pair.Key);
         // collisions reduce speed
         Vector2 l1 = (Vector2)p2 - (Vector2)p1;
         Vector2 l2 = (Vector2)p1 - pair.Value.posAt(0);
         if (l2 != Vector2.Zero)
         {
             b *= Math.Abs(Vector2.Dot(l1, l2)) / (l1.Length() * l2.Length());
         }
         // old
         /*int lowerBound = ToKey(b);
         int upperBound = ToKey(Math.Sqrt(Math.Max(b * b + 2 * r * d, 0)));
         float newPartialTime = 2 * b / l;
         if (true)
         {
             float newT = newPartialTime + pair.Value.totalTime;
             int i = ToKey(b);
             if (!answer.timings.ContainsKey(i) || answer.timings[i].totalTime > newT)
             {
                 answer.timings[i] = new Path(newT, p1, b * normalized, -l * normalized, pair.Value);
             }
          }*/
         // if trying to speed up first
         Parabola fullSpeedPath = new Parabola(r, b, 0);
         Parabola fullRetreatPath = new Parabola(-l, b, 0);
         Paraboloid speedThenRetreat = fullSpeedPath.FollowedBy(fullRetreatPath);
         int lowerBound = ToKey(b);
         int upperBound = ToKey(Math.Sqrt(2*l*d));
         //int upperBound = ToKey();
         for (int i = lowerBound; i <= upperBound; i++)
         {
             float f = FromKey(i);
             float newPartialTime = speedThenRetreat.SpecialShit(0, -f, -1);
             if (newPartialTime >= 0)
             {
                 float newT = newPartialTime + pair.Value.totalTime;
                 if (!answer.timings.ContainsKey(i) || answer.timings[i].totalTime > newT)
                 {
                     //float rT = newPartialTime * 0.27f;
                     //float rT = (l * newPartialTime + f - b) / (l + r);
                     //f=b+rt-lg
                     //T=t+g
                     //lT+f=b+rt+lt
                     //t=(lT+f-b)/(l+r)
                     float rT = (l * newPartialTime - f - b) / (l + r);
                     float lT = newPartialTime - rT;
                     answer.timings[i] = new Path(newT - lT, p1, b * normalized, r * normalized, pair.Value);
                     answer.timings[i] = new Path(newT, answer.timings[i].posAt(rT), answer.timings[i].vAt(rT), -l * normalized, answer.timings[i]);
                 }
             }
         }
     }
     return answer;
 }
예제 #5
0
 internal double improved(PointFunction newTimings)
 {
     double improved = double.PositiveInfinity;
     foreach (var pair in newTimings.timings)
     {
         if (!timings.ContainsKey(pair.Key) || timings[pair.Key].totalTime > pair.Value.totalTime)
         {
             timings[pair.Key] = pair.Value;
             improved = Math.Min(pair.Value.totalTime, improved);
         }
     }
     return improved;
 }