using FastReport.Utils; using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; namespace FastReport { partial class PolyLineObject : IHasEditor { //Current selected point, for move //internal PolyLineObjectToolBar toolbar; //deprecated #region Private Fields private PolyPoint currentPoint; private PolyPoint drawSelectedPointLine; private int drawSelectedPointLineNumber; private int selectedPoint; #endregion Private Fields #region Public Properties /// public override float Height { get { return base.Height; } set { if (base.Height == 0) { base.Height = value; return; } if (IsSelected) { if (SelectionMode == PolygonSelectionMode.MoveAndScale) { float oldHeight = base.Height; if (oldHeight == value) return; if (pointsCollection.Count < 2) return; float scaleY = value / oldHeight; if (float.IsInfinity(scaleY)) return; if (float.IsNaN(scaleY)) return; if (scaleY == 0) return; center.Y = center.Y * scaleY; foreach (PolyPoint point in pointsCollection) { point.ScaleY(scaleY); } base.Height = value; } else RecalculateBounds(); } else base.Height = value; } } /// public override float Width { get { return base.Width; } set { if (base.Width == 0) { base.Width = value; return; } if (IsSelected) { if (SelectionMode == PolygonSelectionMode.MoveAndScale) { float oldWidth = base.Width; if (oldWidth == value) return; if (pointsCollection.Count < 2) return; float scaleX = value / oldWidth; if (float.IsInfinity(scaleX)) return; if (float.IsNaN(scaleX)) return; if (scaleX == 0) return; center.X = center.X * scaleX; foreach (PolyPoint point in pointsCollection) { point.ScaleX(scaleX); } base.Width = value; } else RecalculateBounds(); } else base.Width = value; } } #endregion Public Properties #region Internal Properties internal PolygonSelectionMode SelectionMode { get { return polygonSelectionMode; } set { if (value != polygonSelectionMode) { polygonSelectionMode = value; try { if (IsSelected) { Report.Designer.SelectionChanged(this); } } catch { } polygonSelectionMode = value; } } } #endregion Internal Properties #region Public Methods /// /// Add point to end of polyline and recalculate bounds after add. /// Can be first point. /// Deprecated, use insert point /// /// local x - relative to left-top point /// local y - relative to left-top point [Obsolete] public void AddPointToEnd(float localX, float localY) { insertPoint(pointsCollection.Count, localX, localY, 1); if (Report != null) if (Report.Designer != null) Report.Designer.SetModified(this, "Change"); } /// /// Add point to start of polyline and recalculate bounds after add /// Can be first point /// Deprecated, use insert point /// /// local x - relative to left-top point /// local y - relative to left-top point [Obsolete] public void AddPointToStart(float localX, float localY) { insertPoint(0, localX, localY, 1); if (Report != null) if (Report.Designer != null) Report.Designer.SetModified(this, "Change"); } /// public override void CheckNegativeSize(FRMouseEventArgs e) { // do nothing } /// public override void DrawSelection(FRPaintEventArgs e) { if (SelectionMode == PolygonSelectionMode.AddToLine && drawSelectedPointLineNumber >= 0 && pointsCollection.Count > 0) { if (drawSelectedPointLine != null) { float absLeft = AbsLeft; float absTop = AbsTop; Pen p = e.Cache.GetPen(Color.DarkGray, 1, DashStyle.Solid); if (drawSelectedPointLineNumber > 0 && drawSelectedPointLineNumber - 1 < pointsCollection.Count || this is PolygonObject) { e.Graphics.DrawLine(p, GetPointF(drawSelectedPointLine, e.ScaleX, e.ScaleY, absLeft, absTop), GetPointF(drawSelectedPointLineNumber - 1, e.ScaleX, e.ScaleY, absLeft, absTop)); } if (drawSelectedPointLineNumber < pointsCollection.Count || this is PolygonObject) { e.Graphics.DrawLine(p, GetPointF(drawSelectedPointLine, e.ScaleX, e.ScaleY, absLeft, absTop), GetPointF(drawSelectedPointLineNumber, e.ScaleX, e.ScaleY, absLeft, absTop)); } } } if (SelectionMode == PolygonSelectionMode.MoveAndScale) { base.DrawSelection(e); } else { Pen help_p = e.Cache.GetPen(Color.Black, 1, DashStyle.Dash); if (Page == null) return; bool firstSelected = Report.Designer.SelectedObjects.IndexOf(this) == 0; Pen p = firstSelected ? Pens.Black : Pens.White; Brush b = firstSelected ? Brushes.White : Brushes.Black; SelectionPoint[] selectionPoints = GetSelectionPoints(); IGraphics g = e.Graphics; SelectionPoint lastPoint = null; float m = Report.Designer.DpiMultiplier(); foreach (SelectionPoint pt in selectionPoints) { switch (pt.sizingPoint) { case SizingPoint.LeftTop: { float x = pt.x * e.ScaleX; float y = pt.y * e.ScaleY; g.FillEllipse(Brushes.White, x - 5 * m, y - 5 * m, 10 * m, 10 * m); g.FillEllipse(Brushes.Red, x - 3 * m, y - 3 * m, 6 * m, 6 * m); g.DrawEllipse(Pens.Gray, x - 3 * m, y - 3 * m, 6 * m, 6 * m); lastPoint = pt; } break; case SizingPoint.RightTop: { float x = pt.x * e.ScaleX; float y = pt.y * e.ScaleY; if (lastPoint != null) { e.Graphics.DrawLine(help_p, lastPoint.x * e.ScaleX, lastPoint.y * e.ScaleY, x, y); } g.FillEllipse(Brushes.White, x - 3 * m, y - 3 * m, 6 * m, 6 * m); g.FillEllipse(Brushes.Blue, x - 2 * m, y - 2 * m, 4 * m, 4 * m); g.DrawEllipse(Pens.Gray, x - 2 * m, y - 2 * m, 4 * m, 4 * m); } break; default: lastPoint = pt; DrawSelectionPoint(e, p, b, pt.x, pt.y); break; } } } } /// /// Replace points with star /// /// Minimum value is 3 public void DrawStar(int spikes) { if (spikes < 3) spikes = 3; const float outerRadius = 50; const float innerRadius = 30; float rot = (float)(Math.PI / 2 * 3); const float cx = 0; const float cy = 0; float x = cx; float y = cy; float step = (float)(Math.PI / spikes); base.Width = 100; base.Height = 100; center = new PointF(50, 50); pointsCollection.Clear(); pointsCollection.Add(new PolyPoint(cx, cy - outerRadius)); for (int i = 0; i < spikes; i++) { x = cx + (float)Math.Cos(rot) * outerRadius; y = cy + (float)Math.Sin(rot) * outerRadius; pointsCollection.Add(new PolyPoint(x, y)); rot += step; x = cx + (float)Math.Cos(rot) * innerRadius; y = cy + (float)Math.Sin(rot) * innerRadius; pointsCollection.Add(new PolyPoint(x, y)); rot += step; } } /// public override SizeF GetPreferredSize() { return new SizeF(0, 0); } /// public override void HandleKeyDown(Control sender, KeyEventArgs e) { if (e.KeyCode == Keys.Delete) { if (SelectionMode != PolygonSelectionMode.MoveAndScale) { if (pointsCollection.Count > 0) { DeletePointByIndex(selectedPoint); selectedPoint--; Report.Designer.Refresh(); e.Handled = true; } } } if (!e.Handled) base.HandleKeyDown(sender, e); } /// public override void HandleMouseDown(FRMouseEventArgs e) { //if (toolbar.IsVisible && this.IsSelected) //{ // if (toolbar.ClickPublic(new PointF(AbsLeft, AbsTop < 20 ? 20 : AbsTop), new PointF(e.x, e.y))) // { // e.handled = true; // return; // } //} if (e.button == MouseButtons.Left && currentPoint == null && this.IsSelected) { float absLeft = AbsLeft; float absTop = AbsTop; PointF mousePoint = new PointF(e.x, e.y); PointF mousePointAligned = new PointF((int)((e.x - absLeft - center.X) / Page.SnapSize.Width) * Page.SnapSize.Width, (int)((e.y - absTop - center.Y) / Page.SnapSize.Height) * Page.SnapSize.Height); switch (SelectionMode) { case PolygonSelectionMode.Normal: for (int i = 0; i < pointsCollection.Count; i++) { PolyPoint point = pointsCollection[i]; if (point.LeftCurve != null && PointInSelectionPoint(absLeft + point.X + center.X + point.LeftCurve.X, absTop + point.Y + center.Y + point.LeftCurve.Y, mousePoint)) { currentPoint = point.LeftCurve; e.mode = WorkspaceMode2.Custom; e.handled = true; break; } else if (point.RightCurve != null && PointInSelectionPoint(absLeft + point.X + center.X + point.RightCurve.X, absTop + point.Y + center.Y + point.RightCurve.Y, mousePoint)) { currentPoint = point.RightCurve; e.mode = WorkspaceMode2.Custom; e.handled = true; break; } else if (PointInSelectionPoint(absLeft + point.X + center.X, absTop + point.Y + center.Y, mousePoint)) { currentPoint = point; e.mode = WorkspaceMode2.Custom; e.handled = true; break; } } break; case PolygonSelectionMode.AddToLine: for (int i = 0; i < pointsCollection.Count; i++) { PolyPoint point = pointsCollection[i]; if (PointInSelectionPoint(absLeft + point.X + center.X, absTop + point.Y + center.Y, mousePoint)) { currentPoint = point; e.mode = WorkspaceMode2.Custom; e.handled = true; break; } } if (!e.handled) { e.handled = true; PolyPoint result = InsertPointByLocation(mousePointAligned.X, mousePointAligned.Y, 25); if (result != null) { e.mode = WorkspaceMode2.Custom; currentPoint = result; } } break; case PolygonSelectionMode.AddBezier: for (int i = 0; i < pointsCollection.Count; i++) { PolyPoint point = pointsCollection[i]; if (point.LeftCurve != null) { if (PointInSelectionPoint(absLeft + point.X + center.X + point.LeftCurve.X, absTop + point.Y + center.Y + point.LeftCurve.Y, mousePoint)) { currentPoint = point.LeftCurve; e.mode = WorkspaceMode2.Custom; e.handled = true; break; } } else if (i == selectedPoint) { if (i > 0 || (this is PolygonObject)) { PolyPoint pseudoPoint = GetPseudoPoint(point, pointsCollection[i - 1]); if (PointInSelectionPoint(absLeft + pseudoPoint.X + center.X, absTop + pseudoPoint.Y + center.Y, mousePoint)) { pseudoPoint.X -= point.X; pseudoPoint.Y -= point.Y; point.LeftCurve = pseudoPoint; currentPoint = pseudoPoint; e.mode = WorkspaceMode2.Custom; e.handled = true; break; } } } if (point.RightCurve != null) { if (PointInSelectionPoint(absLeft + point.X + center.X + point.RightCurve.X, absTop + point.Y + center.Y + point.RightCurve.Y, mousePoint)) { currentPoint = point.RightCurve; e.mode = WorkspaceMode2.Custom; e.handled = true; break; } } else { if (i < pointsCollection.Count || (this is PolygonObject)) { PolyPoint pseudoPoint = GetPseudoPoint(point, pointsCollection[i + 1]); if (PointInSelectionPoint(absLeft + pseudoPoint.X + center.X, absTop + pseudoPoint.Y + center.Y, mousePoint)) { pseudoPoint.X -= point.X; pseudoPoint.Y -= point.Y; point.RightCurve = pseudoPoint; currentPoint = pseudoPoint; e.mode = WorkspaceMode2.Custom; e.handled = true; break; } } } if (PointInSelectionPoint(absLeft + point.X + center.X, absTop + point.Y + center.Y, mousePoint)) { currentPoint = point; e.mode = WorkspaceMode2.Custom; e.handled = true; break; } } break; case PolygonSelectionMode.Delete: for (int i = 0; i < pointsCollection.Count; i++) { PolyPoint point = pointsCollection[i]; if (point.LeftCurve != null && PointInSelectionPoint(absLeft + point.X + center.X + point.LeftCurve.X, absTop + point.Y + center.Y + point.LeftCurve.Y, mousePoint)) { point.LeftCurve = null; currentPoint = null; e.mode = WorkspaceMode2.None; e.handled = true; return; } else if (point.RightCurve != null && PointInSelectionPoint(absLeft + point.X + center.X + point.RightCurve.X, absTop + point.Y + center.Y + point.RightCurve.Y, mousePoint)) { point.RightCurve = null; currentPoint = null; e.mode = WorkspaceMode2.None; e.handled = true; return; } else if (PointInSelectionPoint(absLeft + point.X + center.X, absTop + point.Y + center.Y, mousePoint)) { RemovePointAt(i); currentPoint = null; if (i < selectedPoint) selectedPoint--; e.mode = WorkspaceMode2.None; e.handled = true; return; } } break; case PolygonSelectionMode.MoveAndScale: if (pointsCollection.Count < 2) { for (int i = 0; i < pointsCollection.Count; i++) { PolyPoint point = pointsCollection[i]; if (PointInSelectionPoint(absLeft + point.X + center.X, absTop + point.Y + center.Y, mousePoint)) { currentPoint = point; e.mode = WorkspaceMode2.Custom; e.handled = true; break; } } } break; } } if (!e.handled) base.HandleMouseDown(e); } /// public override void HandleMouseMove(FRMouseEventArgs e) { if (currentPoint != null) { currentPoint.X += e.delta.X; currentPoint.Y += e.delta.Y; //points[currentPoint] = point; RecalculateBounds(); e.mode = WorkspaceMode2.Custom; e.handled = true; } if (!e.handled && SelectionMode == PolygonSelectionMode.AddToLine) { PolyPoint mousePointAligned = new PolyPoint((int)((e.x - AbsLeft - center.X) / Page.SnapSize.Width) * Page.SnapSize.Width, (int)((e.y - AbsTop - center.Y) / Page.SnapSize.Height) * Page.SnapSize.Height); drawSelectedPointLineNumber = GetBestPointPosition(mousePointAligned.X, mousePointAligned.Y); if (drawSelectedPointLine == null || !drawSelectedPointLine.Near(mousePointAligned)) { drawSelectedPointLine = mousePointAligned; Report.Designer.Refresh(); } } else { drawSelectedPointLineNumber = -1; } if (!e.handled) { base.HandleMouseMove(e); } if (e.handled) { e.cursor = Cursors.Cross; } if (IsSelected) { switch (SelectionMode) { case PolygonSelectionMode.AddToLine: case PolygonSelectionMode.AddBezier: e.handled = true; e.mode = WorkspaceMode2.Custom; break; } } //if (toolbar != null && toolbar.IsVisible) //{ // //toolbar.MouseMove(e.x, e.y); //} } /// public override void HandleMouseUp(FRMouseEventArgs e) { if (currentPoint != null) { RecalculateBounds(); int index = pointsCollection.IndexOf(currentPoint); if (index >= 0) selectedPoint = index; currentPoint = null; if (Report != null) if (Report.Designer != null) Report.Designer.SetModified(this, "Change"); } if (IsSelected) { int mode = (int)SelectionMode; if (0 < mode) { e.handled = true; } } if (!e.handled) base.HandleMouseUp(e); } /// /// Insert point to desired place of polyline /// Recalculate bounds after insert /// /// Index of place from zero to count /// local x - relative to left-top point /// local y - relative to left-top point public void InsertPointByIndex(int index, float localX, float localY) { insertPoint(index, localX, localY, 0); if (Report != null) if (Report.Designer != null) Report.Designer.SetModified(this, "Change"); } /// /// Insert point to near line /// Recalculate bounds after insert /// /// local x - relative to left-top point /// local y - relative to left-top point /// depricated /// Index of inserted point public PolyPoint InsertPointByLocation(float localX, float localY, float maxDistance) { PolyPoint result; int pointNumber = -1; if (pointsCollection.Count == 0) { result = addPoint(0, 0, 0); pointNumber = 0; } else { pointNumber = GetBestPointPosition(localX, localY); result = insertPoint(pointNumber, localX, localY, 1); } RecalculateBounds(); if (pointNumber >= 0) if (Report != null) if (Report.Designer != null) Report.Designer.SetModified(this, "Change"); return result; } /// public bool InvokeEditor() { if (IsSelected) { if (SelectionMode == PolygonSelectionMode.MoveAndScale) { Report report = Report; if (report != null) { SelectionMode = PolygonSelectionMode.Normal; } return true; } else if (SelectionMode == PolygonSelectionMode.Normal) { Report report = Report; if (report != null) { SelectionMode = PolygonSelectionMode.MoveAndScale; } return true; } } return false; } /// public override void OnAfterInsert(InsertFrom source) { base.OnAfterInsert(source); if (Report != null) { SelectedObjectCollection selectionObjects = Report.Designer.SelectedObjects; selectionObjects.Clear(); selectionObjects.Add(this); } if (pointsCollection.Count < 2) SelectionMode = PolygonSelectionMode.AddToLine; if (pointsCollection.Count > 1) SelectionMode = PolygonSelectionMode.MoveAndScale; } /// public override void OnBeforeInsert(int flags) { float rotation = (float)((flags & 0xF) / 8.0 * Math.PI); int numberOfEdges = (flags & 0xF0) >> 4; if (numberOfEdges >= 5) { float x, y; pointsCollection.Clear(); for (int i = 0; i < numberOfEdges; i++) { base.Width = 100; base.Height = 100; x = 50 + (float)(50 * Math.Cos(rotation + 2 * Math.PI * i / numberOfEdges)); y = 50 + (float)(50 * Math.Sin(rotation + 2 * Math.PI * i / numberOfEdges)); pointsCollection.Add(new PolyPoint(x, y)); } } else { pointsCollection.Add(new PolyPoint(0, 0)); Width = 5; Height = 5; } } /// public override bool PointInObject(PointF point) { using (Pen pen = new Pen(Color.Black, 10)) using (GraphicsPath path = new GraphicsPath()) { float absLeft = AbsLeft; float absTop = AbsTop; if (pointsCollection.Count > 1 && currentPoint == null) for (int i = 0; i < pointsCollection.Count - 1; i++) { PolyPoint prev = pointsCollection[i]; PolyPoint next = pointsCollection[i + 1]; path.AddLine(absLeft + prev.X + center.X, absTop + prev.Y + center.Y, absLeft + next.X + center.X, absTop + next.Y + center.Y); } else path.AddLine(absLeft - 1 + CenterX, absTop - 1 + CenterY, AbsRight + 1 + CenterX, AbsBottom + 1 + CenterY); return path.IsOutlineVisible(point, pen); } } /// /// Delete point from polyline by index /// Recalculate bounds after remove /// /// Index of point in polyline public void RemovePointAt(int index) { deletePoint(index); if (Report != null) if (Report.Designer != null) Report.Designer.SetModified(this, "Change"); } /// public override void SelectionChanged() { base.SelectionChanged(); if (!IsSelected) SelectionMode = PolygonSelectionMode.MoveAndScale; } #endregion Public Methods #region Protected Methods /// /// Delete point from polyline by index. /// Recalculate bounds. /// /// Index of point in polyline protected void DeletePointByIndex(int index) { pointsCollection.Remove(index); RecalculateBounds(); } /// protected override void DrawSelectionPoint(FRPaintEventArgs e, Pen p, Brush b, float x, float y) { if (SelectionMode == PolygonSelectionMode.MoveAndScale) { base.DrawSelectionPoint(e, p, b, x, y); } else { IGraphics g = e.Graphics; x = (float)Math.Round(x * e.ScaleX); y = (float)Math.Round(y * e.ScaleY); float m = Report.Designer.DpiMultiplier(); RectangleF rect = new RectangleF(x - 3 * m, y - 3 * m, 6 * m, 6 * m); g.FillEllipse(b, rect); g.DrawEllipse(p, rect); } } /// protected override SelectionPoint[] GetSelectionPoints() { List selectionPoints = new List(); if (pointsCollection.Count == 0) { return new SelectionPoint[] { new SelectionPoint(AbsLeft + CenterX, AbsTop + CenterY,SizingPoint.None) }; } if (SelectionMode == PolygonSelectionMode.MoveAndScale && pointsCollection.Count > 1) { return base.GetSelectionPoints(); } if (pointsCollection.Count > 0) selectedPoint = (pointsCollection.Count + selectedPoint) % pointsCollection.Count; float absLeft = AbsLeft; float absTop = AbsTop; for (int i = 0; i < pointsCollection.Count; i++) { PolyPoint point = pointsCollection[i]; selectionPoints.Add(new SelectionPoint(point.X + absLeft + center.X, point.Y + absTop + center.Y, i == selectedPoint ? SizingPoint.LeftTop : SizingPoint.RightBottom)); if (SelectionMode != PolygonSelectionMode.AddToLine) { if (point.LeftCurve != null) { selectionPoints.Add(new SelectionPoint(point.X + absLeft + center.X + point.LeftCurve.X, point.Y + absTop + center.Y + point.LeftCurve.Y, SizingPoint.RightTop)); } else if (SelectionMode == PolygonSelectionMode.AddBezier && i == selectedPoint) { if (i > 0 || (this is PolygonObject)) { PolyPoint pseudoPoint = GetPseudoPoint(point, pointsCollection[i - 1]); selectionPoints.Add(new SelectionPoint(pseudoPoint.X + absLeft + center.X, pseudoPoint.Y + absTop + center.Y, SizingPoint.RightTop)); } } if (point.RightCurve != null) { selectionPoints.Add(new SelectionPoint(point.X + absLeft + center.X + point.RightCurve.X, point.Y + absTop + center.Y + point.RightCurve.Y, SizingPoint.RightTop)); } else if (SelectionMode == PolygonSelectionMode.AddBezier && i == selectedPoint) { if (i < pointsCollection.Count - 1 || (this is PolygonObject)) { PolyPoint pseudoPoint = GetPseudoPoint(point, pointsCollection[i + 1]); selectionPoints.Add(new SelectionPoint(pseudoPoint.X + absLeft + center.X, pseudoPoint.Y + absTop + center.Y, SizingPoint.RightTop)); } } } } return selectionPoints.ToArray(); } #endregion Protected Methods #region Private Methods private void DrawDesign0(FRPaintEventArgs e) { if (IsSelected && SelectionMode == PolyLineObject.PolygonSelectionMode.MoveAndScale) { Pen pen = e.Cache.GetPen(Color.Gray, 1, DashStyle.Dot); e.Graphics.DrawRectangle(pen, AbsLeft * e.ScaleX, AbsTop * e.ScaleY, Width * e.ScaleX, Height * e.ScaleY); } } private void DrawDesign1(FRPaintEventArgs e) { } /// /// Returns best new point position based on mouse /// /// private int GetBestPointPosition(float localX, float localY) { if (pointsCollection.Count > 0) { selectedPoint = (pointsCollection.Count + selectedPoint) % pointsCollection.Count; //add near select point //check if point is first or last if (selectedPoint == pointsCollection.Count - 1 && !(this is PolygonObject)) { return pointsCollection.Count; } else if (selectedPoint == 0 && !(this is PolygonObject)) { return 0; } else { PolyPoint local = new PolyPoint(localX, localY); PolyPoint pLeft = pointsCollection[selectedPoint - 1]; PolyPoint pCenter = pointsCollection[selectedPoint]; PolyPoint pRight = pointsCollection[selectedPoint + 1]; //float pLeft_pLocal = // ((pLeft.X + CenterX - localX) * (pLeft.X + CenterX - localX) + (pLeft.Y + CenterY - localY) * (pLeft.Y + CenterY - localY)); //float pRight_pLocal = // ((pRight.X + CenterX - localX) * (pRight.X + CenterX - localX) + (pRight.Y + CenterY - localY) * (pRight.Y + CenterY - localY)); //float pLeft_pCenter = ((pLeft.X - pCenter.X) * (pLeft.X - pCenter.X) + (pLeft.Y - pCenter.Y) * (pLeft.Y - pCenter.Y)); //float pRight_pCenter = ((pRight.X - pCenter.X) * (pRight.X - pCenter.X) + (pRight.Y - pCenter.Y) * (pRight.Y - pCenter.Y)); //float distance1 = pLeft_pLocal/ pLeft_pCenter; //float distance2 = pRight_pLocal / pRight_pCenter; float distance1 = MATH_pnt_seg_dist(local, pLeft, pCenter); float distance2 = MATH_pnt_seg_dist(local, pCenter, pRight); if (distance1 < distance2) { return selectedPoint; } else { return selectedPoint + 1; } } } return 0; } private PointF GetPointF(int index, float scaleX, float scaleY, float absLeft, float absTop) { return GetPointF(pointsCollection[index], scaleX, scaleY, absLeft, absTop); } private PointF GetPointF(PolyPoint point, float scaleX, float scaleY, float absLeft, float absTop) { return new PointF( (point.X + absLeft + center.X) * scaleX, (point.Y + absTop + center.Y) * scaleY ); } private void InitDesign() { currentPoint = null; SelectionMode = PolygonSelectionMode.MoveAndScale; //toolbar = new PolyLineObjectToolBar(this); } private float MATH_dot(float aX, float aY, float bX, float bY) { return aX * bX + aY * bY; } private float MATH_length_squared(PolyPoint a, PolyPoint b) { return (a.X - b.X) * (a.X - b.X) + (a.Y - b.Y) * (a.Y - b.Y); } private float MATH_pnt_seg_dist(PolyPoint p, PolyPoint v, PolyPoint w) { // Return minimum distance between line segment vw and point p float l2 = MATH_length_squared(v, w); // i.e. |w-v|^2 - avoid a sqrt if (l2 == 0.0) return MATH_length_squared(p, v); // v == w case // Consider the line extending the segment, parameterized as v + t (w - v). // We find projection of point p onto the line. // It falls where t = [(p-v) . (w-v)] / |w-v|^2 // We clamp t from [0,1] to handle points outside the segment vw. float t = Math.Max(0, Math.Min(1, MATH_dot(p.X - v.X, p.Y - v.Y, w.X - v.X, w.Y - v.Y) / l2)); PolyPoint projection = new PolyPoint(v.X + t * (w.X - v.X), v.Y + t * (w.Y - v.Y)); // Projection falls on the segment return MATH_length_squared(p, projection); } #endregion Private Methods } }