Drew
Drew

Reputation: 67

WPF Modify Path Data at Runtime

Hi I have a path from GetFlattenedPathGeometry where i can iterate through the figures and segments to get the points to add to a PointCollection.

I then multiply each point.x/y by a scale factor to get a full scaled version of the original path data. (not using scaletransform as it doesn't suit my requirements).

If i use something like:

public static PathGeometry GetPathGeometry(PointCollection polygonCorners)
{
    List<PathSegment> pathSegments = new List<PathSegment> { new     PolyLineSegment(polygonCorners, true) };
    PathGeometry pathGeometry = new PathGeometry();
    pathGeometry.Figures.Add(new PathFigure(polygonCorners[0], pathSegments, true));
    return pathGeometry;
} 

It returns a new path geometry but doesn't handle ellipses with excluded path geometry in that the path is just one continuous line.

Is there a way to convert the PointCollection to Path.Data (eg: with the "M" "L" and such) for me to re-use Geometry.Parse(the new string)?

Here is the code i'm using to get the flattenedgeometry pointcollection:

PathGeometry g = path.Data.GetFlattenedPathGeometry();
foreach (var f in g.Figures)
{
    foreach (var s in f.Segments)
    {
        if (s is PolyLineSegment)
        {
            foreach (var pt in ((PolyLineSegment) s).Points)
            {
                strGeom += pt.ToString();
                Point ptn = new Point(pt.X * ScaleX, pt.Y * ScaleY);
                pcol.Add(ptn);
            }
        }
    }
}

< Edit Images >

Here is the original path with rectangles and ellipses subtracted from the geometry.

enter image description here

And here is what is looks like re-creating from the code.

enter image description here

If i use the original GetFlattenedPathGeometry, it looks like the original but i need to scale the points to a new resolution.

Hope this makes it clearer.

Upvotes: 1

Views: 5189

Answers (2)

Clemens
Clemens

Reputation: 128060

You could simply call ToString on the PathGeometry to get the whole path data string at once:

var sourceGeometry = path.Data.GetFlattenedPathGeometry();
var geometryString = sourceGeometry.ToString(CultureInfo.InvariantCulture);
var targetGeometry = Geometry.Parse(geometryString);

And why can't you just apply a ScaleTransform to the whole geometry before calling GetFlattenedPathGeometry? The following works perfectly for me (with two EllipseGeometries in an excluding CombinedGeometry):

var pathGeometry = path.Data.Clone();
pathGeometry.Transform = new ScaleTransform(0.5, 0.5);
var scaledGeometry = pathGeometry.GetFlattenedPathGeometry();

EDIT: From what you write in your question and comments, I'm guessing that all you actually want to do is to add or combine geometries with different scaling factors. If that is true, your flattened geometry approach is by far to complicated, as you could easily do that with the following two methods:

private PathGeometry AddGeometries(
    Geometry geometry1, Geometry geometry2, double scale)
{
    geometry2 = geometry2.Clone();
    geometry2.Transform = new ScaleTransform(scale, scale);
    var pathGeometry = PathGeometry.CreateFromGeometry(geometry1);
    pathGeometry.AddGeometry(geometry2);
    return pathGeometry;
}

private PathGeometry CombineGeometries(
    Geometry geometry1, Geometry geometry2, GeometryCombineMode mode, double scale)
{
    geometry2 = geometry2.Clone();
    geometry2.Transform = new ScaleTransform(scale, scale);
    return Geometry.Combine(geometry1, geometry2, mode, null);
}

Given a Path with some geometry in its Data property, you may now add (or combine) an arbitray other geometry with a scaling factor with a call like this:

Geometry newGeometry1 = ...
double scale1 = ...
path.Data = AddGeometries(path.Data, newGeometry1, scale1);

Geometry newGeometry2 = ...
double scale2 = ...
path.Data = CombineGeometries(path.Data, newGeometry2,
            GeometryCombineMode.Exclude, scale2);

Upvotes: 1

Drew
Drew

Reputation: 67

Found the answer by perseverance.

The code to get each point of flattenedpathgeometry and add a scale to each point and recreate the same flattenedpathgeometry with the new points. hope it helps someone. And thanks Clemens. Appreciate your efforts.

path.Data = Geometry.Parse(CurrentObject.Geometry1);
PathGeometry g = path.Data.GetFlattenedPathGeometry();

PathGeometry g = path.Data.GetFlattenedPathGeometry();

foreach (var f in g.Figures)
{
Point pt1 = f.StartPoint;
pt1.X = pt1.X * ScaleX;
pt1.Y = pt1.Y * ScaleY;
strGeom += "M" + pt1.ToString();
    foreach (var s in f.Segments)
    if (s is PolyLineSegment)
    {
        count = 0;
        foreach (var pt in ((PolyLineSegment)s).Points)
    {
        int scount = ((PolyLineSegment)s).Points.Count;
        if (count == 0)
        {
            Point pts = new Point(pt.X * ScaleX, pt.Y * ScaleY);
            strGeom += "L" + pts.ToString();
        }
        else if (count < scount)
        {
            Point pts = new Point(pt.X * ScaleX, pt.Y * ScaleY);
            strGeom += " " + pts.ToString();
        }
        else if (count == scount)
        {
            Point pts = new Point(pt.X * ScaleX, pt.Y * ScaleY);
            strGeom += " " + pts.ToString() + "Z";
        }
        count++;
    }
    }
}
path.Data = Geometry.Parse(strGeom);

Here's an image of the paths sent from a remote session: 1366x768 scales to 1920x1080

enter image description here

Upvotes: 0

Related Questions