Example #1
0
 public Parabola2D(Point2D focus, Line2D directrix)
     : base(ShapeType2D.ParametricCurve)
 {
     m_focus = focus;
      m_directrix = directrix;
      m_tOffset = m_directrix.NearestT(m_focus);
 }
Example #2
0
        public Triangle2D(Point2D a, Point2D b, Point2D c)
            : base(ShapeType2D.Triangle)
        {
            m_a = a;
             m_b = b;
             m_c = c;

             m_eab = new Line2D(a, b);
             m_ebc = new Line2D(b, c);
             m_eca = new Line2D(c, a);
        }
Example #3
0
        public Shape2D FindLineIntersection(Line2D line)
        {
            // line-parabola intersection will always have two points, unless we have the degenerate
             // case where the line fails to reach the parabola or passes through the vertex and focus.
             // we're looking for points equidistant from the directrix and focus which line contains.
             // There should be one or two circles along the line (with radius from line to focus/directrix)
             // which fit our criteria
             // line: pt = p0 + v0 * t, xt = x0 + vx * t, yt = y0 + vy * t
             // solve for where distance[linePoint, focus] == distance[linePoint, directrix]
             //
             // if distance[linePoint, focus] == distance[linePoint, directrix],
             // then distance[linePoint, focus]^2 == distance[linePoint, directrix]^2,
             // then distance[linePoint, focus]^2 - distance[linePoint, directrix]^2 == 0
             //
             // distance[linePoint, focus] = Sqrt[(xt - focusX)^2 + (yt - focusY)^2]
             //                            = Sqrt[(x0 + vx * t - focusX)^2 + (y0 + vy * t - focusY)^2]
             //
             // distance[linePoint, focus]^2 = (x0 + vx * t - focusX)^2 + (y0 + vy * t - focusY)^2
             //                              = (vx * t + (x0 - focusX))^2 + (vy * t + y0 - focusY)^2
             //                              = t^2 * vx^2 + t * 2 * vx * (x0 - focusX) + (x0 - focusX)^2 +
             //                                t^2 * vy^2 + t * 2 * vy * (y0 - focusY) + (y0 - focusY)^2
             //                              = t^2 (vx^2 + vy^2) + 2t (vx(x0 - focusX) + vy(y0 - focusY)) + ((x0 - focusX)^2 + (y0 - focusY)^2)
             //
             // let dv = directrixPoint1 - directrixPoint2 = dp1 - dp2
             // let dvPerp = dv.perp();
             // let r = dp1 - pt
             //
             // distance[linePoint, directrix] = |Project r onto dvPerpHat|
             //                                = |r dot dvPerpHat|
             //                                = |r dot dvPerp| / |dvPerp|
             //                                = (rx * dvpx + ry * dvpy) / sqrt(dvpx^2 + dvpy^2)
             //                                = ((dp1x - ptx) * dvpx + (dp1y - pty) * dvpy) / Sqrt[dvpx * dvpx + dvpy * dvpy]
             //                                = ((dp1x - (x0 + vx * t)) * dvpx + (dp1y - (y0 + vy * t)) * dvpy) / Sqrt[dvpx * dvpx + dvpy * dvpy]
             //                                = (dp1x * dvpx + dp1y * dvpy - dvpx * t * vx - dvpy * t * vy - dvpx * x0 - dvpy * y0) / Sqrt[dvpx * dvpx + dvpy * dvpy]
             //                                = (dp1x * dvpx + dp1y * dvpy - dvpx * x0 - dvpy * y0 - dvpx * t * vx - dvpy * t * vy) / Sqrt[dvpx * dvpx + dvpy * dvpy]
             //                                = ((dp1x * dvpx + dp1y * dvpy - dvpx * x0 - dvpy * y0) - dvpx * t * vx - dvpy * t * vy) / Sqrt[dvpx * dvpx + dvpy * dvpy]
             //                                = ((dp1x * dvpx + dp1y * dvpy - dvpx * x0 - dvpy * y0) + (-t)(dvpx * vx + dvpy * vy)) / Sqrt[dvpx * dvpx + dvpy * dvpy]
             //
             // distance[linePoint, directrix]^2 = the above squared.
             // = dp1x^2 dvpx^2 + 2 dp1x dp1y dvpx dvpy + dp1y^2 dvpy^2 - 2 dp1x dvpx^2 t vx - 2 dp1y dvpx dvpy t vx + dvpx^2 t^2 vx^2 - 2 dp1x dvpx dvpy t vy - 2 dp1y dvpy^2 t vy + 2 dvpx dvpy t^2 vx vy + dvpy^2 t^2 vy^2 - 2 dp1x dvpx^2 x0 - 2 dp1y dvpx dvpy x0 + 2 dvpx^2 t vx x0 + 2 dvpx dvpy t vy x0 + dvpx^2 x0^2 - 2 dp1x dvpx dvpy y0 - 2 dp1y dvpy^2 y0 + 2 dvpx dvpy t vx y0 + 2 dvpy^2 t vy y0 + 2 dvpx dvpy x0 y0 + dvpy^2 y0^2
             //
             // back to distance[linePoint, focus]^2 - distance[linePoint, directrix]^2 == 0, we basically have a quadratic equation.
             // a = (vx^2 - dvpx^2 vx^2 - 2 dvpx dvpy vx vy + vy^2 - dvpy^2 vy^2)
             // b = (2 dp1x dvpx^2 vx + 2 dp1y dvpx dvpy vx + 2 dp1x dvpx dvpy vy + 2 dp1y dvpy^2 vy - 2 dvpx^2 vx x0 - 2 dvpx dvpy vy x0 - 2 dvpx dvpy vx y0 - 2 dvpy^2 vy y0 + 2 (vx (-focusX + x0) + vy (-focusY + y0)))
             // c = -dp1x^2 dvpx^2 - 2 dp1x dp1y dvpx dvpy - dp1y^2 dvpy^2 + 2 dp1x dvpx^2 x0 + 2 dp1y dvpx dvpy x0 - dvpx^2 x0^2 + (-focusX + x0)^2 + 2 dp1x dvpx dvpy y0 + 2 dp1y dvpy^2 y0 - 2 dvpx dvpy x0 y0 - dvpy^2 y0^2 + (-focusY + y0)^2
             // at^2 + bt + c == 0... t = (-b +- Sqrt[b^2 - 4ac)) / 2a

             var p0 = line.Start;
             var x0 = p0.X;
             var y0 = p0.Y;
             var v = line.Vector;
             var vx = v.X;
             var vy = v.Y;
             var dp1 = m_directrix.Start;
             var dp2 = m_directrix.PointAtT(1.0);
             var dp1x = dp1.X;
             var dp1y = dp1.Y;
             var dv = dp1 - dp2;
             var dvp = dv.Perp();
             var dvpx = dvp.X;
             var dvpy = dvp.Y;
             var focusX = m_focus.X;
             var focusY = m_focus.Y;
             var a = vx * vx - dvpx * dvpx * vx * vx - 2.0 * dvpx * dvpy * vx * vy + vy * vy - dvpy * dvpy * vy * vy;
             var b = 2.0 * dp1x * dvpx * dvpx * vx + 2.0 * dp1y * dvpx * dvpy * vx + 2.0 * dp1x * dvpx * dvpy * vy + 2.0 * dp1y * dvpy * dvpy * vy - 2.0 * dvpx * dvpx * vx * x0 - 2.0 * dvpx * dvpy * vy * x0 - 2.0 * dvpx * dvpy * vx * y0 - 2.0 * dvpy * dvpy * vy * y0 + 2.0 * (vx * (-focusX + x0) + vy * (-focusY + y0));
             var c = -dp1x * dp1x * dvpx * dvpx - 2.0 * dp1x * dp1y * dvpx * dvpy - dp1y * dp1y * dvpy * dvpy + 2.0 * dp1x * dvpx * dvpx * x0 + 2.0 * dp1y * dvpx * dvpy * x0 - dvpx * dvpx * x0 * x0 + (-focusX + x0) * (-focusX + x0) + 2 * dp1x * dvpx * dvpy * y0 + 2.0 * dp1y * dvpy * dvpy * y0 - 2.0 * dvpx * dvpy * x0 * y0 - dvpy * dvpy * y0 * y0 + (-focusY + y0) * (-focusY + y0);
             var discriminant = b * b - 4.0 * a * c;
             var tCenter = -b / (2 * a);
             if (discriminant < 0)
            return null;
             else if (discriminant.Within(0, kContainsEpsilon))
            return PointAtT(tCenter);
             else
             {
            var tOffset = Math.Sqrt(discriminant);
            return new PointCollection2D(PointAtT(tCenter - tOffset), PointAtT(tCenter + tOffset));
             }
        }
