REVISIT: Help with computing shared face.

Need help, or want to share a macro? Post here!
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
keithsloan52
Veteran
Posts: 2756
Joined: Mon Feb 27, 2012 5:31 pm

Re: Help with computing shared face.

Post by keithsloan52 »

edwilliams16 wrote: Sat Jun 18, 2022 5:58 am

Code: Select all

def shapeGlobal(part):
	placement = part.Placement # in world coords
	if hasattr(part,'LinkedObject'):
		part = part.getLinkedObject()
	gdobjs = [obj for obj in part.OutList if 'GDML' in obj.Name]
	gdobj = gdobjs[0] # only one we assume
	return gdobj.Shape.copy().transformShape(placement.Matrix)

def drawFace(vs):
    wire = Part.makePolygon(vs)
    face = Part.Face(wire)
    return face

doc = App.ActiveDocument
obj = doc.getObject("Detector")
shp1 = shapeGlobal(obj)
obj = doc.getObject("Detector001")
shp2 = shapeGlobal(obj)
v1 = [v.Point for v in shp1.Vertexes]
v2 = [v.Point for v in shp2.Vertexes]
vcommon = [v for v in v1 if any([w.isEqual(v, 1e-7) for w in v2])]
if len(vcommon) ==4:
	Part.show(drawFace(vcommon))
Here's a hack, just comparing vertices.
Okay as you are both recommending checking Vertex the following is my effort

Code: Select all

def printVertexes(i, v1, v2):
    print(f'{i} v1 {v1.X} {v1.Y} {v1.Z} v2 {v2.X} {v2.Y} {v2.Z} {v1.isEqual(v2)}')

def compareVertex(i, v1, v2, tol = 1e-7):
    printVertexes(i, v1, v2)
    #return v1.isEqual(v2, tol)
    return v1.isEqual(v2)

def checkFaces(i, face1, face2):
    for v1 in face1.Vertexes:
        for v2 in face2.Vertexes:
            if compareVertex(i, v1, v2) == False:
               return False
        return True

def commonFace4(shape1, shape2, tol = 1e-7):
    print('CommonFace 4')
    for i, face1 in enumerate(shape1.Faces):
        for face2 in shape2.Faces:
            if checkFaces(i, face1, face2) == True:
               print(f'Common Face {i}')
But all faces print False values

Code: Select all

