Arch/Commands.py

Go to the documentation of this file.
00001 #***************************************************************************
00002 #*                                                                         *
00003 #*   Copyright (c) 2011                                                    *  
00004 #*   Yorik van Havre <yorik@uncreated.net>                                 *  
00005 #*                                                                         *
00006 #*   This program is free software; you can redistribute it and/or modify  *
00007 #*   it under the terms of the GNU General Public License (GPL)            *
00008 #*   as published by the Free Software Foundation; either version 2 of     *
00009 #*   the License, or (at your option) any later version.                   *
00010 #*   for detail see the LICENCE text file.                                 *
00011 #*                                                                         *
00012 #*   This program is distributed in the hope that it will be useful,       *
00013 #*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00014 #*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00015 #*   GNU Library General Public License for more details.                  *
00016 #*                                                                         *
00017 #*   You should have received a copy of the GNU Library General Public     *
00018 #*   License along with this program; if not, write to the Free Software   *
00019 #*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
00020 #*   USA                                                                   *
00021 #*                                                                         *
00022 #***************************************************************************
00023 
00024 import FreeCAD,FreeCADGui,Part,Draft,MeshPart,Component
00025 from draftlibs import fcgeo,fcvec
00026 from FreeCAD import Vector
00027 from PyQt4 import QtCore
00028 
00029 __title__="FreeCAD Arch Commands"
00030 __author__ = "Yorik van Havre"
00031 __url__ = "http://free-cad.sourceforge.net"
00032 
00033 # module functions ###############################################
00034 
00035 def addComponents(objectsList,host):
00036     '''addComponents(objectsList,hostObject): adds the given object or the objects
00037     from the given list as components to the given host Object. Use this for
00038     example to add windows to a wall, or to add walls to a cell or floor.'''
00039     if not isinstance(objectsList,list):
00040         objectsList = [objectsList]
00041     tp = Draft.getType(host)
00042     if tp in ["Cell","Floor","Building","Site"]:
00043         c = host.Components
00044         for o in objectsList:
00045             if not o in c:
00046                 c.append(o)
00047         host.Components = c
00048     elif tp in ["Wall","Structure"]:
00049         a = host.Additions
00050         for o in objectsList:
00051             if not o in a:
00052                 if hasattr(o,"Shape"):
00053                     a.append(o)
00054         host.Additions = a
00055     elif tp in ["SectionPlane"]:
00056         a = host.Objects
00057         for o in objectsList:
00058             if not o in a:
00059                 if hasattr(o,"Shape"):
00060                     a.append(o)
00061         host.Objects = a
00062 
00063 def removeComponents(objectsList,host=None):
00064     '''removeComponents(objectsList,[hostObject]): removes the given component or
00065     the components from the given list from their parents. If a host object is
00066     specified, this function will try adding the components as holes to the host
00067     object instead.'''
00068     if not isinstance(objectsList,list):
00069         objectsList = [objectsList]
00070     if host:
00071         if Draft.getType(host) in ["Wall","Structure"]:
00072             s = host.Subtractions
00073             for o in objectsList:
00074                 if not o in s:
00075                     s.append(o)
00076             host.Subtractions = s
00077     else:
00078         for o in objectsList:
00079             if o.InList:
00080                h = o.InList[0]
00081                tp = Draft.getType(h)
00082                if tp in ["Cell","Floor","Building","Site"]:
00083                    c = h.Components
00084                    if o in c:
00085                        c.remove(o)
00086                        h.Components = c
00087                        o.ViewObject.show()
00088                elif tp in ["Wall","Structure"]:
00089                    a = h.Additions
00090                    s = h.Subtractions
00091                    if o in a:
00092                        a.remove(o)
00093                        h.Additions = a
00094                        o.ViewObject.show()
00095                    elif o in s:
00096                        s.remove(o)
00097                        h.Subtractions = s
00098                        o.ViewObject.show()
00099                elif tp in ["SectionPlane"]:
00100                    a = h.Objects
00101                    if o in a:
00102                        a.remove(o)
00103                        h.Objects = a
00104 
00105 def splitMesh(obj,mark=True):
00106     '''splitMesh(object,[mark]): splits the given mesh object into separated components.
00107     If mark is False, nothing else is done. If True (default), non-manifold components
00108     will be painted in red.'''
00109     if not obj.isDerivedFrom("Mesh::Feature"): return []
00110     basemesh = obj.Mesh
00111     comps = basemesh.getSeparateComponents()
00112     nlist = []
00113     if comps:
00114         basename = obj.Name
00115         FreeCAD.ActiveDocument.removeObject(basename)
00116         for c in comps:
00117             newobj = FreeCAD.ActiveDocument.addObject("Mesh::Feature",basename)
00118             newobj.Mesh = c
00119             if mark and (not(c.isSolid()) or c.hasNonManifolds()):
00120                 newobj.ViewObject.ShapeColor = (1.0,0.0,0.0,1.0)
00121             nlist.append(newobj)
00122         return nlist
00123     return [obj]
00124 
00125 def meshToShape(obj,mark=True):
00126     '''meshToShape(object,[mark]): turns a mesh into a shape, joining coplanar facets. If
00127     mark is True (default), non-solid objects will be marked in red'''
00128     if "Mesh" in obj.PropertiesList:
00129         faces = []      
00130         mesh = obj.Mesh
00131         plac = obj.Placement
00132         segments = mesh.getPlanes(0.001) # use rather strict tolerance here
00133         print len(segments)," segments ",segments
00134         for i in segments:
00135             print "treating",segments.index(i),i
00136             if len(i) > 0:
00137                 wires = MeshPart.wireFromSegment(mesh, i)
00138                 print "wire done"
00139                 print wires
00140                 if len(wires) > 1:
00141                     # a segment can have inner holes
00142                     print "inner wires found"
00143                     ext = None
00144                     max_length = 0
00145                     # cleaning up rubbish in wires
00146                     for i in range(len(wires)):
00147                         wires[i] = fcgeo.removeInterVertices(wires[i])
00148                     for w in wires:
00149                         # we assume that the exterior boundary is that one with
00150                         # the biggest bounding box
00151                         if w.BoundBox.DiagonalLength > max_length:
00152                             max_length = w.BoundBox.DiagonalLength
00153                             ext = w
00154                     print "exterior wire",ext
00155                     wires.remove(ext)
00156                     # all interior wires mark a hole and must reverse
00157                     # their orientation, otherwise Part.Face fails
00158                     for w in wires:
00159                         print "reversing",w
00160                         #w.reverse()
00161                         print "reversed"
00162                     # make sure that the exterior wires comes as first in the list
00163                     wires.insert(0, ext)
00164                     print "done sorting", wires
00165                 faces.append(Part.Face(wires))
00166                 print "done facing"
00167             print "faces",faces
00168 
00169         shell=Part.Compound(faces)
00170         solid = Part.Solid(Part.Shell(faces))
00171         name = obj.Name
00172         if solid.isClosed():
00173             FreeCAD.ActiveDocument.removeObject(name)
00174         newobj = FreeCAD.ActiveDocument.addObject("Part::Feature",name)
00175         newobj.Shape = solid
00176         newobj.Placement = plac
00177         if not solid.isClosed():
00178             newobj.ViewObject.ShapeColor = (1.0,0.0,0.0,1.0)
00179         return newobj
00180     return None
00181 
00182 def removeShape(objs,mark=True):
00183     '''takes an arch object (wall or structure) built on a cubic shape, and removes
00184     the inner shape, keeping its length, width and height as parameters.'''
00185     if not isinstance(objs,list):
00186         objs = [objs]
00187     for obj in objs:
00188         if fcgeo.isCubic(obj.Shape):
00189             dims = fcgeo.getCubicDimensions(obj.Shape)
00190             if dims:
00191                 name = obj.Name
00192                 tp = Draft.getType(obj)
00193                 print tp
00194                 if tp == "Structure":
00195                     FreeCAD.ActiveDocument.removeObject(name)
00196                     import Structure
00197                     str = Structure.makeStructure(length=dims[1],width=dims[2],height=dims[3],name=name)
00198                     str.Placement = dims[0]
00199                 elif tp == "Wall":
00200                     FreeCAD.ActiveDocument.removeObject(name)
00201                     import Wall
00202                     length = dims[1]
00203                     width = dims[2]
00204                     v1 = Vector(length/2,0,0)
00205                     v2 = fcvec.neg(v1)
00206                     v1 = dims[0].multVec(v1)
00207                     v2 = dims[0].multVec(v2)
00208                     line = Draft.makeLine(v1,v2)
00209                     wal = Wall.makeWall(line,width=width,height=dims[3],name=name)
00210         else:
00211             if mark:
00212                 obj.ViewObject.ShapeColor = (1.0,0.0,0.0,1.0)
00213         
00214     
00215 # command definitions ###############################################
00216                        
00217 class CommandAdd:
00218     "the Arch Add command definition"
00219     def GetResources(self):
00220         return {'Pixmap'  : 'Arch_Add',
00221                 'MenuText': QtCore.QT_TRANSLATE_NOOP("Arch_Add","Add component"),
00222                 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Arch_Add","Adds the selected components to the active object")}
00223 
00224     def IsActive(self):
00225         if len(FreeCADGui.Selection.getSelection()) > 1:
00226             return True
00227         else:
00228             return False
00229         
00230     def Activated(self):
00231         sel = FreeCADGui.Selection.getSelection()
00232         host = sel.pop()
00233         FreeCAD.ActiveDocument.openTransaction("Grouping")
00234         addComponents(sel,host)
00235         FreeCAD.ActiveDocument.commitTransaction()
00236 
00237         
00238 class CommandRemove:
00239     "the Arch Add command definition"
00240     def GetResources(self):
00241         return {'Pixmap'  : 'Arch_Remove',
00242                 'MenuText': QtCore.QT_TRANSLATE_NOOP("Arch_Remove","Remove component"),
00243                 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Arch_Remove","Remove the selected components from their parents, or create a hole in a component")}
00244 
00245     def IsActive(self):
00246         if FreeCADGui.Selection.getSelection():
00247             return True
00248         else:
00249             return False
00250         
00251     def Activated(self):
00252         sel = FreeCADGui.Selection.getSelection()
00253         FreeCAD.ActiveDocument.openTransaction("Ungrouping")
00254         if Draft.getType(sel[-1]) in ["Wall","Structure"]:
00255             host = sel.pop()
00256             removeComponents(sel,host)
00257         else:
00258             removeComponents(sel)
00259         FreeCAD.ActiveDocument.commitTransaction()
00260 
00261 
00262 class CommandSplitMesh:
00263     "the Arch SplitMesh command definition"
00264     def GetResources(self):
00265         return {'Pixmap'  : 'Arch_SplitMesh',
00266                 'MenuText': QtCore.QT_TRANSLATE_NOOP("Arch_SplitMesh","Split Mesh"),
00267                 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Arch_SplitMesh","Splits selected meshes into independent components")}
00268 
00269     def IsActive(self):
00270         if len(FreeCADGui.Selection.getSelection()):
00271             return True
00272         else:
00273             return False
00274         
00275     def Activated(self):
00276         if FreeCADGui.Selection.getSelection():
00277             sel = FreeCADGui.Selection.getSelection()
00278             FreeCAD.ActiveDocument.openTransaction("Split Mesh")
00279             for obj in sel:
00280                 n = obj.Name
00281                 nobjs = splitMesh(obj)
00282                 if len(nobjs) > 1:
00283                     g = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup",n)
00284                     for o in nobjs:
00285                         g.addObject(o)
00286             FreeCAD.ActiveDocument.commitTransaction()
00287 
00288             
00289 class CommandMeshToShape:
00290     "the Arch MeshToShape command definition"
00291     def GetResources(self):
00292         return {'Pixmap'  : 'Arch_MeshToShape',
00293                 'MenuText': QtCore.QT_TRANSLATE_NOOP("Arch_MeshToShape","Mesh to Shape"),
00294                 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Arch_MeshToPart","Turns selected meshes into Part Shape objects")}
00295 
00296     def IsActive(self):
00297         if FreeCADGui.Selection.getSelection():
00298             return True
00299         else:
00300             return False
00301         
00302     def Activated(self):
00303         if FreeCADGui.Selection.getSelection():
00304             f = FreeCADGui.Selection.getSelection()[0]
00305             g = None
00306             if f.isDerivedFrom("App::DocumentObjectGroup"):
00307                 g = f
00308                 FreeCADGui.Selection.clearSelection()
00309                 for o in f.OutList:
00310                     FreeCADGui.Selection.addSelection(o)
00311             else:
00312                 if f.InList:
00313                     if f.InList[0].isDerivedFrom("App::DocumentObjectGroup"):
00314                         g = f.InList[0]
00315             FreeCAD.ActiveDocument.openTransaction("Mesh to Shape")
00316             for obj in FreeCADGui.Selection.getSelection():
00317                 newobj = meshToShape(obj)
00318                 if g and newobj:
00319                     g.addObject(newobj)
00320             FreeCAD.ActiveDocument.commitTransaction()
00321 
00322 class CommandSelectNonSolidMeshes:
00323     "the Arch SelectNonSolidMeshes command definition"
00324     def GetResources(self):
00325         return {'MenuText': QtCore.QT_TRANSLATE_NOOP("Arch_SelectNonSolidMeshes","Select non-manifold meshes"),
00326                 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Arch_SelectNonSolidMeshes","Selects all non-manifold meshes from the document or from the selected groups")}
00327         
00328     def Activated(self):
00329         msel = []
00330         if FreeCADGui.Selection.getSelection():
00331             for o in FreeCADGui.Selection.getSelection():
00332                 if o.isDerivedFrom("App::DocumentObjectGroup"):
00333                     msel.extend(o.OutList)
00334         if not msel:
00335             msel = FreeCAD.ActiveDocument.Objects
00336         sel = []
00337         for o in msel:
00338             if o.isDerivedFrom("Mesh::Feature"):
00339                 if (not o.Mesh.isSolid()) or o.Mesh.hasNonManifolds():
00340                     sel.append(o)
00341         if sel:
00342             FreeCADGui.Selection.clearSelection()
00343             for o in sel:
00344                 FreeCADGui.Selection.addSelection(o)
00345 
00346 class CommandRemoveShape:
00347     "the Arch RemoveShape command definition"
00348     def GetResources(self):
00349         return {'Pixmap'  : 'Arch_RemoveShape',
00350                 'MenuText': QtCore.QT_TRANSLATE_NOOP("Arch_RemoveShape","Remove Shape from Arch"),
00351                 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Arch_RemoveShape","Removes cubic shapes from Arch components")}
00352 
00353     def IsActive(self):
00354         if FreeCADGui.Selection.getSelection():
00355             return True
00356         else:
00357             return False
00358         
00359     def Activated(self):
00360         sel = FreeCADGui.Selection.getSelection()
00361         removeShape(sel)
00362 
00363 FreeCADGui.addCommand('Arch_Add',CommandAdd())
00364 FreeCADGui.addCommand('Arch_Remove',CommandRemove())
00365 FreeCADGui.addCommand('Arch_SplitMesh',CommandSplitMesh())
00366 FreeCADGui.addCommand('Arch_MeshToShape',CommandMeshToShape())
00367 FreeCADGui.addCommand('Arch_SelectNonSolidMeshes',CommandSelectNonSolidMeshes())
00368 FreeCADGui.addCommand('Arch_RemoveShape',CommandRemoveShape())

Generated on Wed Nov 23 19:00:03 2011 for FreeCAD by  doxygen 1.6.1