jbuckmccready / cavalier_contours

2D polyline/shape library for offsetting, combining, etc.
Apache License 2.0
144 stars 12 forks source link

[Bug]This polyline cannot be offset outside #13

Closed FishOrBear closed 3 years ago

FishOrBear commented 3 years ago

https://user-images.githubusercontent.com/19372111/122493643-a4f24500-d01a-11eb-97f8-f2e26873c0cd.mp4

This polyline cannot be offset outside


{"vertexes":[[0,0,2.9239855509708432],[422.7001801508977,-2181.678349165927,0.21373279590439873],[1217.850643134374,-1733.2038795014323,4.472986753391631],[961.0754444813574,-155.87051634718955,0.22947158823257166]],"isClosed":true}
jbuckmccready commented 3 years ago

The json text representation has vertexes with bulge > 1, bulge must always be between -1 and 1 (inputs are not sanitized by the library currently).

jbuckmccready commented 3 years ago

I need a working polyline (with bulge values between -1 and 1) to be able to reproduce and fix the issue.

FishOrBear commented 3 years ago

I interrupted it, do you think this is okay?


{"vertexes":[[0,0,0.39225530213565374],[-2466.3785800210244,-67.26296602434104,0.484923954116067],[-2161.7248988609135,-2900.376762550583,0.44171257084882926],[422.7001801508977,-2181.678349165927,0.21373279590439873],[1217.850643134374,-1733.2038795014323,0.47915321276268247],[4134.244054592013,-1954.8763015675465,0.5643966953535755],[3262.8872828398416,1137.416074109292,0.41127495953982673],[961.0754444813574,-155.87051634718955,0.22947158823257166]],"isClosed":true}
jbuckmccready commented 3 years ago

That json works and looks like the one in the video. I am able to offset outward OK with the latest commit on master (I may have fixed it in the process of fixing the overlap bug), are you using the latest commit?

FishOrBear commented 3 years ago

The offset can be normal after interruption The one before the interruption cannot be offset.

I use Google Translate, it may not be very precise

jbuckmccready commented 3 years ago

The library only supports bulge values between -1 and 1. Functions could be added to convert other things (although I'm not sure based on the definition of a vertex bulge what a value greater than 1 means), how are you interpreting bulge values greater than 1?

FishOrBear commented 3 years ago

image

So when bul=1, the arc is a semicircle, and when bul is greater than 1, the arc is larger than the semicircle.

bul= <Tangent value of (quarter central angle)>

    /**
     * 解析两点和凸度所构成的圆弧
     *
     * @param {Vector2} p1
     * @param {Vector2} p2
     * @param {number} bul 凸度,在cad中,凸度为 <(四分之一圆心角)的正切值> 
     */
    ParseFromBul(p1: Vector3 | Vector2, p2: Vector3 | Vector2, bul: number): Arc
    {
        if (p1 instanceof Vector2)
            p1 = AsVector3(p1);
        if (p2 instanceof Vector2)
            p2 = AsVector3(p2);

        let ocsInv = this.OCSInv;
        p1 = p1.clone().applyMatrix4(ocsInv);
        p2 = p2.clone().applyMatrix4(ocsInv);

        //弦向量
        let chordV = p2.clone().sub(p1);
        //弦角度
        let chordAn = angle(chordV);
        //弦长度/2
        let chordLengthHalf = chordV.length() / 2;

        let allAngle = Math.atan(bul) * 4;
        let HalfAngle = allAngle * 0.5;
        //半径
        this._Radius = chordLengthHalf / Math.sin(HalfAngle);

        //指向圆心的角度
        let toCenterAn = chordAn + Math.PI * 0.5;//弦角度转90

        //圆心
        let center = midPoint(p1, p2);
        polar(center, toCenterAn, this._Radius - (bul * chordLengthHalf));
        this.Center = center.clone().applyMatrix4(this.OCS);

        this._Radius = Math.abs(this._Radius);

        this._StartAngle = angle(p1.clone().sub(center));
        this._EndAngle = angle(p2.clone().sub(center));

        this._Clockwise = bul < 0;

        return this;
    }
FishOrBear commented 3 years ago

http://www.lee-mac.com/bulgeconversion.html

This explanation should be more detailed

FishOrBear commented 3 years ago

Simplified code according to leemac

        //a (* 2 (atan b))
        let a = Math.atan(bul) * 2;
        //r (/ (distance p1 p2) 2 (sin a))
        let r = p1.distanceTo(p2) / 2 / Math.sin(a);
        //c (polar p1 (+ (- (/ pi 2) a) (angle p1 p2)) r)
        let c = polar(p1.clone(), Math.PI / 2 - a + angle(p2.clone().sub(p1)), r);

        this._Radius = Math.abs(r);

        this._StartAngle = angle(p1.sub(c));
        this._EndAngle = angle(p2.sub(c));

        this._Clockwise = bul < 0;
export function polar<T extends Vector2 | Vector3>(v: T, an: number, dis: number): T
{
    v.x += Math.cos(an) * dis;
    v.y += Math.sin(an) * dis;
    return v;
}

export function angle(v: Vector3 | Vector2): number
{
    let angle = Math.atan2(v.y, v.x);
    return angle;
}
jbuckmccready commented 3 years ago

Hmm, I knew about the bulge definition (the library is working with bulges!) but I assumed it was restricted to -1 to 1 to ensure that the line between the points always formed the longest chord of the circular segment.

Right now the code all assumes -1 to 1 bulge values, and that helps simplify certain geometry operations since the longest chord is always the line between the points.

I made an issue to track this specific change: https://github.com/jbuckmccready/cavalier_contours/issues/15

jbuckmccready commented 3 years ago

Closing this issue, issue https://github.com/jbuckmccready/cavalier_contours/issues/15 can be used to track this change.