Converting threejs polyline to rhino polyline

I am using threejs to calculate a line and need to transfer it to an rhino polyline. The rhino3dm part is happening on the server-side using python so i only transfer an list of lists containing the coordinations of the threejs polyline points.

The array looks like this:

[[-8.170003268731694, -7.516203318395631, 7.128385066986084], [-8.174189194318933, -7.444498560839938, 7.128385066986084], [-8.170003268731694, -7.516203318395631, 7.128385066986084], [-8.168835152777545, -7.560442983733425, 7.128385066986084], [-8.194239957641955, -7.128663399369692, 7.128385066986084], [-8.196380591596673, -7.053073035222071, 7.128385066986084], [-8.18506618799719, -7.273520068249176, 7.128385066986084],...]

on the server i use this to convert it to rhino:

model = rhino3dm.File3dm()
rhino_points = rhino3dm.Point3dList(len(outline_points))
for point in outline_points:
    rhino_points.Add(point[0],point[1],point[2])
model.Objects.AddPolyline(rhino_points)

i get a valid polyline but the output is wrong and not like in threejs:

Threejs:


Rhino:

Why could this happen and what could i do to fix this?

No ideas?

Hi @atelierkirchhof ,

Please share the full array of points/data or a rhino/gh file containing the data.

I have an idea but need to test against your shape/array of points/data.

import rhinoscriptsyntax as rs

outline_points = [[-8.170003268731694, -7.516203318395631, 7.128385066986084], [-8.174189194318933, -7.444498560839938, 7.128385066986084], [-8.170003268731694, -7.516203318395631, 7.128385066986084], [-8.168835152777545, -7.560442983733425, 7.128385066986084], [-8.194239957641955, -7.128663399369692, 7.128385066986084], [-8.196380591596673, -7.053073035222071, 7.128385066986084], [-8.18506618799719, -7.273520068249176, 7.128385066986084]]

rhino_points = []

for point in outline_points:
    composed_point = (point[0], point[1], point[2])
    rhino_points.append(composed_point)

rs.AddPolyline(rhino_points)  # Test By Adding Polyline To Rhino Model

Thanks!

Attached the outline_points in data.json and the .3dm with the broken line. Your rhinoscriptsyntax should do the same as my code in backend. Im looking forward to see what you like to try.

Thank you

data.json (303.9 KB)
test2.3dm (9.5 MB)

Here is what I was able to cook up:

Here is the relevant code snippet:

    // create three polyline

    const material = new THREE.LineBasicMaterial( { color: 0x0000ff } )

    const points = [];
    points.push( new THREE.Vector3( - 10, 0, 10 ) )
    points.push( new THREE.Vector3( -5, 0, -10 ) )
    points.push( new THREE.Vector3(  0, 0, 10 ) )
    points.push( new THREE.Vector3(  5, 0, -10 ) )
    points.push( new THREE.Vector3(  10, 0, 10 ) )

    const geometry = new THREE.BufferGeometry().setFromPoints( points )

    const polyline = new THREE.Line( geometry, material )

    scene.add( polyline )

    // convert polyline buffer geo to rhino polyline

    doc = new rhino.File3dm()

    const count = geometry.attributes.position.count
    const rhinoPolyline = new rhino.Polyline()

    for (let i = 0; i < count; i++) {

        const x = geometry.attributes.position.getX(i)
        const y = geometry.attributes.position.getY(i)
        const z = geometry.attributes.position.getZ(i)

        rhinoPolyline.add( x, y, z )

    }

    doc.objects().addPolyline( rhinoPolyline, null )

I do this in js assuming you are making the threejs geometry in the front end. It would be important to know how you are creating the array of points you pass to python.

2 Likes

For whatever reason, the points are not in the right order. I would recommend you go through the buffer geometry of the curve like so:

    const points = []
    const count = geometry.attributes.position.count // your curve's buffer geometry

    for (let i = 0; i < count; i++) {

        const x = geometry.attributes.position.getX(i)
        const y = geometry.attributes.position.getY(i)
        const z = geometry.attributes.position.getZ(i)

        points.push( [ x, y, z ] )

    }

    // send points to your python server

Thank you for your investigation. Sadly this doesn’t work. I get the same output as bevor.