Example #4
0
        public Point2D PointAtT(double t)
        {
            t = t + m_tOffset;

             // Form perpendicular bisector of directrix at t
             var offset = m_directrix.OffsetToT(t);
             var perpBisector = new Line2D(m_directrix.Start + offset, m_directrix.Vector.Perp());
             var offsetMagnitude = offset.Magnitude();

             // Find point on perp bisector which is equidistant from directrix and site.
             // directrix distance squared = (vx * t)^2 + (vy * t)^2
             // the point is at p0 + v * t, x = x0 + vx * t, y = y0 + vy * t
             // focus distance squared = (x - focusX)^2 + (y - focusY)^2
             //                        = (x0 + vx * t - focusX)^2 + (y0 + vy * t - focusY)^2
             //                        = (vx * t + (x0 - focusX))^2 + (vy * t + (y0 - focusY))^2
             // let x0f = x0 - focusX, y0f = y0 - focusY
             //                        = (vx * t + x0f)^2 + (vy * t + y0f)^2
             //                        = vx^2 * t^2 + 2 * vx * t * x0f + x0f^2 + vy^2 * t^2 + 2 * vy * t * y0f + y0f^2
             //                        = (vx^2 + vy^2) * t^2 + (2 * vx * x0f + 2 * vy * y0f) * t + (x0f^2 + y0f^2)
             // Equate these two (with t being the only variable) to solve equation...

             // todo: not fully implemented!

             // Find two points on perp bisector at the same distance from point as offset...
             // we want the point with the lowest t, as that is closest to the directrix.
             // this is a simple line-circle intersection.
             // circle: r^2 = (X-focusX)^2 + (Y-focusY)^2
             // line: p@t = p + v*t, xt = x0 + vx * t, yt = y0 + vy * t
             // r^2 = (x0 + vx * t - focusX)^2 + (y0 + vy * t - focusY)^2
             // r^2 = (vx * t + x0 - focusX)^2 + (vy * t + y0 - focusY)^2
             // r^2 = (vx * t)^2 - 2 * (vx * t) * (x0 - focusX) + (x0 - focusX)^2 +
             //       (vy * t)^2 - 2 * (vy * t) * (y0 - focusY) + (y0 - focusY)^2
             // r^2 = t^2 * vx^2 - t * 2 * vx * (x0 - focusX) + (x0 - focusX)^2 +
             //       t^2 * vy^2 - t * 2 * vy * (y0 - focusY) + (y0 - focusY)^2
             // r^2 = t^2 * (vx^2 + vy^2) - t * 2(vx(x0 - focusX) + vy(y0 - focusY)) + ((x0 - focusX)^2 + (y0 - focusY)^2)
             //   0 = t^2 * (vx^2 + vy^2) - t * 2(vx(x0 - focusX) + vy(y0 - focusY)) + ((x0 - focusX)^2 + (y0 - focusY)^2 - r^2)
             // a = vx^2 + vy^2
             // b = -2 (vx(x0 - focusX) + vy(y0 - focusY))
             // c = (x0 - focusX)^2 + (y0 - focusY)^2 - r^2
             // t = (-b +- sqrt[b^2 - 4ac])/2a
             var a = perpBisector.Start.X * perpBisector.Start.X + perpBisector.Start.Y * perpBisector.Start.Y;
             var b = -2.0 * (perpBisector.Vector.X * (perpBisector.Start.X - m_focus.X) +
                         perpBisector.Vector.Y * (perpBisector.Start.Y - m_focus.Y));
             var c = (perpBisector.Start.X - m_focus.X) * (perpBisector.Start.X - m_focus.X) +
                 (perpBisector.Start.Y - m_focus.Y) * (perpBisector.Start.Y - m_focus.Y) -
                 offsetMagnitude * offsetMagnitude;

             var discriminant = b * b - 4.0 * a * c;
             var amul2 = a * 2.0;
             var tCenter = -b / amul2;
             if (discriminant < 0)
            throw new Exception("Math error - discriminant shouldn't ever be 0...");
             else if (discriminant <= double.Epsilon)
            return perpBisector.PointAtT(tCenter);
             else // select the lower t; it's closer to the start of the perp bisector
             {
            var tOffset = Math.Sqrt(discriminant) / amul2; // always positive
            return perpBisector.PointAtT(tCenter - tOffset);
             }
        }