18:42:02  CommonFace 4
18:42:02  0 v1 -1000.0 -1000.0 1000.0 v2 1000.0 -1000.0 1000.0 False
18:42:02  0 v1 -1000.0 -1000.0 1000.0 v2 3000.0 -1000.0 1000.0 False
18:42:02  0 v1 -1000.0 -1000.0 1000.0 v2 3000.0 -1000.0 -1000.0 False
18:42:02  0 v1 -1000.0 -1000.0 1000.0 v2 3000.0 1000.0 -1000.0 False
18:42:02  0 v1 -1000.0 -1000.0 1000.0 v2 1000.0 1000.0 -1000.0 False
18:42:02  0 v1 -1000.0 -1000.0 1000.0 v2 1000.0 1000.0 1000.0 False
18:42:02  1 v1 1000.0 -1000.0 1000.0 v2 1000.0 -1000.0 1000.0 False
18:42:02  1 v1 1000.0 -1000.0 1000.0 v2 3000.0 -1000.0 1000.0 False
18:42:02  1 v1 1000.0 -1000.0 1000.0 v2 3000.0 -1000.0 -1000.0 False
18:42:02  1 v1 1000.0 -1000.0 1000.0 v2 3000.0 1000.0 -1000.0 False
18:42:02  1 v1 1000.0 -1000.0 1000.0 v2 1000.0 1000.0 -1000.0 False
18:42:02  1 v1 1000.0 -1000.0 1000.0 v2 1000.0 1000.0 1000.0 False
18:42:02  2 v1 1000.0 -1000.0 -1000.0 v2 1000.0 -1000.0 1000.0 False
18:42:02  2 v1 1000.0 -1000.0 -1000.0 v2 3000.0 -1000.0 1000.0 False
18:42:02  2 v1 1000.0 -1000.0 -1000.0 v2 3000.0 -1000.0 -1000.0 False
18:42:02  2 v1 1000.0 -1000.0 -1000.0 v2 3000.0 1000.0 -1000.0 False
18:42:02  2 v1 1000.0 -1000.0 -1000.0 v2 1000.0 1000.0 -1000.0 False
18:42:02  2 v1 1000.0 -1000.0 -1000.0 v2 1000.0 1000.0 1000.0 False
18:42:02  3 v1 1000.0 1000.0 -1000.0 v2 1000.0 -1000.0 1000.0 False
18:42:02  3 v1 1000.0 1000.0 -1000.0 v2 3000.0 -1000.0 1000.0 False
18:42:02  3 v1 1000.0 1000.0 -1000.0 v2 3000.0 -1000.0 -1000.0 False
18:42:02  3 v1 1000.0 1000.0 -1000.0 v2 3000.0 1000.0 -1000.0 False
18:42:02  3 v1 1000.0 1000.0 -1000.0 v2 1000.0 1000.0 -1000.0 False
18:42:02  3 v1 1000.0 1000.0 -1000.0 v2 1000.0 1000.0 1000.0 False
18:42:02  4 v1 -1000.0 1000.0 -1000.0 v2 1000.0 -1000.0 1000.0 False
18:42:02  4 v1 -1000.0 1000.0 -1000.0 v2 3000.0 -1000.0 1000.0 False
18:42:02  4 v1 -1000.0 1000.0 -1000.0 v2 3000.0 -1000.0 -1000.0 False
18:42:02  4 v1 -1000.0 1000.0 -1000.0 v2 3000.0 1000.0 -1000.0 False
18:42:02  4 v1 -1000.0 1000.0 -1000.0 v2 1000.0 1000.0 -1000.0 False
18:42:02  4 v1 -1000.0 1000.0 -1000.0 v2 1000.0 1000.0 1000.0 False
18:42:02  5 v1 -1000.0 1000.0 1000.0 v2 1000.0 -1000.0 1000.0 False
18:42:02  5 v1 -1000.0 1000.0 1000.0 v2 3000.0 -1000.0 1000.0 False
18:42:02  5 v1 -1000.0 1000.0 1000.0 v2 3000.0 -1000.0 -1000.0 False
18:42:02  5 v1 -1000.0 1000.0 1000.0 v2 3000.0 1000.0 -1000.0 False
18:42:02  5 v1 -1000.0 1000.0 1000.0 v2 1000.0 1000.0 -1000.0 False
18:42:02  5 v1 -1000.0 1000.0 1000.0 v2 1000.0 1000.0 1000.0 False
Yet
18:42:02 1 v1 1000.0 -1000.0 1000.0 v2 1000.0 -1000.0 1000.0 False
Surely should have printed
18:42:02 1 v1 1000.0 -1000.0 1000.0 v2 1000.0 -1000.0 1000.0 True

I have a problem if I pass a tolerance to isEqual in compareVertex
edwilliams16
Veteran
Posts: 3108
Joined: Thu Sep 24, 2020 10:31 pm
Location: Hawaii
Contact:

Re: Help with computing shared face.

Post by edwilliams16 »

keithsloan52 wrote: Sat Jun 18, 2022 5:48 pm
I compared the vectors i.e.

Code: Select all

v1.Point.isEqual(v2.Point, 1e-7)
not

Code: Select all

v1.isEqual(v2)
It's at least clear exactly what the former compares.
edwilliams16
Veteran
Posts: 3108
Joined: Thu Sep 24, 2020 10:31 pm
Location: Hawaii
Contact:

Re: Help with computing shared face.

Post by edwilliams16 »

