在C#中选择一系列线段

时间:2015-12-28 21:46:12

标签: c# intersection

我正在努力为我正在研发的家庭酿造计算机辅助加工软件应用程序创建一个非常简单的功能。基本上,我已经绘制了一些工具路径,可以告诉铣床在哪里旅行。所以,想象一下我有3组线段,每个线段有100个单独的线段,每个线段都包含在自己的List中,如下所示:

List<PointF> points = new List<PointF>();
List<PointF> pointsOffsetHigh = new List<PointF>();  
List<PointF> pointsOffsetLow = new List<PointF>(); 

让我们说它们在屏幕上彼此纵横交错,我希望当我点击其中的任何线段时,每一个都被视为自己的对象。我该怎么做?我已经可以使用StackOverflow中的这个优秀示例选择单独的线段:Graphic - DrawLine - draw line and move it

一旦我选择了一系列线段,我就会看到它与另一系列线段相交的位置,然后擦除它的一半。它对于任何CAD程序来说都是非常基础的,但是在屏幕上看起来如此简单的东西背后有如此多的复杂性。

如果有人可以提供帮助,我会很感激。代码,一般方法,我会采取任何行动。

2 个答案:

答案 0 :(得分:1)

这将是一项严肃的开发工作,因此在重新创建所有内容之前,您一定要检查是否有任何开源或第三方库可以满足您的需求。但是,如果您继续从头开始推出自己的解决方案,我建议使用LineSegment类作为基础(原子对象),而不是List<PointF>。此提议的LineSegment课程中的基本成员字段为pxpyqxqy,它们代表两个端点的坐标。线段。

您在上面发布的“可移动”线段图形解决方案可以自然地使用此对象。任何两个LineSegment对象之间的交叉测试也可以使用此处概述的逻辑来完成:http://www.geeksforgeeks.org/check-if-two-given-line-segments-intersect/

如果您想要创建一系列连接的线段,可以将这些单独的LineSegment对象放入List<LineSegment>(或者将public LineSegment Next;成员引用添加到类中以进行连接任何两个对象以链表方式组合在一起)。我意识到会有一些冗余,因为每个段的第二个点将与下一个段的第一个点相同(如果这些段确实是空间连接的),但我可以从经验中说这个原子结构将更容易从长远来看,比简单的点,尤其是拼接线,剪切子节,传递给辅助函数等等。

LineSegment类也可以自然地扩展,以支持更多的行特定属性,如标签,线条颜色,线宽等,这些属性无法自然地分配给一个点列表。即使CAD程序中的曲线通常也是直线的扩展(请参阅如何从线段生成Bézier curves)。

希望这有帮助。

答案 1 :(得分:0)

