multiCut?
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
Be nice to others! Respect the FreeCAD code of conduct!
multiCut?
I see that @wmayer brought the multFuse function to FreeCAD about a year ago. It's great, especially because of the fuzzy Boolean logic it employs.
Is anyone aware of any specific reason why there's no multiCut analog in the code base?
Is anyone aware of any specific reason why there's no multiCut analog in the code base?
Re: multiCut?
Higreyltc wrote:I see that @wmayer brought the multFuse function to FreeCAD about a year ago. It's great, especially because of the fuzzy Boolean logic it employs.
Is anyone aware of any specific reason why there's no multiCut analog in the code base?
This was discussed a long time ago on these forums. Multi cut is a logical impossibility because "order of operation" effects multi cut but this is not the case with multi fuse. A multi cut tool would have to include some complex method to allow the user to define the order of operations and hence define what they want, otherwise the out come is not defined.
For example Large box - small shoe box - a shoe = what?
1)If you cut the small box from the large box you get a large hollow box, if you then cut the shoe from that ...you still get the same large hollow box
2) if you cut the shoe from the small box first, you get a small box with a shoe shaped hollow in side, if you then cut that from the large box ...you get a similar large hollow box to 1) except there would also be a shoe shape inside the void.
Re: multiCut?
I see your point.jmaustpc wrote:Multi cut is a logical impossibility because "order of operation" effects
I'm not sure the implementation really needs to be so complicated though. I was actually only hoping to find a dead simple approach: the first object in the list of objects passed to multiCut is the "master" and the remaining objects are subtracted from that.
Re: multiCut?
And as I said above even given that, it is still not defined behaviour, in some simple cases it would work but not in others...just think about it, if the cut objects intersect then you have a problem.greyltc wrote:I see your point.jmaustpc wrote:Multi cut is a logical impossibility because "order of operation" effects
I'm not sure the implementation really needs to be so complicated though. I was actually only hoping to find a dead simple approach: the first object in the list of objects passed to multiCut is the "master" and the remaining objects are subtracted from that.
Re: multiCut?
There's nothing ambiguous about the "dead simple" approach. I must not be explaining myself clearly here.
Another try:
A list of at least two objects is passed to multiCut.
The first object is the "master" object.
The remaining objects are "child" objects. These child objects don't interact with each other, they only interact with the master (or what remains of it).
Each child object is subtracted (logical AND NOT) from the master (the order of subtraction is irrelevant).
Whatever is left of the master is returned.
If I pass [largeBox, shoeBox, shoe] to multiCut the answer is always the same as the result largeBox.cut(shoeBox), even though maybe (depending on the order the subtraction was done in) there was an intermediate object where the hollowed out shape was the shape of a shoe.
The answer is actually firstObject.cut(multiFuse([list, of, all, the, other, objects])
Another try:
A list of at least two objects is passed to multiCut.
The first object is the "master" object.
The remaining objects are "child" objects. These child objects don't interact with each other, they only interact with the master (or what remains of it).
Each child object is subtracted (logical AND NOT) from the master (the order of subtraction is irrelevant).
Whatever is left of the master is returned.
If I pass [largeBox, shoeBox, shoe] to multiCut the answer is always the same as the result largeBox.cut(shoeBox), even though maybe (depending on the order the subtraction was done in) there was an intermediate object where the hollowed out shape was the shape of a shoe.
The answer is actually firstObject.cut(multiFuse([list, of, all, the, other, objects])
Re: multiCut?
If that is what you want then simply do that ...as we all do...that is create a Fuse or compound etc. and the do a cut. You could write a macro to do as you said if you want to and if you don't want to do so manually.greyltc wrote:The answer is actually firstObject.cut(multiFuse([list, of, all, the, other, objects])
Your interpretation is only one possible out come. This was explained at great length in repeated posts a year or two ago, if you go find that topic you will get more information. In the end the point is that it is an undefined situation and the idea was rejected by the lead developers for that reason.
Re: multiCut?
There is defnitly some room for Interpretation for a multicut. Greyltec assumes that
Means a-b-c-d which would Work well defined and would be undependend of order of b,c and d. However it could also mean a-(b-(c-d)). So it is imho a question of documenting it right so that the User knows what happens. Version 1 is what occ has recently implemented and where they gain some speed, so we could also implement it. Of course someone would Need to do the work.
Code: Select all
a.multicut (b,c,d)
Re: multiCut?
This can get more complicated when one of the cut operations yields multiple disconnected objects. The multicut algorithm would then need to branch to handle the extra objects that are created in this case
Re: multiCut?
Below is what I've come up with for a multiCut function (in python). Thoughts?
Note: The commented multiFuse() bit I have there at the start is not needed, but it will reduce the number of iterations the while loop needs to complete, in case some of the child objects touch/overlap.
Edit: fixed a bug that would modify inputs
Note: The commented multiFuse() bit I have there at the start is not needed, but it will reduce the number of iterations the while loop needs to complete, in case some of the child objects touch/overlap.
Edit: fixed a bug that would modify inputs
Code: Select all
# multiCut() subtracts a list of childObjects away from a parentObject
# input objects can be faces or solids (don't even think about mixing 'em!)
# childObjects can be a list or one face/solid
# the output will be a list only if it needs to be
def multiCut(parentObject,childObjects,tol=1e-5):
if type(childObjects) is not list:
childObjectsInternal = [childObjects]
else:
childObjectsInternal = list(childObjects)
#if len(childObjectsInternal) > 1: #fuse cutting objects
#childFuse = childObjectsInternal[0].multiFuse(childObjectsInternal[1::],tol).removeSplitter()
#if len(childFuse.Solids) > 0:
#childObjectsInternal = childFuse.Solids
#else:
#childObjectsInternal = childFuse.Faces
cuttingTools = childObjectsInternal # we'll call our child objects cutting tools
workpieces = [parentObject]
while (len(cuttingTools) is not 0): # let's cut away until our tools run out
nPieces = len(workpieces)
for i in range(nPieces):
cutResult = workpieces[i].cut(cuttingTools[0]).removeSplitter()
if len(cutResult.Solids) > 0:
cutResult = cutResult.Solids # there's a solid in our results, so we'll assume to be operating on those
else:
cutResult = cutResult.Faces # no solids, so we must be operating on faces
# let's inspect the result of our cut. there are three options:
if len(cutResult) is 0: # the cut has eliminated the workpiece
workpieces[i] = [] # mark this workpiece for removal
elif len(cutResult) > 1: # the workpiece has been segmented into two or more pieces by the cut
workpieces[i] = [] # mark this workpiece for removal, it was split up
workpieces += cutResult # add the new split pieces to our list of things to be cut
else: # the piece being cut was not split and not consumed by the cut
workpieces[i] = cutResult[0]
# we've finished cutting all the workpieces; throw away the current cutting tool
del cuttingTools[0]
# before we move onto the next cutting tool, delete all the extraneous workpieces
workpieces = [x for x in workpieces if x != []]
if (len(workpieces) is 1):
return workpieces[0]
else:
return workpieces