# Split sphere problem - is there better way?

Hello. I am dealing with unpleasant problem and I would like to ask people for help.

I work on script that makes joints without boolean operations (because of computational time). The outcome consists of cylinders and sphere. The joint looks like this:

I calculate arcs, where cylinder cuts sphere. And the goal is to cut spere to get only residual surface, which is not affected by any cylinder. I was not able to find computationaly fast solution to achieve that.
My approach so far:

• split sphere with curves
• measure distance of each cylinder centroid and all fragments
• get distances equal or larger than cylinder radius
• get rid of all fragments that are located closer than radius

My problem is rounding. Borders of fragments are somehow approximated and I am not able to set the threshold properly, so I sometimes filter out wrong frafments (on both sides). I try to use "similarity"component to get any closer to good result, but sometimes there are little fragments that ruin this approach completely (in uploaded code, itās branch {32}.

I found out that the biggest issue is āstitchā of sphere surface.

So I politely ask for help or some hints that would help me solve this problem. I bet there is a way how to do this better. Would you be so glad to look at my script, please?

splitting spheres problem.gh (74.2 KB)

Hi @PetrVacek,

Not an answer, but I have some observations:
a) I donāt know if I understand your intent here:

I thought you wanted to remove duplicates, but this doesnāt do that. It just takes the first line emanating from each of your vertices resulting in an incomplete set of lines to create the intersections with the spheres.
b) You state that your goal is to produce a result that is computationally quicker than booleaning. Given that you are doing pretty much everything that a boolean has to do, but with the overhead of doing it in Grasshopper, I am not convinced that you can achieve that aim.
c) If you have the skills, you might consider writing a gh component in C#, allowing you to trim each sphere with one cylinder at a time instead of simultaneously - that would prevent the fragmentation of the unwanted surfaces which is causing you problems.

Regards
Jeremy

Just in case this is going to be 3D printed, you donāt necessarily have to bother with the intersections. In order to avoid voids inside the node, Iād create cylinders with holes not going all the way through. You could export the Breps of each node as STL without joining or meshing. Most slicers donāt require joined meshes and simply combine whatās there.

Hereās a video of a similar node in Preform, Formlabs print software:

4 Likes

Hi @jeremy5

a) My intention is to orient sphere axis to one (doesnāt matter which) edge, so the cut always removes a big portion of surface edge. I found out that splitting WorldXY oriented sphere can produce more little fragments that are difficult to remove.

b) It actually is way quicker, because I donāt work with solids but only ruled surfaces and find the intersection mathematically by evaluating domains. Hence the biggest issue is to figure out sphere intersections. I will share time coparsion once the result will be comparable. I even tried mesh booleaning, which was faster than solid booleaning, but it just didnāt work every time and was strongly dependent on meshing settingsā¦actually it was not realiable at all.

c) I was considering that, but my C# is power is not ready yet What I wanted to explore is to cut sphere by planes and always get rid of the fragment that is oriented above the plane. I will definitely look into Rhion dev database.

Hello @martinsiegrist

Thanks for your comment and example. You are right, this will be 3D printed and we already have some promising samples. I know that slicers can handle quite a big mess. What I can do is to move each āholeā not to cut through joint sphere, itās easy. But what is more challenging are cylinders. Hereās why:

1 Like

Ok, got you!

I have been playing around with boolean union a while ago. I attached a definition with a loop, using Anemone components. It creates a union one after another.

20_05_15_boolean_union_loop.gh (25.1 KB)

Sorry, canāt help you on the depth of the holes right now. Not enough time.

2 Likes

Hi @PetrVacek,

This looks like a simpler way to get the spherical segments, without the unwanted bits.

splitting spheres problem_j1.gh (92.5 KB)

Speed seems OK on my laptop (<11 secs), but I donāt know what your target is. I added in a deduping stage for the links but it made no significant difference to the overall solution time.

Regards
Jeremy

1 Like

Try Sasquatch Trim with many planes

4 Likes

Hey @seghierkhaled,

Nice solution - 10 times quicker. Thanks for the intro to Sasquatch, itāll be part of my toolset from now on.

Regards
Jeremy

why not just boolean union everything?

Thank you @jeremy5 and @martinsiegrist for your scripts and advices. I looked into it today. I was hoping for about 500ms to complete this operation, but it seems impossible.
What @seghierkhaled recommended is exactly what I was looking for (and itās a great collection of useful tools, so thanks for sharing!). But I would like to run my script on @shapediver and they just donāt support Sasquatch plugin.
So I tried hard with my limited knowledge of C# and came up with a messy buggy code that does the same, just somehow looses a few fragments somewhere on the way And still it takes double time to compute than Sasquatchā¦

The code:

``````// set data tree for resulting fragments
DataTree<Brep> fragmentsTree = new DataTree<Brep>();

int branchIndex = 0;
double tolerance = 0.01;

