/// <summary> /// Проверяет дистанцию от точки p до отрезка p0 p1 /// </summary> /// <param name="p0"></param> /// <param name="p1"></param> /// <param name="p"></param> /// <param name="dist"></param> /// <returns></returns> public static bool CheckDistance(PointV p0, PointV p1, PointV p, double dist) { //Взято тут: //http://algolist.manual.ru/maths/geom/distance/pointline.php if (p0.Equals(p1)) { return CheckDistance(p0, p, dist); } PointV p0v = p - p0; PointV p1v = p - p1; PointV sv = p1 - p0; double dx, dy; //Проверяем знак скалярного произведения векторов //Если меньше 0, значит основание перпендикуляра от точки лежит за пределами отрезка if (p0v.X * sv.X + p0v.Y * sv.Y < 0) { dx = p.X - p0.X; dy = p.Y - p0.Y; return dist >= dx * dx + dy * dy; } //Аналогично, для конца отрезка sv = p0 - p1; if (p1v.X * sv.X + p1v.Y * sv.Y < 0) { dx = p.X - p1.X; dy = p.Y - p1.Y; return dist >= dx * dx + dy * dy; } //Если до сих пор функция еще выполняется, значит основание перпендикуляра лежит //в пределах отрезка. Проверяем расстояние от точки до прямой sv.Length = 1; //Нормализуем вектор p1-p0 //Находим векторное произведение для двумерного случая return dist >= Math.Abs( sv.X * p1v.Y - sv.Y * p1v.X); }
public static void DrawControls(Graphics graph, PointF rootPos, IEditable o, DrawParametres p) { PointV p0 = new PointV(o.Location); PointV pp = new PointV(o.ParentPoint); PointV p0r, ppr; p0r = new PointV(PointV.Add(rootPos, p0.Point)); ppr = new PointV(PointV.Add(rootPos, pp.Point)); PointF p0f = p0r.Point; PointF ppf = ppr.Point; Pen linePen = new Pen(Color.Gray); linePen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash; graph.DrawLine(linePen, p0f, ppf); graph.DrawEllipse(Pens.Blue, ppf.X - 2, ppf.Y - 2, 4, 4); float x1Size = 20; graph.DrawLine(Pens.Blue, p0f.X, p0f.Y - x1Size, p0f.X, p0f.Y + x1Size); graph.DrawLine(Pens.Blue, p0f.X - x1Size, p0f.Y, p0f.X + x1Size, p0f.Y); if (o is BoneImage) { } PointV p1; PointV p2; if ((p & DrawParametres.DrawAngleCtl) == DrawParametres.DrawAngleCtl/* || (p & DrawParametres.DrawFreeEditCtl) == DrawParametres.DrawFreeEditCtl*/) { Pen pen = new Pen(Color.Green); int r = 20; pen.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor; pen.Width = 5f; p2 = new PointV(o.AbsoluteAngle, 50, true); p2 = p2.Add(rootPos).Add(p0); float k = (float)(180 / Math.PI); graph.DrawArc(pen, new RectangleF((float)p2.X - r, (float)p2.Y - r, r * 2, r * 2), (float)o.AbsoluteAngle * k, 90); graph.DrawArc(pen, new RectangleF((float)p2.X - r, (float)p2.Y - r, r * 2, r * 2), (float)o.AbsoluteAngle * k, -90); } if ((p & DrawParametres.DrawShiftCtl) == DrawParametres.DrawShiftCtl) { int padding = 4; int length = 16; Pen pen = new Pen(Color.Blue); pen.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor; pen.Width = 5f; p2 = p0.Add(rootPos); graph.DrawLine(pen, (float)p2.X, (float)p2.Y + padding, (float)p2.X, (float)p2.Y + padding + length); graph.DrawLine(pen, (float)p2.X, (float)p2.Y - padding, (float)p2.X, (float)p2.Y - padding - length); graph.DrawLine(pen, (float)p2.X + padding, (float)p2.Y, (float)p2.X + padding + length, (float)p2.Y); graph.DrawLine(pen, (float)p2.X - padding, (float)p2.Y, (float)p2.X - padding - length, (float)p2.Y); } }
public static void DrawBone(Bone b, Graphics graph, PointF rootPos, bool selected = false) { if (b.IsRoot) { if (selected) { graph.DrawEllipse(Pens.Orange, rootPos.X - 30, rootPos.Y - 30, 60, 60); } else { graph.DrawEllipse(Pens.Black, rootPos.X - 30, rootPos.Y - 30, 60, 60); } } else { PointV p0 = new PointV(b.StartPoint); PointV p3 = new PointV(b.EndPoint); PointV p1 = p3 - p0; PointV p2 = p1.Rotate(-0.2745); p1 = p1.Rotate(0.2745); p2.Length = p2.Length * 0.2; p1.Length = p1.Length * 0.2; p2 = p2 + p0; p1 = p1 + p0; Pen pen0 = new Pen(Color.Black); Brush brush0 = new SolidBrush(Color.FromArgb(180, Color.DarkGray)); Pen pen1 = new Pen(Color.Black); pen1.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash; PointF[] pts = new PointF[] { p0.Add(rootPos).Point, p1.Add(rootPos).Point, p3.Add(rootPos).Point, p2.Add(rootPos).Point }; if (selected) { brush0 = new SolidBrush(Color.FromArgb(180, Color.Orange)); pen1.Color = Color.Orange; pen0.Color = Color.Orange; graph.DrawPolygon(pen0, pts); graph.FillPolygon(brush0, pts); graph.DrawLine(pen1, PointV.Add(rootPos, b.StartPoint), PointV.Add(rootPos, b.Parent.EndPoint)); } else { graph.DrawPolygon(pen0, pts); graph.FillPolygon(brush0, pts); graph.DrawLine(pen1, PointV.Add(rootPos, b.StartPoint), PointV.Add(rootPos, b.Parent.EndPoint)); } } }
public bool Equals(PointV pt) { return pt.x == x && pt.y == y; }
public PointV Add(PointV point) { return new PointV(x + point.x, y + point.y); }
public static PointV Rotate(PointF p, double angle) { //Переделать PointV pt = new PointV(p); return pt.Rotate(angle); }
public static void DrawControls(Graphics graph, PointF rootPos, Bone b, DrawParametres p) { PointV p0 = new PointV(b.StartPoint); PointV p3 = new PointV(b.EndPoint); PointV p1; PointV p2; Pen gpen = new Pen(Color.Blue); gpen.Width = 2f; gpen.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor; if (b is BoneGraphics) { PointF pp = b.ParentPoint; graph.DrawEllipse(Pens.Blue, pp.X - 3, pp.Y - 3, 6, 6); float psize = 5; p1 = p0.Add(rootPos); graph.DrawLine(Pens.Blue, (float)p1.X, (float)p1.Y - psize, (float)p1.X, (float)p1.Y + psize); graph.DrawLine(Pens.Blue, (float)p1.X - psize, (float)p1.Y, (float)p1.X + psize, (float)p1.Y); graph.DrawLine(gpen, p0.Add(rootPos), p3.Add(rootPos)); } if (b is BoneImage) { PointF pp = b.ParentPoint; graph.DrawEllipse(Pens.Blue, pp.X - 3, pp.Y - 3, 6, 6); float psize = 5; p1 = p0.Add(rootPos); graph.DrawLine(Pens.Green, (float)p1.X, (float)p1.Y - psize, (float)p1.X, (float)p1.Y + psize); graph.DrawLine(Pens.Green, (float)p1.X - psize, (float)p1.Y, (float)p1.X + psize, (float)p1.Y); gpen.Color = Color.Green; graph.DrawLine(gpen, p0.Add(rootPos), p3.Add(rootPos)); p1 = p3 - p0; p2 = p1.Rotate(Math.PI / 2); p1.Length = (b as BoneImage).Image.Height; p2.Length = (b as BoneImage).Image.Width; graph.DrawPolygon(Pens.Green, new PointF[]{ p0.Add(rootPos), p0.Add(p2).Add(rootPos) , p0.Add(p1).Add(p2).Add(rootPos) , p0.Add(p1).Add(rootPos) }); } if ((p & DrawParametres.DrawAngleCtl) == DrawParametres.DrawAngleCtl || (p & DrawParametres.DrawFreeEditCtl) == DrawParametres.DrawFreeEditCtl) { Pen pen = new Pen(Color.Green); int r = 20; pen.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor; pen.Width = 5f; p2 = p3 - p0; p2.Length = p2.Length - r; p2 = p2.Add(rootPos).Add(p0); float k = (float)(180 / Math.PI); graph.DrawArc(pen, new RectangleF((float)p2.X - r, (float)p2.Y - r, r * 2, r * 2), (float)b.AbsoluteAngle * k, 90); graph.DrawArc(pen, new RectangleF((float)p2.X - r, (float)p2.Y - r, r * 2, r * 2), (float)b.AbsoluteAngle * k, -90); } if ((p & DrawParametres.DrawShiftCtl) == DrawParametres.DrawShiftCtl) { int padding = 4; int length = 16; Pen pen = new Pen(Color.Blue); pen.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor; pen.Width = 5f; p2 = p0.Add(rootPos); graph.DrawLine(pen, (float)p2.X, (float)p2.Y + padding, (float)p2.X, (float)p2.Y + padding + length); graph.DrawLine(pen, (float)p2.X, (float)p2.Y - padding, (float)p2.X, (float)p2.Y - padding - length); graph.DrawLine(pen, (float)p2.X + padding, (float)p2.Y, (float)p2.X + padding + length, (float)p2.Y); graph.DrawLine(pen, (float)p2.X - padding, (float)p2.Y, (float)p2.X - padding - length, (float)p2.Y); } if ((p & DrawParametres.DrawStretchCtl) == DrawParametres.DrawStretchCtl || (p & DrawParametres.DrawFreeEditCtl) == DrawParametres.DrawFreeEditCtl) { int padding = 4; int length = 20; Pen pen = new Pen(Color.Blue); pen.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor; pen.Width = 5f; p2 = p3 - p0; p1 = p3 - p0; p2.Length = length; p1.Length = padding; graph.DrawLine(pen, p1.Add(rootPos).Add(p3).Point, p2.Add(rootPos).Add(p3).Point); p1 = p1.Rotate(Math.PI); p2 = p2.Rotate(Math.PI); graph.DrawLine(pen, p1.Add(rootPos).Add(p3).Point, p2.Add(rootPos).Add(p3).Point); } }
void picBox_MouseMove(object sender, MouseEventArgs e) { //Тут жесть полнейшая //Проверка, теряло ли изображение фокус //чтобы при получении фокуса сразу же не происходило редактирование if (picLostFocus) return; if (e.Button == MouseButtons.Left) { if (selectedBone == null) return; PointF loc = e.Location; //Если нужно, приводим координаты к сетке if (SnapGrid) { loc.X = (((int)loc.X) / GreedStep) * GreedStep; loc.Y = (((int)loc.Y) / GreedStep) * GreedStep; } ToRootBoneCoordinates(ref loc); PointV p = null, p0 = null, p1 = null , sv = null , pv = null; p = new PointV(loc); p0 = new PointV(selectedBone.StartPoint); p1 = new PointV(selectedBone.EndPoint); pv = p - p0; sv = p1 - p0; switch (editMode) { case EditModes.BONE_ROTATE: #region Вращение double da; da = pv.Angle - sv.Angle; selectedBone.Angle = selectedBone.Angle + da; break; #endregion case EditModes.BONE_SHIFT: #region Сдвиг if (!selectedBone.IsRoot) { PointV shift = new PointV(PointV.Sub(loc, selectedBone.Parent.EndPoint)); shift.Angle -= selectedBone.Parent.AbsoluteAngle; selectedBone.Shift = shift.Point; } else { screenCenter = e.Location; } break; #endregion case EditModes.BONE_STRETCH: #region Растяжение double proj = (pv.X * sv.X + pv.Y * sv.Y) / sv.Length; selectedBone.Length = proj; break; #endregion case EditModes.BONE_STRETCH_ROTATE: #region Растяжение и вращение da = pv.Angle - sv.Angle; selectedBone.Angle = selectedBone.Angle + da; proj = (pv.X * sv.X + pv.Y * sv.Y) / sv.Length; selectedBone.Length = proj; break; #endregion } Redraw(); } }
/// <summary> /// Квадрат расстояния /// </summary> /// <param name="p1"></param> /// <param name="p2"></param> /// <returns></returns> public static double SqrDistance(PointV p1, PointV p2) { double dx, dy; dx = p1.X - p2.X; dy = p1.Y - p2.Y; return dx * dx + dy * dy; }
public static bool CheckDistance(PointV p1, PointV p2, double dist) { dist *= dist; double dx = p1.X - p2.X, dy = p1.Y - p2.Y; return dx * dx + dy * dy <= dist; }
public static double ScalarProduct(PointV vec1, PointV vec2) { return vec1.X * vec2.X + vec1.Y * vec2.Y; }
public static double GetDistance(PointF p0, PointF p1, PointF p) { //Взято тут: //http://algolist.manual.ru/maths/geom/distance/pointline.php if (p0 == p1) { return Distance(ref p0, ref p); } PointV p0v = new PointV(PointV.Sub(ref p, ref p0)); PointV p1v = new PointV(PointV.Sub(ref p, ref p1)); PointV sv = new PointV(PointV.Sub(ref p1, ref p0)); double dx, dy; //Проверяем знак скалярного произведения векторов //Если меньше 0, значит основание перпендикуляра от точки лежит за пределами отрезка if (p0v.X * sv.X + p0v.Y * sv.Y < 0) { return 100; dx = p.X - p0.X; dy = p.Y - p0.Y; return dx * dx + dy * dy; } //Аналогично, для конца отрезка sv = new PointV(PointV.Sub(ref p0, ref p1)); if (p1v.X * sv.X + p1v.Y * sv.Y < 0) { return 100; dx = p.X - p1.X; dy = p.Y - p1.Y; return dx * dx + dy * dy; } //Если до сих пор функция еще выполняется, значит основание перпендикуляра лежит //в пределах отрезка. Проверяем расстояние от точки до прямой //Находим векторное произведение для двумерного случая return (sv.Y * p1v.X - sv.X * p1v.Y)/sv.Length; }
public static double Distance(PointV p1, PointV p2) { double dx, dy; dx = p1.X - p2.X; dy = p1.Y - p2.Y; return Math.Sqrt(dx * dx + dy * dy); }