Geometric same solids
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
Be nice to others! Respect the FreeCAD code of conduct!
-
- Posts: 9
- Joined: Tue Mar 14, 2023 10:26 am
Geometric same solids
Since from my understanding, isSame, isPartner and isEqual are kinda useless to see if this is the case,
what else can I use to filter exactly the same solids ?
Basic example STP in attach.
I dont care where they are, i just want to filter identicals.
If there is no such thing, i can make a custom made filter, but im not sure on what i should compare.
Area + Volume + faces + edges ? Or more ?
Thanks in advance !
what else can I use to filter exactly the same solids ?
Basic example STP in attach.
I dont care where they are, i just want to filter identicals.
If there is no such thing, i can make a custom made filter, but im not sure on what i should compare.
Area + Volume + faces + edges ? Or more ?
Thanks in advance !
- Attachments
-
- TestDubbel.stp
- (13.71 KiB) Downloaded 19 times
Re: Geometric same solids
Probably same should be explained.
Same for Python is an object that has the same "memory position", so it depends:
See maybe if these post that are dealing with the use of isSame.... will help you on some extent:
viewtopic.php?p=586336#p586336
viewtopic.php?p=614776#p614776
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/
-
- Posts: 9
- Joined: Tue Mar 14, 2023 10:26 am
Re: Geometric same solids
Yeah...
That didnt help me really, thanks for the effort anyway.
That didnt help me really, thanks for the effort anyway.
Re: Geometric same solids
Stp file is not a native FreeCAD format, so you must transform it in a FreeCAD solid.HalpPlease wrote: ↑Tue Mar 14, 2023 1:01 pm Yeah...
That didnt help me really, thanks for the effort anyway.
So what you are trying to confront?
you posted only one stp file, so there are nothing to confront with.
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/
-
- Posts: 9
- Joined: Tue Mar 14, 2023 10:26 am
Re: Geometric same solids
Thanks in advance for ur effort.
The plan is to upload a stp file in a webapp, let a python script extract all
the usefull data in it, and make a sort of assembly of it.
Detecting bends, holes, ect...
At the moment I want to filter out the solids that are exactly the same.
The follow up question would be how would i detect if they are the same, but mirrored.
The current python script:
import sys
import FreeCAD
import Part
import Import
import json
class Test:
def __init__(self, shape,ShapeType, valid, area, volume, length, num_faces):
self.shape = shape
self.ShapeType = ShapeType
self.valid = valid
self.area = area
self.volume = volume
self.length = length
self.num_faces = num_faces
self.face_data = []
for face in self.shape.Faces:
#print(dir(face.Placement.Base))
face_dict = {
"valid": face.isValid(),
# "WhatBeInIt": dir(face),
"area": face.Area,
"volume":face.Volume,
# "isSame": face.isSame(),
# "center_of_mass": face.CenterOfMass,
# "normal": face.normalAt(0.5, 0.5),
# "isClosed": face.isClosed, An error occurred: Object of type 'builtin_function_or_method' is not JSON serializable
# "hashCode": face.hashCode, An error occurred: Object of type 'builtin_function_or_method' is not JSON serializable
"lengte": face.Length,
'X': face.Placement.Base.x,
"Y": face.Placement.Base.y,
"Z": face.Placement.Base.z,
"faces": len(face.Faces),
"num_wires": len(face.Wires),
"num_edges": len(face.Edges),
}
self.face_data.append(face_dict)
try:
data = Part.Shape()
# data.read("./assets/test/Weldment02-Staander_Midden.stp")
data.read("./assets/test/TestDubbel.stp")
# Read in the STP file and extract the desired lines of text
# with open("./assets/test/Weldment02-Staander_Midden.stp", "r") as f:
with open("./assets/test/TestDubbel.stp", "r") as f:
stp_text = f.readlines()
# Loop through each line in stp_text
product_lines = []
found_occurrence = False
occurrence_lines = []
for line in stp_text:
if "=NEXT_ASSEMBLY_USAGE_OCCURRENCE('" in line:
found_occurrence = True
occurrence_lines.append(line)
elif found_occurrence:
occurrence_lines.append(line)
if ";" in line:
found_occurrence = False
product_lines.append("".join(occurrence_lines))
occurrence_lines = []
ShapeType = data.ShapeType
valid = data.isValid()
area = data.Area
volume = data.Volume
length = data.Length
# faces = data.Faces
num_faces = len(data.Faces)
num_solids = len(data.Solids)
# Create a Test object with the extracted data
# print(dir(faceCollection), 'what be in it')
test = Test(data,ShapeType, valid, area, volume, length, num_faces)
# Create a list of dictionaries to hold the data for each object
object_list = []
# Append the data for the first object
object_dict = {
"stuknaam": product_lines[-1],
"ShapeType": test.ShapeType,
"valid_stuk": test.valid,
"oppervlakte": test.area,
"volume": test.volume,
"lengte": test.length,
"aantalFaces": test.num_faces,
# "isSame": test.isSame(),
# "faces": faceCollection,
"subparts": num_solids,
"face_data": test.face_data,
}
object_list.append(object_dict)
# Check if there are subparts and extract data from them
if num_solids > 0:
for i, solid in enumerate(data.Solids):
sub_valid = solid.isValid()
sub_ShapeType = solid.ShapeType
sub_area = solid.Area
sub_volume = solid.Volume
sub_length = solid.Length
sub_num_faces = len(solid.Faces)
sub_test = Test(solid,sub_ShapeType, sub_valid, sub_area, sub_volume, sub_length, sub_num_faces)
sub_object_dict = {
"stuknaam": product_lines,
"ShapeType": sub_test.ShapeType,
"valid_stuk": sub_test.valid,
"oppervlakte": sub_test.area,
"volume": sub_test.volume,
"lengte": sub_test.length,
"aantalFaces": sub_test.num_faces,
"subparts": len(sub_test.shape.Solids),
}
object_list.append(sub_object_dict)
print(data.Solids[1].Area == data.Solids[0].Area)
print(data.Solids[1].Volume == data.Solids[0].Volume)
print(dir(data.Solids[1]) == dir(data.Solids[0]))
print(data.Solids[1].Area == data.Solids[0].Area)
# print(data.isPartner(data.Solids[0]))
# Print the list of dictionaries, met json.dumps, anders krijgen we gewoon een vlakke string.
# print(object_list)
print(json.dumps(object_list))
except Exception as e:
print("An error occurred:", e)
sys.exit(1)
The plan is to upload a stp file in a webapp, let a python script extract all
the usefull data in it, and make a sort of assembly of it.
Detecting bends, holes, ect...
At the moment I want to filter out the solids that are exactly the same.
The follow up question would be how would i detect if they are the same, but mirrored.
The current python script:
import sys
import FreeCAD
import Part
import Import
import json
class Test:
def __init__(self, shape,ShapeType, valid, area, volume, length, num_faces):
self.shape = shape
self.ShapeType = ShapeType
self.valid = valid
self.area = area
self.volume = volume
self.length = length
self.num_faces = num_faces
self.face_data = []
for face in self.shape.Faces:
#print(dir(face.Placement.Base))
face_dict = {
"valid": face.isValid(),
# "WhatBeInIt": dir(face),
"area": face.Area,
"volume":face.Volume,
# "isSame": face.isSame(),
# "center_of_mass": face.CenterOfMass,
# "normal": face.normalAt(0.5, 0.5),
# "isClosed": face.isClosed, An error occurred: Object of type 'builtin_function_or_method' is not JSON serializable
# "hashCode": face.hashCode, An error occurred: Object of type 'builtin_function_or_method' is not JSON serializable
"lengte": face.Length,
'X': face.Placement.Base.x,
"Y": face.Placement.Base.y,
"Z": face.Placement.Base.z,
"faces": len(face.Faces),
"num_wires": len(face.Wires),
"num_edges": len(face.Edges),
}
self.face_data.append(face_dict)
try:
data = Part.Shape()
# data.read("./assets/test/Weldment02-Staander_Midden.stp")
data.read("./assets/test/TestDubbel.stp")
# Read in the STP file and extract the desired lines of text
# with open("./assets/test/Weldment02-Staander_Midden.stp", "r") as f:
with open("./assets/test/TestDubbel.stp", "r") as f:
stp_text = f.readlines()
# Loop through each line in stp_text
product_lines = []
found_occurrence = False
occurrence_lines = []
for line in stp_text:
if "=NEXT_ASSEMBLY_USAGE_OCCURRENCE('" in line:
found_occurrence = True
occurrence_lines.append(line)
elif found_occurrence:
occurrence_lines.append(line)
if ";" in line:
found_occurrence = False
product_lines.append("".join(occurrence_lines))
occurrence_lines = []
ShapeType = data.ShapeType
valid = data.isValid()
area = data.Area
volume = data.Volume
length = data.Length
# faces = data.Faces
num_faces = len(data.Faces)
num_solids = len(data.Solids)
# Create a Test object with the extracted data
# print(dir(faceCollection), 'what be in it')
test = Test(data,ShapeType, valid, area, volume, length, num_faces)
# Create a list of dictionaries to hold the data for each object
object_list = []
# Append the data for the first object
object_dict = {
"stuknaam": product_lines[-1],
"ShapeType": test.ShapeType,
"valid_stuk": test.valid,
"oppervlakte": test.area,
"volume": test.volume,
"lengte": test.length,
"aantalFaces": test.num_faces,
# "isSame": test.isSame(),
# "faces": faceCollection,
"subparts": num_solids,
"face_data": test.face_data,
}
object_list.append(object_dict)
# Check if there are subparts and extract data from them
if num_solids > 0:
for i, solid in enumerate(data.Solids):
sub_valid = solid.isValid()
sub_ShapeType = solid.ShapeType
sub_area = solid.Area
sub_volume = solid.Volume
sub_length = solid.Length
sub_num_faces = len(solid.Faces)
sub_test = Test(solid,sub_ShapeType, sub_valid, sub_area, sub_volume, sub_length, sub_num_faces)
sub_object_dict = {
"stuknaam": product_lines,
"ShapeType": sub_test.ShapeType,
"valid_stuk": sub_test.valid,
"oppervlakte": sub_test.area,
"volume": sub_test.volume,
"lengte": sub_test.length,
"aantalFaces": sub_test.num_faces,
"subparts": len(sub_test.shape.Solids),
}
object_list.append(sub_object_dict)
print(data.Solids[1].Area == data.Solids[0].Area)
print(data.Solids[1].Volume == data.Solids[0].Volume)
print(dir(data.Solids[1]) == dir(data.Solids[0]))
print(data.Solids[1].Area == data.Solids[0].Area)
# print(data.isPartner(data.Solids[0]))
# Print the list of dictionaries, met json.dumps, anders krijgen we gewoon een vlakke string.
# print(object_list)
print(json.dumps(object_list))
except Exception as e:
print("An error occurred:", e)
sys.exit(1)
Re: Geometric same solids
Please use the </> when posting code if not is impossible to load it properly in an editor.
Some considerations it will be possible to use FreeCAD in a Webapp but it is out of my knowledge as it involve to use "FreeCAD as a library".
Let's see if some more expert of this sort of things will step in and gave you some useful hints.
Regards
Carlo D.
Some considerations it will be possible to use FreeCAD in a Webapp but it is out of my knowledge as it involve to use "FreeCAD as a library".
Let's see if some more expert of this sort of things will step in and gave you some useful hints.
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: Geometric same solids
Why do you say isPartner is useless? It seems to work for the shapes in your example file.
Code: Select all
doc = App.ActiveDocument
obj1 = doc.getObject("Part__Feature")
obj2 = doc.getObject("Part__Feature001")
obj1.Shape.isPartner(obj2.Shape)
Re: Geometric same solids
My solution to this problem is the function snippet below. Note however that this implementation requires the pose (FreeCAD.Placement) to be identical (or at least very similar) already. I personally use this as a method of validating test outputs against solids in pre-approved reference files.
Also this is obviously very computationally expensive for a comparison.
Also this is obviously very computationally expensive for a comparison.
Code: Select all
def equate_solids_by_volume(
solid_1: Part.Solid | Part.Shape,
solid_2: Part.Solid | Part.Shape,
max_volume_tolerance: float = 0.001,
max_proportional_tolerance: float = 0.05,
proportional: bool = False,
) -> bool:
"""Checks if 2 Solids are approximately equivalent by how their volumes overlap.
NOTE: This requires the placements of the 2 shapes/solids to be equal already, it
does not account for identical shapes in different positions or rotations.
Args:
solid_1 (Part.Solid | Part.Shape): First input Solid to be tested for equality.
solid_2 (Part.Solid | Part.Shape): Second input Solid to be tested for equality.
max_volume_tolerance (float): The maximum volume of the difference between
solids for equality if proportional == False
max_proportional_tolerance (float): The maximum proportional difference in
volume if proportional == True
proportional (bool): if false, volumes are directly checked against
max_volume_tolerance, else they are compared to max_proportional_tolerance
standardized against solid_1.Volume
Returns:
bool: True if the Solids are approximately equivalent by checking the
difference in volume of the fusion and solid_1.
"""
# This is needed to make sure that the inputs are pre-fused together themselves.
# If they aren't, overlapping solids will have their volumes considered separately.
fused_solid_1 = Part.Shape() # type: ignore
for solid in solid_1.Solids:
fused_solid_1 = fused_solid_1.fuse(solid)
fused_solid_2 = Part.Shape() # type: ignore
for solid in solid_2.Solids:
fused_solid_2 = fused_solid_2.fuse(solid)
solid_1 = fused_solid_1
solid_2 = fused_solid_2
# If the difference in volume values is too much, already done - no need to compare
# with fuses.
volume_diff = abs(solid_1.Volume - solid_2.Volume)
if proportional and ((volume_diff / solid_1.Volume) > max_proportional_tolerance):
return False
if not proportional and volume_diff > max_volume_tolerance:
return False
# If not, we need to determine the volume change when they are fused together.
fuse_volume = solid_1.fuse(solid_2).Volume
diff_volume = abs(fuse_volume - solid_1.Volume)
if proportional:
return bool((diff_volume / solid_1.Volume) < max_proportional_tolerance)
return bool(diff_volume < max_volume_tolerance)
-
- Posts: 9
- Joined: Tue Mar 14, 2023 10:26 am
Re: Geometric same solids
Well thanks for the effort anyway.
I found a solution in this form:
I found a solution in this form:
Code: Select all
for i, solid in enumerate(data.Solids):
properties = (round(solid.Area, 2), round(solid.Volume, 2), round(solid.Length, 2), len(solid.Faces), len(solid.Edges))
if properties not in properties_list:
face_collection = []
for face in solid.Faces:
area = face.Area
face_collection.append(area)
max_area = max(face_collection)
count = face_collection.count(max_area)
properties_dict = {
'count': 1,
'valid': solid.isValid(),
'ShapeType': solid.ShapeType,
'area': solid.Area,
'volume': solid.Volume,
'length': solid.Length,
'num_faces': len(solid.Faces),
'num_edges': len(solid.Edges),
'highestFaceArea': max_area,
'highestFaceAreaCount': count
}
properties_list.append(properties)
properties_dict['properties'] = properties
properties_dict['sub_objects'] = []
properties_dict['sub_objects'].append(i)
object_list.append(properties_dict)
else:
index = properties_list.index(properties)
properties_dict = object_list[index+1]
properties_dict['count'] += 1
properties_dict['sub_objects'].append(i)
print(json.dumps(object_list))