From d44e4d324b08790c693144b3ecac3ca830411fbc Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Sun, 20 Jul 2014 12:00:47 -0300 Subject: [PATCH] Arch: moved ifc-related functions to importIFC --- src/Mod/Arch/ArchCommands.py | 187 --------------------------------- src/Mod/Arch/ArchSpace.py | 4 +- src/Mod/Arch/importIFC.py | 197 ++++++++++++++++++++++++++++++++++- 3 files changed, 196 insertions(+), 192 deletions(-) diff --git a/src/Mod/Arch/ArchCommands.py b/src/Mod/Arch/ArchCommands.py index e1db5e181..e863e8e15 100644 --- a/src/Mod/Arch/ArchCommands.py +++ b/src/Mod/Arch/ArchCommands.py @@ -37,8 +37,6 @@ __title__="FreeCAD Arch Commands" __author__ = "Yorik van Havre" __url__ = "http://www.freecadweb.org" -CURVEMODE = "PARAMETER" # For trimmed curves. CARTESIAN or PARAMETER - # module functions ############################################### def getStringList(objects): @@ -597,191 +595,6 @@ def check(objectslist,includehidden=False): bad.append([o,translate("Arch","contains faces that are not part of any solid")]) return bad -def getTuples(data,scale=1,placement=None,normal=None,close=True): - """getTuples(data,[scale,placement,normal,close]): returns a tuple or a list of tuples from a vector - or from the vertices of a shape. Scale can indicate a scale factor""" - rnd = False - import Part - if isinstance(data,FreeCAD.Vector): - if placement: - data = placement.multVec(data) - if rnd: - data = DraftVecUtils.rounded(data) - return (data.x*scale,data.y*scale,data.z*scale) - elif isinstance(data,Part.Shape): - t = [] - if len(data.Wires) == 1: - import Part,DraftGeomUtils - data = Part.Wire(DraftGeomUtils.sortEdges(data.Wires[0].Edges)) - verts = data.Vertexes - try: - c = data.CenterOfMass - v1 = verts[0].Point.sub(c) - v2 = verts[1].Point.sub(c) - if DraftVecUtils.angle(v2,v1,normal) >= 0: - # inverting verts order if the direction is couterclockwise - verts.reverse() - except: - pass - for v in verts: - pt = v.Point - if placement: - if not placement.isNull(): - pt = placement.multVec(pt) - if rnd: - pt = DraftVecUtils.rounded(pt) - t.append((pt.x*scale,pt.y*scale,pt.z*scale)) - - if close: # faceloops must not be closed, but ifc profiles must. - t.append(t[0]) - else: - print "Arch.getTuples(): Wrong profile data" - return t - -def getIfcExtrusionData(obj,scale=1,nosubs=False): - """getIfcExtrusionData(obj,[scale,nosubs]): returns a closed path (a list of tuples), a tuple expressing an extrusion - vector, and a list of 3 tuples for base position, x axis and z axis. Or returns None, if a base loop and - an extrusion direction cannot be extracted. Scale can indicate a scale factor.""" - if hasattr(obj,"Additions"): - if obj.Additions: - # TODO provisorily treat objs with additions as breps - return None - if hasattr(obj,"Subtractions") and not nosubs: - if obj.Subtractions: - return None - if hasattr(obj,"Proxy"): - if hasattr(obj.Proxy,"getProfiles"): - p = obj.Proxy.getProfiles(obj,noplacement=True) - v = obj.Proxy.getExtrusionVector(obj,noplacement=True) - if (len(p) == 1) and v: - p = p[0] - r = FreeCAD.Placement() - #b = p.CenterOfMass - r = obj.Proxy.getPlacement(obj) - #b = obj.Placement.multVec(FreeCAD.Vector()) - #r.Rotation = DraftVecUtils.getRotation(v,FreeCAD.Vector(0,0,1)) - d = [r.Base,DraftVecUtils.rounded(r.Rotation.multVec(FreeCAD.Vector(1,0,0))),DraftVecUtils.rounded(r.Rotation.multVec(FreeCAD.Vector(0,0,1)))] - #r = r.inverse() - #print "getExtrusionData: computed placement:",r - import Part - if len(p.Edges) == 1: - if isinstance(p.Edges[0].Curve,Part.Circle): - # Circle profile - r1 = p.Edges[0].Curve.Radius*scale - return "circle", [getTuples(p.Edges[0].Curve.Center,scale), r1], getTuples(v,scale), d - elif isinstance(p.Edges[0].Curve,Part.Ellipse): - # Ellipse profile - r1 = p.Edges[0].Curve.MajorRadius*scale - r2 = p.Edges[0].Curve.MinorRadius*scale - return "ellipse", [getTuples(p.Edges[0].Curve.Center,scale), r1, r2], getTuples(v,scale), d - curves = False - for e in p.Edges: - if isinstance(e.Curve,Part.Circle): - curves = True - elif not isinstance(e.Curve,Part.Line): - print "Arch.getIfcExtrusionData: Warning: unsupported edge type in profile" - if curves: - # Composite profile - ecurves = [] - last = None - import DraftGeomUtils - edges = DraftGeomUtils.sortEdges(p.Edges) - for e in edges: - if isinstance(e.Curve,Part.Circle): - import math - follow = True - if last: - if not DraftVecUtils.equals(last,e.Vertexes[0].Point): - follow = False - last = e.Vertexes[0].Point - else: - last = e.Vertexes[-1].Point - else: - last = e.Vertexes[-1].Point - p1 = math.degrees(-DraftVecUtils.angle(e.Vertexes[0].Point.sub(e.Curve.Center))) - p2 = math.degrees(-DraftVecUtils.angle(e.Vertexes[-1].Point.sub(e.Curve.Center))) - da = DraftVecUtils.angle(e.valueAt(e.FirstParameter+0.1).sub(e.Curve.Center),e.Vertexes[0].Point.sub(e.Curve.Center)) - if p1 < 0: - p1 = 360 + p1 - if p2 < 0: - p2 = 360 + p2 - if da > 0: - follow = not(follow) - if CURVEMODE == "CARTESIAN": - # BUGGY - p1 = getTuples(e.Vertexes[0].Point,scale) - p2 = getTuples(e.Vertexes[-1].Point,scale) - ecurves.append(["arc",getTuples(e.Curve.Center,scale),e.Curve.Radius*scale,[p1,p2],follow,CURVEMODE]) - else: - verts = [vertex.Point for vertex in e.Vertexes] - if last: - if not DraftVecUtils.equals(last,verts[0]): - verts.reverse() - last = e.Vertexes[0].Point - else: - last = e.Vertexes[-1].Point - else: - last = e.Vertexes[-1].Point - ecurves.append(["line",[getTuples(vert,scale) for vert in verts]]) - return "composite", ecurves, getTuples(v,scale), d - else: - # Polyline profile - return "polyline", getTuples(p,scale), getTuples(v,scale), d - return None - -def getIfcBrepFacesData(obj,scale=1,sub=False,tessellation=1): - """getIfcBrepFacesData(obj,[scale,tesselation]): returns a list(0) of lists(1) of lists(2) of lists(3), - list(3) being a list of vertices defining a loop, list(2) describing a face from one or - more loops, list(1) being the whole solid made of several faces, list(0) being the list - of solids inside the object. Scale can indicate a scaling factor. Tesselation is the tesselation - factor to apply on curved faces.""" - shape = None - if sub: - if hasattr(obj,"Proxy"): - if hasattr(obj.Proxy,"getSubVolume"): - shape = obj.Proxy.getSubVolume(obj) - if not shape: - if hasattr(obj,"Shape"): - if obj.Shape: - if not obj.Shape.isNull(): - if obj.Shape.isValid(): - shape = obj.Shape - if shape: - import Part - sols = [] - for sol in shape.Solids: - s = [] - curves = False - for face in sol.Faces: - for e in face.Edges: - if not isinstance(e.Curve,Part.Line): - curves = True - if curves: - tris = sol.tessellate(tessellation) - for tri in tris[1]: - f = [] - for i in tri: - f.append(getTuples(tris[0][i],scale)) - s.append([f]) - else: - for face in sol.Faces: - f = [] - f.append(getTuples(face.OuterWire,scale,normal=face.normalAt(0,0),close=False)) - for wire in face.Wires: - if wire.hashCode() != face.OuterWire.hashCode(): - f.append(getTuples(wire,scale,normal=DraftVecUtils.neg(face.normalAt(0,0)),close=False)) - s.append(f) - sols.append(s) - return sols - return None - -def getIfcElevation(obj): - """getIfcElevation(obj): Returns the lowest height (Z coordinate) of this object""" - if obj.isDerivedFrom("Part::Feature"): - b = obj.Shape.BoundBox - return b.ZMin - return 0 - def getHost(obj,strict=True): """getHost(obj,[strict]): returns the host of the current object. If strict is true (default), the host can only be an object of a higher level than the given one, or in other words, if a wall diff --git a/src/Mod/Arch/ArchSpace.py b/src/Mod/Arch/ArchSpace.py index 5276b7be6..e50a8abea 100644 --- a/src/Mod/Arch/ArchSpace.py +++ b/src/Mod/Arch/ArchSpace.py @@ -34,7 +34,7 @@ else: def translate(ctxt,txt): return txt -def makeSpace(objects=None,name=translate("Arch","Space")): +def makeSpace(objects=None,baseobj=None,name=translate("Arch","Space")): """makeSpace([objects]): Creates a space object from the given objects. Objects can be one document object, in which case it becomes the base shape of the space object, or a list of selection objects as got from getSelectionEx(), or a list of tuples (object, subobjectname)""" @@ -42,6 +42,8 @@ def makeSpace(objects=None,name=translate("Arch","Space")): _Space(obj) if FreeCAD.GuiUp: _ViewProviderSpace(obj.ViewObject) + if baseobj: + objects = baseobj if objects: if not isinstance(objects,list): objects = [objects] diff --git a/src/Mod/Arch/importIFC.py b/src/Mod/Arch/importIFC.py index 2d62b4820..a488f5b36 100644 --- a/src/Mod/Arch/importIFC.py +++ b/src/Mod/Arch/importIFC.py @@ -1048,10 +1048,10 @@ def export(exportList,filename): # get representation if (not forcebrep) and (not brepflag): - gdata = Arch.getIfcExtrusionData(obj,scaling,SEPARATE_OPENINGS) + gdata = getIfcExtrusionData(obj,scaling,SEPARATE_OPENINGS) #if DEBUG: print " extrusion data for ",obj.Label," : ",gdata if not gdata: - fdata = Arch.getIfcBrepFacesData(obj,scaling) + fdata = getIfcBrepFacesData(obj,scaling) #if DEBUG: print " brep data for ",obj.Label," : ",fdata if not fdata: if obj.isDerivedFrom("Part::Feature"): @@ -1094,7 +1094,7 @@ def export(exportList,filename): elif otype == "Window": extra = [obj.Width.Value*scaling, obj.Height.Value*scaling] elif otype == "Space": - extra = ["ELEMENT","INTERNAL",Arch.getIfcElevation(obj)] + extra = ["ELEMENT","INTERNAL",getIfcElevation(obj)] elif otype == "Part": extra = ["ELEMENT"] if not ifctype in supportedIfcTypes: @@ -1109,7 +1109,7 @@ def export(exportList,filename): if SEPARATE_OPENINGS and gdata: for o in obj.Subtractions: print "Subtracting ",o.Label - fdata = Arch.getIfcBrepFacesData(o,scaling,sub=True) + fdata = getIfcBrepFacesData(o,scaling,sub=True) representation = [ifc.addFacetedBrep(f, color=color) for f in fdata] p2 = ifc.addProduct( "IfcOpeningElement", representation, storey=product, placement=None, name=str(o.Label), description=None) @@ -1172,6 +1172,195 @@ def export(exportList,filename): print " " + o.Label +def getTuples(data,scale=1,placement=None,normal=None,close=True): + """getTuples(data,[scale,placement,normal,close]): returns a tuple or a list of tuples from a vector + or from the vertices of a shape. Scale can indicate a scale factor""" + rnd = False + import Part + if isinstance(data,FreeCAD.Vector): + if placement: + data = placement.multVec(data) + if rnd: + data = DraftVecUtils.rounded(data) + return (data.x*scale,data.y*scale,data.z*scale) + elif isinstance(data,Part.Shape): + t = [] + if len(data.Wires) == 1: + import Part,DraftGeomUtils + data = Part.Wire(DraftGeomUtils.sortEdges(data.Wires[0].Edges)) + verts = data.Vertexes + try: + c = data.CenterOfMass + v1 = verts[0].Point.sub(c) + v2 = verts[1].Point.sub(c) + if DraftVecUtils.angle(v2,v1,normal) >= 0: + # inverting verts order if the direction is couterclockwise + verts.reverse() + except: + pass + for v in verts: + pt = v.Point + if placement: + if not placement.isNull(): + pt = placement.multVec(pt) + if rnd: + pt = DraftVecUtils.rounded(pt) + t.append((pt.x*scale,pt.y*scale,pt.z*scale)) + + if close: # faceloops must not be closed, but ifc profiles must. + t.append(t[0]) + else: + print "Arch.getTuples(): Wrong profile data" + return t + +def getIfcExtrusionData(obj,scale=1,nosubs=False): + """getIfcExtrusionData(obj,[scale,nosubs]): returns a closed path (a list of tuples), a tuple expressing an extrusion + vector, and a list of 3 tuples for base position, x axis and z axis. Or returns None, if a base loop and + an extrusion direction cannot be extracted. Scale can indicate a scale factor.""" + + CURVEMODE = "PARAMETER" # For trimmed curves. CARTESIAN or PARAMETER + + if hasattr(obj,"Additions"): + if obj.Additions: + # TODO provisorily treat objs with additions as breps + return None + if hasattr(obj,"Subtractions") and not nosubs: + if obj.Subtractions: + return None + if hasattr(obj,"Proxy"): + if hasattr(obj.Proxy,"getProfiles"): + p = obj.Proxy.getProfiles(obj,noplacement=True) + v = obj.Proxy.getExtrusionVector(obj,noplacement=True) + if (len(p) == 1) and v: + p = p[0] + r = FreeCAD.Placement() + #b = p.CenterOfMass + r = obj.Proxy.getPlacement(obj) + #b = obj.Placement.multVec(FreeCAD.Vector()) + #r.Rotation = DraftVecUtils.getRotation(v,FreeCAD.Vector(0,0,1)) + d = [r.Base,DraftVecUtils.rounded(r.Rotation.multVec(FreeCAD.Vector(1,0,0))),DraftVecUtils.rounded(r.Rotation.multVec(FreeCAD.Vector(0,0,1)))] + #r = r.inverse() + #print "getExtrusionData: computed placement:",r + import Part + if len(p.Edges) == 1: + if isinstance(p.Edges[0].Curve,Part.Circle): + # Circle profile + r1 = p.Edges[0].Curve.Radius*scale + return "circle", [getTuples(p.Edges[0].Curve.Center,scale), r1], getTuples(v,scale), d + elif isinstance(p.Edges[0].Curve,Part.Ellipse): + # Ellipse profile + r1 = p.Edges[0].Curve.MajorRadius*scale + r2 = p.Edges[0].Curve.MinorRadius*scale + return "ellipse", [getTuples(p.Edges[0].Curve.Center,scale), r1, r2], getTuples(v,scale), d + curves = False + for e in p.Edges: + if isinstance(e.Curve,Part.Circle): + curves = True + elif not isinstance(e.Curve,Part.Line): + print "Arch.getIfcExtrusionData: Warning: unsupported edge type in profile" + if curves: + # Composite profile + ecurves = [] + last = None + import DraftGeomUtils + edges = DraftGeomUtils.sortEdges(p.Edges) + for e in edges: + if isinstance(e.Curve,Part.Circle): + import math + follow = True + if last: + if not DraftVecUtils.equals(last,e.Vertexes[0].Point): + follow = False + last = e.Vertexes[0].Point + else: + last = e.Vertexes[-1].Point + else: + last = e.Vertexes[-1].Point + p1 = math.degrees(-DraftVecUtils.angle(e.Vertexes[0].Point.sub(e.Curve.Center))) + p2 = math.degrees(-DraftVecUtils.angle(e.Vertexes[-1].Point.sub(e.Curve.Center))) + da = DraftVecUtils.angle(e.valueAt(e.FirstParameter+0.1).sub(e.Curve.Center),e.Vertexes[0].Point.sub(e.Curve.Center)) + if p1 < 0: + p1 = 360 + p1 + if p2 < 0: + p2 = 360 + p2 + if da > 0: + follow = not(follow) + if CURVEMODE == "CARTESIAN": + # BUGGY + p1 = getTuples(e.Vertexes[0].Point,scale) + p2 = getTuples(e.Vertexes[-1].Point,scale) + ecurves.append(["arc",getTuples(e.Curve.Center,scale),e.Curve.Radius*scale,[p1,p2],follow,CURVEMODE]) + else: + verts = [vertex.Point for vertex in e.Vertexes] + if last: + if not DraftVecUtils.equals(last,verts[0]): + verts.reverse() + last = e.Vertexes[0].Point + else: + last = e.Vertexes[-1].Point + else: + last = e.Vertexes[-1].Point + ecurves.append(["line",[getTuples(vert,scale) for vert in verts]]) + return "composite", ecurves, getTuples(v,scale), d + else: + # Polyline profile + return "polyline", getTuples(p,scale), getTuples(v,scale), d + return None + +def getIfcBrepFacesData(obj,scale=1,sub=False,tessellation=1): + """getIfcBrepFacesData(obj,[scale,tesselation]): returns a list(0) of lists(1) of lists(2) of lists(3), + list(3) being a list of vertices defining a loop, list(2) describing a face from one or + more loops, list(1) being the whole solid made of several faces, list(0) being the list + of solids inside the object. Scale can indicate a scaling factor. Tesselation is the tesselation + factor to apply on curved faces.""" + shape = None + if sub: + if hasattr(obj,"Proxy"): + if hasattr(obj.Proxy,"getSubVolume"): + shape = obj.Proxy.getSubVolume(obj) + if not shape: + if hasattr(obj,"Shape"): + if obj.Shape: + if not obj.Shape.isNull(): + if obj.Shape.isValid(): + shape = obj.Shape + if shape: + import Part + sols = [] + for sol in shape.Solids: + s = [] + curves = False + for face in sol.Faces: + for e in face.Edges: + if not isinstance(e.Curve,Part.Line): + curves = True + if curves: + tris = sol.tessellate(tessellation) + for tri in tris[1]: + f = [] + for i in tri: + f.append(getTuples(tris[0][i],scale)) + s.append([f]) + else: + for face in sol.Faces: + f = [] + f.append(getTuples(face.OuterWire,scale,normal=face.normalAt(0,0),close=False)) + for wire in face.Wires: + if wire.hashCode() != face.OuterWire.hashCode(): + f.append(getTuples(wire,scale,normal=DraftVecUtils.neg(face.normalAt(0,0)),close=False)) + s.append(f) + sols.append(s) + return sols + return None + +def getIfcElevation(obj): + """getIfcElevation(obj): Returns the lowest height (Z coordinate) of this object""" + if obj.isDerivedFrom("Part::Feature"): + b = obj.Shape.BoundBox + return b.ZMin + return 0 + + def explore(filename=None): "explore the contents of an ifc file in a Qt dialog" if not filename: