This project has moved. For the latest updates, please go here.

Linetype Generation LwPolyline and Offsets

May 13, 2015 at 3:00 PM
Edited May 13, 2015 at 3:03 PM
How can I set the Linetype Generation property to true?
And how can I make a offset with this polylines?
Thanks!
Coordinator
May 14, 2015 at 4:29 PM
Edited May 14, 2015 at 6:07 PM
The Linetype Generation is not available at the moment, but it will not be a problem to add it.

The offset is a different story, the library does not pretend to solve geometric problems, so you will have to do it yourself. Perhaps you would like to take a look at the MLine entity. Nevertheless, there are a few methods in the code that might help you. Check the methods OffsetLine and FindIntersection in the MathHelper class. Bear in mind that most probably the place and signature of those methods will change, I have plans to include, sometime, utility methods for geometric entities like distances, intersections, and stuff like that.

Daniel
May 15, 2015 at 4:10 PM
Ok, thanks man.

I solved my problem by creating a new property inside the LwPolyline class called EnableLinetypeGeneration.
public bool EnableLinetypeGeneration
{
     get { return (this.flags & PolylineTypeFlags.ContinuousLineTypePatter) == PolylineTypeFlags.ContinuousLineTypePatter; }
     set { this.flags = value ? PolylineTypeFlags.ContinuousLineTypePatter : PolylineTypeFlags.OpenPolyline; }
}
May 15, 2015 at 5:01 PM
So, I solved the offset too.

I only created more 2 methods:
public LwPolyline GetOffsetCurves(double offsetDist)
{
     LwPolyline entityOffset = (LwPolyline)this.Clone();
     entityOffset.Vertexes.Clear();

      for (int i = 0; i < this.Vertexes.Count; i++)
      {
          if (i == (this.Vertexes.Count - 1))
          {
               entityOffset.Vertexes.Add(GetVertexOffset(this.Vertexes[i-1], this.Vertexes[i], this.Vertexes[i], offsetDist));
               break;
          }
          entityOffset.Vertexes.Add(GetVertexOffset(this.Vertexes[i], this.Vertexes[i + 1], this.Vertexes[i], offsetDist));
    }
    return entityOffset;
}
private LwPolylineVertex GetVertexOffset(LwPolylineVertex startVertex, LwPolylineVertex endVertex, LwPolylineVertex middleVertex, double distance)
{
     LwPolylineVertex middle = middleVertex;
      LwPolylineVertex vector = new LwPolylineVertex(startVertex.Location.X - endVertex.Location.X, startVertex.Location.Y - endVertex.Location.Y);
      LwPolylineVertex n = new LwPolylineVertex(-vector.Location.Y, vector.Location.X);

     double normLenght = Math.Sqrt((n.Location.X * n.Location.X) + (n.Location.Y * n.Location.Y));

      n.Location = new Vector2(n.Location.X / normLenght, n.Location.Y / normLenght);

     return new LwPolylineVertex(middle.Location.X + (distance * n.Location.X), middle.Location.Y + (distance * n.Location.Y));
}
How to use:

I call the method "GetOffsetCurves" and I put the distance parameter, that is the distance of my offset, in this case "12".
Obs:
Positive numbers = offset to the right.
Negative numbers = offset to the left.
LwPolyline poly = new LwPolyline();

poly.Vertexes.Add(new LwPolylineVertex(10,10,0));
poly.Vertexes.Add(new LwPolylineVertex(30, 30, 0));
poly.Vertexes.Add(new LwPolylineVertex(50, 50, 0));
poly.Vertexes.Add(new LwPolylineVertex(70, 70, 0));
poly.Vertexes.Add(new LwPolylineVertex(90, 90, 0));
poly.Vertexes.Add(new LwPolylineVertex(110, 110, 0));

LwPolyline polyOffsetRight = poly.GetOffsetCurves(12);
LwPolyline polyOffsetLeft = poly.GetOffsetCurves(-12);

documento.AddEntity(poly);
documento.AddEntity(polyOffsetRight);
documento.AddEntity(polyOffsetLeft);
Feb 8, 2016 at 9:21 AM
Edited Feb 8, 2016 at 9:26 AM
Thank you for sharing this nice offset function. It helped me a lot as I also need to offset polylines.

When I was testing the code, I saw that the start- and endpoints of the offsetlines are not exactly correct.
You notice that when you make a offset curve of a rectangle.