Example #5
0
 public void ConnectWith(Cell other)
 {
     var segment = new Line2D(new Point2D(x, y), new Point2D(other.X, other.Y));
      var connector = new CellConnector(this, other, segment, ConnectorState.Unlinked);
      connectors.Add(connector);
      other.connectors.Add(connector);
 }
Example #6
0
 public void CutLine(Line2D line, Renderer renderer = null)
 {
     foreach (var connector in grid.Cells.SelectMany(x => x.Connectors).Distinct()) {
     var intersection = connector.Segment.FindLineIntersection(line);
     if (intersection == line) {
        // wrong
        connector.connectorState = ConnectorState.Banned;
     } else if (intersection is Point2D) {
        var t1 = connector.Segment.NearestT((Point2D)intersection);
        var t2 = line.NearestT((Point2D)intersection);
        if (t1 >= 0 && t1 <= 1 && t2 >= 0 && t2 <= 1) {
           connector.connectorState = ConnectorState.Banned;
        }
     }
      }
      renderer?.RenderGrid(grid);
 }
Example #7
0
 public CellConnector(Cell first, Cell second, Line2D segment,  ConnectorState connectorState = ConnectorState.Unlinked)
 {
     this.first = first;
      this.second = second;
      this.segment = segment;
      this.connectorState = connectorState;
 }
 public Voronoi(Point2D[] points, Line2D[] edges)
 {
 }
Example #9
0
        // - Intersections --------------------------------------------------------------------------
        public Shape2D FindLineIntersection(Line2D line)
        {
            // :: handle the cases where lines are both horizontal or both vertical
             if (m_isEssentiallyHorizontal && line.m_isEssentiallyHorizontal)
            return Math.Abs(m_p.Y - line.m_p.Y) < kContainsEpsilon ? this : null;

             if (m_isEssentiallyVertical && line.m_isEssentiallyVertical)
            return Math.Abs(m_p.X - line.m_p.X) < kContainsEpsilon ? this : null;

             // :: handle the case where we have a horizontal and a vertical line.
             if (m_isEssentiallyHorizontal && line.m_isEssentiallyVertical)
            return new Point2D(line.m_p.X, m_p.Y);

             if (m_isEssentiallyVertical && line.m_isEssentiallyHorizontal)
            return new Point2D(m_p.X, line.m_p.Y);

             // :: handle the case where one of the lines is horizontal/vertical and the other isn't
             Line2D a = this;
             Line2D b = line;
             if ((!m_isEssentiallyHorizontal && line.m_isEssentiallyHorizontal) ||
             (!m_isEssentiallyVertical && line.m_isEssentiallyVertical))
             {
            a = line;
            b = this;
             }

             // :: a can be horizontal/vertical, b cannot be either.
             if (a.m_isEssentiallyVertical)
            return b.PointAtX(a.m_p.X);

             if (a.m_isEssentiallyHorizontal)
            return b.PointAtY(a.m_p.Y);

             // :: neither is vertical or horizontal, reparameterize line to start at m_p.x
             var lineStart = line.PointAtX(m_p.X);

             // let height = y difference, also find dHeight/dX
             var height = lineStart.Y - m_p.Y;
             var dhdx = (line.m_v.Y / line.m_v.X) - (m_v.Y / m_v.X);

             var dxToIntersect = -(height / dhdx);
             return m_p + (m_v / m_v.X) * dxToIntersect;
        }
