diff --git a/__init__.py b/__init__.py index 1ce135f..042347c 100644 --- a/__init__.py +++ b/__init__.py @@ -27,7 +27,7 @@ " 99% completely broken.", "author": "ambi", "location": "3D view > Tools > Edit > Mesh toolbox", - "version": (1, 1, 16), + "version": (1, 1, 17), "blender": (2, 80, 0), "support": "TESTING", "tracker_url": "https://github.com/amb/ambitools/issues", @@ -1497,23 +1497,6 @@ def lap(p): self.payload = _pl -class FloorPlan_OP(mesh_ops.MeshOperatorGenerator): - def generate(self): - self.props["wall_thickness"] = bpy.props.FloatProperty( - name="Wall thickness", default=0.01, min=0.0 - ) - - self.prefix = "floor_plan" - self.info = "Floor Plan" - self.category = "Build" - - def _pl(self, bm, context): - self.report({"INFO"}, "To be done") - pass - - self.payload = _pl - - class ExtendRetopoLoop_OP(mesh_ops.MeshOperatorGenerator): def generate(self): self.props["base_object"] = bpy.props.PointerProperty(name="Target", type=bpy.types.Object) @@ -1677,6 +1660,189 @@ def _pl(self, bm, context): self.payload = _pl +class FloorPlan_OP(mesh_ops.MeshOperatorGenerator): + def generate(self): + self.props["wall_thickness"] = bpy.props.FloatProperty( + name="Wall thickness", default=0.01, min=0.0 + ) + + self.prefix = "floor_plan" + self.info = "Floor Plan" + self.category = "Build" + + def _pl(self, bm, context): + self.report({"INFO"}, "To be done") + pass + + self.payload = _pl + + +class OffsetPolygon_OP(mesh_ops.MeshOperatorGenerator): + def generate(self): + self.props["offset_polygon"] = bpy.props.FloatProperty(name="Offset", default=0.0, min=0.0) + + self.prefix = "offset_polygon" + self.info = "Offset polygon" + self.category = "Build" + + def _pl(self, bm, context): + self.report({"INFO"}, "To be done") + pass + + self.payload = _pl + + +class RemoveBevel_OP(mesh_ops.MeshOperatorGenerator): + def generate(self): + self.props["repetitions"] = bpy.props.IntProperty(name="Repetitions", default=3, min=1) + + self.prefix = "remove_bevel" + self.info = "Remove Bevel" + self.category = "Refine" + self.apply_modifiers = False + self.fastmesh = True + + def _pl(self, mesh, context): + with au.Mode_set("EDIT"), abm.Bmesh_from_edit(mesh) as bm: + selected = [] + for f in bm.faces: + if f.select: + selected.append(f) + for e in f.edges: + if not e.is_manifold: + self.report({"INFO"}, "Face not manifold. Aborting operation.") + return + + # Save original unselected faces + original_faces = set(f for f in bm.faces if f.select == False) + + # Delete all selected faces + bmesh.ops.delete(bm, geom=selected, context="FACES") + + # ASSUMPTION: delete operation leaves corner edges selected + corner_edges = [e for e in bm.edges if e.select] + + extruded_faces = [] + + # Go through each corner edge and extrude to continue the face + for e in corner_edges: + # # Get face normal + # ef = e.link_faces + # if len(ef) != 1: + # continue + # ef = ef[0] + # f_vec = ef.normal + + # Get the 2D extrude directions in 3D plane + ll = e.link_loops[0] + + # Check that the verts match + llne = ll.link_loop_next.edge + llpe = ll.link_loop_prev.edge + assert llne != ll.edge + assert llpe != ll.edge + + lel = ll.edge + evec = (lel.verts[0].co - lel.verts[1].co).normalized() + + nvec = (llne.verts[0].co - llne.verts[1].co).normalized() + pvec = (llpe.verts[0].co - llpe.verts[1].co).normalized() + + # Shared points nvec + if llne.verts[1].co == ll.edge.verts[0].co: + # print("E-10 ", end='') + nvec = (-nvec + evec).normalized() + elif llne.verts[0].co == ll.edge.verts[0].co: + # print("E-00 ", end='') + nvec = (nvec + evec).normalized() + else: + assert False + + # Shared points pvec + if llpe.verts[1].co == ll.edge.verts[1].co: + # print("P-11 ", end='') + pvec = (-pvec - evec).normalized() + elif llpe.verts[0].co == ll.edge.verts[1].co: + # print("P-01 ", end='') + pvec = (pvec - evec).normalized() + else: + assert False + + # Extrude to the direction of xprod of face normal and the edge + ret = bmesh.ops.extrude_edge_only(bm, edges=[e]) + new_edge = [i for i in ret["geom"] if isinstance(i, bmesh.types.BMEdge)][0] + new_face = [i for i in ret["geom"] if isinstance(i, bmesh.types.BMFace)][0] + + # new_face.select = True + extruded_faces.append(new_face) + # e_vec = (e.verts[0].co - e.verts[1].co).normalized() + # trs = e_vec.cross(f_vec) + # bmesh.ops.translate(bm, verts=new_edge.verts, vec=trs) + + new_edge.verts[1].co += pvec + new_edge.verts[0].co += nvec + + # HACK: knife intersect ALL the faces + # for f in extruded_faces[:]: + # for i in extruded_faces[:]: + # i.select = True + # f.select = False + # bpy.ops.mesh.intersect() + + # Remove duplicated faces after intersect process + # bmesh.ops.delete(bm, geom=extruded_faces[:], context='FACES') + + # Remove doubles + bmesh.ops.remove_doubles(bm, verts=bm.verts[:], dist=0.001) + + for f in bm.faces: + f.select = f not in original_faces + + # HACK: Intersect is not perfect, so repeat it, hopefully it will work :s + for _ in range(2): + bpy.ops.mesh.intersect(mode="SELECT", separate_mode="CUT") + with au.Mode_set("EDIT"), abm.Bmesh_from_edit(mesh) as bm: + # Select all faces that have selected edges (grow by edges selection) + es_idx = set(e.index for e in corner_edges) + for f in bm.faces: + for e in f.edges: + if e.index in es_idx: + f.select = True + break + + # Delete all not selected + bmesh.ops.delete( + bm, geom=[f for f in bm.faces if not f.select], context="FACES" + ) + + # Remove doubles + bmesh.ops.remove_doubles(bm, verts=bm.verts[:], dist=0.001) + + # Select all not in original_faces + for f in bm.faces: + f.select = f not in original_faces + + # Remove wires + # orig_edges = set() + # for f in original_faces: + # for e in f.edges: + # orig_edges.add(e) + + remove_edges = [] + for e in bm.edges[:]: + if len(e.link_faces) == 0: + remove_edges.append(e) + bmesh.ops.delete(bm, geom=remove_edges, context='EDGES') + + + + # edge_set = set(corner_edges) + # for f in corner_edges: + # e.select = True + + self.payload = _pl + + # Detect all relevant classes in namespace load_these = [] for name, obj in locals().copy().items():