jbuckmccready / CavalierContours

2D polyline library for offsetting, combining, etc.
MIT License
421 stars 79 forks source link

Remove Bluge After offset #30

Open Prakash19921206 opened 3 years ago

Prakash19921206 commented 3 years ago

Hi, Thanks for the nice library, i just started to try few values.

Not sure if this is a bug or my mistake in code. Below is the code i'm trying

int main()
{
    Polyline<double> input;
    input.addVertex(0, 0, 0.0);
    input.addVertex(0, 40, 0.0);
    input.addVertex(10, 40, 0.0);
    input.addVertex(10, 10, 0.0);
    input.addVertex(40, 10, 0.0);
    input.addVertex(40, 0, 0.0);

    input.isClosed() = true;

    vector<Polyline<double>> results = parallelOffset(input, -2.0);
    vector<PlineVertex<double>> points =  results[0].vertexes();
    for (int i = 0; i < points.size(); i++)
    {
        PlineVertex<double> point = points.at(i);
        cout << "x: " << point.x() << " y: "  << point.y() << " Bluge: "<<point.bulge()<< endl;
    }
}

Below is the output

x: 2 y: 2 Bluge: 0 x: 2 y: 38 Bluge: 0 x: 8 y: 38 Bluge: 0 x: 8 y: 10 Bluge: 0.414214 //Why this Bluge appeared? x: 10 y: 8 Bluge: 0 x: 38 y: 8 Bluge: 0 x: 38 y: 2 Bluge: 0

Is there a way to make sure we get straight lines after offset? expected output was :

x: 2 y: 2 Bluge: 0 x: 2 y: 38 Bluge: 0 x: 8 y: 38 Bluge: 0 x: 8 y: 8 Bluge: 0 x: 38 y: 8 Bluge: 0 x: 38 y: 2 Bluge: 0

I have added reference image below. Reference Offset values

Thanks & Regards Prakash

jbuckmccready commented 3 years ago

The algorithm always produces offset curves which are exactly parallel to the input curve (unless the offset is too large and it becomes collapsed). To maintain exactly 2 units away from the input curve the offset curve must have an arc to go around the corner at point (10, 10) in your picture. Arcs will always be generated in the case of a convex (relative to the offset curve) bend point regardless of the angle of the bend to maintain constant offset distance.

Currently there are no options to change this behavior, and I don't currently plan on adding any.

Depending on your use case you may be able to write a simple function to process the output curves and remove the arcs by extending the connecting lines to the point where they intersect.

image

From the above image you just need to set the bulge on vertex 1 to zero and insert a new vertex after it at the intersect point. You can find all the places this needs to happen by checking the bulge of the vertexes.

You can use the segTangentVector function to find the points that describe the lines required to find the intersect, see code here: https://github.com/jbuckmccready/CavalierContours/blob/master/include/cavc/plinesegment.hpp#L134. v1 would be the vertex labeled 1 in the picture, v2 would be the vertex labeled 2 in the picture, and pointOnSeg argument would be v1.pos() for one line and v2.pos() for the other.

You can use the intrLineSeg2LineSeg2 function to find the intersect point, see code here: https://github.com/jbuckmccready/CavalierContours/blob/master/include/cavc/intrlineseg2lineseg2.hpp#L32.

Pseudo code something like this:

for each vertex in the offset output:
  if !vertex.bulgeIsZero() then:
    let line1Pt1= vertex.pos()
    let line1Pt2 = segTangentVector(vertex, nextVertex, vertex.pos()) + vertex.pos()
    let line2Pt1 = segTangentVector(vertex, nextVertex, nextVertex.pos()) + nextVertex.pos()
    let line2Pt2 = nextVertex.pos()
    let intersectPoint = intrLineSeg2LineSeg2(line1Pt1, line1Pt2, line2Pt1, line2Pt2)
    insert new vertex with pos at IntersectPoint and bulge equal 0
    vertex.bulge() = 0

NOTE: segTangentVector just returns a vector pointing in the tangent direction from the origin (0, 0), that's why it must be added to the vertex positions to get the actual points on the lines.