Example #10
0
        public Shape2D FindIntersection(Shape2D shape)
        {
            // ensure that 'this' is less or as primative as shape
             if (Type > shape.Type)
            return shape.FindIntersection(this);

             // find intersection
             if (this.Type == ShapeType2D.Point)
            return shape.Contains((Point2D)this) ? this : null;
             else if (this.Type == ShapeType2D.Line) {
            if (shape.Type == ShapeType2D.Line)
               return ((Line2D)this).FindLineIntersection((Line2D)shape);
            else if (shape.Type == ShapeType2D.Triangle) {
               var line = (Line2D)this;
               var triangle = (Triangle2D)shape;
               var abLine = new Line2D(triangle.A, triangle.B);
               var abIntersection = line.FindIntersection(abLine);
               var bcLine = new Line2D(triangle.B, triangle.C);
               var bcIntersection = line.FindIntersection(bcLine);
               var caLine = new Line2D(triangle.C, triangle.A);
               var caIntersection = line.FindIntersection(caLine);

               var abIntersectionLine = abIntersection as Line2D;
               var bcIntersectionLine = bcIntersection as Line2D;
               var caIntersectionLine = caIntersection as Line2D;
               var intersectionLine = abIntersectionLine ?? bcIntersectionLine ?? caIntersectionLine;
               if (intersectionLine != null) {
                  return intersectionLine;
               } else {
                  var points = new List<Point2D>();
                  if (abIntersection != null) {
                     var abIntersectionPoint = (Point2D)abIntersection;
                     var t = abLine.NearestT(abIntersectionPoint);
                     if (0 <= t && t <= 1) {
                        points.Add(abIntersectionPoint);
                     }
                        Console.WriteLine(t);
                  }

                  if (bcIntersection != null) {
                     var bcIntersectionPoint = (Point2D)bcIntersection;
                     var t = bcLine.NearestT(bcIntersectionPoint);
                     if (0 <= t && t <= 1) {
                        points.Add(bcIntersectionPoint);
                     }
                     Console.WriteLine(t);
                  }

                  if (caIntersection != null) {
                     var caIntersectionPoint = (Point2D)caIntersection;
                     var t = caLine.NearestT(caIntersectionPoint);
                     if (0 <= t && t <= 1) {
                        points.Add(caIntersectionPoint);
                     }
                     Console.WriteLine(t);
                  }

                  if (points.Count == 0) {
                     return null;
                  } else if (points.Count == 1) {
                     return points.First();
                  } else {
                     Console.WriteLine(points.Count);
                     Trace.Assert(points.Count == 2);
                     var pointCollection = new PointCollection2D(points.ToArray());
                     return pointCollection;
                  }
               }
            }
             }
             throw new System.NotImplementedException("Intersection between " + shape.Type + " and " + Type + " not implemented.");
        }
        private void HandleRender(object sender, RenderEventArgs e)
        {
            var startPoint = new Point2D(15, 5);
             var endPoint = new Point2D(55, 40);
             this.gridlet.Cells[(int)(startPoint.X + startPoint.Y * gridlet.XLength)].Flags |= CellFlags.Debug;
             this.gridlet.Cells[(int)(endPoint.X + endPoint.Y * gridlet.XLength)].Flags |= CellFlags.Debug;

             if (!isGraphicsInitialized) {
            InitializeGraphics(e.GraphicsDevice);
            isGraphicsInitialized = true;
             }

             var graphicsDevice = e.GraphicsDevice;
             var renderer = e.Renderer;
             e.BasicEffect.World = gridlet.Orientation * Matrix.Translation(gridlet.X, gridlet.Y, gridlet.Z);
             e.BasicEffect.Texture = debugTexture;
             e.BasicEffect.TextureEnabled = true;
             e.BasicEffect.DiffuseColor = Vector4.One;
             var samplerStateDescription = SamplerStateDescription.Default();
             samplerStateDescription.Filter = Filter.ComparisonMinMagMipPoint;
             e.BasicEffect.Sampler = SamplerState.New(graphicsDevice, samplerStateDescription);
             e.BasicEffect.CurrentTechnique.Passes[0].Apply();
             graphicsDevice.SetRasterizerState(graphicsDevice.RasterizerStates.CullBack);
             graphicsDevice.SetVertexBuffer(0, vertexBuffer, 0);
             graphicsDevice.SetVertexInputLayout(vertexInputLayout);
             graphicsDevice.SetIndexBuffer(indexBuffer, true);
             graphicsDevice.DrawIndexed(PrimitiveType.TriangleList, indexBuffer.ElementCount);

             var meshTransform = gridlet.Orientation * Matrix.Translation(gridlet.X, gridlet.Y, gridlet.Z);
             foreach (var meshTriangle in gridlet.Mesh) {
            var a = new Vector3((float)meshTriangle.Points[0].X, (float)meshTriangle.Points[0].Y, 0);
            var b = new Vector3((float)meshTriangle.Points[1].X, (float)meshTriangle.Points[1].Y, 0);
            var c = new Vector3((float)meshTriangle.Points[2].X, (float)meshTriangle.Points[2].Y, 0);
            Vector3.Transform(ref a, ref meshTransform, out a);
            Vector3.Transform(ref b, ref meshTransform, out b);
            Vector3.Transform(ref c, ref meshTransform, out c);
            //            var n = meshTriangle. Vector3.Cross((a - b), b - c);
            var color = true ? Color.Cyan : Color.Green;
            renderer.DrawDebugLine(a, b, color);
            ;
            renderer.DrawDebugLine(b, c, color);
            renderer.DrawDebugLine(c, a, color);

            foreach (var neighbor in meshTriangle.Neighbors.Where(n => n != null)) {
               Console.WriteLine(neighbor.IsInterior);
            }

            foreach (var neighbor in meshTriangle.Neighbors.Where(n => n != null && n.IsInterior)) {
               Console.WriteLine("!@#!@#@#");
               var meshCentroid = meshTriangle.Centroid();
               var neighborCentroid = neighbor.Centroid();
               var centroidA = new Vector3(meshCentroid.Xf, meshCentroid.Yf, 0);
               var centroidB = new Vector3(neighborCentroid.Xf, neighborCentroid.Yf, 0);
               Vector3.Transform(ref centroidA, ref meshTransform, out centroidA);
               Vector3.Transform(ref centroidB, ref meshTransform, out centroidB);
               renderer.DrawDebugLine(
                  centroidA,
                  centroidB,
                  Color.Red
               );
            }
             }

             foreach (var neighbor in gridlet.Neighbors) {
            renderer.DrawDebugLine(
               gridlet.OrientedBoundingBox.Center,
               neighbor.OrientedBoundingBox.Center,
               Color.Magenta
            );
             }

             var mesh = gridlet.Mesh;
             var startTriangle = mesh.First(
            x => new Triangle2D(
               new Point2D(x.Points[0].Xf, x.Points[0].Yf),
               new Point2D(x.Points[1].Xf, x.Points[1].Yf),
               new Point2D(x.Points[2].Xf, x.Points[2].Yf)).Contains(startPoint - new Point2D(gridlet.XLength / 2.0, gridlet.YLength / 2.0))
             );
             var endTriangle = mesh.First(
            x => new Triangle2D(
               new Point2D(x.Points[0].Xf, x.Points[0].Yf),
               new Point2D(x.Points[1].Xf, x.Points[1].Yf),
               new Point2D(x.Points[2].Xf, x.Points[2].Yf)).Contains(endPoint - new Point2D(gridlet.XLength / 2.0, gridlet.YLength / 2.0))
             );

             ConcurrentDictionary<DelaunayTriangle, double> distancesByTriangle = new ConcurrentDictionary<DelaunayTriangle, double>();
             distancesByTriangle.TryAdd(startTriangle, 0);
             var lastCount = 0;
             while (lastCount != distancesByTriangle.Count) {
            lastCount = distancesByTriangle.Count;
            foreach (var kvp in distancesByTriangle) {
               var triangle = kvp.Key;
               var distance = kvp.Value;
               foreach (var neighbor in triangle.Neighbors.Where(n => n != null && n.IsInterior).Where(n => n.Points.Union(triangle.Points).Distinct().Count() == 4)) {
                  var triangleCentroid = triangle.Centroid();
                  if (triangle == startTriangle) {
                     triangleCentroid = new TriangulationPoint(startPoint.X - gridlet.XLength / 2.0, startPoint.Y - gridlet.YLength / 2.0);
                  } else if (triangle == endTriangle) {
                     triangleCentroid = new TriangulationPoint(endPoint.X - gridlet.XLength / 2.0, endPoint.Y - gridlet.YLength / 2.0);
                  }
                  var neighborCentorid = neighbor.Centroid();
                  var neighborDistance = distance + Math.Pow(triangleCentroid.X - neighborCentorid.X, 2) + Math.Pow(triangleCentroid.Y - neighborCentorid.Y, 2);
                  distancesByTriangle.AddOrUpdate(
                     neighbor,
                     add => neighborDistance,
                     (update, existing) => Math.Min(existing, neighborDistance)
                  );
               }
            }
             }
             foreach (var kvp in distancesByTriangle) {
            var triangle = kvp.Key;
            var distance = kvp.Value;
            foreach (var neighbor in triangle.Neighbors.Where(n => n != null && n.IsInterior)) {
               var triangleCentroid = triangle.Centroid();
               var neighborCentorid = neighbor.Centroid();
               var neighborDistance = distance + Math.Pow(triangleCentroid.X - neighborCentorid.X, 2) + Math.Pow(triangleCentroid.Y - neighborCentorid.Y, 2);
               distancesByTriangle.AddOrUpdate(
                  neighbor,
                  add => neighborDistance,
                  (update, existing) => Math.Min(existing, neighborDistance)
               );
            }
             }
             var path = new List<DelaunayTriangle>();
             {
            var currentNode = endTriangle;
            while (currentNode != startTriangle) {
               path.Insert(0, currentNode);
               currentNode = currentNode.Neighbors.Where(n => n != null && n.IsInterior).MinBy(distancesByTriangle.Get);
            }
            path.Insert(0, currentNode);
             }

             for (var i = 0; i < path.Count - 1; i++) {
            var startCentroid = new Vector3(path[i].Centroid().Xf, path[i].Centroid().Yf, 0);
            var endCentroid = new Vector3(path[i + 1].Centroid().Xf, path[i + 1].Centroid().Yf, 0);

            Vector3.Transform(ref startCentroid, ref meshTransform, out startCentroid);
            Vector3.Transform(ref endCentroid, ref meshTransform, out endCentroid);
            e.Renderer.DrawDebugLine(startCentroid, endCentroid, Color.White);
             }
            //         path = new[] { 5, 6, 13, 12, 11, 0 }.Select(mesh.Get).ToList();
             {

            var finalPath = new List<Point2D>();
            var currentPoint = new Point2D(startPoint.X - Gridlet.XLength / 2.0, startPoint.Y - gridlet.YLength / 2.0);
            var currentSharedPoints = path[0].Points.Intersect(path[1].Points).ToArray();
            finalPath.Add(currentPoint);
            try {
               for (var i = 1; i < path.Count; i++) {
                  TriangulationPoint[] sharedPoints;
                  Point2D commonPoint, newPoint, oldOther;
                  if (i < path.Count - 1) {
                     sharedPoints = path[i].Points.Intersect(path[i + 1].Points).ToArray();
                     var commonPoints = sharedPoints.Intersect(currentSharedPoints).ToArray();
                     Trace.Assert(commonPoints.Length == 1);
                     var commonPoint_ = commonPoints[0];
                     commonPoint = new Point2D(commonPoint_.X, commonPoint_.Y);
                     var newPoint_ = sharedPoints.First(p => !p.Equals(commonPoint_));
                     newPoint = new Point2D(newPoint_.X, newPoint_.Y);
                     var oldOther_ = currentSharedPoints.First(p => !p.Equals(commonPoint_));
                     oldOther = new Point2D(oldOther_.X, oldOther_.Y);
                  } else {
                     sharedPoints = null;
                     var commonPoint_ = currentSharedPoints.First();
                     commonPoint = new Point2D(commonPoint_.X, commonPoint_.Y);
                     var oldOther_ = currentSharedPoints.Skip(1).First();
                     oldOther = new Point2D(oldOther_.X, oldOther_.Y);
                     newPoint = new Point2D(endPoint.X - Gridlet.XLength / 2.0, endPoint.Y - gridlet.YLength / 2.0);

                     var windingOldCurrentNew = GeometryUtilities.GetClockness(oldOther, currentPoint, newPoint);
                     var windingOldCurrentCommon = GeometryUtilities.GetClockness(oldOther, currentPoint, commonPoint);
                     if (windingOldCurrentNew == windingOldCurrentCommon) {
                        var temp = commonPoint;
                        commonPoint = oldOther;
                        oldOther = temp;
                     }
                  }

                  var oldOtherVector = new Vector2D(currentPoint, oldOther).ToUnitVector();
                  var commonVector = new Vector2D(currentPoint, commonPoint).ToUnitVector();
                  var newVector = new Vector2D(currentPoint, newPoint).ToUnitVector();

                  var oldAngle = Math.Acos(oldOtherVector.Dot(commonVector));
                  var newAngle = Math.Acos(newVector.Dot(commonVector));
                  var oldWinding = GeometryUtilities.GetClockness(commonPoint, currentPoint, oldOther);
                  var newWinding = GeometryUtilities.GetClockness(commonPoint, currentPoint, newPoint);

                  if (oldAngle > newAngle && oldWinding == newWinding) {
                     currentSharedPoints = sharedPoints;
                  } else {
                     finalPath.Add(oldOther);
                     currentPoint = oldOther;
                     currentSharedPoints = sharedPoints;
                  }

            //                  if (i == 4) {
            //                     Console.WriteLine(i + " SDFDFSD " + path.Count);
            //                     var currentPointVect = new Vector3((float)currentPoint.X, (float)currentPoint.Y, 0);
            //                     var commonPointVect = new Vector3((float)commonPoint.X, (float)commonPoint.Y, 0);
            //                     var oldOtherPointVect = new Vector3((float)oldOther.X, (float)oldOther.Y, 0);
            //                     var newPointVect = new Vector3((float)newPoint.X, (float)newPoint.Y, 0);
            //
            //                     Vector3.Transform(ref currentPointVect, ref meshTransform, out currentPointVect);
            //                     Vector3.Transform(ref commonPointVect, ref meshTransform, out commonPointVect);
            //                     Vector3.Transform(ref oldOtherPointVect, ref meshTransform, out oldOtherPointVect);
            //                     Vector3.Transform(ref newPointVect, ref meshTransform, out newPointVect);
            //                     e.Renderer.DrawDebugLine(currentPointVect, commonPointVect, Color.Green);
            //                     e.Renderer.DrawDebugLine(currentPointVect, oldOtherPointVect, Color.Orange);
            //                     e.Renderer.DrawDebugLine(currentPointVect, newPointVect, Color.Chocolate);
            //                     renderer.DrawCube(Matrix.Translation((float)currentPointVect.X, (float)currentPointVect.Y, 1), new Vector4(0, 0, 1, 1), false);
            //                     renderer.DrawCube(Matrix.Translation((float)commonPointVect.X, (float)commonPointVect.Y, 1), new Vector4(0, 1, 0, 1), false);
            //                     renderer.DrawCube(Matrix.Translation((float)oldOtherPointVect.X, (float)oldOtherPointVect.Y, 1), new Vector4(1, 0.5f, 0, 1), false);
            //                     renderer.DrawCube(Matrix.Translation((float)newPointVect.X, (float)newPointVect.Y, 1), new Vector4(0.5f, 0.25f, 0, 1), false);
            //
            //                     foreach (var p in finalPath) {
            //                        renderer.DrawCube(Matrix.Translation((float)p.X, (float)p.Y, 1.5f), new Vector4(1, 1, 1, 1), false);
            //                     }
            //
            //                     for (var j = 0; j < finalPath.Count - 1; j++) {
            //                        Console.WriteLine("!@#@!###!@ " + finalPath.Count);
            //                        var startCentroid = new Vector3((float)finalPath[j].X, (float)finalPath[j].Y, 0);
            //                        var endCentroid = new Vector3((float)finalPath[j + 1].X, (float)finalPath[j + 1].Y, 0);
            //
            //                        Vector3.Transform(ref startCentroid, ref meshTransform, out startCentroid);
            //                        Vector3.Transform(ref endCentroid, ref meshTransform, out endCentroid);
            //                        e.Renderer.DrawDebugLine(startCentroid, endCentroid, Color.Magenta);
            //                     }
            //                     break;
            //                  }
               }
               finalPath.Add(new Point2D(endPoint.X - Gridlet.XLength / 2.0, endPoint.Y - gridlet.YLength / 2.0));

               var simplePathLine = new Line2D(
                  new Point2D(startPoint.X - Gridlet.XLength / 2.0, startPoint.Y - gridlet.YLength / 2.0),
                  new Point2D(endPoint.X - Gridlet.XLength / 2.0, endPoint.Y - gridlet.YLength / 2.0)
               );

            //               for (var t = 0.0f; t < 1.0f; t+= 0.1f) {
            //                  var p = simplePathLine.PointAtT(t);
            //                  renderer.DrawCube(Matrix.Scaling(2) * Matrix.Translation((float)p.X, (float)p.Y, 2), new Vector4(1, 1, 1, 1), false);
            //               }

            //               var triangle = new Triangle2D(
            //                  new Point2D(-32.5, 32.5),
            //                  new Point2D(-10, 0),
            //                  new Point2D(-32.5, -32.5));
            //               MessageBox.Show(triangle.FindIntersection(simplePathLine)?.ToString() ?? "null");
            //               var abLine = new Line2D(triangle.A, triangle.B);
            //               var abIntersection = (Point2D)abLine.FindLineIntersection(simplePathLine);
            //               var bcLine = new Line2D(triangle.B, triangle.C);
            //               var bcIntersection = (Point2D)bcLine.FindLineIntersection(simplePathLine);
            //               Console.WriteLine("AB INTERSECTION: " + abLine.NearestT(abIntersection) + " " + abLine.PointAtT(abLine.NearestT(abIntersection)) + " " + abIntersection);
            //               Console.WriteLine("BC INTERSECTION: " + bcLine.NearestT(bcIntersection));

            //               var f = new Form();
            //               var pb = new PictureBox();
            //               var b = new Bitmap(100, 100);
            //               using (var g = Graphics.FromImage(b)) {
            //                  for (var t = 0.0; t < 1.0f; t += 0.05f) {
            //                     var p = abLine.PointAtT(t);
            //                     g.DrawRectangle(Pens.Red, (float)(p.X + 50 - 1), (float)(p.Y + 50 - 1), 2, 2);
            //                  }
            //
            //                  g.DrawRectangle(Pens.Orange, (float)(abIntersection.X + 50 - 3), (float)(abIntersection.Y + 50 - 3), 6, 6);
            //
            //
            //                  g.DrawRectangle(Pens.Red, (float)(triangle.A.X + 50 - 1), (float)(triangle.A.Y + 50 - 1), 2, 2);
            //                  g.DrawRectangle(Pens.Green, (float)(triangle.B.X + 50 - 1), (float)(triangle.B.Y + 50 - 1), 2, 2);
            //                  g.DrawRectangle(Pens.Blue, (float)(triangle.C.X + 50 - 1), (float)(triangle.C.Y + 50 - 1), 2, 2);
            //                  g.DrawLine(Pens.Lime, -25 + 50, -25 + 50, -20 + 50, 25 + 50);
            //               }
            //               pb.Image = b;
            //               pb.SizeMode = PictureBoxSizeMode.AutoSize;
            //               f.Controls.Add(pb);
            //               f.ClientSize = b.Size;
            //               f.Show();
            //               Application.Run();

               var tritris = mesh.Where(
                  x => new Triangle2D(
                     new Point2D(x.Points[0].Xf, x.Points[0].Yf),
                     new Point2D(x.Points[1].Xf, x.Points[1].Yf),
                     new Point2D(x.Points[2].Xf, x.Points[2].Yf)).FindIntersection(simplePathLine) != null
               ).ToArray();
               if (tritris.Any()) {
                  var sadfaces = new ICL.HashSet<DelaunayTriangle>(tritris);
                  var s = new Stack<DelaunayTriangle>();
                  s.Push(tritris.First());
                  var lastSadfacesCount = 0;
                  while (s.Any() && lastSadfacesCount != sadfaces.Count) {
                     lastSadfacesCount = sadfaces.Count;
                     var tri = s.Pop();
                     sadfaces.Remove(tri);
                     foreach (var other in sadfaces) {
                        if (other.Points.Union(tri.Points).Distinct().Count() <= 4) {
                           s.Push(other);
                        }
                     }
                  }
                  if (sadfaces.None()) {
            //                     MessageBox.Show("!@#!#!@#");
                     finalPath.Clear();
                     finalPath.Add(simplePathLine.Start);
                     finalPath.Add(simplePathLine.PointAtT(1));
                  }
               }

               Console.WriteLine("!@#!@#!@ " + tritris.SelectMany(x => x.Points).Distinct().Count() + " " + tritris.Length);

               Console.WriteLine("!@#!@##@@!#@!@!@# " + tritris.Length);
               foreach (var tri in tritris) {
                  var centroid = tri.Centroid();
                  var centroidVector = new Vector3(centroid.Xf, centroid.Yf, 0);
                  renderer.DrawCube(Matrix.Scaling(4) * Matrix.Translation(centroidVector), new Vector4(0, 1, 1, 1), false);
               }

               foreach (var p in finalPath) {
                  renderer.DrawCube(Matrix.Translation((float)p.X, (float)p.Y, 1.5f), new Vector4(1, 1, 1, 1), false);
               }

               for (var j = 0; j < finalPath.Count - 1; j++) {
                  Console.WriteLine("!@#@!###!@ " + finalPath.Count);
                  var startCentroid = new Vector3((float)finalPath[j].X, (float)finalPath[j].Y, 0);
                  var endCentroid = new Vector3((float)finalPath[j + 1].X, (float)finalPath[j + 1].Y, 0);

                  Vector3.Transform(ref startCentroid, ref meshTransform, out startCentroid);
                  Vector3.Transform(ref endCentroid, ref meshTransform, out endCentroid);
                  e.Renderer.DrawDebugLine(startCentroid, endCentroid, Color.Magenta);
               }
            } catch (Exception exsaqsd) {
               Console.WriteLine(exsaqsd);
            }

            //            for (var i = 0; i < finalPath.Count - 1; i++) {
            //               var startCentroid = new Vector3((float)finalPath[i].X - Gridlet.XLength / 2.0f, (float)finalPath[i].Y - Gridlet.YLength / 2.0f, 0);
            //               var endCentroid = new Vector3((float)finalPath[i + 1].X - Gridlet.XLength / 2.0f, (float)finalPath[i + 1].Y - Gridlet.YLength / 2.0f, 0);

            //               Vector3.Transform(ref startCentroid, ref meshTransform, out startCentroid);
            //               Vector3.Transform(ref endCentroid, ref meshTransform, out endCentroid);
            //               e.Renderer.DrawDebugLine(startCentroid, endCentroid, Color.Magenta);
            //            }
             }
        }