30
from FreeCAD import Vector
34
from PySide import QtCore, QtGui
35
from draftutils.translate import translate
36
from PySide.QtCore import QT_TRANSLATE_NOOP
39
def translate(ctxt, txt):
41
def QT_TRANSLATE_NOOP(ctxt, txt):
53
__title__ = "FreeCAD Roof"
54
__author__ = "Yorik van Havre", "Jonathan Wiedemann"
55
__url__ = "https://www.freecad.org"
58
def adjust_list_len (lst, newLn, val):
59
'''Returns a clone of lst with length newLn, val is appended if required'''
64
return lst[:] + ([val] * (newLn - ln))
67
def find_inters (edge1, edge2, infinite1=True, infinite2=True):
68
'''Future wrapper for DraftGeomUtils.findIntersection. The function now
69
contains a modified copy of getLineIntersections from that function.
71
def getLineIntersections(pt1, pt2, pt3, pt4, infinite1, infinite2):
78
norm1 = pt2.sub(pt1).cross(pt3.sub(pt1))
79
norm2 = pt2.sub(pt4).cross(pt3.sub(pt4))
81
if not DraftVecUtils.isNull(norm1):
87
if not DraftVecUtils.isNull(norm2):
93
if DraftVecUtils.isNull(norm1.cross(norm2)):
96
if DraftVecUtils.isNull(vec1) or DraftVecUtils.isNull(vec2):
101
except Part.OCCError:
103
norm3 = vec1.cross(vec2)
104
denom = norm3.x + norm3.y + norm3.z
105
if not DraftVecUtils.isNull(norm3) and denom != 0:
106
k = ((pt3.z - pt1.z) * (vec2.x - vec2.y)
107
+ (pt3.y - pt1.y) * (vec2.z - vec2.x)
108
+ (pt3.x - pt1.x) * (vec2.y - vec2.z)) / denom
112
if infinite1 is False and not isPtOnEdge(intp, edge1):
115
if infinite2 is False and not isPtOnEdge(intp, edge2):
124
pt1, pt2, pt3, pt4 = [edge1.Vertexes[0].Point,
125
edge1.Vertexes[1].Point,
126
edge2.Vertexes[0].Point,
127
edge2.Vertexes[1].Point]
129
return getLineIntersections(pt1, pt2, pt3, pt4, infinite1, infinite2)
132
def face_from_points(ptLst):
133
ptLst.append(ptLst[0])
135
ptLst = DraftVecUtils.removeDoubles(ptLst)
140
for i in range(ln - 1):
141
edge = Part.makeLine(ptLst[i], ptLst[i + 1])
143
wire = Part.Wire(edgeLst)
144
return Part.Face(wire)
148
class _Roof(ArchComponent.Component):
149
'''The Roof object'''
150
def __init__(self, obj):
151
ArchComponent.Component.__init__(self, obj)
152
self.setProperties(obj)
156
def setProperties(self, obj):
157
pl = obj.PropertiesList
158
if not "Angles" in pl:
159
obj.addProperty("App::PropertyFloatList",
162
QT_TRANSLATE_NOOP("App::Property", "The list of angles of the roof segments"))
164
obj.addProperty("App::PropertyFloatList",
167
QT_TRANSLATE_NOOP("App::Property", "The list of horizontal length projections of the roof segments"))
168
if not "IdRel" in pl:
169
obj.addProperty("App::PropertyIntegerList",
172
QT_TRANSLATE_NOOP("App::Property", "The list of IDs of the relative profiles of the roof segments"))
173
if not "Thickness" in pl:
174
obj.addProperty("App::PropertyFloatList",
177
QT_TRANSLATE_NOOP("App::Property", "The list of thicknesses of the roof segments"))
178
if not "Overhang" in pl:
179
obj.addProperty("App::PropertyFloatList",
182
QT_TRANSLATE_NOOP("App::Property", "The list of overhangs of the roof segments"))
183
if not "Heights" in pl:
184
obj.addProperty("App::PropertyFloatList",
187
QT_TRANSLATE_NOOP("App::Property", "The list of calculated heights of the roof segments"))
189
obj.addProperty("App::PropertyInteger",
192
QT_TRANSLATE_NOOP("App::Property", "The face number of the base object used to build the roof"))
193
if not "RidgeLength" in pl:
194
obj.addProperty("App::PropertyLength",
197
QT_TRANSLATE_NOOP("App::Property", "The total length of the ridges and hips of the roof"))
198
obj.setEditorMode("RidgeLength",1)
199
if not "BorderLength" in pl:
200
obj.addProperty("App::PropertyLength",
203
QT_TRANSLATE_NOOP("App::Property", "The total length of the borders of the roof"))
204
obj.setEditorMode("BorderLength",1)
206
obj.addProperty("App::PropertyBool",
209
QT_TRANSLATE_NOOP("App::Property", "Specifies if the direction of the roof should be flipped"))
210
if not "Subvolume" in pl:
211
obj.addProperty("App::PropertyLink",
214
QT_TRANSLATE_NOOP("App::Property", "An optional object that defines a volume to be subtracted from walls. If field is set - it has a priority over auto-generated subvolume"))
217
def onDocumentRestored(self, obj):
218
ArchComponent.Component.onDocumentRestored(self, obj)
219
self.setProperties(obj)
221
def flipEdges(self, edges):
225
NewEdge = DraftGeomUtils.edg(edge.Vertexes[1].Point, edge.Vertexes[0].Point)
226
newEdges.append(NewEdge)
229
def calcHeight(self, id):
230
'''Get the height from run and angle of the given roof profile'''
231
htRel = self.profilsDico[id]["run"] * (math.tan(math.radians(self.profilsDico[id]["angle"])))
234
def calcRun(self, id):
235
'''Get the run from height and angle of the given roof profile'''
236
runRel = self.profilsDico[id]["height"] / (math.tan(math.radians(self.profilsDico[id]["angle"])))
239
def calcAngle(self, id):
240
'''Get the angle from height and run of the given roof profile'''
241
ang = math.degrees(math.atan(self.profilsDico[id]["height"] / self.profilsDico[id]["run"]))
244
def getPerpendicular(self, vec, rotEdge, l):
245
'''Get the perpendicular vec of given edge on xy plane'''
246
norm = Vector(0.0, 0.0, 1.0)
247
if hasattr(self, "normal"):
250
per = vec.cross(norm)
251
if -180.0 <= rotEdge < -90.0:
252
per[0] = -abs(per[0])
253
per[1] = -abs(per[1])
254
elif -90.0 <= rotEdge <= 0.0:
255
per[0] = -abs(per[0])
257
elif 0.0 < rotEdge <= 90.0:
260
elif 90.0 < rotEdge <= 180.0:
262
per[1] = -abs(per[1])
264
print("Unknown Angle")
267
per = per.multiply(l)
270
def makeRoofProfilsDic(self, id, angle, run, idrel, overhang, thickness):
272
profilDico["id"] = id
274
profilDico["name"] = "Gable" + str(id)
275
profilDico["run"] = 0.0
277
profilDico["name"] = "Sloped" + str(id)
278
profilDico["run"] = run
279
profilDico["angle"] = angle
280
profilDico["idrel"] = idrel
281
profilDico["overhang"] = overhang
282
profilDico["thickness"] = thickness
283
profilDico["height"] = None
284
profilDico["points"] = []
285
self.profilsDico.append(profilDico)
287
def calcEdgeGeometry(self, i, edge):
288
profilCurr = self.profilsDico[i]
289
profilCurr["edge"] = edge
290
vec = edge.Vertexes[1].Point.sub(edge.Vertexes[0].Point)
291
profilCurr["vec"] = vec
292
rot = math.degrees(DraftVecUtils.angle(vec))
293
profilCurr["rot"] = rot
295
def helperCalcApex(self, profilCurr, profilOpposite):
296
ptCurr = profilCurr["edge"].Vertexes[0].Point
297
ptOpposite = profilOpposite["edge"].Vertexes[0].Point
298
dis = ptCurr.distanceToLine(ptOpposite, profilOpposite["vec"])
299
if dis < profilCurr["run"] + profilOpposite["run"]:
300
angCurr = profilCurr["angle"]
301
angOpposite = profilOpposite["angle"]
302
return dis / (math.tan(math.radians(angCurr)) / math.tan(math.radians(angOpposite)) + 1.0)
303
return profilCurr["run"]
305
def calcApex(self, i, numEdges):
306
'''Recalculate the run and height if there is an opposite roof segment
307
with a parallel edge, and if the sum of the runs of the segments is
308
larger than the distance between the edges of the segments.
310
profilCurr = self.findProfil(i)
311
if 0 <= profilCurr["idrel"] < numEdges:
313
if not 0.0 < profilCurr["angle"] < 90.0:
315
profilNext2 = self.findProfil(i + 2)
316
profilBack2 = self.findProfil(i - 2)
317
vecCurr = profilCurr["vec"]
318
vecNext2 = profilNext2["vec"]
319
vecBack2 = profilBack2["vec"]
321
if ((not 0 <= profilNext2["idrel"] < numEdges)
322
and 0.0 < profilNext2["angle"] < 90.0
323
and vecCurr.getAngle(vecNext2) == math.pi):
324
runs.append((self.helperCalcApex(profilCurr, profilNext2)))
325
if ((not 0 <= profilBack2["idrel"] < numEdges)
326
and 0.0 < profilBack2["angle"] < 90.0
327
and vecCurr.getAngle(vecBack2) == math.pi):
328
runs.append((self.helperCalcApex(profilCurr, profilBack2)))
330
if len(runs) != 0 and runs[0] != profilCurr["run"]:
331
profilCurr["run"] = runs[0]
332
hgt = self.calcHeight(i)
333
profilCurr["height"] = hgt
335
def calcMissingData(self, i, numEdges):
336
profilCurr = self.profilsDico[i]
337
ang = profilCurr["angle"]
338
run = profilCurr["run"]
339
rel = profilCurr["idrel"]
340
if i != rel and 0 <= rel < numEdges:
341
profilRel = self.profilsDico[rel]
343
if (0 <= profilRel["idrel"] < numEdges
344
and rel != profilRel["idrel"]
345
and (profilRel["angle"] == 0.0 or profilRel["run"] == 0.0)):
346
hgt = self.calcHeight(i)
347
profilCurr["height"] = hgt
348
elif ang == 0.0 and run == 0.0:
349
profilCurr["run"] = profilRel["run"]
350
profilCurr["angle"] = profilRel["angle"]
351
profilCurr["height"] = self.calcHeight(i)
354
htRel = self.calcHeight(rel)
355
profilCurr["height"] = htRel
357
htRel = self.calcHeight(rel)
358
profilCurr["height"] = htRel
359
run = self.calcRun(i)
360
profilCurr["run"] = run
362
htRel = self.calcHeight(rel)
363
profilCurr["height"] = htRel
364
ang = self.calcAngle(i)
365
profilCurr["angle"] = ang
367
hgt = self.calcHeight(i)
368
profilCurr["height"] = hgt
370
hgt = self.calcHeight(i)
371
profilCurr["height"] = hgt
373
def calcDraftEdges(self, i):
374
profilCurr = self.profilsDico[i]
375
edge = profilCurr["edge"]
376
vec = profilCurr["vec"]
377
rot = profilCurr["rot"]
378
ang = profilCurr["angle"]
379
run = profilCurr["run"]
380
if ang != 90 and run == 0.0:
383
overhang = profilCurr["overhang"]
384
per = self.getPerpendicular(vec, rot, overhang).negative()
385
eaveDraft = DraftGeomUtils.offset(edge, per)
386
profilCurr["eaveDraft"] = eaveDraft
387
per = self.getPerpendicular(vec, rot, run)
388
ridge = DraftGeomUtils.offset(edge, per)
389
profilCurr["ridge"] = ridge
391
def calcEave(self, i):
392
profilCurr = self.findProfil(i)
393
ptInterEaves1Lst = find_inters(profilCurr["eaveDraft"], self.findProfil(i - 1)["eaveDraft"])
395
ptInterEaves1 = ptInterEaves1Lst[0]
397
ptInterEaves1 = profilCurr["eaveDraft"].Vertexes[0].Point
398
ptInterEaves2Lst = find_inters(profilCurr["eaveDraft"], self.findProfil(i + 1)["eaveDraft"])
400
ptInterEaves2 = ptInterEaves2Lst[0]
402
ptInterEaves2 = profilCurr["eaveDraft"].Vertexes[1].Point
403
profilCurr["eavePtLst"] = [ptInterEaves1, ptInterEaves2]
405
def findProfil(self, i):
406
if 0 <= i < len(self.profilsDico):
407
profil = self.profilsDico[i]
409
i = abs(abs(i) - len(self.profilsDico))
410
profil = self.profilsDico[i]
413
def helperGable(self, profilCurr, profilOther, isBack):
418
ptIntLst = find_inters(profilCurr["ridge"], profilOther["eaveDraft"])
420
ptProjLst = [ptIntLst[0]]
422
ptProjLst = [profilCurr["ridge"].Vertexes[i].Point]
423
ptProjLst = ptProjLst + [profilCurr["eavePtLst"][i]]
426
for ptProj in ptProjLst:
427
self.ptsPaneProject.append(ptProj)
429
def backGable(self, i):
430
profilCurr = self.findProfil(i)
431
profilBack = self.findProfil(i - 1)
432
self.helperGable(profilCurr, profilBack, isBack = True)
434
def nextGable(self, i):
435
profilCurr = self.findProfil(i)
436
profilNext = self.findProfil(i + 1)
437
self.helperGable(profilCurr, profilNext, isBack = False)
439
def helperSloped(self, profilCurr, profilOther, ridgeCurr, ridgeOther, isBack, otherIsLower=False):
444
ptIntLst = find_inters(ridgeCurr, ridgeOther)
448
ptRidgeLst = find_inters(profilCurr["ridge"], profilOther["ridge"])
449
ptProjLst = [ptRidgeLst[0], ptInt]
452
hip = DraftGeomUtils.edg(ptInt, profilCurr["edge"].Vertexes[i].Point)
453
ptEaveCurrLst = find_inters(hip, profilCurr["eaveDraft"])
454
ptEaveOtherLst = find_inters(hip, profilOther["eaveDraft"])
455
if ptEaveCurrLst and ptEaveOtherLst:
456
lenToEaveCurr = ptEaveCurrLst[0].sub(ptInt).Length
457
lenToEaveOther = ptEaveOtherLst[0].sub(ptInt).Length
458
if lenToEaveCurr < lenToEaveOther:
459
ptProjLst = ptProjLst + [ptEaveCurrLst[0]]
461
ptProjLst = ptProjLst + [ptEaveOtherLst[0],
462
profilCurr["eavePtLst"][i]]
464
ptProjLst = ptProjLst + [ptEaveCurrLst[0]]
466
ptProjLst = ptProjLst + [ptEaveOtherLst[0],
467
profilCurr["eavePtLst"][i]]
469
print("Error determining outline")
471
ptProjLst = [profilCurr["ridge"].Vertexes[i].Point,
472
profilCurr["eavePtLst"][i]]
475
for ptProj in ptProjLst:
476
self.ptsPaneProject.append(ptProj)
478
def backSameHeight(self, i):
479
profilCurr = self.findProfil(i)
480
profilBack = self.findProfil(i - 1)
481
self.helperSloped(profilCurr,
487
def nextSameHeight(self, i):
488
profilCurr = self.findProfil(i)
489
profilNext = self.findProfil(i + 1)
490
self.helperSloped(profilCurr,
496
def backHigher(self, i):
497
profilCurr = self.findProfil(i)
498
profilBack = self.findProfil(i - 1)
499
dec = profilCurr["height"] / math.tan(math.radians(profilBack["angle"]))
500
per = self.getPerpendicular(profilBack["vec"], profilBack["rot"], dec)
501
edgeRidgeOnPane = DraftGeomUtils.offset(profilBack["edge"], per)
502
self.helperSloped(profilCurr,
508
def nextHigher(self, i):
509
profilCurr = self.findProfil(i)
510
profilNext = self.findProfil(i + 1)
511
dec = profilCurr["height"] / math.tan(math.radians(profilNext["angle"]))
512
per = self.getPerpendicular(profilNext["vec"], profilNext["rot"], dec)
513
edgeRidgeOnPane = DraftGeomUtils.offset(profilNext["edge"], per)
514
self.helperSloped(profilCurr,
520
def backLower(self, i):
521
profilCurr = self.findProfil(i)
522
profilBack = self.findProfil(i - 1)
523
dec = profilBack["height"] / math.tan(math.radians(profilCurr["angle"]))
524
per = self.getPerpendicular(profilCurr["vec"], profilCurr["rot"], dec)
525
edgeRidgeOnPane = DraftGeomUtils.offset(profilCurr["edge"], per)
526
self.helperSloped(profilCurr,
533
def nextLower(self, i):
534
profilCurr = self.findProfil(i)
535
profilNext = self.findProfil(i + 1)
536
dec = profilNext["height"] / math.tan(math.radians(profilCurr["angle"]))
537
per = self.getPerpendicular(profilCurr["vec"], profilCurr["rot"], dec)
538
edgeRidgeOnPane = DraftGeomUtils.offset(profilCurr["edge"], per)
539
self.helperSloped(profilCurr,
546
def getRoofPaneProject(self, i):
547
self.ptsPaneProject = []
548
profilCurr = self.findProfil(i)
549
profilBack = self.findProfil(i - 1)
550
profilNext = self.findProfil(i + 1)
551
if profilCurr["angle"] == 90.0 or profilCurr["run"] == 0.0:
552
self.ptsPaneProject = []
554
if profilBack["angle"] == 90.0 or profilBack["run"] == 0.0:
556
elif profilBack["height"] == profilCurr["height"]:
557
self.backSameHeight(i)
558
elif profilBack["height"] < profilCurr["height"]:
560
elif profilBack["height"] > profilCurr["height"]:
563
print("Arch Roof: Case not implemented")
565
if profilNext["angle"] == 90.0 or profilNext["run"] == 0.0:
567
elif profilNext["height"] == profilCurr["height"]:
568
self.nextSameHeight(i)
569
elif profilNext["height"] < profilCurr["height"]:
571
elif profilNext["height"] > profilCurr["height"]:
574
print("Arch Roof: Case not implemented")
576
profilCurr["points"] = self.ptsPaneProject
578
def createProfilShape (self, points, midpoint, rot, vec, run, diag, sol):
580
points.append(points[0])
583
edge = Part.makeLine(points[i],points[i + 1])
584
edgesWire.append(edge)
585
profil = Part.Wire(edgesWire)
586
profil.translate(midpoint)
587
profil.rotate(midpoint, Vector(0.0, 0.0, 1.0), 90.0 - rot)
588
per = self.getPerpendicular(vec, rot, run)
589
profil.rotate(midpoint, per, 90.0)
590
vecT = vec.normalize()
592
profil.translate(vecT)
593
vecE = vecT.multiply(-2.0)
594
profilFace = Part.Face(profil)
595
profilShp = profilFace.extrude(vecE)
596
profilShp = sol.common(profilShp)
600
def execute(self, obj):
608
if hasattr(obj, "Flip"):
614
if hasattr(obj.Base, "Shape"):
615
if obj.Base.Shape.Solids:
616
base = obj.Base.Shape
619
if (obj.Base.Shape.Faces and obj.Face):
620
baseWire = obj.Base.Shape.Faces[obj.Face-1].Wires[0]
621
elif obj.Base.Shape.Wires:
622
baseWire = obj.Base.Shape.Wires[0]
624
if baseWire.isClosed():
625
self.profilsDico = []
629
edges = Part.__sortEdges__(baseWire.Edges)
631
edges = self.flipEdges(edges)
635
obj.Angles = adjust_list_len(obj.Angles, ln, obj.Angles[0])
636
obj.Runs = adjust_list_len(obj.Runs, ln, obj.Runs[0])
637
obj.IdRel = adjust_list_len(obj.IdRel, ln, obj.IdRel[0])
638
obj.Thickness = adjust_list_len(obj.Thickness, ln, obj.Thickness[0])
639
obj.Overhang = adjust_list_len(obj.Overhang, ln, obj.Overhang[0])
642
self.makeRoofProfilsDic(i, obj.Angles[i], obj.Runs[i], obj.IdRel[i], obj.Overhang[i], obj.Thickness[i])
644
self.calcEdgeGeometry(i, edges[i])
648
self.calcMissingData(i, ln)
650
self.calcDraftEdges(i)
653
for profil in self.profilsDico:
654
heights.append(profil["height"])
655
obj.Heights = heights
657
self.getRoofPaneProject(i)
658
profilCurr = self.profilsDico[i]
659
ptsPaneProject = profilCurr["points"]
660
if len(ptsPaneProject) == 0:
662
face = face_from_points(ptsPaneProject)
664
diag = face.BoundBox.DiagonalLength
665
midpoint = DraftGeomUtils.findMidpoint(profilCurr["edge"])
666
thicknessV = profilCurr["thickness"] / (math.cos(math.radians(profilCurr["angle"])))
667
overhangV = profilCurr["overhang"] * math.tan(math.radians(profilCurr["angle"]))
668
sol = face.extrude(Vector(0.0, 0.0, profilCurr["height"] + 1000000.0))
669
sol.translate(Vector(0.0, 0.0, -2.0 * overhangV))
672
ptsPaneProfil = [Vector(-profilCurr["overhang"], -overhangV, 0.0),
673
Vector(profilCurr["run"], profilCurr["height"], 0.0),
674
Vector(profilCurr["run"], profilCurr["height"] + thicknessV, 0.0),
675
Vector(-profilCurr["overhang"], -overhangV + thicknessV, 0.0)]
676
self.shps.append(self.createProfilShape(ptsPaneProfil,
685
ptsSubVolProfil = [Vector(-profilCurr["overhang"], -overhangV, 0.0),
686
Vector(profilCurr["run"], profilCurr["height"], 0.0),
687
Vector(profilCurr["run"], profilCurr["height"] + 900000.0, 0.0),
688
Vector(-profilCurr["overhang"], profilCurr["height"] + 900000.0, 0.0)]
689
self.subVolShps.append(self.createProfilShape(ptsSubVolProfil,
697
if len(self.shps) == 0:
701
ptsPaneProject.append(self.profilsDico[i]["eavePtLst"][0])
702
face = face_from_points(ptsPaneProject)
704
thk = max(1.0, self.profilsDico[0]["thickness"])
705
self.shps = [face.extrude(Vector(0.0, 0.0, thk))]
706
self.subVolShps = [face.extrude(Vector(0.0, 0.0, 1000000.0))]
709
base = self.shps.pop()
712
base = self.processSubShapes(obj, base, pl)
713
self.applyShape(obj, base, pl, allownosolid = True)
716
self.sub = self.subVolShps.pop()
717
for s in self.subVolShps:
718
self.sub = self.sub.fuse(s)
719
self.sub = self.sub.removeSplitter()
720
if not self.sub.isNull():
721
if not DraftGeomUtils.isNull(pl):
722
self.sub.Placement = pl
725
base = self.processSubShapes(obj, base, pl)
726
self.applyShape(obj, base, pl, allownosolid = True)
728
FreeCAD.Console.PrintMessage(translate("Arch", "Unable to create a roof"))
730
def getSubVolume(self, obj):
731
'''returns a volume to be subtracted'''
732
custom_subvolume = getattr(obj, 'Subvolume', None)
734
return custom_subvolume.Shape
739
if not hasattr(obj.Base, "Shape"):
742
if obj.Base.Shape.Solids:
753
for f in obj.Base.Shape.Faces:
768
solid = f.extrude(Vector(0.0, 0.0, 1000000.0))
770
compound = Part.Compound(solids)
773
sub_field = getattr(self, 'sub', None)
779
def computeAreas(self, obj):
780
'''computes border and ridge roof edges length'''
781
if hasattr(obj, "RidgeLength") and hasattr(obj, "BorderLength"):
789
for face in obj.Shape.Faces:
790
if face.normalAt(0, 0).getAngle(Vector(0.0, 0.0, 1.0)) < math.pi / 2.0:
794
shell = Part.Shell(faceLst)
800
for face in shell.Faces:
801
for edge in face.Edges:
804
lut[hc] = lut[hc] + 1
807
for edge in shell.Edges:
808
if lut[edge.hashCode()] == 1:
811
elif lut[edge.hashCode()] == 2:
814
if obj.RidgeLength.Value != rl:
817
if obj.BorderLength.Value != bl:
818
obj.BorderLength = bl
820
ArchComponent.Component.computeAreas(self, obj)
823
class _ViewProviderRoof(ArchComponent.ViewProviderComponent):
824
'''A View Provider for the Roof object'''
825
def __init__(self, vobj):
826
ArchComponent.ViewProviderComponent.__init__(self, vobj)
829
return ":/icons/Arch_Roof_Tree.svg"
831
def attach(self, vobj):
832
self.Object = vobj.Object
835
def setEdit(self, vobj, mode=0):
839
if vobj.Object.Base.Shape.Solids:
840
taskd = ArchComponent.ComponentTaskPanel()
841
taskd.obj = self.Object
843
FreeCADGui.Control.showDialog(taskd)
845
taskd = _RoofTaskPanel()
846
taskd.obj = self.Object
848
FreeCADGui.Control.showDialog(taskd)
853
'''The editmode TaskPanel for Roof objects'''
855
self.updating = False
857
self.form = QtGui.QWidget()
858
self.form.setObjectName("TaskPanel")
859
self.grid = QtGui.QGridLayout(self.form)
860
self.grid.setObjectName("grid")
861
self.title = QtGui.QLabel(self.form)
862
self.grid.addWidget(self.title, 0, 0, 1, 1)
865
self.tree = QtGui.QTreeWidget(self.form)
866
self.grid.addWidget(self.tree, 1, 0, 1, 1)
867
self.tree.setRootIsDecorated(False)
868
self.tree.setColumnCount(7)
869
self.tree.header().resizeSection(0, 37)
870
self.tree.header().resizeSection(1, 70)
871
self.tree.header().resizeSection(2, 62)
872
self.tree.header().resizeSection(3, 37)
873
self.tree.header().resizeSection(4, 60)
874
self.tree.header().resizeSection(5, 60)
875
self.tree.header().resizeSection(6, 70)
877
QtCore.QObject.connect(self.tree, QtCore.SIGNAL("itemChanged(QTreeWidgetItem *, int)"), self.edit)
880
def isAllowedAlterSelection(self):
883
def isAllowedAlterView(self):
886
def getStandardButtons(self):
887
return QtGui.QDialogButtonBox.Close
890
'''fills the treewidget'''
893
root = self.tree.invisibleRootItem()
894
if root.childCount() == 0:
895
for i in range(len(self.obj.Angles)):
896
QtGui.QTreeWidgetItem(self.tree)
897
for i in range(len(self.obj.Angles)):
899
item.setText(0, str(i))
900
item.setText(1, str(self.obj.Angles[i]))
901
item.setText(2, str(self.obj.Runs[i]))
902
item.setText(3, str(self.obj.IdRel[i]))
903
item.setText(4, str(self.obj.Thickness[i]))
904
item.setText(5, str(self.obj.Overhang[i]))
905
item.setText(6, str(self.obj.Heights[i]))
906
item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
909
self.retranslateUi(self.form)
910
self.updating = False
912
def edit(self, item, column):
913
if not self.updating:
916
def resetObject(self, remove=None):
917
'''transfers the values from the widget to the object'''
923
root = self.tree.invisibleRootItem()
924
for it in root.takeChildren():
925
ang.append(float(it.text(1)))
926
run.append(float(it.text(2)))
927
rel.append(int(it.text(3)))
928
thick.append(float(it.text(4)))
929
over.append(float(it.text(5)))
931
self.obj.Angles = ang
933
self.obj.Thickness = thick
934
self.obj.Overhang = over
936
FreeCAD.ActiveDocument.recompute()
940
FreeCAD.ActiveDocument.recompute()
941
FreeCADGui.ActiveDocument.resetEdit()
944
def retranslateUi(self, TaskPanel):
945
TaskPanel.setWindowTitle(QtGui.QApplication.translate("Arch", "Roof", None))
946
self.title.setText(QtGui.QApplication.translate("Arch", "Parameters of the roof profiles :\n* Angle : slope in degrees relative to the horizontal.\n* Run : horizontal distance between the wall and the ridge.\n* Thickness : thickness of the roof.\n* Overhang : horizontal distance between the eave and the wall.\n* Height : height of the ridge above the base (calculated automatically).\n* IdRel : Id of the relative profile used for automatic calculations.\n---\nIf Angle = 0 and Run = 0 then the profile is identical to the relative profile.\nIf Angle = 0 then the angle is calculated so that the height is the same as the relative profile.\nIf Run = 0 then the run is calculated so that the height is the same as the relative profile.", None))
947
self.tree.setHeaderLabels([QtGui.QApplication.translate("Arch", "Id", None),
948
QtGui.QApplication.translate("Arch", "Angle (deg)", None),
949
QtGui.QApplication.translate("Arch", "Run (mm)", None),
950
QtGui.QApplication.translate("Arch", "IdRel", None),
951
QtGui.QApplication.translate("Arch", "Thickness (mm)", None),
952
QtGui.QApplication.translate("Arch", "Overhang (mm)", None),
953
QtGui.QApplication.translate("Arch", "Height (mm)", None)])