// loop for each sphere (one sphere per each node)
foreach (List<Surface> spheres in S.Branches)
{
Surface sphere = spheres[0];

// set list for fragments of each of spheres
List<Brep> fragments = new List<Brep>();
// convert surface to brep
Brep sphereBrep = Brep.CreateFromSurface(sphere);
// add brep to list for first iteration

// now take every plane in each branch and perform splitting process for fragments in the list
foreach (Plane plane in P.Branch(branchIndex))
{

foreach(Brep fragment in fragments)
{
Curve[] intCurve = {};
Point3d[] intPt = {};

// intersect plane and brep to get splitting curve
bool result = Rhino.Geometry.Intersect.Intersection.BrepPlane(fragment, plane, tolerance, out intCurve, out intPt);
if (result) // some planes might not cut any fragment
{

// split fragment with curve
Brep[] split = fragment.Split(intCurve, tolerance);
// set temporary storage for fragments to pass to next iteration
List<Brep> tempFragments = new List<Brep>();

foreach (Brep testedFragment in split)
{
// get bounding box of tested fragment
BoundingBox bBox = testedFragment.GetBoundingBox(plane);
// get center point of that bbox
Point3d center = bBox.Center;
// evaluate if this center exists above or below the plane
if (center.Z < 0)
{
// is the fragment is below the plane, add it to temporary storage
}

// pass all "valid" fragments to the next nested iteration for further splitting
fragments = tempFragments;
}
}
}
}

// add residual portions of sphere to corresponding branch and iterate on next sphere
GH_Path path = new GH_Path(branchIndex);

branchIndex += 1;
}

F = fragmentsTree;
``````

The script: splitting spheres progress.gh (35.9 KB)

With Python you can trim brep with plane , this is a simple code work with single plane cutter.
Maybe someone have a solution to cut tree of breps with tree of planes

``````import rhinoscriptsyntax as rs
import Rhino.Geometry as rg

tol = 0.001

result = rs.TrimBrep(brep,cutter,tol)

result = rg.Brep.Trim(brep,cutter,tol)``````
1 Like

Thanks @seghierkhaled for tips, it is really useful.
I tried to substitute my C# script with Python and itās 0.3 sec faster and has no issues. But still way slower than Sasquatch. I feel that I am pretty close to satisfying result, but what makes the difference is parallel computing. When I turn parallel computing in Sasquatch component off, it has the same computational time that I get with python. Does anybody know how to perform parallel computing on my code, please? How should the function look like? I read several threads, but itās still unclear to me, so simple hint will be appreciatedā¦

``````import rhinoscriptsyntax as rs
import Rhino.Geometry as rg
import ghpythonlib.treehelpers as th

tol = 0.001
fragmentsTree = []

for i in range(S.BranchCount):

sphere = rg.Brep.CreateFromSurface(S.Branch(i)[0])
fragments = []

for plane in P.Branch(i):
newFragments = []
for fragment in fragments:
newFragment = rs.TrimBrep(fragment,plane,tol)

if len(newFragment) != 0:
for f in newFragment:
else:

fragments = newFragments

fragmentsTree.append(fragments)

fragmentsTree = th.list_to_tree(fragmentsTree,source=[])
F = fragmentsTree
``````

1 Like

Check this:

1 Like

Good new and bad new. I finally scripted āTrim Brep With Many Planesā into Python using parallel computing. Itās working perfectly the same time as @sasquatch. Thatās the good new:

The bad new is that my script behaves somehow unstable. I once opened .gh file and component gave me message, that some index is out oof range. Also, this happened when trying to place āpanelā onto canvas:

No idea what it means. So I restarted Rhino & Grasshopper and everything works just fine. Any ideas how to get this more reliable? Is there some problem with memory or? This is way above my knowledge, so any help is appreciated.

GH for testing, if anyone is interestedā¦ TrimBrepWithPlanesParallel.gh (39.0 KB)

The script is:

``````import rhinoscriptsyntax as rs
import Rhino.Geometry as rg
import ghpythonlib.treehelpers as th
import ghpythonlib.parallel as gp

# define function that trim sphere with many places and return list of fragments
def getFragments(index):

i = index
# convert surface to brep
sphere = rg.Brep.CreateFromSurface(S.Branch(i)[0])
# create empty list to store resulting fragments after each iteration
fragments = []
# add first fragment, which, for the first iteration, is actually full sphere

for plane in P.Branch(i):
# new list at the beginning of trimming with each new plane
newFragments = []
# try to trim each fragment by actual trimming plane
for fragment in fragments:
newFragment = rs.TrimBrep(fragment,plane,tol)
# in case that there is intersection, add result of trimming
if len(newFragment) != 0:
for f in newFragment:
else:
# in case that tere is no intersection, add actual fragment
# assing new fragments to the list to trim with next plane
fragments = newFragments

return fragments

# check for inputs
if S.BranchCount != 0 and P.BranchCount != 0:

# tolerance for trimming
tol = 0.001

# create empty list to be filled with fragments
fragmentsTree = []

# create list of indexes that will serve as argument of .parallel method
index = []
for i in range(S.BranchCount):
index.append(i)

# execute trim brep function using multithreading
result = gp.run(getFragments, index, False)
fragmentsTree.append(result)

# convert list to data tree
fragmentsTree = th.list_to_tree(fragmentsTree,source=[])
F = fragmentsTree
else:

# return empty list if no inputs are provided
F = []``````

yes !!
need to find the smallest angle between pipes at node then we can figure out the min distance

i tried to find the min angle but could not find it
if some one could refer that here be so much thankfulā¦

RP

I would avoid using rhinoscriptsyntax inside of any multithreaded code. rhinoscriptsyntax directly works with the document and typically adds geometry to the document. Specifically, I can see that `rs.TrimBrep` is going to be problematic in the above script.