I modified your code to solve this issue:
public LwPolyline GetOffsetCurves(double offsetDist)
{
    LwPolyline entityOffset = (LwPolyline)this.Clone();
    entityOffset.Vertexes.Clear();

    for (int i = 0; i < this.Vertexes.Count; i++)
    {
        if (i == 0)
            entityOffset.Vertexes.Add(GetVertexOffset(this.Vertexes[this.Vertexes.Count - 1], this.Vertexes[i + 1], this.Vertexes[i], offsetDist));
        else if (i == (this.Vertexes.Count - 1))
            entityOffset.Vertexes.Add(GetVertexOffset(this.Vertexes[i - 1], this.Vertexes[0], this.Vertexes[i], offsetDist));
        else
            entityOffset.Vertexes.Add(GetVertexOffset(this.Vertexes[i - 1], this.Vertexes[i + 1], this.Vertexes[i], offsetDist));
    }
    return entityOffset;
}
private LwPolylineVertex GetVertexOffset(LwPolylineVertex startVertex, LwPolylineVertex endVertex, LwPolylineVertex middleVertex, double distance)
{
    Vector2 sm = Vector2.Normalize(middleVertex.Location - startVertex.Location);
    Vector2 me = Vector2.Normalize(endVertex.Location - middleVertex.Location);
    Vector2 se = Vector2.Round(sm + me, 4);

    Vector2 n = new Vector2(-se.Y, se.X);
    n = Vector2.Normalize(n);

    var alpha = Vector2.AngleBetween(n, new Vector2(-sm.Y, sm.X));
    n = n * 1 / Math.Cos(alpha);

    return new LwPolylineVertex(middleVertex.Location.X + (distance * n.X), middleVertex.Location.Y + (distance * n.Y), middleVertex.Bulge);
}
I also have a question about the use of this method:

I have a closed outline as a LwPolyline and want to have a offset curve of it outside the original curve.
To detect the right offset direction (right or left) I have to know if the polyline goes clockwise or counterclockwise right?
Is there any method or property that gives me this information?
I thought it could be the "Normal" property but it is alsways positive no matter which direction the polyline runs.

Thanks

Seeb
Coordinator
Feb 9, 2016 at 3:41 PM
Edited Feb 9, 2016 at 3:49 PM
The normal of an entity defines the plane in which it is defined. The LwPolyline vertexes are defined locally to its construction plane and, most of the time, they are defined in the XY plane, therefore, its normal will return (0,0,1). The normal value is independent to the winding direction of its vertexes, and you will have to calculate your self if they are CW or CCW.

You can easily find information about this in the web, but for non-self-intersecting polygons there is an easy solution, you can just use the cross product. Something like:
List<Vector2> vertexes; // your polygon vertexes list
double cross = 0.0;
for (int i = 0; i < vertexes.Count-1; i++)
{
     cross += Vector2.CrossProduct(vertexes[i], vertexes[i+1]);
}
cross += Vector2.CrossProduct(vertexes[vertexes.Count-1], vertexes[0]);

if (cross>0) Console.WriteLine("CCW");
else if (cross < 0) Console.WriteLine("CW");
else Console.WriteLine("Unknown");
A completely generic solution capable of handling self-intersecting polygons is a different story.

Daniel
Feb 11, 2016 at 11:17 AM
Thank you. I had a similar solution but not as nice as yours.

What's also nice about this is that you get the enclosed area of the polyline if it is closed and not selfintersecting.
Jul 28, 2016 at 8:52 AM
public LwPolyline GetOffsetCurves(double offsetDist)
{
    LwPolyline entityOffset = (LwPolyline)this.Clone();
    entityOffset.Vertexes.Clear();

    for (int i = 0; i < this.Vertexes.Count; i++)
    {
        if (i == 0)

            entityOffset.Vertexes.Add(GetVertexOffset(this.Vertexes[this.Vertexes.Count - 1], this.Vertexes[i + 1], this.Vertexes[i], offsetDist));

        else if (i == (this.Vertexes.Count - 1))
            entityOffset.Vertexes.Add(GetVertexOffset(this.Vertexes[i - 1], this.Vertexes[0], this.Vertexes[i], offsetDist));
        else
            entityOffset.Vertexes.Add(GetVertexOffset(this.Vertexes[i - 1], this.Vertexes[i + 1], this.Vertexes[i], offsetDist));
    }
    return entityOffset;
}
its for closed polylines.

what about open LWpolies
 entityOffset.Vertexes.Add(GetVertexOffset(this.Vertexes[this.Vertexes.Count - 1], this.Vertexes[i + 1], this.Vertexes[i], offsetDist));
this have to be change