How to trim three curves by each other?

Yep, exactly. The idea was to create a planar surface that’s bigger then the bounding box of the curves, so I get the bb, polyline the corners, then scale it up a bit… Then the idea is to split the surface with all the curves and remove the outermost part. What is left (hopefully) is one or more joinable planar breps, so I join them, merge the faces and then get the outer boundary.

All that because I’m not a math guy and it’s fairly difficult to figure out which curves compose the outer boundary - the script was made assuming that one also might have crossing curves.

I have a half-dozen varieties of this script, and I also tried to work out some that were entirely curve based - but they were not as foolproof.

Of course, the easy way out with just a few lines of code is to get the bb, find the most positive corner (generally index [2]) and add a small increment to it, then select all the curves and script _CurveBoolean as an rs.Command() using the positive point above as a pick point. As that should be fully outside, you will get the outline (assuming coplanar etc.).

Timelines merging? Sci-fi stuff (the good stuff).

1 Like

I was puzzled because, isn’t it easier/faster/simpler to just use the bounding box create a brep.face with it then split the face. Why the scale?

I am also trying to figure out how to create a brep.face by creating a patch from the curves, but that’s insanely confusing. I’ll create another thread because that is a huge topic on its own.

There are may ways to get to the same result. As it’s working off of existing curve geometry I took advantage of using rs.BoundingBox() which gives me the combined bounding box result of all the curves. Otherwise in RhinoCommon, you have to loop through all the curves and get their individual bounding box and union the resulting boxes (look at the underlying code for rs.BoundingBox). As this method outputs corners directly, I used the corners to create a polyline to create a planar surface. I probably could have created a surface from corner points as well.

The scale up is simply to ensure that the surface exceeds the curves in all directions, as it is possible otherwise that some part of one or more of the the curves could lie directly on the bounding box edge, and depending on tolerances, that might create a split failure. Also, it ensures that the entire outer part of the surface is in one piece after splitting with the curves, which makes it easier to detect.

1 Like

It is funny, though, if you want to create a surface from intersecting curves you have to:

  • create bbox of the curves
  • create a planar brep face from the bbox
  • trim the brep face surface with the curves
  • extract (duplicate) the boundary of that surface
  • then use this boundary curve to create a surface out of. In case this is the workflow you expected / wish to use.

@stevebaer, @dale, isn’t it possible to just have a method added to trim and join intersecting curves, without brep involvement?
It has to be with better performance this way, right?

Btw, one of the flaws of the above approach is the increase in number of control points, when trimming the brep-face compared with the original curves.

Well, what you could do in this case is first split all the curves at all intersections. Then, once you have the boundary curve derived from the surface as above, check each one of your split original curve parts start, end and mid points against the boundary curve. If all 3 lie exactly on the boundary curve, keep the split part; if not discard. You should then be left with just the outer boundary segments which you can join, since they have not been re-derived from the surface edges they should not have added control points.

Then we come to this problem:

Not necessarily…

import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino
import Rhino.Geometry.Intersect as RGI


def SplitCrvsAtAllIntersections(crvs,tol):
    #there are probably more efficient ways to do this, but...
    i_pts=[]
    for i in range(0,len(crvs)-1):
        for j in range(i+1,len(crvs)):
            insec=RGI.Intersection.CurveCurve(crvs[i],crvs[j],tol,tol)
            if insec:
                for event in insec:
                    i_pts.append(event.PointA)
                    if event.IsOverlap:
                        i_pts.append(event.PointA2)
    if i_pts: i_pts=Rhino.Geometry.Point3d.CullDuplicates(i_pts,tol)
    split_coll=[]
    for i,crv in enumerate(crvs):
        split_params=[]
        for pt in i_pts:
            rc,t=crv.ClosestPoint(pt,tol)
            if rc:
                split_params.append(t)
        if split_params:
            split_coll.extend(crv.Split(split_params))
    return split_coll


def TestSplitAllCrvs():
    crvIDs=rs.GetObjects("Select intersecting curves to spplit",4,preselect=True)
    if not crvIDs: return
    crvs=[rs.coercecurve(crvID) for crvID in crvIDs]
    split_result=SplitCrvsAtAllIntersections(crvs,sc.doc.ModelAbsoluteTolerance)
    if split_result:
        rs.EnableRedraw(False)
        split_IDs=[sc.doc.Objects.AddCurve(crv) for crv in split_result]
        rs.SelectObjects(split_IDs)
        print "{} curves split into {} pieces".format(len(crvIDs),len(split_IDs))
    else:
        print "No intersections found, nothing split"
TestSplitAllCrvs()

…unless you need to order the curves for another reason… Of course, it may be slow with very large numbers of curves.

1 Like

Performance wise, it is hard to beat scripting the command TestGetPlanarRegions and extracting the outer borders of the resulting selected brep(s). This would give you joined curve segments in proper order and you just have to remove the brep(s). No looping, sorting or trimming required.

_
c.

Hmm, Test*

I remember back in the days when I was using AutoCAD there was a command, you simply click in the area between a net of intersecting lines/curves and you get a region of that area where you clicked. I was looking for this in Rhino.

Question is how to implement this (no scripting) :stuck_out_tongue_winking_eye:

If there’s a method for that, this is exactly what I am looking for. I don’t want to script a command as this is a small piece of what I am trying to develop.

Hi @ivelin.peychev, why not select all curves, start _CurveBoolean and click in the region ?

_
c.

that requires me to select each curve, not clicking inside.

Nevertheless, as I said, I need this as a RhinoCommon method and not as a scripted command. I have no control over the result this way.

If you already know that it does not exist in RhinoCommon, scripting the command is the only way to get the functionality you’re after and this with the least amount of code and best currently possible performance.

Why ? You know when the command succeded and when it created something.

_
c.

I almost have it developed, despite not being a direct RhinoCommon method and the performance is a price I am willing to pay, since it does exactly what I want it to do and gives the output(s) that I want.

This is what I meant with

I may want as output not just the closed curve, I want to disable redraw while the command is running, or debug printing messages during the implementation, I can’t do that when I am scripting a command.

It just requires a bit of imagination, try Rhino.Geometry.Brep.CreateSolid

_
c.

1 Like

I believe I suggested using/scripting CurveBoolean further up in this thread. One point pick (which can also be scripted) somewhere outside the whole figure will get just the outer boundary.

@clement TestGetPlanarRegions is integrated into CurveBoolean as the AllRegions command line option. So no *Test command necessary.

@ivelin.peychev It also appears that if you have Output=Curves in CurveBoolean that it does not re-derive the curves from surface edges, the result has the same control point structure as if the original curves were trimmed to each other.

1 Like

Yes, I see that. I am focused on doing this by code. Without scripting any command.

FWIW there are many parts in Rhino and plug-ins that work through running commands behind the scenes.

It is programming as much as writing other kinds of code.

Unless the scriptable version allows access to at least stop redraw for me it’s not worth doing it this way. Also there’s the issue where you have multiple inputs in the scripted command (e.g. like Squish)

You can always cut the viewport redraw with rs.EnableRedraw(False). What you can’t eliminate (unfortunately) is any command line reporting of the result. So you will see that rolling along on the command line.

These are difficult to deal with certainly, but usually solvable with a combination of selection of pre-named objects, groups and the like.

1 Like