public void DrawCurvedLine(Graphics g, PointF[] points, int radius) { using (GraphicsPath path = new GraphicsPath()) { PointF lastQ = new PointF(0, 0); PointF nextStart = new PointF(points[0].X, points[0].Y); for (int i = 0; i < points.Length - 2; i++) { PointF Q = GetQ(points[i], points[i + 1], points[i + 2], radius); PointF A = points[i + 1].Take(points[i]).Normalised(); PointF B = points[i + 2].Take(points[i + 1]).Normalised(); float toLeave = Math.Abs(Q.Dot(A)); PointF toDraw = A.ScaleBy(points[i].DistanceTo(points[i + 1]) - toLeave); path.AddLine(nextStart.X, nextStart.Y, toDraw.X + points[i].X, toDraw.Y + points[i].Y); nextStart = B.ScaleBy(Math.Abs(Q.Dot(B))).Plus(points[i + 1]); //path.AddBezier(toDraw.X + points[i].X, toDraw.Y + points[i].Y, points[i + 1].X, points[i + 1].Y, points[i + 1].X, points[i + 1].Y, nextStart.X, nextStart.Y); var arcLocation = Q.Plus(points[i + 1]).Plus(-radius, -radius); float a1 = (float)(Math.Atan2(A.Y, A.X) * 180 / Math.PI); float a2 = (float)(Math.Atan2(B.Y, B.X) * 180 / Math.PI); float dif21 = a2 - a1; if (dif21 < 0) { dif21 += 360; } float dif12 = a1 - a2; if (dif12 < 0) { dif12 += 360; } path.AddArc(arcLocation.X, arcLocation.Y, radius * 2.0f, radius * 2.0f, a1 + dif12, Math.Abs(-dif12) < Math.Abs(dif21) ? -dif12 : dif21); //path.AddArc(arcLocation.X, arcLocation.Y, radius, radius, a1, dif12); lastQ = Q; } path.AddLine(path.GetLastPoint(), new PointF(points[points.Length - 1].X, points[points.Length - 1].Y)); //g.DrawLines(Outline, points); //for (int i = 1; i < points.Length - 1; i++) //DrawArc(g, points[i - 1], points[i], points[i + 1], radius); g.DrawPath(Outline, path); } }
internal void MouseMove(MouseEventArgs e) { MousePosition = new PointF(e.X, e.Y); StickyMousePosition = Snap(MousePosition); Hover = simulation.Vertices.Where(v => MousePosition.Sub(v.Position).Mag() < v.Radius); HoverEdges = simulation.Edges.Where(edge => { // hledání úseček v dané (či menší) vzdálenosti od bodu // https://en.wikipedia.org/wiki/Vector_projection // vektor od V do U PointF delta = edge.U.Position.Sub(edge.V.Position); float length = delta.Mag(); PointF unit = delta.MultiplyScalar(1f / length); // vektor od V do pozice myši PointF deltaMouse = MousePosition.Sub(edge.V.Position); // skalární projekce - musí být > 0 && < délka úsečky UV // jinak je projekce bodu myši mimo tuto úsečku a tedy // myš není u úsečky ale někde před ní nebo za ní float scalarProjection = unit.Dot(deltaMouse); if (scalarProjection < edge.U.Radius || scalarProjection > length - edge.V.Radius) { return(false); } // vektorová projekce PointF a1 = unit.MultiplyScalar(scalarProjection); // rozdíl, tedy kolmý vektor na UV ukazující od úsečky k bodu myši PointF a2 = deltaMouse.Sub(a1); // "kolmá" vzdálenost úsečky a myši float mouseDistance = a2.Mag(); float maxDistance = Math.Max(edge.U.Radius, edge.V.Radius); return(mouseDistance < maxDistance); }); foreach (Vertex v in Dragging) { if (simulation.Pause) { // přesouvání bodu probíhá při vypnuté simulaci // přímým nastavením pozice bodu v.Position = StickyMousePosition; v.PrevPos = StickyMousePosition; IEnumerable <Edge> affectedEdges = simulation.GetEdges(v); foreach (Edge edge in affectedEdges) { edge.ResetLength(); } } else { // přesouvání bodu probíhá při běžící simulaci // pomocí aplikací síly v.SetTarget(MousePosition); } } }
private static PointF GetQ(PointF p1, PointF p2, PointF p3, int radius) { PointF A = p1.Take(p2).Normalised(); PointF B = p3.Take(p2).Normalised(); PointF ApB = A.Plus(B); float apbls = ApB.LengthSquared(); float hs = apbls * radius * radius / (float)(apbls - (1 - A.Dot(B))); float l = (float)Math.Sqrt(hs / apbls); PointF Q = new PointF(ApB.X * l, ApB.Y * l); return(Q); }