Skip to content

Commit

Permalink
improved decimation alghoritm
Browse files Browse the repository at this point in the history
  • Loading branch information
maxcapodi78 authored and maxcapodi78 committed May 21, 2024
1 parent 4a0b4ac commit 4157b0b
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 36 deletions.
24 changes: 23 additions & 1 deletion pyaedt/modeler/cad/Primitives.py
Original file line number Diff line number Diff line change
Expand Up @@ -4612,6 +4612,11 @@ def import_3d_cad(
separate_disjoints_lumped_object=False,
import_free_surfaces=False,
point_coicidence_tolerance=1e-6,
heal_stl=True,
reduce_stl=False,
reduce_percentage=0,
reduce_error=0,
merge_planar_faces=True,
):
"""Import a CAD model.
Expand Down Expand Up @@ -4643,6 +4648,16 @@ def import_3d_cad(
Either to import free surfaces parts. The default is ``False``.
point_coicidence_tolerance : float, optional
Tolerance on point. Default is ``1e-6``.
heal_stl : bool, optional
Whether to heal the stl file on import or not. Default is ``True``.
reduce_stl : bool, optional
Whether to reduce the stl file on import or not. Default is ``True``.
reduce_percentage : int, optional
Stl reduce percentage. Default is ``0``.
reduce_error : int, optional
Stl error percentage during reduce operation. Default is ``0``.
merge_planar_faces : bool, optional
Stl automatic planar face merge during import. Default is ``True``.
Returns
-------
Expand All @@ -4668,7 +4683,14 @@ def import_3d_cad(
vArg1.append("GroupByAssembly:="), vArg1.append(group_by_assembly)
vArg1.append("CreateGroup:="), vArg1.append(create_group)
vArg1.append("STLFileUnit:="), vArg1.append("Auto")
vArg1.append("MergeFacesAngle:="), vArg1.append(-1)
vArg1.append("MergeFacesAngle:="), vArg1.append(
0.05 if input_file.endswith(".stl") and merge_planar_faces else -1
)
if input_file.endswith(".stl"):
vArg1.append("HealSTL:="), vArg1.append(heal_stl)
vArg1.append("ReduceSTL:="), vArg1.append(reduce_stl)
vArg1.append("ReduceMaxError:="), vArg1.append(reduce_error)
vArg1.append("ReducePercentage:="), vArg1.append(reduce_percentage)
vArg1.append("PointCoincidenceTol:="), vArg1.append(point_coicidence_tolerance)
vArg1.append("CreateLightweightPart:="), vArg1.append(create_lightweigth_part)
vArg1.append("ImportMaterialNames:="), vArg1.append(import_materials)
Expand Down
90 changes: 55 additions & 35 deletions pyaedt/modeler/modeler3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -902,7 +902,7 @@ def import_nastran(
import_as_light_weight : bool, optional
Import the stl generatated as light weight. It works only on SBR+ and HFSS Regions. Default is ``False``.
decimation : float, optional
Fraction of the original mesh to remove. If set to ``0.9``,
Fraction of the original mesh to remove before creating the stl file. If set to ``0.9``,
this function will try to reduce the data set to 10% of its
original size and will remove 90% of the input triangles.
group_parts : bool, optional
Expand All @@ -917,10 +917,10 @@ def import_nastran(
)
self._app.odesktop.EnableAutoSave(False)

def _write_solid_stl(triangle, nas_to_dict):
def _write_solid_stl(triangle, pp):
try:
# points = [nas_to_dict["Points"][id] for id in triangle]
points = [nas_to_dict[id] for id in triangle]
points = [pp[i] for i in triangle]
except KeyError:
return
fc = GeometryOperators.get_polygon_centroid(points)
Expand Down Expand Up @@ -1118,79 +1118,99 @@ def _write_solid_stl(triangle, nas_to_dict):
[nas_to_dict["PointsId"][int(n1)], nas_to_dict["PointsId"][int(n2)]]
]

self.logger.info_timer("File loaded")
self.logger.info("File loaded")
objs_before = [i for i in self.object_names]

if nas_to_dict["Triangles"] or nas_to_dict["Solids"] or nas_to_dict["Lines"]:
self.logger.reset_timer()
self.logger.info("Creating STL file with detected faces")
f = open(os.path.join(self._app.working_directory, self._app.design_name + "_test.stl"), "w")
tria_stl = False
if nas_to_dict["Triangles"]:
f = open(os.path.join(self._app.working_directory, self._app.design_name + "_tria.stl"), "w")
tria_stl = True

def decimate(points_in, faces_in, points_out, faces_out):
if 0 < decimation < 1:
try:
import fast_simplification

aggressivity = 4
if 0.7 > decimation > 0.3:
aggressivity = 6
elif decimation >= 0.7:
aggressivity = 8
points_out, faces_out = fast_simplification.simplify(
points_in, faces_in, decimation, agg=aggressivity
)
self.logger.info("Decimation completed.")
except Exception:
self.logger.error("Package fast-decimation is needed to perform model simplification.")
self.logger.error("Please install it using pip.")
aggressivity = 2
if 0.7 > decimation > 0.3:
aggressivity = 3
elif decimation >= 0.7:
aggressivity = 5
points_out, faces_out = fast_simplification.simplify(
points_in, faces_in, decimation, agg=aggressivity
)

return points_out, faces_out

for tri_id, triangles in nas_to_dict["Triangles"].items():
tri_out = triangles
p_out = nas_to_dict["Points"]
p_out = nas_to_dict["Points"][::]
if decimation > 0:
try:
import fast_simplification

p_out, tri_out = decimate(nas_to_dict["Points"], tri_out, p_out, tri_out)
p_out, tri_out = decimate(nas_to_dict["Points"], tri_out, p_out, tri_out)
except Exception:
self.logger.error("Package fast-decimation is needed to perform model simplification.")
self.logger.error("Please install it using pip.")
f.write("solid Sheet_{}\n".format(tri_id))

for triangle in tri_out:
_write_solid_stl(triangle, p_out)
f.write("endsolid\n")
if nas_to_dict["Triangles"]:
f.close()
solid_stl = False
if nas_to_dict["Solids"]:
solid_stl = True
f = open(os.path.join(self._app.working_directory, self._app.design_name + "_solids.stl"), "w")
for solidid, solid_triangles in nas_to_dict["Solids"].items():
f.write("solid Solid_{}\n".format(solidid))
import pandas as pd

df = pd.Series(solid_triangles)
tri_out = df.drop_duplicates(keep=False).to_list()
p_out = nas_to_dict["Points"]
p_out, tri_out = decimate(nas_to_dict["Points"], tri_out, p_out, tri_out)
p_out = nas_to_dict["Points"][::]
if decimation > 0:
try:
import fast_simplification

p_out, tri_out = decimate(nas_to_dict["Points"], tri_out, p_out, tri_out)
except Exception:
self.logger.error("Package fast-decimation is needed to perform model simplification.")
self.logger.error("Please install it using pip.")
for triangle in tri_out:
_write_solid_stl(triangle, p_out)
f.write("endsolid\n")
f.close()
self.logger.info_timer("STL file created")
self.logger.info("STL file created")
self._app.odesktop.CloseAllWindows()
self.logger.reset_timer()
self.logger.info("Importing STL in 3D Modeler")
self.import_3d_cad(
os.path.join(self._app.working_directory, self._app.design_name + "_test.stl"),
create_lightweigth_part=import_as_light_weight,
)
if tria_stl:
self.import_3d_cad(
os.path.join(self._app.working_directory, self._app.design_name + "_tria.stl"),
create_lightweigth_part=import_as_light_weight,
healing=False,
)
if solid_stl:
self.import_3d_cad(
os.path.join(self._app.working_directory, self._app.design_name + "_solids.stl"),
create_lightweigth_part=import_as_light_weight,
healing=False,
)
self.logger.info("Model imported")

if group_parts:
self.logger.reset_timer()
for el in nas_to_dict["Solids"].keys():
obj_names = [i for i in self.object_names if i.startswith("Solid_{}".format(el))]
self.create_group(obj_names, group_name=str(el))
objs = self.object_names[::]
for el in nas_to_dict["Triangles"].keys():
obj_names = [i for i in objs if i == "Sheet_{}".format(el) or i.startswith("Sheet_{}_".format(el))]
self.create_group(obj_names, group_name=str(el))
self.logger.info_timer("Parts grouped")
self.logger.info("Parts grouped")

if import_lines and nas_to_dict["Lines"]:
self.logger.reset_timer()
for line_name, lines in nas_to_dict["Lines"].items():
if lines_thickness:
self._app["x_section_{}".format(line_name)] = lines_thickness
Expand Down Expand Up @@ -1219,13 +1239,13 @@ def decimate(points_in, faces_in, points_out, faces_out):
out_poly = self.unite(polys, purge=not lines_thickness)
if not lines_thickness and out_poly:
self.generate_object_history(out_poly)
self.logger.info_timer("Lines imported")
self.logger.info("Lines imported")

objs_after = [i for i in self.object_names]
new_objects = [self[i] for i in objs_after if i not in objs_before]
self._app.oproject.SetActiveDesign(self._app.design_name)
self._app.odesktop.EnableAutoSave(autosave)

self.logger.info_timer("Nastran model correctly imported.")
return new_objects

@pyaedt_function_handler()
Expand Down

0 comments on commit 4157b0b

Please sign in to comment.