从 PathGeometry 获取列表 <Segment>

Get List<Segment> from a PathGeometry

我画了canvas几个形状。我有两种形状:椭圆和路径。

现在,当我点击我的 Canvas 时,我想获得最近的形状。

我可以设法为 Ellipse 做一些事情,但是对于 Path 我没能找到如何获取它的坐标。

这是我用来生成列表的代码,以防某些方法在该方法中不是最优的:

具体来说,"percage"是钻孔,如果Type=12,表示我画了一个slot(Path)。否则我画一个圆(椭圆)

if (percage.Type == 12)
{
    double r = percage.Diametre / 2;
    LineSegment ligne1 = new LineSegment();
    LineSegment ligne2 = new LineSegment();
    Point ptCentre = new Point(dx + percage.Coor_X, this.MyScrollViewer.ActualHeight * echelle - dy - percage.Coor_Y);
    double angle = percage.AnglePer;
    double xLeft = ptCentre.X - r;
    double xRight = ptCentre.X + r;
    double yUp = ptCentre.Y - ((percage.Longueur / 2) - r);
    double yDown = ptCentre.Y + ((percage.Longueur / 2) - r);
    Point pt1 = new Point(xLeft, yUp);
    Point pt2 = new Point(xRight, yUp);
    Point pt3 = new Point(xRight, yDown);
    Point pt4 = new Point(xLeft, yDown);
    pt1 = Global.RotatePoint(pt1, ptCentre, angle - 90);
    pt2 = Global.RotatePoint(pt2, ptCentre, angle - 90);
    pt3 = Global.RotatePoint(pt3, ptCentre, angle - 90);
    pt4 = Global.RotatePoint(pt4, ptCentre, angle - 90);

    Path arc_path1 = new Path();
    arc_path1.Stroke = Brushes.Red;
    arc_path1.StrokeThickness = 2;
    PathGeometry pathGeometry = new PathGeometry();
    ArcSegment arc1 = new ArcSegment();
    ArcSegment arc2 = new ArcSegment();
    PathFigure pathfigure1 = new PathFigure();
    PathFigure pathfigure2 = new PathFigure();
    arc1.Point = new Point(pt2.X, pt2.Y);
    arc1.Point = new Point(pt4.X, pt4.Y);
    pathfigure1.StartPoint = new Point(pt1.X, pt1.Y);
    pathfigure1.StartPoint = new Point(pt3.X, pt3.Y);
    SweepDirection sd = SweepDirection.Counterclockwise;
    if (yUp < yDown)
    {
        sd = SweepDirection.Clockwise;
    }
    arc1.Size = new Size(r, r);
    arc1.SweepDirection = sd;
    arc2.Size = new Size(r, r);
    arc2.SweepDirection = sd;
    arc1.Point = pt2;
    arc2.Point = pt4;
    ligne1.Point = new Point(pt3.X, pt3.Y);
    ligne2.Point = new Point(pt1.X, pt1.Y);
    pathfigure1.StartPoint = new Point(pt1.X, pt1.Y);
    pathfigure1.Segments.Add(arc1);
    pathfigure1.Segments.Add(ligne1);
    pathfigure1.Segments.Add(arc2);
    pathfigure1.Segments.Add(ligne2);
    pathGeometry.Figures.Add(pathfigure1);
    arc_path1.Data = pathGeometry;
    arc_path1.Tag = percage;

    percage.ListShapes.Add(arc_path1);

}
else
{
    Ellipse ellipse = new Ellipse();
    ellipse.Stroke = System.Windows.Media.Brushes.Red;
    ellipse.StrokeThickness = 1;
    ellipse.Fill = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.Red);
    ellipse.Width = percage.Diametre;
    ellipse.Height = percage.Diametre;
    percage.Coor_X_Graph = X1 + dx - (percage.Diametre / 2);
    percage.Coor_Y_Graph = this.MyScrollViewer.ActualHeight * echelle - (Y1 + dy) - (percage.Diametre / 2);
    ellipse.Margin = new System.Windows.Thickness(percage.Coor_X_Graph, percage.Coor_Y_Graph, 0, 0);
    ellipse.Tag = percage;

    percage.ListShapes.Add(ellipse);
}

然后,为了得到最近的形状,我开始编写代码: 对于椭圆我可以检索它的坐标,但是对于路径,找不到里面的线段列表。

StartPoint = e.GetPosition(monDessin);
double distance=-1;
Shape selectedShape = null;
for (int i = monDessin.Children.Count - 1; i > -1; i--)
{

    if (monDessin.Children[i] is Ellipse)
    {
        Ellipse ell = (Ellipse)monDessin.Children[i];
        double x = ell.Margin.Left + Width / 2;
        double y = ell.Margin.Top - ell.Height / 2;
        double dist = Math.Sqrt((StartPoint.X - x) * (StartPoint.X - x) + (StartPoint.Y -y) * (StartPoint.Y - y));
        if(distance==-1 || dist<distance)
        {
            distance = dist;
        }
    }
    else if(monDessin.Children[i] is Path)
    {
        Path path=(Path)monDessin.Children[i];
        Geometry geometry = path.Data;
        foreach(PathFigure pf in ?????)
    }
}

最后,我可以自己做,在网上多看一点(不确定这是我开始这个主题的最佳方式,所以欢迎任何其他建议)

我找到了一些 "solution" here 但是代码不起作用,在下面一行出错(不明白为什么,也不明白它做了什么)

string value = seralizer.ConvertToString(geomerty, null);

最后我在 msdn 网站上对其进行了修改,我发现 geometry.GetOutlinedPathGeometry() and pathGeometry.Figures 允许获取图表列表。我只是不明白为什么我所有的 ArcSegment 都变成了 BezierSegment。 无论如何,它工作正常,所以我把代码放在这里:

StartPoint = e.GetPosition(monDessin);
double distance=-1;
double dist;
Shape selectedShape = null;
for (int i = monDessin.Children.Count - 1; i > -1; i--)
{
    string type = monDessin.Children[i].GetType().ToString();

    if (monDessin.Children[i] is Ellipse)
    {
        Ellipse ell = (Ellipse)monDessin.Children[i];
        double x = ell.Margin.Left + ell.Width / 2;
        double y = ell.Margin.Top - ell.Height / 2;
        dist = Math.Sqrt((StartPoint.X - x) * (StartPoint.X - x) + (StartPoint.Y -y) * (StartPoint.Y - y));
        if(distance==-1 || dist<distance)
        {
            distance = dist;
        }
    }
    else if(monDessin.Children[i] is Path)
        {
            Path path=(Path)monDessin.Children[i];
            string titi = path.Tag.GetType().ToString();
            Geometry geometry = path.Data;
            PathGeometry pathGeometry = geometry.GetOutlinedPathGeometry();
            PathFigureCollection figures = pathGeometry.Figures;
            if (figures != null)
            {
               foreach (PathFigure figure in figures)
               {
                   foreach (PathSegment segment in figure.Segments)
                   {
                       //first syntax : if(segment is LineSegment)
                       if(segment is LineSegment)
                       {
                          LineSegment lineSegment = (LineSegment)segment;
                          double x = lineSegment.Point.X;
                          ouble y = lineSegment.Point.Y;
                       }
                       //2nd syntax : 
                       //ArcSegment arcSegment = segment as ArcSegment;
                       //Then check if not null
                       ArcSegment arcSegment = segment as ArcSegment;
                       if (arcSegment != null)
                       {
                           double x = arcSegment.Point.X;
                           double y = arcSegment.Point.Y;
                           dist = Math.Sqrt((StartPoint.X - x) * (StartPoint.X - x) + (StartPoint.Y - y) * (StartPoint.Y - y));
                           if (distance == -1 || dist < distance)
                           {
                               distance = dist;
                           }
                       }
                       BezierSegment bezierSegment = segment as BezierSegment;
                       if (bezierSegment != null)
                       {
                           double x = bezierSegment.Point3.X;
                           double y = bezierSegment.Point3.Y;
                           dist = Math.Sqrt((StartPoint.X - x) * (StartPoint.X - x) + (StartPoint.Y - y) * (StartPoint.Y - y));
                           if (distance == -1 || dist < distance)
                           {
                                distance = dist;
                           }
                       }
                   }
              }
          }
     }
}

注意:我发现了两种不同的语法来检查段的类型(即 LineSegment),我不知道哪种方法最好,第一种语法似乎更好,但第二种语法的优点是检查是否它是空的(即使理论上它可能永远不会发生???)