Extrusion functionality in 3dm makes it difficult to include holes

Hello,

I’ve noticed what I think is a strange behaviour in rhino3dm.js. I’ve already found a working solution, but I feel like it’s a bit unintuitive and not very elegant, so I’m posting here to let you know and/or to see if I’m missing something.

I’m trying to create an Extrusion from a geojson polygon. In geojson the first curve is always the boundary and if there are more curves, those are holes.

This was my original attempt at doing this:

type Coordinate = [number, number]

toExtrusion(coordinates: Coordinate[][], referencePoint: Coordinate, height: number) {
    const [first, ...rest] = (await this.toPolylineList(coordinates, referencePoint)).map((p) => p.toNurbsCurve())

    const extrusion = rhino.Extrusion.create(first, height, true)
    if (rest.length === 0) return extrusion

    for (const curve of rest) {
      extrusion.addInnerProfile(curve)
    }
    return extrusion
  }

but when I saved the geometry to a .3dm this is what I ended up with:

After some messing around I figured out that Extrusion.addInnerProfile() uses the local plane of the extrusion rather than the worldXY plane as the reference plane. The plane defaults to the plane spanned by the tangent vector of the curve it’s created from and a 90-degree rotated vector in the same plane.

Anyway, the point is that since there is no create function in 3dmjs that takes a reference plane as an argument, I have to manually transform the holes to be in the same plane as the boundary like this:

toExtrusion(coordinates: Coordinate[][], referencePoint: Coordinate, height: number) {
    const [first, ...rest] = (await this.toPolylineList(coordinates, referencePoint)).map((p) => p.toNurbsCurve())

    const extrusion = rhino.Extrusion.create(first, height, true)
    if (rest.length === 0) return extrusion

   // Here I'm recreating the plane to make a transform for the hole-curve so it gets placed in the right place. 
    let plane = rhino.Plane.worldXY()
    const tangent = first.tangentAt(0)
    plane.xAxis = tangent
    plane.yAxis = this.crossProduct(tangent, [0, 0, 1])
    plane.origin = extrusion.pathStart
    const pathXform = rhino.Transform.planeToPlane(plane, rhino.Plane.worldXY())

    for (const curve of rest) {
      curve.transform(pathXform)
      extrusion.addInnerProfile(curve)
    }
    return extrusion
  }

and I get this result (like the original gejson):

So my question is, would it be possible to include this version of the Create() method that takes in a plane in the next release of 3dm

https://developer.rhino3d.com/api/rhinocommon/rhino.geometry.extrusion/create

or is there something I’m missing here? :slight_smile:

Thanks a lot and sorry for a long post!
Erik

@fraguada

1 Like

Do you get the result you are after with this Create() method? That is, if you use this from RhinoCommon, can you then call extrusion.addInnerProfile(curve) and get the result you want without doing the plane transform?

In any case, I can add this to the list Add Extrusion.Create that takes a plane · Issue #636 · mcneel/rhino3dm · GitHub

Hello Luis,

thanks for your quick reply. I think that’s what I’m doing here in the first example:

..

const extrusion = rhino.Extrusion.create(first, height, true)
 for (const curve of rest) {
      extrusion.addInnerProfile(curve)
    }
..

From what I can see, the method taking in the curve, height and capped? is the only Create function avaliable. Extrusion | rhino3dm

Am I missing something?

Best,
Erik

What I was trying to verify is if the Create method you are requesting to be added to rhino3dm, which already exists in RhinoCommon, actually does what you want it to do, that is, avoid having to transform the inner profile curves.

Hi again Luis,

I’ve tried it in C# inside grasshopper with this code

private void RunScript(Curve x, Curve y, Curve z, ref object a)
    {
        Rhino.Geometry.Extrusion ext = Rhino.Geometry.Extrusion.Create(x, Rhino.Geometry.Plane.WorldXY, 10, true); 
        ext.AddInnerProfile(y); 
        ext.AddInnerProfile(z); 

      a = ext;
    }

and there it works when I use the version that takes in a plane, but it does the same thing when I use the version without the plane (where it uses the plane defined by the curve in the create() method).

Best,
Erik

1 Like

What do you mean “it works”? You mean that you don’t have to transform your inner profiles?

Here you are using the WorldXY, isn’t that the same plane used as a default in the function that does not take a plane argument?

Yes, sorry for being unclear - what I mean is that the hole goes where I expect it to go from where my original curves x and y are placed. When I run this code I get back my original curves:

var componentIndexType = ComponentIndexType.ExtrusionBottomProfile;
Curve outerCurve  = extrusion.Profile3d(new ComponentIndex(componentIndexType, 0));
Curve innerCurve = extrusion.Profile3d(new ComponentIndex(componentIndexType, 1));

The attached file will make it clear.
to and from extrusion.gh (14.6 KB)

Edit: Forgot to internalize

Best,
Erik

1 Like

Thanks. Will look to get this into rhino3dm soon.

Hello again,

I looked into my 3dm code again and I noticed that my z-axis was flipped so the extrusion went in the negative z-direction instead and I haven’t been able to figure out a solution for this. I can’t really figure out how to get the results I’m after with the hole curve in the center in 3dm. Any chance you have an idea of how to solve it? By solve I mean the tranformation that I need to apply to the hole curve to project it to its original position.

Best,
Erik

No, the default plane is the plan of the TryGetPlane() method of the curve used to create the extrusion, that’s what’s confusing. Most of the time the geometries will be in the same projection when you want to make an extrusion so that what I found strange.

Hi again @fraguada,

just wanted to check in on this again. Was it clear what I meant or do you need any more information on this?

Best,
Erik

@erikforsberg95 I have pushed an update to rhino3dm that adds an Extrusion.CreateWithPlane for js and py. This is still unreleased, but you can find a debug version here: https://github.com/mcneel/rhino3dm/actions/runs/12032058486/artifacts/2239130567 (expires in 15 days)

Thanks @fraguada, appreciate it! Will this be included in the next stable rhino3dm release?

Correct. I will release a beta soon that will be available via npm/pypi/nuget

1 Like

Amazing, thanks!

btw, I just released a beta to npm: rhino3dm - npm

npm i rhino3dm@8.15.0-beta