SplitFace-Extrude mystery

As per some other discussions about Push-Pull modeling I was curious, so I prototyped a small script to draw a polyline on a planar polysurface face and then use it to split the face (inside the script). Then I stumbled on an interesting phenomenon I can’t explain.

3SplitFaces.3dm (116.0 KB)

In the file above, on the left is a (pink) cube with 3 split faces - they were split by using the script to draw the polylines on the faces and then split them - 3 separate runs of the script, one for each face.

In the part on the right (turquoise), I used the same polylines to manually split each face using the SplitFace command in Rhino (3 times as well).

They LOOK identical. The What command also gives basically the same info for each, a closed polysurface composed of 9 surfaces.

Now, subobject select, say the two ‘Front’ facing middle surfaces (the parts inside the split) and use ExtrudeSrf with DeleteInput=Yes and extrude them a bit into the cube. On the manual one, the behavior is as expected. On the script created one, the unused splits on the other two faces disappear! It appears that a MergeAllCoPlanarFaces is being called behind the scenes - but only on the script created object.

If, before extruding, I do a ShrinkTrimmedSrfToEdge on the script-created cube, it reports that 3 of the 9 surfaces were shrunk (the inner ones, of course). After that, when extruding one face, the unused splits no longer disappear. However, on the manually created split face cube, Shrink on the whole object also reports 3 surfaces were shrunk… So I still don’t see how they are different.

Can anyone tell me what is different in the geometric definitions of the two cubes that might be causing this?

Not yet, anyway…

-Pascal

Funny, no? there’s gotta be something a bit esoteric about the difference. I do have a hunch what might have caused this, but it would be cool to be able to figure out what’s different between the two by doing some sort of ‘autopsy’ on the two objects.

If you explode the left cube and rejoin before extruding, the inner faces no longer disappear. If you extract and rejoin just one, it no longer disappears but its compatriot still does.

And if you extrude with the gumball the inner faces don’t disappear.

Yes, but why? However, that gets nearer my hypothesis that it’s the edge joins that may be causing the problem.

The scripted split one seems to contain 6 surfaces and nine faces. The manual split one seems to have nine of each. I’d look at whether there is some mismatch in your code between the handling of these two types of object. It looks like your script is splitting the faces but not the surfaces.

HTH
Jeremy

1 Like

It’s not exactly a mismatch, but yes, that looks like it is the problem - good catch. I split the face, which appears to return a valid, brep object with the splits, but it is not the same as actually splitting the brep and then joining the split results.

1 Like

It is possible to make 2 faces reference the same surface.
We don’t do that because as you see it causes confusion later, but the brep definition allows it at a low level.
I looks like that happens with your script.
If I delete all but the front-facing plane of the pink cube and list the remaining brep, I see that the brep has 2 faces and 1 surface and both face(0) and face(1) reference surface(0)
Speculating here, I think the polysurface is duplicated in the process of extruding in to it and the original is deleted, but the duplicate may find two outer trim loops on the same surface and remove one of them or some such validation.
The first thing that would be good to figure out is what initially makes the two faces that share a surface. Splitting a face should duplicate the surface.

Hi @lowell

Here is a super simple example file and some code. Run the code, select the front face of the box, then the single closed curve that is on it. The result is a split face box that has 7 faces but only 6 surfaces.

The code uses BrepFace.Split()…

https://developer.rhino3d.com/api/RhinoCommon/html/M_Rhino_Geometry_BrepFace_Split.htm

I tried this a workaround for not having to deal with the overloads on Brep.Split(); that’s how I ended up here with this topic.

CubeSplitFaceExample.3dm (74 KB)

import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino

def GetOneBrepFace(prompt):
    #if successful, returns base object and face index
    go = Rhino.Input.Custom.GetObject()
    go.SetCommandPrompt(prompt)
    go.EnablePreSelect
    go.GeometryFilter=Rhino.DocObjects.ObjectType.Surface
    go.Get()
    if go.CommandResult()!=Rhino.Commands.Result.Success: return None, None
    objref = go.Object(0)
    if not objref: return None, None
    index=objref.GeometryComponentIndex.Index
    return objref.Object(),index

brep_obj,face_index=GetOneBrepFace("Select the front face of the box")
if brep_obj is not None:
    crv_id=rs.GetObject("Select the curve on the front face",4)
    if crv_id:
        brep=brep_obj.Geometry
        crv=rs.coercecurve(crv_id)
        tol=sc.doc.ModelAbsoluteTolerance
        #split the face
        split_brep=brep.Faces[face_index].Split([crv],tol)
        if split_brep:
            sc.doc.Objects.Replace(brep_obj.Id,split_brep)
            sc.doc.Views.Redraw()
            print "Face count = {}".format(split_brep.Faces.Count)
            print "Surface count = {}".format(split_brep.Surfaces.Count)
1 Like

This gets you the surface object, but you have to go another step to get the surface face, as in this example:

# Surface to orient on
    gs = Rhino.Input.Custom.GetObject()
    gs.SetCommandPrompt("Surface to orient on")
    gs.GeometryFilter = Rhino.DocObjects.ObjectType.Surface
    gs.SubObjectSelect = True
    gs.DeselectAllBeforePostSelect = False
    gs.OneByOnePostSelect = True
    gs.Get()
    if gs.CommandResult()!=Rhino.Commands.Result.Success:
        return gs.CommandResult()

    objref = gs.Object(0)
    # get selected surface object
    obj = objref.Object()
    if not obj: return Rhino.Commands.Result.Failure
    # get selected surface (face)
    surface = objref.Surface()  # <<<<<------------------------------------
    if not surface: return Rhino.Commands.Result.Failure
    # Unselect surface
    obj.Select(False)

BrepFace.Split() should duplicate the surface.
https://mcneel.myjetbrains.com/youtrack/issue/RH-62734

1 Like

BrepFace.Split() should duplicate the surface.

I don’t think this counts for every situation out there. I’ve spend a day trying to figure out why a plugin I am working on fails to work in r7, even though it works fine in r5, and it turns out that this is it.

Firstly, re-using data as much as possible is not a bad thing. Surface duplication can become costly very quickly. Secondly, faces pointing to the same surface can be used to figure out which faces were affected after a split operation. I need this functionality for splitting a brep with a projected, closed curve, and to then find the indexes of all faces which fall within this closed curve.

I think there should be an option to not duplicate the surface.

1 Like