This is my js-code to get the points in threejs. Maybe someone see the error there?

    _meshOutline(real_geometry){
        let a = new Vector3();
        let b = new Vector3();
        let c = new Vector3();
        real_geometry.geometry = BufferGeometryUtils.mergeVertices (real_geometry.geometry);
        var obj = real_geometry;
        const isIndexed = obj.geometry.index !== null;
        const pos = obj.geometry.attributes.position;
        const idx = obj.geometry.index;
        const faceCount = (isIndexed ? idx.count : pos.count) / 3;

        const clippingPlane = this._createIntersectionPlane(obj);

        let positions = [];

        for (let i = 0; i < faceCount; i++) {
          let baseIdx = i * 3;
          let idxA = baseIdx + 0;
          a.fromBufferAttribute(pos, isIndexed ? idx.getX(idxA) : idxA);
          let idxB = baseIdx + 1;
          b.fromBufferAttribute(pos, isIndexed ? idx.getX(idxB) : idxB);
          let idxC = baseIdx + 2;
          c.fromBufferAttribute(pos, isIndexed ? idx.getX(idxC) : idxC);

          obj.localToWorld(a);
          obj.localToWorld(b);
          obj.localToWorld(c);

          var lineAB = new Line3(a, b);
          var lineBC = new Line3(b, c);
          var lineCA = new Line3(c, a);

          this._setPointOfIntersection(lineAB, clippingPlane, positions);
          this._setPointOfIntersection(lineBC, clippingPlane, positions);
          this._setPointOfIntersection(lineCA, clippingPlane, positions);
          }
        //positions.unshift(positions[positions.length -1]);
        const points = [];
        const geometry = new BufferGeometry().setFromPoints( positions );
        const count = geometry.attributes.position.count // your curve's buffer geometry
        for (let i = 0; i < count; i++) {

            const x = geometry.attributes.position.getX(i);
            const y = geometry.attributes.position.getY(i);
            const z = geometry.attributes.position.getZ(i);

            points.push([x, y, z]);

        };
        return points;
    }
    
    _setPointOfIntersection(line, planarSrf, pos) {
        let vec = new Vector3();
       const intersect = planarSrf.intersectLine(line, vec);
       if (vec !== null && !isNaN(vec.x) && vec.x !== 0 && vec.y !== 0) {
         //let vec = intersect.clone();
         //pos.push([vec.x,vec.y,vec.z]);
         pos.push( vec.clone() );
       }
    }
    
    _createIntersectionPlane(obj) {
        var triangle = new Triangle();
        var target = new Vector3();
        const boundingBox = new Box3().setFromObject(obj);
        var testpoint1 = new Vector3(1000,0,boundingBox.max.z);
        var testpoint2 = new Vector3(-1000,0,boundingBox.max.z);
        var testpoint3 = new Vector3(0,1000,boundingBox.max.z);
        var testpoint4 = new Vector3(0,-1000,boundingBox.max.z);
        var z1 = 0;
        var z2 = 0;
        var z3 = 0;
        var z4 = 0;
        var geometry = obj.geometry;
        var index = geometry.index;
        var position = geometry.attributes.position;

        var minDistance1 = Infinity;
        var minDistance2 = Infinity;
        var minDistance3 = Infinity;
        var minDistance4 = Infinity;

        for ( let i = 0, l = index.count; i < l; i += 3 ) {

                var a = index.getX( i );
                var b = index.getX( i + 1 );
                var c = index.getX( i + 2 );

                triangle.a.fromBufferAttribute( position, a );
                triangle.b.fromBufferAttribute( position, b );
                triangle.c.fromBufferAttribute( position, c );

                triangle.closestPointToPoint( testpoint1, target );
                var distanceSq1 = testpoint1.distanceToSquared( target );
                if ( distanceSq1 < minDistance1 ) {
                    z1 = target.z;
                }
                triangle.closestPointToPoint( testpoint2, target );
                var distanceSq2 = testpoint2.distanceToSquared( target );
                if ( distanceSq2 < minDistance2 ) {
                    z2 = target.z;
                }
                triangle.closestPointToPoint( testpoint3, target );
                var distanceSq3 = testpoint3.distanceToSquared( target );
                if ( distanceSq3 < minDistance3 ) {
                    z3 = target.z;
                }
                triangle.closestPointToPoint( testpoint4, target );
                var distanceSq4 = testpoint4.distanceToSquared( target );
                if ( distanceSq4 < minDistance4 ) {
                    z4 = target.z;
                }

        }
        const middle = (z1+z2+z3+z4) /4;
        
        var plane = new Plane( new Vector3( 0, 0, -1 ), 10 );
        plane.set(plane.normal, middle);
        return plane;
    }

this code is just some prove of concept and could me optimized. I just added your code in the “_meshOutline” function. Bevor i just worked with the points in “positions” without loading it to a BufferGemeometry

It is hard to know the consequences of the operations you are preforming prior to structuring the data for your back end server. Looking at the data.json file you posted, it is already in the wrong order. Things like merge vertices could have other consequences as well.