diff --git a/src/geouned/GEOUNED/utils/basic_functions_part1.py b/src/geouned/GEOUNED/utils/basic_functions_part1.py index a29e0c6e..596968bc 100644 --- a/src/geouned/GEOUNED/utils/basic_functions_part1.py +++ b/src/geouned/GEOUNED/utils/basic_functions_part1.py @@ -196,3 +196,19 @@ def __str__(self): MajorRadius: {self.MajorRadius} MinorRadius: {self.MinorRadius} """ return outstr + + +class MetaPlanesParams: + def __init__(self, params): + self.PlaneNumber = len(params[0]) + self.Planes = [] + self.Edges = params[1] + self.Vertexes = params[2] + for pm in params[0]: + self.Planes.append(PlaneParams(pm)) + + def __str__(self): + outstr = f"""Metaplane :\n""" + for p in self.Planes: + outstr += f"{p.__str__()} \n" + return outstr diff --git a/src/geouned/GEOUNED/utils/functions.py b/src/geouned/GEOUNED/utils/functions.py index 2fecafaa..ceef4cf0 100644 --- a/src/geouned/GEOUNED/utils/functions.py +++ b/src/geouned/GEOUNED/utils/functions.py @@ -18,12 +18,14 @@ PlaneParams, SphereParams, TorusParams, + MetaPlanesParams, is_parallel, ) from . import basic_functions_part2 as BF from .data_classes import NumericFormat, Options, Tolerances + def get_box(comp, enlargeBox): bb = FreeCAD.BoundBox(comp.BoundBox) bb.enlarge(enlargeBox) @@ -208,6 +210,9 @@ def __init__(self, params, boundBox, Face=None): elif params[0] == "Torus": self.Type = params[0] self.Surf = TorusParams(params[1]) + elif params[0] == "MetaP": + self.Type = params[0] + self.Surf = MetaPlanesParams(params[1]) self.shape = Face @@ -321,18 +326,27 @@ def build_surface(self): torus = Part.makeTorus(majorR, minorR, center, axis) self.shape = torus.Faces[0] return + elif self.type == "MetaP": + planes = self.Surf.Planes + vertexes = self.Surf.Vertexes + metaplanes = makeMetaPlane(planes, vertexes, self.__boundBox__) + self.shape = metaplanes + else: logger.error(f"Type {self.Type} is not defined") return class SurfacesDict(dict): - def __init__(self, surfaces=None, offset: int = 0, + def __init__( + self, + surfaces=None, + offset: int = 0, options: Options = Options(), tolerances: Tolerances = Tolerances(), numeric_format: NumericFormat = NumericFormat(), - ): - + ): + self.IndexOffset = offset self.options = options self.tolerance = tolerances @@ -405,8 +419,6 @@ def extend(self, surface): for s in surface["Tor"]: self.add_torus(s) - - def add_plane(self, plane, fuzzy): ex = FreeCAD.Vector(1, 0, 0) ey = FreeCAD.Vector(0, 1, 0) @@ -626,6 +638,7 @@ def add_metaplane(self, mp, fuzzy=False): else: return index, True + def split_bop(solid, tools, tolerance, options, scale=0.1): if tolerance >= 0.1: diff --git a/src/geouned/GEOUNED/utils/meta_planes.py b/src/geouned/GEOUNED/utils/meta_planes.py index 3e0deba2..51011ed0 100644 --- a/src/geouned/GEOUNED/utils/meta_planes.py +++ b/src/geouned/GEOUNED/utils/meta_planes.py @@ -1,7 +1,11 @@ +import FreeCAD import Part +import numpy +from .geometry_gu import PlaneGu +from .functions import GeounedSurface -def get_metaplanes(solid): +def get_metaplanes(solid, universe_box): planes = [] for f in solid.Faces: if type(f.Surface) is Part.Plane: @@ -19,7 +23,13 @@ def get_metaplanes(solid): meta_loop([p], metap, planes) if len(metap) != 1: if no_convex(metap): - metaplane_list.append(metap) + mp_params = build_metap_params(metap) + mp = GeounedSurface( + ("MetaPlane", mp_params), + universe_box, + Face="Build", + ) + metaplane_list.append(mp) return metaplane_list @@ -117,3 +127,232 @@ def other_face_edge(current_edge, current_face, Faces, outer_only=False): for edge in Edges: if current_edge.isSame(edge): return face + + +def build_metap_params(plane_list): + + planeparams = [] + edges = [] + vertexes = [] + + for p in plane_list: + plane = PlaneGu(p) + planeparams.append((plane.Position, plane.Axis, plane.dim1, plane.dim2)) + + ajdacent_planes = [[] for i in range(len(plane_list))] + for i, p1 in enumerate(plane_list): + for j, p2 in enumerate(plane[i + 1 :]): + e = commonEdge(p1, p2) + if e is not None: + ajdacent_planes[i].append((j, e)) + ajdacent_planes[j].append((i, e)) + + vertex_list = [] + for i, e1 in enumerate(edges): + + for e2 in edges[i + 1 :]: + vertex_list.extend(commonVertex(e1, e2)) + + vertexes = [] + while len(vertex_list) > 0: + v = vertex_list.pop() + n = 0 + for vi in reversed(vertex_list): + if v == vi: + n += 1 + vertex_list.remove(vi) + if n > 0: + vertexes.append((v, n + 1)) + + return (planeparams, edges, vertexes) + + +def commonVertex(e1, e2): + if e1.distToShape(e2) > 0: + return [] + + common = [] + if e1.Vertexes[0] == e2.Vertexes[0]: + common.append(e1.Vertexes[0]) + elif e1.Vertexes[0] == e2.Vertexes[1]: + common.append(e1.Vertexes[0]) + + if e1.Vertexes[1] == e2.Vertexes[0]: + common.append(e1.Vertexes[1]) + elif e1.Vertexes[1] == e2.Vertexes[1]: + common.append(e1.Vertexes[1]) + + return common + + +def commonEdge(face1, face2, outer_only=True): + if face1.distToShape[0] > 0: + return None + + Edges1 = face1.OuterWire.Edges if outer_only else face1.Edges + Edges2 = face2.OuterWire.Edges if outer_only else face2.Edges + for e1 in Edges1: + for e2 in Edges2: + if e1.isSame(e2): + return e1 + return None + + +def makeBoxFaces(box): + if isinstance(box[0], (int, float)): + xmin, ymin, zmin, xmax, ymax, zmax = box + v0 = FreeCAD.Vector(xmin, ymin, zmin) + v1 = FreeCAD.Vector(xmin, ymax, zmin) + v2 = FreeCAD.Vector(xmin, ymax, zmax) + v3 = FreeCAD.Vector(xmin, ymin, zmax) + v4 = FreeCAD.Vector(xmax, ymin, zmin) + v5 = FreeCAD.Vector(xmax, ymax, zmin) + v6 = FreeCAD.Vector(xmax, ymax, zmax) + v7 = FreeCAD.Vector(xmax, ymin, zmax) + face1 = (v0, v1, v2, v3) + face2 = (v7, v6, v5, v4) + face3 = (v0, v3, v7, v4) + face4 = (v5, v6, v2, v1) + face5 = (v4, v5, v1, v0) + face6 = (v6, v7, v3, v2) + + faces_points = (face1, face2, face3, face4, face5, face6) + else: + faces_points = box + + faces = [] + for f in faces_points: + faces.append(Part.Face(Part.makePolygon(f, True))) + return faces + + +def cut_face(face, plane): + line = face.Surface.intersect(plane) + inter = [] + if len(line) > 0: + l = line[0] + for e in face.Edges: + pt = l.intersect(e.Curve) + if len(pt) > 0: + point = pt[0].toShape().Point + if e.isInside(point, 1e-12, True): + inter.append(point) + + newpoints = inter[:] + for v in face.Vertexes: + if v.Point.dot(plane.Axis) > 0: + newpoints.append(v.Point) + if len(newpoints) == 0: + return None, None + else: + sorted = sort_points(newpoints, face.Surface.Axis) + return sorted, inter + + +def cut_box(faces, plane): + updatedfaces = [] + newface_points = [] + for f in faces: + newface, newpoints = cut_face(f, plane) + if newface is None: + continue + updatedfaces.append(newface) + newface_points.extend(newpoints) + + sorted = sort_points(newface_points, plane.Axis) + updatedfaces.append(sorted) + + return updatedfaces + + +def sort_points(point_list, normal): + + if len(point_list) == 0: + return [] + + s = FreeCAD.Vector((0, 0, 0)) + for v in point_list: + s = s + v + s = s / len(point_list) + + vtxvec = [] + for v in point_list: + vtxvec.append(v - s) + + X0 = vtxvec[0] + Y0 = normal.cross(X0) + + orden = [] + for i, v in enumerate(vtxvec): + phi = numpy.arctan2(v.dot(Y0), v.dot(X0)) + orden.append((phi, i)) + orden.sort() + + points = tuple(point_list[p[1]] for p in orden) + return points + + +def remove_box_faces(point_face_list, faces, boxlim): + plane_points = [] + for i, face in enumerate(faces): + if abs(face.Surface.Axis.dot(FreeCAD.Vector(1, 0, 0)) - 1) < 1e-12 and abs(boxlim[0] - face.Surface.Position.X) < 1e-12: + continue + elif ( + abs(face.Surface.Axis.dot(FreeCAD.Vector(-1, 0, 0)) - 1) < 1e-12 + and abs(boxlim[3] - face.Surface.Position.X) < 1e-12 + ): + continue + elif ( + abs(face.Surface.Axis.dot(FreeCAD.Vector(0, 1, 0)) - 1) < 1e-12 and abs(boxlim[1] - face.Surface.Position.Y) < 1e-12 + ): + continue + elif ( + abs(face.Surface.Axis.dot(FreeCAD.Vector(0, -1, 0)) - 1) < 1e-12 + and abs(boxlim[4] - face.Surface.Position.Y) < 1e-12 + ): + continue + elif ( + abs(face.Surface.Axis.dot(FreeCAD.Vector(0, 0, 1)) - 1) < 1e-12 and abs(boxlim[2] - face.Surface.Position.Z) < 1e-12 + ): + continue + elif ( + abs(face.Surface.Axis.dot(FreeCAD.Vector(0, 0, -1)) - 1) < 1e-12 + and abs(boxlim[5] - face.Surface.Position.Z) < 1e-12 + ): + continue + plane_points.append(point_face_list[i]) + + return plane_points + + +def fix_points(point_plane_list, vertex_list): + tol = 1e-8 + for i, current_plane in enumerate(point_plane_list): + for point in current_plane: + for planepts in point_plane_list[i + 1 :]: + for j in range(len(planepts)): + r = point - planepts[j] + if r.Length < tol: + planepts[j] = point + + for v in vertex_list: + for planpts in point_plane_list: + for i in range(len(planpts)): + r = v.Point - planepts[i] + if r.Length < tol: + planpts[i] = v.Point + + +def makeMetaPlanes(plane_list, vertex_list, box): + boxlim = (box.Xmin, box.YMin, box.Zmin, box.XMax, box.YMax, box.ZMax) + cutfaces = makeBoxFaces(boxlim) + for p in plane_list: + plane = Part.Plane(p.Position, p.Axis) + newbox_points = cut_box(cutfaces, plane) + cutfaces = makeBoxFaces(newbox_points) + + plane_points = remove_box_faces(newbox_points, cutfaces, boxlim) + fix_points(plane_points, vertex_list) + metaFaces = Part.Shell(makeBoxFaces(plane_points)) + + return metaFaces