Arch: Support for IfcGrid
This commit is contained in:
@@ -57,7 +57,7 @@ def makeAxis(num=5,size=1000,name="Axes"):
|
||||
if not FreeCAD.ActiveDocument:
|
||||
FreeCAD.Console.PrintError("No active document. Aborting\n")
|
||||
return
|
||||
obj = FreeCAD.ActiveDocument.addObject("App::FeaturePython",name)
|
||||
obj = FreeCAD.ActiveDocument.addObject("App::FeaturePython","Axis")
|
||||
obj.Label = translate("Arch",name)
|
||||
_Axis(obj)
|
||||
if FreeCAD.GuiUp:
|
||||
@@ -83,7 +83,7 @@ def makeAxisSystem(axes,name="Axis System"):
|
||||
|
||||
if not isinstance(axes,list):
|
||||
axes = [axes]
|
||||
obj = FreeCAD.ActiveDocument.addObject("App::FeaturePython",name)
|
||||
obj = FreeCAD.ActiveDocument.addObject("App::FeaturePython","AxisSystem")
|
||||
obj.Label = translate("Arch",name)
|
||||
_AxisSystem(obj)
|
||||
obj.Axes = axes
|
||||
@@ -97,7 +97,7 @@ def makeGrid(name="Grid"):
|
||||
|
||||
'''makeGrid(): makes a grid object'''
|
||||
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython",name)
|
||||
obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","Grid")
|
||||
obj.Label = translate("Arch",name)
|
||||
ArchGrid(obj)
|
||||
if FreeCAD.GuiUp:
|
||||
@@ -208,6 +208,8 @@ class _Axis:
|
||||
obj.addProperty("App::PropertyFloatList","Angles","Axis", QT_TRANSLATE_NOOP("App::Property","The angles of each axis"))
|
||||
if not "Labels" in pl:
|
||||
obj.addProperty("App::PropertyStringList","Labels","Axis", QT_TRANSLATE_NOOP("App::Property","The label of each axis"))
|
||||
if not "CustomNumber" in pl:
|
||||
obj.addProperty("App::PropertyString","CustomNumber","Axis", QT_TRANSLATE_NOOP("App::Property","An optional custom bubble number"))
|
||||
if not "Length" in pl:
|
||||
obj.addProperty("App::PropertyLength","Length","Axis", QT_TRANSLATE_NOOP("App::Property","The length of the axes"))
|
||||
obj.Length=3000
|
||||
@@ -265,6 +267,21 @@ class _Axis:
|
||||
pts.append(e.Vertexes[0].Point)
|
||||
return pts
|
||||
|
||||
def getAxisData(self,obj):
|
||||
data = []
|
||||
num = 0
|
||||
for e in obj.Shape.Edges:
|
||||
axdata = []
|
||||
axdata.append(e.Vertexes[0].Point)
|
||||
axdata.append(e.Vertexes[-1].Point)
|
||||
if obj.ViewObject:
|
||||
axdata.append(obj.ViewObject.Proxy.getNumber(obj.ViewObject,num))
|
||||
else:
|
||||
axdata.append(str(num))
|
||||
data.append(axdata)
|
||||
num += 1
|
||||
return data
|
||||
|
||||
|
||||
class _ViewProviderAxis:
|
||||
|
||||
@@ -490,52 +507,13 @@ class _ViewProviderAxis:
|
||||
self.onChanged(vobj,"ShowLabel")
|
||||
elif prop in ["NumberingStyle","StartNumber"]:
|
||||
if hasattr(self,"bubbletexts"):
|
||||
chars = "abcdefghijklmnopqrstuvwxyz"
|
||||
roman=(('M',1000),('CM',900),('D',500),('CD',400),
|
||||
('C',100),('XC',90),('L',50),('XL',40),
|
||||
('X',10),('IX',9),('V',5),('IV',4),('I',1))
|
||||
num = 0
|
||||
if hasattr(vobj,"StartNumber"):
|
||||
if vobj.StartNumber > 1:
|
||||
num = vobj.StartNumber-1
|
||||
alt = False
|
||||
for t in self.bubbletexts:
|
||||
if hasattr(vobj,"NumberingStyle"):
|
||||
if vobj.NumberingStyle == "1,2,3":
|
||||
t.string = str(num+1)
|
||||
elif vobj.NumberingStyle == "01,02,03":
|
||||
t.string = str(num+1).zfill(2)
|
||||
elif vobj.NumberingStyle == "001,002,003":
|
||||
t.string = str(num+1).zfill(3)
|
||||
elif vobj.NumberingStyle == "A,B,C":
|
||||
result = ""
|
||||
base = num/26
|
||||
if base:
|
||||
result += chars[base].upper()
|
||||
remainder = num % 26
|
||||
result += chars[remainder].upper()
|
||||
t.string = result
|
||||
elif vobj.NumberingStyle == "a,b,c":
|
||||
result = ""
|
||||
base = num/26
|
||||
if base:
|
||||
result += chars[base]
|
||||
remainder = num % 26
|
||||
result += chars[remainder]
|
||||
t.string = result
|
||||
elif vobj.NumberingStyle == "I,II,III":
|
||||
result = ""
|
||||
n = num
|
||||
n += 1
|
||||
for numeral, integer in roman:
|
||||
while n >= integer:
|
||||
result += numeral
|
||||
n -= integer
|
||||
t.string = result
|
||||
elif vobj.NumberingStyle == "L0,L1,L2":
|
||||
t.string = "L"+str(num)
|
||||
else:
|
||||
t.string = str(num+1)
|
||||
t.string = self.getNumber(vobj,num)
|
||||
num += 1
|
||||
if hasattr(vobj,"BubblePosition"):
|
||||
if vobj.BubblePosition == "Both":
|
||||
@@ -590,6 +568,50 @@ class _ViewProviderAxis:
|
||||
self.labels.addChild(st)
|
||||
self.labelset.addChild(self.labels)
|
||||
|
||||
def getNumber(self,vobj,num):
|
||||
|
||||
chars = "abcdefghijklmnopqrstuvwxyz"
|
||||
roman=(('M',1000),('CM',900),('D',500),('CD',400),
|
||||
('C',100),('XC',90),('L',50),('XL',40),
|
||||
('X',10),('IX',9),('V',5),('IV',4),('I',1))
|
||||
if hasattr(vobj.Object,"CustomNumber") and vobj.Object.CustomNumber:
|
||||
return vobj.Object.CustomNumber.encode("utf8")
|
||||
elif hasattr(vobj,"NumberingStyle"):
|
||||
if vobj.NumberingStyle == "1,2,3":
|
||||
return str(num+1)
|
||||
elif vobj.NumberingStyle == "01,02,03":
|
||||
return str(num+1).zfill(2)
|
||||
elif vobj.NumberingStyle == "001,002,003":
|
||||
return str(num+1).zfill(3)
|
||||
elif vobj.NumberingStyle == "A,B,C":
|
||||
result = ""
|
||||
base = num/26
|
||||
if base:
|
||||
result += chars[base].upper()
|
||||
remainder = num % 26
|
||||
result += chars[remainder].upper()
|
||||
return result
|
||||
elif vobj.NumberingStyle == "a,b,c":
|
||||
result = ""
|
||||
base = num/26
|
||||
if base:
|
||||
result += chars[base]
|
||||
remainder = num % 26
|
||||
result += chars[remainder]
|
||||
return result
|
||||
elif vobj.NumberingStyle == "I,II,III":
|
||||
result = ""
|
||||
n = num
|
||||
n += 1
|
||||
for numeral, integer in roman:
|
||||
while n >= integer:
|
||||
result += numeral
|
||||
n -= integer
|
||||
return result
|
||||
elif vobj.NumberingStyle == "L0,L1,L2":
|
||||
return "L"+str(num)
|
||||
else:
|
||||
return str(num+1)
|
||||
|
||||
def setEdit(self,vobj,mode=0):
|
||||
|
||||
@@ -841,6 +863,13 @@ class _AxisSystem:
|
||||
pts.extend([p.add(v) for p in bset])
|
||||
return pts
|
||||
|
||||
def getAxisData(self,obj):
|
||||
data = []
|
||||
for axis in obj.Axes:
|
||||
if hasattr(axis,"Proxy") and hasattr(axis.Proxy,"getAxisData"):
|
||||
data.append(axis.Proxy.getAxisData(axis))
|
||||
return data
|
||||
|
||||
|
||||
class _ViewProviderAxisSystem:
|
||||
|
||||
@@ -855,6 +884,10 @@ class _ViewProviderAxisSystem:
|
||||
import Arch_rc
|
||||
return ":/icons/Arch_Axis_System_Tree.svg"
|
||||
|
||||
def isShow(self):
|
||||
|
||||
return True
|
||||
|
||||
def claimChildren(self):
|
||||
|
||||
if hasattr(self,"axes"):
|
||||
|
||||
@@ -219,13 +219,16 @@ def makeFloor(objectslist=None,baseobj=None,name="Floor"):
|
||||
|
||||
def makeBuilding(objectslist=None,baseobj=None,name="Building"):
|
||||
|
||||
"""overwrites ArchBuilding.makeBiulding"""
|
||||
"""overwrites ArchBuilding.makeBuilding"""
|
||||
|
||||
obj = makeBuildingPart(objectslist)
|
||||
obj.Label = name
|
||||
obj.IfcRole = "Building"
|
||||
obj.addProperty("App::PropertyEnumeration","BuildingType","Arch",QT_TRANSLATE_NOOP("App::Property","The type of this building"))
|
||||
obj.addProperty("App::PropertyEnumeration","BuildingType","Building",QT_TRANSLATE_NOOP("App::Property","The type of this building"))
|
||||
obj.BuildingType = BuildingTypes
|
||||
if FreeCAD.GuiUp:
|
||||
obj.ViewObject.ShowLevel = False
|
||||
obj.ViewObject.ShowLabel = False
|
||||
return obj
|
||||
|
||||
|
||||
|
||||
@@ -461,6 +461,15 @@ def insert(filename,docname,skip=[],only=[],root=None):
|
||||
if it.Items[0].id() == r.id():
|
||||
colors[m.RepresentedMaterial.id()] = (c.Red,c.Green,c.Blue)
|
||||
|
||||
# move IfcGrids from products to annotations
|
||||
tp = []
|
||||
for product in products:
|
||||
if product.is_a("IfcGrid") and not (product in annotations):
|
||||
annotations.append(product)
|
||||
else:
|
||||
tp.append(product)
|
||||
products = tp
|
||||
|
||||
if only: # only import a list of IDs and their children
|
||||
ids = []
|
||||
while only:
|
||||
@@ -1000,28 +1009,67 @@ def insert(filename,docname,skip=[],only=[],root=None):
|
||||
scaling = getScaling(ifcfile)
|
||||
#print "scaling factor =",scaling
|
||||
for annotation in annotations:
|
||||
anno = None
|
||||
aid = annotation.id()
|
||||
if aid in skip: continue # user given id skip list
|
||||
if annotation.is_a() in SKIP: continue # preferences-set type skip list
|
||||
name = "Annotation"
|
||||
if annotation.Name:
|
||||
name = annotation.Name.encode("utf8")
|
||||
if "annotation" not in name.lower():
|
||||
name = "Annotation " + name
|
||||
if PREFIX_NUMBERS: name = "ID" + str(aid) + " " + name
|
||||
shapes2d = []
|
||||
for rep in annotation.Representation.Representations:
|
||||
if rep.RepresentationIdentifier in ["Annotation","FootPrint","Axis"]:
|
||||
shapes2d.extend(setRepresentation(rep,scaling))
|
||||
if shapes2d:
|
||||
sh = Part.makeCompound(shapes2d)
|
||||
pc = str(int((float(count)/(len(products)+len(annotations))*100)))+"% "
|
||||
if DEBUG: print(pc,"creating object ",aid," : Annotation with shape: ",sh)
|
||||
o = FreeCAD.ActiveDocument.addObject("Part::Feature",name)
|
||||
o.Shape = sh
|
||||
p = getPlacement(annotation.ObjectPlacement,scaling)
|
||||
if p: # and annotation.is_a("IfcAnnotation"):
|
||||
o.Placement = p
|
||||
if aid in skip:
|
||||
continue # user given id skip list
|
||||
if annotation.is_a() in SKIP:
|
||||
continue # preferences-set type skip list
|
||||
if annotation.is_a("IfcGrid"):
|
||||
axes = []
|
||||
uvwaxes = ()
|
||||
if annotation.UAxes:
|
||||
uvwaxes = annotation.UAxes
|
||||
if annotation.VAxes:
|
||||
uvwaxes = uvwaxes + annotation.VAxes
|
||||
if annotation.WAxes:
|
||||
uvwaxes = uvwaxes + annotation.WAxes
|
||||
for axis in uvwaxes:
|
||||
if axis.AxisCurve:
|
||||
sh = setRepresentation(axis.AxisCurve,scaling)
|
||||
if sh and (len(sh[0].Vertexes) == 2): # currently only straight axes are supported
|
||||
sh = sh[0]
|
||||
l = sh.Length
|
||||
pl = FreeCAD.Placement()
|
||||
pl.Base = sh.Vertexes[0].Point
|
||||
pl.Rotation = FreeCAD.Rotation(FreeCAD.Vector(0,1,0),sh.Vertexes[-1].Point.sub(sh.Vertexes[0].Point))
|
||||
o = Arch.makeAxis(1,l)
|
||||
o.Length = l
|
||||
o.Placement = pl
|
||||
o.CustomNumber = axis.AxisTag
|
||||
axes.append(o)
|
||||
if axes:
|
||||
name = "Grid"
|
||||
if annotation.Name:
|
||||
name = annotation.Name.encode("utf8")
|
||||
if PREFIX_NUMBERS:
|
||||
name = "ID" + str(aid) + " " + name
|
||||
anno = Arch.makeAxisSystem(axes,name)
|
||||
else:
|
||||
name = "Annotation"
|
||||
if annotation.Name:
|
||||
name = annotation.Name.encode("utf8")
|
||||
if "annotation" not in name.lower():
|
||||
name = "Annotation " + name
|
||||
if PREFIX_NUMBERS: name = "ID" + str(aid) + " " + name
|
||||
shapes2d = []
|
||||
for rep in annotation.Representation.Representations:
|
||||
if rep.RepresentationIdentifier in ["Annotation","FootPrint","Axis"]:
|
||||
shapes2d.extend(setRepresentation(rep,scaling))
|
||||
if shapes2d:
|
||||
sh = Part.makeCompound(shapes2d)
|
||||
pc = str(int((float(count)/(len(products)+len(annotations))*100)))+"% "
|
||||
if DEBUG: print(pc,"creating object ",aid," : Annotation with shape: ",sh)
|
||||
anno = FreeCAD.ActiveDocument.addObject("Part::Feature",name)
|
||||
anno.Shape = sh
|
||||
p = getPlacement(annotation.ObjectPlacement,scaling)
|
||||
if p: # and annotation.is_a("IfcAnnotation"):
|
||||
anno.Placement = p
|
||||
# placing in container if needed
|
||||
if anno:
|
||||
for host,children in additions.items():
|
||||
if (aid in children) and (host in objects.keys()):
|
||||
Arch.addComponents(anno,objects[host])
|
||||
|
||||
count += 1
|
||||
|
||||
@@ -1206,6 +1254,52 @@ def export(exportList,filename):
|
||||
if ifctype == "IfcGroup":
|
||||
groups[obj.Name] = [o.Name for o in obj.Group]
|
||||
continue
|
||||
if (Draft.getType(obj) == "BuildingPart") and hasattr(obj,"IfcRole") and (obj.IfcRole == "Undefined"):
|
||||
ifctype = "IfcBuildingStorey" # export BuildingParts as Storeys if their type wasn't explicitely set
|
||||
|
||||
# export grids
|
||||
|
||||
if ifctype in ["IfcAxis","IfcAxisSystem","IfcGrid"]:
|
||||
ifctype = "IfcGrid"
|
||||
ifcaxes = []
|
||||
ifcpols = []
|
||||
for axg in obj.Proxy.getAxisData(obj):
|
||||
ifcaxg = []
|
||||
for ax in axg:
|
||||
p1 = ifcfile.createIfcCartesianPoint(tuple(FreeCAD.Vector(ax[0]).multiply(0.001)))
|
||||
p2 = ifcfile.createIfcCartesianPoint(tuple(FreeCAD.Vector(ax[1]).multiply(0.001)))
|
||||
pol = ifcfile.createIfcPolyline([p1,p2])
|
||||
ifcpols.append(pol)
|
||||
axis = ifcfile.createIfcGridAxis(ax[2],pol,True)
|
||||
ifcaxg.append(axis)
|
||||
if len(ifcaxes) < 3:
|
||||
ifcaxes.append(ifcaxg)
|
||||
else:
|
||||
ifcaxes[2] = ifcaxes[2]+ifcaxg # IfcGrid can have max 3 axes systems
|
||||
u = None
|
||||
v = None
|
||||
w = None
|
||||
if ifcaxes:
|
||||
u = ifcaxes[0]
|
||||
if len(ifcaxes) > 1:
|
||||
v = ifcaxes[1]
|
||||
if len(ifcaxes) > 2:
|
||||
v = ifcaxes[2]
|
||||
if DEBUG: print(str(count).ljust(3)," : ", ifctype, " (",str(len(ifcpols)),"axes ) : ",name)
|
||||
xvc = ifcfile.createIfcDirection((1.0,0.0,0.0))
|
||||
zvc = ifcfile.createIfcDirection((0.0,0.0,1.0))
|
||||
ovc = ifcfile.createIfcCartesianPoint((0.0,0.0,0.0))
|
||||
gpl = ifcfile.createIfcAxis2Placement3D(ovc,zvc,xvc)
|
||||
plac = ifcfile.createIfcLocalPlacement(None,gpl)
|
||||
cset = ifcfile.createIfcGeometricCurveSet(ifcpols)
|
||||
#subc = ifcfile.createIfcGeometricRepresentationSubContext('FootPrint','Model',context,None,"MODEL_VIEW",None,None,None,None,None)
|
||||
srep = ifcfile.createIfcShapeRepresentation(context,'FootPrint',"GeometricCurveSet",ifcpols)
|
||||
pdef = ifcfile.createIfcProductDefinitionShape(None,None,[srep])
|
||||
grid = ifcfile.createIfcGrid(uid,history,name,description,None,plac,pdef,u,v,w)
|
||||
products[obj.Name] = grid
|
||||
count += 1
|
||||
continue
|
||||
|
||||
from ArchComponent import IFCTYPES
|
||||
if ifctype not in IFCTYPES:
|
||||
ifctype = "IfcBuildingElementProxy"
|
||||
@@ -1534,7 +1628,7 @@ def export(exportList,filename):
|
||||
f = products[floor.Name]
|
||||
if children:
|
||||
ifcfile.createIfcRelContainedInSpatialStructure(ifcopenshell.guid.compress(uuid.uuid1().hex),history,'StoreyLink','',children,f)
|
||||
floors.append(floor.Name)
|
||||
floors.append(f)
|
||||
defaulthost = f
|
||||
for building in Draft.getObjectsOfType(objectslist,"Building"):
|
||||
objs = Draft.getGroupContents(building,walls=True,addgroups=True)
|
||||
@@ -1545,7 +1639,7 @@ def export(exportList,filename):
|
||||
if not (c.Name in treated):
|
||||
if c.Name != building.Name: # getGroupContents + addgroups will include the building itself
|
||||
if c.Name in products.keys():
|
||||
if Draft.getType(c) == "Floor":
|
||||
if Draft.getType(c) in ["Floor","BuildingPart"]:
|
||||
childfloors.append(products[c.Name])
|
||||
treated.append(c.Name)
|
||||
elif not (c.Name in treated):
|
||||
@@ -1580,12 +1674,14 @@ def export(exportList,filename):
|
||||
if not buildings:
|
||||
if DEBUG: print("No building found. Adding default building")
|
||||
buildings = [ifcfile.createIfcBuilding(ifcopenshell.guid.compress(uuid.uuid1().hex),history,"Default Building",'',None,None,None,None,"ELEMENT",None,None,None)]
|
||||
if floors:
|
||||
ifcfile.createIfcRelAggregates(ifcopenshell.guid.compress(uuid.uuid1().hex),history,'BuildingLink','',buildings[0],floors)
|
||||
ifcfile.createIfcRelAggregates(ifcopenshell.guid.compress(uuid.uuid1().hex),history,'SiteLink','',sites[0],buildings)
|
||||
untreated = []
|
||||
for k,v in products.items():
|
||||
if not(k in treated):
|
||||
if k != buildings[0].Name:
|
||||
if not(Draft.getType(FreeCAD.ActiveDocument.getObject(k)) in ["Site","Building","Floor"]):
|
||||
if not(Draft.getType(FreeCAD.ActiveDocument.getObject(k)) in ["Site","Building","Floor","BuildingPart"]):
|
||||
untreated.append(v)
|
||||
if untreated:
|
||||
if not defaulthost:
|
||||
@@ -2241,6 +2337,17 @@ def setRepresentation(representation,scaling=1000):
|
||||
pts.append(c)
|
||||
return Part.makePolygon(pts)
|
||||
|
||||
def getLine(ent):
|
||||
pts = []
|
||||
p1 = getVector(ent.Pnt)
|
||||
p1.multiply(scaling)
|
||||
pts.append(p1)
|
||||
p2 = getVector(ent.Dir)
|
||||
p2.multiply(scaling)
|
||||
p2 = p1.add(p2)
|
||||
pts.append(p2)
|
||||
return Part.makePolygon(pts)
|
||||
|
||||
def getCircle(ent):
|
||||
c = ent.Position.Location.Coordinates
|
||||
c = FreeCAD.Vector(c[0],c[1],c[2] if len(c) > 2 else 0)
|
||||
@@ -2250,9 +2357,15 @@ def setRepresentation(representation,scaling=1000):
|
||||
|
||||
def getCurveSet(ent):
|
||||
result = []
|
||||
for el in ent.Elements:
|
||||
if ent.is_a() in ["IfcGeometricCurveSet","IfcGeometricSet"]:
|
||||
elts = ent.Elements
|
||||
elif ent.is_a() in ["IfcLine","IfcPolyline","IfcCircle","IfcTrimmedCurve"]:
|
||||
elts = [ent]
|
||||
for el in elts:
|
||||
if el.is_a("IfcPolyline"):
|
||||
result.append(getPolyline(el))
|
||||
elif el.is_a("IfcLine"):
|
||||
result.append(getLine(el))
|
||||
elif el.is_a("IfcCircle"):
|
||||
result.append(getCircle(el))
|
||||
elif el.is_a("IfcTrimmedCurve"):
|
||||
@@ -2291,6 +2404,8 @@ def setRepresentation(representation,scaling=1000):
|
||||
result.append(r)
|
||||
else:
|
||||
result = preresult
|
||||
elif representation.is_a() in ["IfcPolyline","IfcCircle","IfcTrimmedCurve"]:
|
||||
result = getCurveSet(representation)
|
||||
return result
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user