keithsloan52 wrote: Sat Jun 18, 2022 5:48 pm
This also seems to work, but it returns the faces rather than just the coordinates. I had to write a function to return the face belonging to the list of its vertices. I didn't find an existing one.

Code: Select all

def shapeGlobal(part):
	placement = part.Placement # in world coords
	if hasattr(part,'LinkedObject'):
		part = part.getLinkedObject()
	gdobjs = [obj for obj in part.OutList if 'GDML' in obj.Name]
	gdobj = gdobjs[0] # only one we assume
	return gdobj.Shape.copy().transformShape(placement.Matrix)


def isAncestorOfType(obj, sub1, sub2):
	'''is sub2 an ancestor of sub1 in obj?'''
	a = obj.ancestorsOfType(sub1, type(sub2))
	return any(sub2.isEqual(s) for s in a)

def whichFace(obj, vertexList):
	''' which face of obj has all of the vertices in vertexList'''
	for i, face in enumerate(obj.Faces):
		if all([isAncestorOfType(obj, v, face) for v in vertexList]):
			return (face, i)
	return None

doc = App.ActiveDocument
obj = doc.getObject("Detector")
shp1 = shapeGlobal(obj)
obj = doc.getObject("Detector001")
shp2 = shapeGlobal(obj)
v1 = shp1.Vertexes
v2 = shp2.Vertexes
vcommon1 = [v for v in v1 if any([w.Point.isEqual(v.Point, 1e-7) for w in v2])]
vcommon2 = [v for v in v2 if any([w.Point.isEqual(v.Point, 1e-7) for w in v1])]
wf1 = whichFace(shp1, vcommon1)
wf2 = whichFace(shp2, vcommon2)
print(f'shp1 Face{wf1[1]+1} vertices {[v.Point for v in wf1[0].Vertexes]}')
print(f'shp2 Face{wf2[1]+1} vertices {[v.Point for v in wf2[0].Vertexes]}')
keithsloan52
Veteran
Posts: 2756
Joined: Mon Feb 27, 2012 5:31 pm

Re: Help with computing shared face.

Post by keithsloan52 »

edwilliams16 wrote: Sat Jun 18, 2022 7:24 pm
keithsloan52 wrote: Sat Jun 18, 2022 5:48 pm
This also seems to work, but it returns the faces rather than just the coordinates. I had to write a function to return the face belonging to the list of its vertices. I didn't find an existing one.

Code: Select all

def shapeGlobal(part):
	placement = part.Placement # in world coords
	if hasattr(part,'LinkedObject'):
		part = part.getLinkedObject()
	gdobjs = [obj for obj in part.OutList if 'GDML' in obj.Name]
	gdobj = gdobjs[0] # only one we assume
	return gdobj.Shape.copy().transformShape(placement.Matrix)


def isAncestorOfType(obj, sub1, sub2):
	'''is sub2 an ancestor of sub1 in obj?'''
	a = obj.ancestorsOfType(sub1, type(sub2))
	return any(sub2.isEqual(s) for s in a)

def whichFace(obj, vertexList):
	''' which face of obj has all of the vertices in vertexList'''
	for i, face in enumerate(obj.Faces):
		if all([isAncestorOfType(obj, v, face) for v in vertexList]):
			return (face, i)
	return None

