From 9d1cd19afbad5a202967e25baca09d049601b86a Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Wed, 18 Jul 2012 11:27:31 -0300 Subject: [PATCH 1/3] Arch: improved OBJ exporter --- src/Mod/Arch/importOBJ.py | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/Mod/Arch/importOBJ.py b/src/Mod/Arch/importOBJ.py index 4622e1adf..1e2f7373e 100644 --- a/src/Mod/Arch/importOBJ.py +++ b/src/Mod/Arch/importOBJ.py @@ -21,7 +21,7 @@ #* * #*************************************************************************** -import FreeCAD, DraftGeomUtils +import FreeCAD, DraftGeomUtils, Part if open.__module__ == '__builtin__': pythonopen = open @@ -35,20 +35,27 @@ def findVert(aVertex,aList): def getIndices(shape,offset): "returns a list with 2 lists: vertices and face indexes, offsetted with the given amount" vlist = [] + elist = [] flist = [] for v in shape.Vertexes: - vlist.append(" "+str(round(v.X,4))+" "+str(round(v.Z,4))+" "+str(round(v.Y,4))) + vlist.append(" "+str(round(v.X,4))+" "+str(round(v.Y,4))+" "+str(round(v.Z,4))) + if not shape.Faces: + for e in shape.Edges: + if isinstance(e,Part.Line): + ei = " " + str(findVert(e.Vertexes[0],shape.Vertexes)+offset) + ei += " " + str(findVert(e.Vertexes[-1],shape.Vertexes)+offset) + elist.append(ei) for f in shape.Faces: fi = "" # OCC vertices are unsorted. We need to sort in the right order... edges = DraftGeomUtils.sortEdges(f.Wire.Edges) - print edges + #print edges for e in edges: - print e.Vertexes[0].Point,e.Vertexes[1].Point + #print e.Vertexes[0].Point,e.Vertexes[1].Point v = e.Vertexes[0] fi+=" "+str(findVert(v,shape.Vertexes)+offset) flist.append(fi) - return vlist,flist + return vlist,elist,flist def export(exportList,filename): "called when freecad exports a file" @@ -59,13 +66,16 @@ def export(exportList,filename): offset = 1 for obj in exportList: if obj.isDerivedFrom("Part::Feature"): - vlist,flist = getIndices(obj.Shape,offset) - offset += len(vlist) - outfile.write("o " + obj.Name + "\n") - for v in vlist: - outfile.write("v" + v + "\n") - for f in flist: - outfile.write("f" + f + "\n") + if obj.ViewObject.isVisible(): + vlist,elist,flist = getIndices(obj.Shape,offset) + offset += len(vlist) + outfile.write("o " + obj.Name + "\n") + for v in vlist: + outfile.write("v" + v + "\n") + for e in elist: + outfile.write("l" + e + "\n") + for f in flist: + outfile.write("f" + f + "\n") outfile.close() FreeCAD.Console.PrintMessage("successfully written "+filename) From 7b0d0aa2f7c01f37a66e552118cba3873138faad Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Wed, 18 Jul 2012 15:04:56 -0300 Subject: [PATCH 2/3] Arch: Minor fixes --- src/Mod/Arch/InitGui.py | 6 +++-- src/Mod/Arch/importOBJ.py | 44 ++++++++++++++++++++++++------------- src/Mod/Draft/DraftTools.py | 13 ++++++++--- src/Mod/Draft/InitGui.py | 2 +- 4 files changed, 44 insertions(+), 21 deletions(-) diff --git a/src/Mod/Arch/InitGui.py b/src/Mod/Arch/InitGui.py index 523fc2352..69838792c 100644 --- a/src/Mod/Arch/InitGui.py +++ b/src/Mod/Arch/InitGui.py @@ -57,7 +57,7 @@ class ArchWorkbench(Workbench): ToolTip = "Architecture workbench" def Initialize(self): - import DraftTools,DraftGui,Arch_rc,Arch + import DraftTools,DraftGui,Arch_rc,Arch,Draft_rc # arch tools self.archtools = ["Arch_Wall","Arch_Structure", @@ -91,6 +91,8 @@ class ArchWorkbench(Workbench): FreeCADGui.addIconPath(":/icons") FreeCADGui.addLanguagePath(":/translations") FreeCADGui.addPreferencePage(":/ui/archprefs-base.ui","Arch") + FreeCADGui.addPreferencePage(":/ui/userprefs-base.ui","Draft") + FreeCADGui.addPreferencePage(":/ui/userprefs-import.ui","Draft") Log ('Loading Arch module... done\n') def Activated(self): @@ -106,7 +108,7 @@ class ArchWorkbench(Workbench): Msg("Arch workbench deactivated\n") def ContextMenu(self, recipient): - self.appendContextMenu("Display tools",self.draftcontexttools) + self.appendContextMenu("Draft context tools",self.draftcontexttools) def GetClassName(self): return "Gui::PythonWorkbench" diff --git a/src/Mod/Arch/importOBJ.py b/src/Mod/Arch/importOBJ.py index 1e2f7373e..f947afbcd 100644 --- a/src/Mod/Arch/importOBJ.py +++ b/src/Mod/Arch/importOBJ.py @@ -21,7 +21,9 @@ #* * #*************************************************************************** -import FreeCAD, DraftGeomUtils, Part +import FreeCAD, DraftGeomUtils, Part, Draft + +p = Draft.precision() if open.__module__ == '__builtin__': pythonopen = open @@ -29,8 +31,10 @@ if open.__module__ == '__builtin__': def findVert(aVertex,aList): "finds aVertex in aList, returns index" for i in range(len(aList)): - if (aVertex.X == aList[i].X) and (aVertex.Y == aList[i].Y) and (aVertex.Z == aList[i].Z): - return i + if ( round(aVertex.X,p) == round(aList[i].X,p) ): + if ( round(aVertex.Y,p) == round(aList[i].Y,p) ): + if ( round(aVertex.Z,p) == round(aList[i].Z,p) ): + return i def getIndices(shape,offset): "returns a list with 2 lists: vertices and face indexes, offsetted with the given amount" @@ -38,23 +42,33 @@ def getIndices(shape,offset): elist = [] flist = [] for v in shape.Vertexes: - vlist.append(" "+str(round(v.X,4))+" "+str(round(v.Y,4))+" "+str(round(v.Z,4))) + vlist.append(" "+str(round(v.X,p))+" "+str(round(v.Y,p))+" "+str(round(v.Z,p))) if not shape.Faces: for e in shape.Edges: if isinstance(e,Part.Line): - ei = " " + str(findVert(e.Vertexes[0],shape.Vertexes)+offset) - ei += " " + str(findVert(e.Vertexes[-1],shape.Vertexes)+offset) + ei = " " + str(findVert(e.Vertexes[0],shape.Vertexes) + offset) + ei += " " + str(findVert(e.Vertexes[-1],shape.Vertexes) + offset) elist.append(ei) for f in shape.Faces: - fi = "" - # OCC vertices are unsorted. We need to sort in the right order... - edges = DraftGeomUtils.sortEdges(f.Wire.Edges) - #print edges - for e in edges: - #print e.Vertexes[0].Point,e.Vertexes[1].Point - v = e.Vertexes[0] - fi+=" "+str(findVert(v,shape.Vertexes)+offset) - flist.append(fi) + if len(f.Wires) > 1: + # if we have holes, we triangulate + tris = f.tessellate(1) + for fdata in tris[1]: + fi = "" + for vi in fdata: + vdata = Part.Vertex(tris[0][vi]) + fi += " " + str(findVert(vdata,shape.Vertexes) + offset) + flist.append(fi) + else: + fi = "" + # OCC vertices are unsorted. We need to sort in the right order... + edges = DraftGeomUtils.sortEdges(f.Wire.Edges) + #print edges + for e in edges: + #print e.Vertexes[0].Point,e.Vertexes[1].Point + v = e.Vertexes[0] + fi += " " + str(findVert(v,shape.Vertexes) + offset) + flist.append(fi) return vlist,elist,flist def export(exportList,filename): diff --git a/src/Mod/Draft/DraftTools.py b/src/Mod/Draft/DraftTools.py index f8eeca25e..10d1bb382 100644 --- a/src/Mod/Draft/DraftTools.py +++ b/src/Mod/Draft/DraftTools.py @@ -3617,7 +3617,7 @@ class WireToBSpline(Modifier): def finish(self): Modifier.finish(self) - + class SelectGroup(): "The SelectGroup FreeCAD command definition" @@ -3634,7 +3634,14 @@ class SelectGroup(): def Activated(self): sellist = [] - for ob in Draft.getSelection(): + sel = Draft.getSelection() + if len(sel) == 1: + if sel[0].isDerivedFrom("App::DocumentObjectGroup"): + cts = Draft.getGroupContents(FreeCADGui.Selection.getSelection()) + for o in cts: + FreeCADGui.Selection.addSelection(o) + return + for ob in sel: for child in ob.OutList: FreeCADGui.Selection.addSelection(child) for parent in ob.InList: @@ -3642,7 +3649,7 @@ class SelectGroup(): for child in parent.OutList: FreeCADGui.Selection.addSelection(child) - + class Shape2DView(): "The Shape2DView FreeCAD command definition" def GetResources(self): diff --git a/src/Mod/Draft/InitGui.py b/src/Mod/Draft/InitGui.py index b4b83ee35..ea71b0d00 100644 --- a/src/Mod/Draft/InitGui.py +++ b/src/Mod/Draft/InitGui.py @@ -225,7 +225,7 @@ class DraftWorkbench (Workbench): self.appendContextMenu("",self.lineList) else: if (FreeCADGui.Selection.getSelection()): - self.appendContextMenu("Display options",self.treecmdList) + self.appendContextMenu("Draft context tools",self.treecmdList) def GetClassName(self): return "Gui::PythonWorkbench" From 75d9bfc9256ac82aabc57e64384c648c7e78c85e Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Thu, 19 Jul 2012 20:55:25 -0300 Subject: [PATCH 3/3] Arch: added new closeHoles command --- src/Mod/Arch/ArchCommands.py | 52 +++++++++++++++++++++++++++++++++--- src/Mod/Arch/InitGui.py | 3 ++- 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/src/Mod/Arch/ArchCommands.py b/src/Mod/Arch/ArchCommands.py index f98c61c88..6952f4d13 100644 --- a/src/Mod/Arch/ArchCommands.py +++ b/src/Mod/Arch/ArchCommands.py @@ -235,6 +235,33 @@ def makeFace(wires,method=2,cleanup=False): #print "makeFace: final face:",mf.Faces return mf.Faces[0] +def closeHole(shape): + '''closeHole(shape): closes a hole in an open shape''' + import DraftGeomUtils, Part + # creating an edges lookup table + lut = {} + for face in shape.Faces: + for edge in face.Edges: + hc = edge.hashCode() + if lut.has_key(hc): + lut[hc] = lut[hc] + 1 + else: + lut[hc] = 1 + # filter out the edges shared by more than one face + bound = [] + for e in shape.Edges: + if lut[e.hashCode()] == 1: + bound.append(e) + bound = DraftGeomUtils.sortEdges(bound) + try: + nface = Part.Face(Part.Wire(bound)) + shell = Part.makeShell(shape.Faces+[nface]) + solid = Part.Solid(shell) + except: + raise + else: + return solid + def meshToShape(obj,mark=True): '''meshToShape(object,[mark]): turns a mesh into a shape, joining coplanar facets. If mark is True (default), non-solid objects will be marked in red''' @@ -242,10 +269,10 @@ def meshToShape(obj,mark=True): name = obj.Name import Part, MeshPart, DraftGeomUtils if "Mesh" in obj.PropertiesList: - faces = [] + faces = [] mesh = obj.Mesh plac = obj.Placement - segments = mesh.getPlanes(0.001) # use rather strict tolerance here + segments = mesh.getPlanarSegments(0.001) # use rather strict tolerance here print len(segments)," segments ",segments for i in segments: print "treating",segments.index(i),i @@ -262,7 +289,7 @@ def meshToShape(obj,mark=True): se = Part.makeShell(faces) solid = Part.Solid(se) except: - pass + raise else: if solid.isClosed(): FreeCAD.ActiveDocument.removeObject(name) @@ -522,9 +549,28 @@ class _CommandRemoveShape: sel = FreeCADGui.Selection.getSelection() removeShape(sel) +class _CommandCloseHoles: + "the Arch CloseHoles command definition" + def GetResources(self): + return {'MenuText': QtCore.QT_TRANSLATE_NOOP("Arch_CloseHoles","Close holes"), + 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Arch_RemoveShape","Closes holes in open shapes, turning them solids")} + + def IsActive(self): + if FreeCADGui.Selection.getSelection(): + return True + else: + return False + + def Activated(self): + for o in FreeCADGui.Selection.getSelection(): + s = closeHole(o.Shape) + if s: + o.Shape = s + FreeCADGui.addCommand('Arch_Add',_CommandAdd()) FreeCADGui.addCommand('Arch_Remove',_CommandRemove()) FreeCADGui.addCommand('Arch_SplitMesh',_CommandSplitMesh()) FreeCADGui.addCommand('Arch_MeshToShape',_CommandMeshToShape()) FreeCADGui.addCommand('Arch_SelectNonSolidMeshes',_CommandSelectNonSolidMeshes()) FreeCADGui.addCommand('Arch_RemoveShape',_CommandRemoveShape()) +FreeCADGui.addCommand('Arch_CloseHoles',_CommandCloseHoles()) diff --git a/src/Mod/Arch/InitGui.py b/src/Mod/Arch/InitGui.py index 69838792c..bd0feb54e 100644 --- a/src/Mod/Arch/InitGui.py +++ b/src/Mod/Arch/InitGui.py @@ -65,7 +65,8 @@ class ArchWorkbench(Workbench): "Arch_Window","Arch_Roof","Arch_Axis", "Arch_SectionPlane","Arch_Add","Arch_Remove"] self.meshtools = ["Arch_SplitMesh","Arch_MeshToShape", - "Arch_SelectNonSolidMeshes","Arch_RemoveShape"] + "Arch_SelectNonSolidMeshes","Arch_RemoveShape", + "Arch_CloseHoles"] # draft tools self.drafttools = ["Draft_Line","Draft_Wire","Draft_Circle","Draft_Arc",