Identifying Intersecting edges of two fused objects
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
Be nice to others! Respect the FreeCAD code of conduct!
Identifying Intersecting edges of two fused objects
Hi Friends,
I don't know if this is a basic thing or not, but after hours of search i cannot find any way to identify the edges of two fused objects like in the picture. My goal is to generate two shapes, then fuse them and then create a Fillet of the edges where the two objects connect each other.
Thanks for your help.
I don't know if this is a basic thing or not, but after hours of search i cannot find any way to identify the edges of two fused objects like in the picture. My goal is to generate two shapes, then fuse them and then create a Fillet of the edges where the two objects connect each other.
Thanks for your help.
-
- Posts: 8
- Joined: Thu Jan 23, 2020 6:49 am
Re: Identifying Intersecting edges of two fused objects
The only way I know is to find some special property of the edges which should get a fillet which distinguishes the from the rest. This can be for example their length, position, curvature or curve type. I'm not aware of a better way, but there may well be one!
In the example you posted one could look at the angle formed between the two faces meeting at each edge. It seems that the edges to get a fillet are the only ones where this angle changes along the length of the edge - for all others it is constant 90 deg. Below is a snippet I used to calculate angle between two faces along a common edge. Perhaps it can be modified for this purpose.
I'm looking for a more general approach to this problem as well.
In the example you posted one could look at the angle formed between the two faces meeting at each edge. It seems that the edges to get a fillet are the only ones where this angle changes along the length of the edge - for all others it is constant 90 deg. Below is a snippet I used to calculate angle between two faces along a common edge. Perhaps it can be modified for this purpose.
I'm looking for a more general approach to this problem as well.
Code: Select all
def max_angle_between_faces(face1, face2, edge):
"""Find maximum angle between face1 and face2 along common edge"""
max_angle = 0.0
points = edge.discretize(Number=10) # edge is discretized into a number of points
for pp in points:
pt = App.Base.Vector(pp.x,pp.y,pp.z)
uv1 = face1.Surface.parameter(pt)
u1 = uv1[0]
v1 = uv1[1]
normal1 = face1.normalAt(u1,v1)
uv2 = face2.Surface.parameter(pt)
u2 = uv2[0]
v2 = uv2[1]
normal2 = face2.normalAt(u2,v2)
angle = math.degrees(normal1.getAngle(normal2))
if angle > max_angle:
max_angle = angle
return max_angle
-
- Posts: 8
- Joined: Thu Jan 23, 2020 6:49 am
Re: Identifying Intersecting edges of two fused objects
Regarding the more genenral approach, I wonder if this could work..? We could loop over edges of the fused shape and look whether each edge is also part of either of the two base shapes. If yes, then it's an old edge and we don't want to apply a fillet. If not, then it's a new edge formed by the fusion. The catch would be how to write such a function for comparing edges. They won't always be identical, it's enough if a part of the edges overlaps. In your example the cylinder cuts one of the cube edges and splits it into two. The compare function would need to recognise that the two new shorter cube edges overlap with the original longer cube edge and thus is not a new entity. I suspect this approach would be rather ugly and would depend on discretisation and tolerances. But it's a thought.
Re: Identifying Intersecting edges of two fused objects
This is probably very closely related to the toponaming, i.e. this may have to be recomputed on other changes as well. The behaviour may change when using realthunders toponaming changes, which still have to be merged.
A Sketcher Lecture with in-depth information is available in English, auf Deutsch, en français, en español.
Re: Identifying Intersecting edges of two fused objects
you can scan the edges and obtain some values to be checked against:
In this case I was in need to determine the edges of the bottom face of a box (body in the code).
I've checked the edges CenterOfMass, roughly the half ot the edge and cheched them againt the max height (VCM[2] < (alt *0.99)) CenterOfMass return a Vector so VCM[2] is the Z component.
Then I've added the edge number, beware that for example a fille like in my case, they start from 1 and not from 0 as idx is starting, plus the data of the two radius (I don't know why are two radius, I suppose for two different axis, maybe XZ or XY)
There are attributes for an edge, this is the output of the Python Console:
['Area', 'BoundBox', 'CenterOfMass', 'Closed', 'CompSolids', 'Compounds', 'Content', 'Curve', 'Degenerated', 'Edges', 'Faces', 'FirstParameter', 'LastParameter', 'Length', 'Mass', 'Matrix', 'MatrixOfInertia', 'MemSize', 'Module', 'Orientation', 'ParameterRange', 'Placement', 'PrincipalProperties', 'ShapeType', 'Shells', 'Solids', 'StaticMoments', 'Tolerance', 'TypeId', 'Vertexes', 'Volume', 'Wires', '__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', 'ancestorsOfType', 'centerOfCurvatureAt', 'check', 'childShapes', 'cleaned', 'common', 'complement', 'copy', 'curvatureAt', 'cut', 'defeaturing', 'derivative1At', 'derivative2At', 'derivative3At', 'discretize', 'distToShape', 'dumpContent', 'dumpToString', 'exportBinary', 'exportBrep', 'exportBrepToString', 'exportIges', 'exportStep', 'exportStl', 'extrude', 'firstVertex', 'fix', 'fixTolerance', 'fuse', 'generalFuse', 'getAllDerivedFrom', 'getElement', 'getFacesFromSubelement', 'getParameterByLength', 'getTolerance', 'globalTolerance', 'hashCode', 'importBinary', 'importBrep', 'importBrepFromString', 'inTolerance', 'isClosed', 'isDerivedFrom', 'isEqual', 'isInside', 'isNull', 'isPartner', 'isSame', 'isSeam', 'isValid', 'lastVertex', 'limitTolerance', 'makeChamfer', 'makeFillet', 'makeOffset2D', 'makeOffsetShape', 'makeParallelProjection', 'makePerspectiveProjection', 'makeShapeFromMesh', 'makeThickness', 'mirror', 'multiFuse', 'normalAt', 'nullify', 'oldFuse', 'optimalBoundingBox', 'overTolerance', 'parameterAt', 'parameters', 'project', 'proximity', 'read', 'reflectLines', 'removeInternalWires', 'removeShape', 'removeSplitter', 'replaceShape', 'restoreContent', 'reverse', 'revolve', 'rotate', 'scale', 'section', 'sewShape', 'slice', 'slices', 'split', 'tangentAt', 'tessellate', 'toNurbs', 'transformGeometry', 'transformShape', 'translate', 'valueAt', 'writeInventor']
How to obtain this?
use this trick:
- create a solid in FreeCAD, say you have created a document named "test" with a Box, named "box", in the python console, type:
suppose you want to analyze the methods exposed by say BounBox:
['Center', 'DiagonalLength', 'XLength', 'XMax', 'XMin', 'YLength', 'YMax', 'YMin', 'ZLength', 'ZMax', 'ZMin', '__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'add', 'closestPoint', 'enlarge', 'getEdge', 'getIntersectionPoint', 'getPoint', 'intersect', 'intersected', 'isCutPlane', 'isInside', 'isValid', 'move', 'scale', 'setVoid', 'transformed', 'united']
and so on.
will print this informations.
Bound box class
A bounding box is an orthographic cube which is a way to describe outer boundaries.
You get a bounding box from a lot of 3D types. It is often used to check if a 3D
entity lies in the range of another object. Checking for bounding interference first
can save a lot of computing time!
Constructor:
App.BoundBox([Xmin,Ymin,Zmin,Xmax,Ymax,Zmax])
App.BoundBox(Tuple, Tuple)
App.BoundBox(Vector, Vector)
App.BoundBox(BoundBox)
Hope it will help
Regards
Carlo D.
Code: Select all
for idx, edge in enumerate(body.Shape.Edges):
VCM = edge.CenterOfMass
#print("edge {0}: {1} ".format(idx, VCM))
if VCM[2] < (alt * 0.99):
fillet_e.append((idx + 1, rag_ext, rag_ext))
I've checked the edges CenterOfMass, roughly the half ot the edge and cheched them againt the max height (VCM[2] < (alt *0.99)) CenterOfMass return a Vector so VCM[2] is the Z component.
Then I've added the edge number, beware that for example a fille like in my case, they start from 1 and not from 0 as idx is starting, plus the data of the two radius (I don't know why are two radius, I suppose for two different axis, maybe XZ or XY)
There are attributes for an edge, this is the output of the Python Console:
['Area', 'BoundBox', 'CenterOfMass', 'Closed', 'CompSolids', 'Compounds', 'Content', 'Curve', 'Degenerated', 'Edges', 'Faces', 'FirstParameter', 'LastParameter', 'Length', 'Mass', 'Matrix', 'MatrixOfInertia', 'MemSize', 'Module', 'Orientation', 'ParameterRange', 'Placement', 'PrincipalProperties', 'ShapeType', 'Shells', 'Solids', 'StaticMoments', 'Tolerance', 'TypeId', 'Vertexes', 'Volume', 'Wires', '__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', 'ancestorsOfType', 'centerOfCurvatureAt', 'check', 'childShapes', 'cleaned', 'common', 'complement', 'copy', 'curvatureAt', 'cut', 'defeaturing', 'derivative1At', 'derivative2At', 'derivative3At', 'discretize', 'distToShape', 'dumpContent', 'dumpToString', 'exportBinary', 'exportBrep', 'exportBrepToString', 'exportIges', 'exportStep', 'exportStl', 'extrude', 'firstVertex', 'fix', 'fixTolerance', 'fuse', 'generalFuse', 'getAllDerivedFrom', 'getElement', 'getFacesFromSubelement', 'getParameterByLength', 'getTolerance', 'globalTolerance', 'hashCode', 'importBinary', 'importBrep', 'importBrepFromString', 'inTolerance', 'isClosed', 'isDerivedFrom', 'isEqual', 'isInside', 'isNull', 'isPartner', 'isSame', 'isSeam', 'isValid', 'lastVertex', 'limitTolerance', 'makeChamfer', 'makeFillet', 'makeOffset2D', 'makeOffsetShape', 'makeParallelProjection', 'makePerspectiveProjection', 'makeShapeFromMesh', 'makeThickness', 'mirror', 'multiFuse', 'normalAt', 'nullify', 'oldFuse', 'optimalBoundingBox', 'overTolerance', 'parameterAt', 'parameters', 'project', 'proximity', 'read', 'reflectLines', 'removeInternalWires', 'removeShape', 'removeSplitter', 'replaceShape', 'restoreContent', 'reverse', 'revolve', 'rotate', 'scale', 'section', 'sewShape', 'slice', 'slices', 'split', 'tangentAt', 'tessellate', 'toNurbs', 'transformGeometry', 'transformShape', 'translate', 'valueAt', 'writeInventor']
How to obtain this?
use this trick:
- create a solid in FreeCAD, say you have created a document named "test" with a Box, named "box", in the python console, type:
Code: Select all
obj = App.getDocument("test").getObject("box")
obj1 =obj.Shape.Edges[0]
dir(obj1)
Code: Select all
dir(obj1.BoundBox)
and so on.
Code: Select all
bb1 = obj1.BounBox
print(bb1.__doc__)
Bound box class
A bounding box is an orthographic cube which is a way to describe outer boundaries.
You get a bounding box from a lot of 3D types. It is often used to check if a 3D
entity lies in the range of another object. Checking for bounding interference first
can save a lot of computing time!
Constructor:
App.BoundBox([Xmin,Ymin,Zmin,Xmax,Ymax,Zmax])
App.BoundBox(Tuple, Tuple)
App.BoundBox(Vector, Vector)
App.BoundBox(BoundBox)
Hope it will help
Regards
Carlo D.
GitHub page: https://github.com/onekk/freecad-doc.
- In deep articles on FreeCAD.
- Learning how to model with scripting.
- Various other stuffs.
Blog: https://okkmkblog.wordpress.com/
- In deep articles on FreeCAD.
- Learning how to model with scripting.
- Various other stuffs.
Blog: https://okkmkblog.wordpress.com/
Re: Identifying Intersecting edges of two fused objects
Hi Friends, thank you for your help. It looks very difficult to do, especially with irregular arbitrary solids. The cube and Cylinder was an oversimplified example.
What i am trying to archive is a general Fuse operation with an additional parameter: fillet radius. The idea is that all edges in the section have a fillet.
What i am trying to archive is a general Fuse operation with an additional parameter: fillet radius. The idea is that all edges in the section have a fillet.
Re: Identifying Intersecting edges of two fused objects
You could check the distance of all edges of the fused object with the distance to each individual edge of original objects. Best to use a midpoint of the edge, because the newly created edge(s) at the cube have also zero distance to the cylinder. Only midpoints which have zero distance to at least 2 original objects are common. This would be a geometrical solution which is slow.
Just an Idea: Maybe it would be also possible to use hashCode() on original and fused object edge vertexes. Only if both vertex hashcodes of an fused object edge are not in the originals vertex hashcode list this edge is a common one. But maybe the vertex hashcodes change over the fuse operation (I do not know). This would be more of a logical solution which is faster than the geometrical one.
Code: Select all
edgelist=fusedobj.Edges
#create the edgemidvertexes by walking edgelist
candidateidx=[]
for vtxnb,midvertex in enumerate(edgemidvertexes):
count=0
for obj in sourceobjects: #should also work with more than 2 objects
d=midvertex.distToShape(obj)[0] #the distance
if d<1e-3:
count=count+1
if count==2:
candidateidx.append(vtxnb) #this has corespondence to edgelist indexes,must be the common edges
break
- microelly2
- Veteran
- Posts: 4688
- Joined: Tue Nov 12, 2013 4:06 pm
- Contact:
Re: Identifying Intersecting edges of two fused objects
To identify a subobject you need a key which is relative unique.
I use for faces this:
The key for edges is still under testing, but it has a simiular structure.
I will post it when my tests are finished.
The results of face analysis you find in this video (its in German) but you can see the topogocigal structure of the faces in a workflow of unions and cuts. The process for edges will be the same. I think I can make the vidoe for edges till weekend.
https://www.youtube.com/watch?v=Dh43wd_3hrA
I use for faces this:
Code: Select all
def pkey2(c,pa,pb,r):
return tuple([c,r]+list(np.round(pa,2))+list(np.round(pb,2)))
def getFaceKey(face):
'''facekey for face type'''
f=face
typ=f.Surface.__class__.__name__
if typ == 'Cone':
pk=pkey2('cone',f.Surface.Apex,f.Surface.Axis,f.Surface.SemiAngle)
k=geokey(f)
elif typ == 'Plane':
pk=pkey2('plane',f.Surface.Position,f.Surface.Axis,0)
elif typ == 'Sphere':
pk=pkey2('sphere',f.Surface.Center,f.Surface.Axis,f.Surface.Radius)
elif typ == 'Cylinder':
pk=pkey2('cyli',f.Surface.Center,f.Surface.Axis,f.Surface.Radius)
else:
raise Exception("unexpected surface type")
return pk
I will post it when my tests are finished.
The results of face analysis you find in this video (its in German) but you can see the topogocigal structure of the faces in a workflow of unions and cuts. The process for edges will be the same. I think I can make the vidoe for edges till weekend.
https://www.youtube.com/watch?v=Dh43wd_3hrA
- microelly2
- Veteran
- Posts: 4688
- Joined: Tue Nov 12, 2013 4:06 pm
- Contact:
Re: Identifying Intersecting edges of two fused objects
Here the example code for edge classification
Code: Select all
def runEdges():
edgesA={}
for i,e in enumerate(FreeCAD.ActiveDocument.Cut.Shape.Edges):
t=e.Curve.__class__.__name__
print (i,t)
k=None
if t =='Circle':
k=np.round((list(e.ParameterRange)+ list( e.Curve.Location) + [e.Curve.Radius] +list(e.Curve.Axis)),2)
if t =='Line':
k=np.round((list(e.ParameterRange)+ list( e.Curve.Location) + [e.Length] +list(e.Curve.Direction)),2)
if t =='Hyperbola':
k=np.round((list(e.ParameterRange)+ list( e.Curve.Location) + [e.Curve.Eccentricity] +list(e.Curve.Axis)),2)
if t =='BSplineCurve':
k=list(np.round((list(e.ParameterRange)+ list( e.Curve.getPoles()[0]) + list(e.Curve.getPoles()[-1])),2))
k += list(np.round(e.MatrixOfInertia.A,2))
#print(k)
assert k is not None
edgesA[tuple(k)]=i
print('\n'*4)
col=[]
col_new=[]
for i,e in enumerate(FreeCAD.ActiveDocument.Cut001.Shape.Edges):
t=e.Curve.__class__.__name__
k=None
if t =='Circle':
k=np.round((list(e.ParameterRange)+ list( e.Curve.Location) + [e.Curve.Radius] +list(e.Curve.Axis)),2)
if t =='Line':
k=np.round((list(e.ParameterRange)+ list( e.Curve.Location) + [e.Length] +list(e.Curve.Direction)),2)
if t =='Hyperbola':
k=np.round((list(e.ParameterRange)+ list( e.Curve.Location) + [e.Curve.Eccentricity] +list(e.Curve.Axis)),2)
if t =='BSplineCurve':
k=list(np.round((list(e.ParameterRange)+ list( e.Curve.getPoles()[0]) + list(e.Curve.getPoles()[-1])),2))
k += list(np.round(e.MatrixOfInertia.A,2))
assert k is not None
try:
ii=edgesA[tuple(k)]
print ("found ", i, ii)
col += [e]
except:
print ("not found")
col_new += [e]
Part.show(Part.Compound(col))
FreeCAD.ActiveDocument.ActiveObject.Label="reused Edges"
FreeCAD.ActiveDocument.ActiveObject.ViewObject.LineColor=(0.,1.,0.)
Part.show(Part.Compound(col_new))
FreeCAD.ActiveDocument.ActiveObject.Label="new or modified Edges"
FreeCAD.ActiveDocument.ActiveObject.ViewObject.LineColor=(1.,0.,0.)
Re: Identifying Intersecting edges of two fused objects
Interesting ideas, I will try to follow them...
Thank you Friends.
Thank you Friends.