我发布了下面的工作代码。基本上曲线由线段组成,线段由两个GraphLines组成。它检查曲线是否选择了其中一个线段,然后如果为真则点亮整条曲线。有关该代码,请参阅LineMover_Paint。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace LightUpWholeCurve
{

public partial class Form1 : Form
{
    public List<GraphLine> SinArr = new List<GraphLine>();
    public List<GraphLine> Bowditch = new List<GraphLine>();
    public List<GraphLine> CircArr = new List<GraphLine>();


    public List<List<GraphLine>> MasterArr = new List<List<GraphLine>>();


    public List<GraphLine> MasterArrayOfGraphLines = new List<GraphLine>();




    GraphLine SelectedLine = null;
    MoveInfo Moving = null;



    public Form1()
    {
        this.DoubleBuffered = true;

        this.Paint += new PaintEventHandler(LineMover_Paint);
        this.MouseMove += new MouseEventHandler(LineMover_MouseMove);
        this.MouseDown += new MouseEventHandler(LineMover_MouseDown);
        this.MouseUp += new MouseEventHandler(LineMover_MouseUp);

        MakeSinArray();
        MakeBowditchArray();
        MakeCircleArray();


        //Create a lists of lists of each curve
        this.MasterArr.Add(SinArr);
        this.MasterArr.Add(Bowditch);
        this.MasterArr.Add(CircArr);

        foreach (var fullcurve in MasterArr)
        {
            foreach (var GL in fullcurve)
            {
                MasterArrayOfGraphLines.Add(GL);
            }
        }




        //You must use initialize component or you'll get a small window
        //Also, keep in mind that if you cut and paste a whole file you
        //must change the namespace, or it won't recognize "InitializeComponent
        InitializeComponent();
    }

    void MakeBowditchArray()
    {
        int numberOfSeg = 100;
        double TwoPI = (float)(2 * Math.PI) / numberOfSeg;
        for (int t = 0; t <= numberOfSeg; t++)
            this.Bowditch.Add(new GraphLine(
                500 + 25 * (float)Math.Sin(3 * TwoPI * t),
                300 + 25 * (float)Math.Cos(5 * TwoPI * t),
                500 + 25 * (float)Math.Sin(3 * TwoPI * (t + 1)),
                300 + 25 * (float)Math.Cos(5 * TwoPI * (t + 1))));

    }

    void MakeSinArray()
    {
        int numberOfSeg = 100;
        double TwoPI = (float)(2 * Math.PI) / numberOfSeg;
        for (int t = 0; t <= numberOfSeg; t++)
            this.SinArr.Add(new GraphLine(
                200 + 25 * (float)t / 20,
                200 + 25 * (float)Math.Sin(3 * TwoPI * t),
                200 + 25 * (float)(t + 1) / 20,
                200 + 25 * (float)Math.Sin(3 * TwoPI * (t + 1))));
    }

    void MakeCircleArray()
    {
        int numberOfSeg = 50;
        double TwoPI = (float)(2 * Math.PI) / numberOfSeg;
        for (int t = 0; t <= numberOfSeg; t++)
            this.CircArr.Add(new GraphLine(
                300 + 25 * (float)Math.Sin(TwoPI * t),
                300 + 25 * (float)Math.Cos(TwoPI * t),
                300 + 25 * (float)Math.Sin(TwoPI * (t + 1)),
                300 + 25 * (float)Math.Cos(TwoPI * (t + 1))));
    }



    private void LineMover_MouseUp(object sender, MouseEventArgs e)
    {
        if (Moving != null)
        {
            this.Capture = false;  //Capture is part of Control.Capture
            Moving = null;
        }
        RefreshLineSelection(e.Location);
    }

    private void LineMover_MouseDown(object sender, MouseEventArgs e)
    {
        RefreshLineSelection(e.Location);
        if (this.SelectedLine != null && Moving == null)
        {
            this.Capture = true; //gets or sets a bool whether control has captured the mouse.
            Moving = new MoveInfo
            {
                Line = this.SelectedLine,
                StartLinePoint = SelectedLine.StartPoint,
                EndLinePoint = SelectedLine.EndPoint,
                StartMoveMousePoint = e.Location
            };
        }
        RefreshLineSelection(e.Location);

    }

    private void LineMover_MouseMove(object sender, MouseEventArgs e)
    {
        if (Moving != null)
        {

            Moving.Line.StartPoint = new PointF(Moving.StartLinePoint.X + e.X - Moving.StartMoveMousePoint.X, Moving.StartLinePoint.Y + e.Y - Moving.StartMoveMousePoint.Y);
            Moving.Line.EndPoint = new PointF(Moving.EndLinePoint.X + e.X - Moving.StartMoveMousePoint.X, Moving.EndLinePoint.Y + e.Y - Moving.StartMoveMousePoint.Y);
        }
        RefreshLineSelection(e.Location);
    }




    private void LineMover_Paint(object sender, PaintEventArgs e)
    {
        e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
        e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;


        //Look at every GraphLine in SinArray and if it is the segment selected, 
        //then turn it to the color Red
        Color color1 = Color.Blue;
        Pen pen1 = new Pen(color1, 2);

        foreach (var line in SinArr)
        {
            if (line == SelectedLine)
            {
                color1 = Color.Red;
                pen1 = new Pen(color1, 2);
                break;
            }
        }

        foreach (var line in SinArr)
        {
            e.Graphics.DrawLine(pen1, line.StartPoint, line.EndPoint);
        }

        //Go through entire array in Bowditch and check to see if any line was selected.
        //If it was, then set color to Red

        color1 = Color.Blue;
        pen1 = new Pen(color1, 2);

        foreach (var line in Bowditch)
        {
            if (line == SelectedLine)
            {
                color1 = Color.Red;
                pen1 = new Pen(color1, 2);
                break;
            }   
        }

        foreach (var line in Bowditch)
        {
            e.Graphics.DrawLine(pen1, line.StartPoint, line.EndPoint);
        }






        color1 = Color.Blue;
        pen1 = new Pen(color1, 2);

        foreach (var line in CircArr)
        {
            if (line == SelectedLine)
            {
                color1 = Color.Red;
                pen1 = new Pen(color1, 2);
                break;
            }
        }

        foreach (var line in CircArr)
        {
            e.Graphics.DrawLine(pen1, line.StartPoint, line.EndPoint);
        }


    }


    private void RefreshLineSelection(Point point)
    {



        var selectedLine = FindLineByPoint(MasterArrayOfGraphLines, point);
        if (selectedLine != this.SelectedLine)
        {
            this.SelectedLine = selectedLine;
            this.Invalidate();
        }
        if (Moving != null)
            this.Invalidate();



        this.Cursor =
            Moving != null ? Cursors.Hand :
            SelectedLine != null ? Cursors.SizeAll :
              Cursors.Default;

    }


    static GraphLine FindLineByPoint(List<GraphLine> lines, Point p)
    {
        var size = 40;
        var buffer = new Bitmap(size * 2, size * 2);

        foreach (var line in lines)
        {
            //draw each line on small region around current point p and check pixel in point p 
            //does it really draw all the lines from this.Lines = new List<GraphLine>() ? [I wrote that]

            using (var g = Graphics.FromImage(buffer))
            {
                g.Clear(Color.Black);  //Makes entire buffer black
                g.DrawLine(new Pen(Color.Green, 3),  //makes a line through it green
                    line.StartPoint.X - p.X + size,
                    line.StartPoint.Y - p.Y + size,
                    line.EndPoint.X - p.X + size,
                    line.EndPoint.Y - p.Y + size);
            }

            if (buffer.GetPixel(size, size).ToArgb() != Color.Black.ToArgb())
                return line;
        }
        return null;
    }


    public class MoveInfo
    {
        public GraphLine Line;
        public PointF StartLinePoint;
        public PointF EndLinePoint;
        public Point StartMoveMousePoint;
    }
    public class GraphLine
    {
        public GraphLine(float x1, float y1, float x2, float y2)
        {
            this.StartPoint = new PointF(x1, y1);
            this.EndPoint = new PointF(x2, y2);
        }
        public PointF StartPoint;
        public PointF EndPoint;
    }

    private void Form1_Load(object sender, EventArgs e)
    {

    }

}
}