doc = App.ActiveDocument
obj = doc.getObject("Detector")
shp1 = shapeGlobal(obj)
obj = doc.getObject("Detector001")
shp2 = shapeGlobal(obj)
v1 = shp1.Vertexes
v2 = shp2.Vertexes
vcommon1 = [v for v in v1 if any([w.Point.isEqual(v.Point, 1e-7) for w in v2])]
vcommon2 = [v for v in v2 if any([w.Point.isEqual(v.Point, 1e-7) for w in v1])]
wf1 = whichFace(shp1, vcommon1)
wf2 = whichFace(shp2, vcommon2)
print(f'shp1 Face{wf1[1]+1} vertices {[v.Point for v in wf1[0].Vertexes]}')
print(f'shp2 Face{wf2[1]+1} vertices {[v.Point for v in wf2[0].Vertexes]}')
Well is not the integer in the print out not the Face number (Of the Face in shape1 where call is commonFace4(shape1, shape2, tol)?
That. is the integer is printed six times each one corresponding to a Face in shape2.

Printing all info I get

Code: Select all

20:46:50  CommonFace 4
20:46:50  0 v1 -1000.0 -1000.0 1000.0 v2 1000.0 -1000.0 1000.0 False
20:46:50  0 v1 -1000.0 -1000.0 1000.0 v2 3000.0 -1000.0 1000.0 False
20:46:50  0 v1 -1000.0 -1000.0 1000.0 v2 3000.0 -1000.0 -1000.0 False
20:46:50  0 v1 -1000.0 -1000.0 1000.0 v2 3000.0 1000.0 -1000.0 False
20:46:50  0 v1 -1000.0 -1000.0 1000.0 v2 1000.0 1000.0 -1000.0 False
20:46:50  0 v1 -1000.0 -1000.0 1000.0 v2 1000.0 1000.0 1000.0 False
20:46:50  1 v1 1000.0 -1000.0 1000.0 v2 1000.0 -1000.0 1000.0 True
20:46:50  1 v1 1000.0 -1000.0 1000.0 v2 1000.0 -1000.0 1000.0 True
20:46:50  1 v1 1000.0 -1000.0 1000.0 v2 1000.0 -1000.0 -1000.0 False
20:46:50  1 v1 1000.0 -1000.0 1000.0 v2 3000.0 -1000.0 1000.0 False
20:46:50  1 v1 1000.0 -1000.0 1000.0 v2 3000.0 -1000.0 -1000.0 False
20:46:50  1 v1 1000.0 -1000.0 1000.0 v2 3000.0 1000.0 -1000.0 False
20:46:50  1 v1 1000.0 -1000.0 1000.0 v2 1000.0 1000.0 -1000.0 False
20:46:50  1 v1 1000.0 -1000.0 1000.0 v2 1000.0 1000.0 1000.0 False
20:46:50  2 v1 1000.0 -1000.0 -1000.0 v2 1000.0 -1000.0 1000.0 False
20:46:50  2 v1 1000.0 -1000.0 -1000.0 v2 3000.0 -1000.0 1000.0 False
20:46:50  2 v1 1000.0 -1000.0 -1000.0 v2 3000.0 -1000.0 -1000.0 False
20:46:50  2 v1 1000.0 -1000.0 -1000.0 v2 3000.0 1000.0 -1000.0 False
20:46:50  2 v1 1000.0 -1000.0 -1000.0 v2 1000.0 1000.0 -1000.0 False
20:46:50  2 v1 1000.0 -1000.0 -1000.0 v2 1000.0 1000.0 1000.0 False
20:46:50  3 v1 1000.0 1000.0 -1000.0 v2 1000.0 -1000.0 1000.0 False
20:46:50  3 v1 1000.0 1000.0 -1000.0 v2 3000.0 -1000.0 1000.0 False
20:46:50  3 v1 1000.0 1000.0 -1000.0 v2 3000.0 -1000.0 -1000.0 False
20:46:50  3 v1 1000.0 1000.0 -1000.0 v2 3000.0 1000.0 -1000.0 False
20:46:50  3 v1 1000.0 1000.0 -1000.0 v2 1000.0 1000.0 -1000.0 True
20:46:50  3 v1 1000.0 1000.0 -1000.0 v2 1000.0 1000.0 -1000.0 True
20:46:50  3 v1 1000.0 1000.0 -1000.0 v2 1000.0 -1000.0 -1000.0 False
20:46:50  3 v1 1000.0 1000.0 -1000.0 v2 1000.0 1000.0 1000.0 False
20:46:50  4 v1 -1000.0 1000.0 -1000.0 v2 1000.0 -1000.0 1000.0 False
20:46:50  4 v1 -1000.0 1000.0 -1000.0 v2 3000.0 -1000.0 1000.0 False
20:46:50  4 v1 -1000.0 1000.0 -1000.0 v2 3000.0 -1000.0 -1000.0 False
20:46:50  4 v1 -1000.0 1000.0 -1000.0 v2 3000.0 1000.0 -1000.0 False
20:46:50  4 v1 -1000.0 1000.0 -1000.0 v2 1000.0 1000.0 -1000.0 False
20:46:50  4 v1 -1000.0 1000.0 -1000.0 v2 1000.0 1000.0 1000.0 False
20:46:50  5 v1 -1000.0 1000.0 1000.0 v2 1000.0 -1000.0 1000.0 False
20:46:50  5 v1 -1000.0 1000.0 1000.0 v2 3000.0 -1000.0 1000.0 False
20:46:50  5 v1 -1000.0 1000.0 1000.0 v2 3000.0 -1000.0 -1000.0 False
20:46:50  5 v1 -1000.0 1000.0 1000.0 v2 3000.0 1000.0 -1000.0 False
20:46:50  5 v1 -1000.0 1000.0 1000.0 v2 1000.0 1000.0 -1000.0 False
20:46:50  5 v1 -1000.0 1000.0 1000.0 v2 1000.0 1000.0 1000.0 False
20:46:51  End processing GDML file
If I only print out where values are True I get

Code: Select all


21:15:18  CommonFace 4
21:15:18  1 v1 1000.0 -1000.0 1000.0 v2 1000.0 -1000.0 1000.0 True
21:15:18  3 v1 1000.0 1000.0 -1000.0 v2 1000.0 1000.0 -1000.0 True
21:15:19  End processing GDML file
That is two faces where as I am only seeing one common Face
keithsloan52
Veteran
Posts: 2756
Joined: Mon Feb 27, 2012 5:31 pm

Re: Help with computing shared face.

Post by keithsloan52 »

edwilliams16 wrote: Sat Jun 18, 2022 7:24 pm
keithsloan52 wrote: Sat Jun 18, 2022 5:48 pm
This also seems to work, but it returns the faces rather than just the coordinates. I had to write a function to return the face belonging to the list of its vertices. I didn't find an existing one.
My latest attempt is

Code: Select all

def printVertexes(i, v1, v2, tol):
    #print(f'{i} v1 {v1.X} {v1.Y} {v1.Z} v2 {v2.X} {v2.Y} {v2.Z} {v1.Point.isEqual(v2.Point, tol)}')
    if v1.Point.isEqual(v2.Point, tol):
       print(f'{i} v1 {v1.X} {v1.Y} {v1.Z} v2 {v2.X} {v2.Y} {v2.Z} {v1.Point.isEqual(v2.Point, tol)}')

def compareVertex(i, v1, v2, tol = 1e-7):
    printVertexes(i, v1, v2, tol)
    return v1.Point.isEqual(v2.Point, tol)

def checkFaces(i, face1, face2):
    for v1 in face1.Vertexes:
        for v2 in face2.Vertexes:
            if compareVertex(i, v1, v2) == False:
               return False
        return True

def commonFace4(shape1, shape2, tol = 1e-7):
    print('CommonFace 4')
    for i, face1 in enumerate(shape1.Faces):
        for face2 in shape2.Faces:
            if checkFaces(i, face1, face2) == True:
               print(f'Common Face {i}')
               
Well is not the integer in the print out not the Face number (Of the Face in shape1 where call is commonFace4(shape1, shape2, tol)?
That. is the integer is printed six times each one corresponding to a Face in shape2.

Not sure why I never see the print('Common Face') message

Printing all info I get
[code]
20:46:50  CommonFace 4
20:46:50  0 v1 -1000.0 -1000.0 1000.0 v2 1000.0 -1000.0 1000.0 False
20:46:50  0 v1 -1000.0 -1000.0 1000.0 v2 3000.0 -1000.0 1000.0 False
20:46:50  0 v1 -1000.0 -1000.0 1000.0 v2 3000.0 -1000.0 -1000.0 False
20:46:50  0 v1 -1000.0 -1000.0 1000.0 v2 3000.0 1000.0 -1000.0 False
20:46:50  0 v1 -1000.0 -1000.0 1000.0 v2 1000.0 1000.0 -1000.0 False
20:46:50  0 v1 -1000.0 -1000.0 1000.0 v2 1000.0 1000.0 1000.0 False
20:46:50  1 v1 1000.0 -1000.0 1000.0 v2 1000.0 -1000.0 1000.0 True
20:46:50  1 v1 1000.0 -1000.0 1000.0 v2 1000.0 -1000.0 1000.0 True
20:46:50  1 v1 1000.0 -1000.0 1000.0 v2 1000.0 -1000.0 -1000.0 False
20:46:50  1 v1 1000.0 -1000.0 1000.0 v2 3000.0 -1000.0 1000.0 False
20:46:50  1 v1 1000.0 -1000.0 1000.0 v2 3000.0 -1000.0 -1000.0 False
20:46:50  1 v1 1000.0 -1000.0 1000.0 v2 3000.0 1000.0 -1000.0 False
20:46:50  1 v1 1000.0 -1000.0 1000.0 v2 1000.0 1000.0 -1000.0 False
20:46:50  1 v1 1000.0 -1000.0 1000.0 v2 1000.0 1000.0 1000.0 False
20:46:50  2 v1 1000.0 -1000.0 -1000.0 v2 1000.0 -1000.0 1000.0 False
20:46:50  2 v1 1000.0 -1000.0 -1000.0 v2 3000.0 -1000.0 1000.0 False
20:46:50  2 v1 1000.0 -1000.0 -1000.0 v2 3000.0 -1000.0 -1000.0 False
20:46:50  2 v1 1000.0 -1000.0 -1000.0 v2 3000.0 1000.0 -1000.0 False
20:46:50  2 v1 1000.0 -1000.0 -1000.0 v2 1000.0 1000.0 -1000.0 False
20:46:50  2 v1 1000.0 -1000.0 -1000.0 v2 1000.0 1000.0 1000.0 False
20:46:50  3 v1 1000.0 1000.0 -1000.0 v2 1000.0 -1000.0 1000.0 False
20:46:50  3 v1 1000.0 1000.0 -1000.0 v2 3000.0 -1000.0 1000.0 False
20:46:50  3 v1 1000.0 1000.0 -1000.0 v2 3000.0 -1000.0 -1000.0 False
20:46:50  3 v1 1000.0 1000.0 -1000.0 v2 3000.0 1000.0 -1000.0 False
20:46:50  3 v1 1000.0 1000.0 -1000.0 v2 1000.0 1000.0 -1000.0 True
20:46:50  3 v1 1000.0 1000.0 -1000.0 v2 1000.0 1000.0 -1000.0 True
20:46:50  3 v1 1000.0 1000.0 -1000.0 v2 1000.0 -1000.0 -1000.0 False
20:46:50  3 v1 1000.0 1000.0 -1000.0 v2 1000.0 1000.0 1000.0 False
20:46:50  4 v1 -1000.0 1000.0 -1000.0 v2 1000.0 -1000.0 1000.0 False
20:46:50  4 v1 -1000.0 1000.0 -1000.0 v2 3000.0 -1000.0 1000.0 False
20:46:50  4 v1 -1000.0 1000.0 -1000.0 v2 3000.0 -1000.0 -1000.0 False
20:46:50  4 v1 -1000.0 1000.0 -1000.0 v2 3000.0 1000.0 -1000.0 False
20:46:50  4 v1 -1000.0 1000.0 -1000.0 v2 1000.0 1000.0 -1000.0 False
20:46:50  4 v1 -1000.0 1000.0 -1000.0 v2 1000.0 1000.0 1000.0 False
20:46:50  5 v1 -1000.0 1000.0 1000.0 v2 1000.0 -1000.0 1000.0 False
20:46:50  5 v1 -1000.0 1000.0 1000.0 v2 3000.0 -1000.0 1000.0 False
20:46:50  5 v1 -1000.0 1000.0 1000.0 v2 3000.0 -1000.0 -1000.0 False
20:46:50  5 v1 -1000.0 1000.0 1000.0 v2 3000.0 1000.0 -1000.0 False
20:46:50  5 v1 -1000.0 1000.0 1000.0 v2 1000.0 1000.0 -1000.0 False
20:46:50  5 v1 -1000.0 1000.0 1000.0 v2 1000.0 1000.0 1000.0 False
20:46:51  End processing GDML file
If I only print out where values are True I get

Code: Select all


21:15:18  CommonFace 4
21:15:18  1 v1 1000.0 -1000.0 1000.0 v2 1000.0 -1000.0 1000.0 True
21:15:18  3 v1 1000.0 1000.0 -1000.0 v2 1000.0 1000.0 -1000.0 True
21:15:19  End processing GDML file
That is two faces where as I am only seeing one common Face
edwilliams16
Veteran
Posts: 3108
Joined: Thu Sep 24, 2020 10:31 pm
Location: Hawaii
Contact:

Re: Help with computing shared face.

Post by edwilliams16 »

keithsloan52 wrote: Sat Jun 18, 2022 8:26 pm

Code: Select all

def checkFaces(i, face1, face2):
    for v1 in face1.Vertexes:
        for v2 in face2.Vertexes:
            if compareVertex(i, v1, v2) == False:
               return False
        return True

I don't see how that can work. face1.Vertexes and face2.Vertexes won't necessarily return the vertices in the same order.

Code: Select all

v1 = shp1.Vertexes
v2 = shp2.Vertexes
vcommon1 = [v for v in v1 if any([w.Point.isEqual(v.Point, 1e-7) for w in v2])]
vcommon2 = [v for v in v2 if any([w.Point.isEqual(v.Point, 1e-7) for w in v1])]
My code above dealt with that issue, finding the vertices that had locations in common with those of the other shape.

EDIT My code does return the correct shared faces and vertex locations:

Code: Select all

shp1 Face2 vertices [Vector (1000.0, -1000.0, 1000.0), Vector (1000.0, -1000.0, -1000.0), Vector (1000.0, 1000.0, 1000.0), Vector (1000.0, 1000.0, -1000.0)]
shp2 Face1 vertices [Vector (1000.0, -1000.0, 1000.0), Vector (1000.0, -1000.0, -1000.0), Vector (1000.0, 1000.0, 1000.0), Vector (1000.0, 1000.0, -1000.0)]
which says Face2 of shp1 matches Face1 of shp2 which can be verified in the status bar, as can the locations of the shared vertices.
realthunder
Veteran
Posts: 2190
Joined: Tue Jan 03, 2017 10:55 am

Re: Help with computing shared face.

Post by realthunder »

Here is my take.

Code: Select all

shape1 = App.ActiveDocument.World.getSubObject('Detector.GDMLBox_det.')
shape2 = App.ActiveDocument.World.getSubObject('Detector001.GDMLBox_det.')
for i, face1 in enumerate(shape1.Faces):
    center1 = face1.BoundBox.Center
    vertices1 = face1.Vertexes
    for j, face2 in enumerate(shape2.Faces):
        center2 = face2.BoundBox.Center
        if center1.distanceToPoint(center2) > 1e-7:
            break
        vertices2 = face2.Vertexes
        if len(vertices1) != len(vertices2):
            continue
        count = 0
        for n, v1 in enumerate(vertices1):
            for v2 in vertices2:
                if v1.Point.distanceToPoint(v2.Point) <= 1e-7:
                    count += 1
                    break
            if count != n+1:
                break
        if count == len(vertices1):
            print(f'found Face{i+1} -> Face{j+1}')
            break
A few points. It's not necessary to call shape.copy() and then transform. This is a deep copy, which is slow and waste of memory for complex shape. And, although not relevant in your particular case here, deep copy nullifies the shape compare APIs of Part.Shape, like isPartner/isEqual/isSame(). Instead, you can do shallow copy like this

Code: Select all

copy = Part.Shape(shape)
copy.Placement = new_placement
Or, like the code I posted above, you can use the getSubObject() API for any objects to get the transformed shape in global coordinate space. Depending on your use case, one way to get various sub-object path to a given object is through its Parents attribute. See example below

Code: Select all

for parent, path in App.ActiveDocument.GDMLBox_det.Parents:
	shape = parent.getSubObject(path)
	print(f'Path: {parent.Name}.{path}')
The other way is to use Gui.Selection. BTW, getSubObject() even works with sub-element. So if you are selecting a face, the 'shape' in the code below will contain the selected face in the global coordinate space.

Code: Select all

# First argument for document name. Empty means current active document. The extra argument 0 to get the full object path
for sel in Gui.Selection.getSelectionEx('', 0):
    for sub in sel.SubElementNames if sel.SubElementNames else ['']:
        # in case you only want whole shape, uncomment the following line
        # sub = '.'.join(sub.split('.')[:-1]) + '.'
        shape = sel.Object.getSubObject(sub)
        print(f'Path: {sel.Object.Name}.{sub}')
Try Assembly3 with my custom build of FreeCAD at here.
And if you'd like to show your support, you can donate through patreon, liberapay, or paypal
edwilliams16
Veteran
Posts: 3108
Joined: Thu Sep 24, 2020 10:31 pm
Location: Hawaii
Contact:

Re: Help with computing shared face.

Post by edwilliams16 »

realthunder wrote: Sun Jun 19, 2022 12:22 am Here is my take.
Thank you. The parent, path material for traversing the document tree with links was very helpful. I hadn't been able to figure it out through my own explorations. Is there more documentation of getSubObject(s) somewhere?
realthunder
Veteran
Posts: 2190
Joined: Tue Jan 03, 2017 10:55 am

Re: Help with computing shared face.

Post by realthunder »

edwilliams16 wrote: Sun Jun 19, 2022 7:13 pm Thank you. The parent, path material for traversing the document tree with links was very helpful. I hadn't been able to figure it out through my own explorations. Is there more documentation of getSubObject(s) somewhere?
You're welcome. Not sure if there is other dedicated documentation for this, but you can always consult the doc string. PS. getSubObject() is a somewhat low level API. In most cases, it's recommended to use Part.getShape() API, which internally calls getSubObject() with extra shape caching and stuff. For example, if the Link has a scale factor, Part.getShape() will cache the scaled shape to make it faster the next time you obtain the shape, while getSubObject() will just perform the scale operation every time it is called. This has noticeable difference for link to a complex object or a group of objects.
Try Assembly3 with my custom build of FreeCAD at here.
And if you'd like to show your support, you can donate through patreon, liberapay, or paypal
keithsloan52
Veteran
Posts: 2756
Joined: Mon Feb 27, 2012 5:31 pm

Re: Help with computing shared face.

Post by keithsloan52 »

I am afraid vertexes does not cut the mustard.

Attached is a GDML file and the FreeCAD file that gets created on import.

Obj is Part (GDML Volume ) that contains a GDMLBox. There are five Volumes Det and 4 linked volumes Det__001 to Det__004 that all contain
the same GDMLTube.

It is possible to have boardersurfaces between Obj and the various volumes because all the GDMLTubes lie on a plane of one side of Obj's GDMLBox, this is what I need to check for. I apologies that compute shared faces is probably not the best definition of the problem.
simpleLarTPC.gdml.txt
(23.12 KiB) Downloaded 24 times
OpticalSurfaces-World.gdml.txt
(1.98 KiB) Downloaded 27 times
BorderSurface.FCStd.txt
(165.01 KiB) Downloaded 25 times
Post Reply