Merge remote-tracking branch 'upstream/main' into bim-cleanup-imports
This commit is contained in:
@@ -26,7 +26,6 @@ SET(Arch_SRCS
|
||||
ArchStairs.py
|
||||
ArchSpace.py
|
||||
ArchRebar.py
|
||||
TestArch.py
|
||||
ArchFrame.py
|
||||
ArchPanel.py
|
||||
ArchEquipment.py
|
||||
@@ -46,6 +45,8 @@ SET(Arch_SRCS
|
||||
ArchSketchObject.py
|
||||
BimSelect.py
|
||||
BimStatus.py
|
||||
TestArch.py
|
||||
TestArchGui.py
|
||||
)
|
||||
|
||||
SET(importers_SRCS
|
||||
@@ -196,6 +197,13 @@ SET(nativeifc_SRCS
|
||||
nativeifc/ifc_classification.py
|
||||
)
|
||||
|
||||
SET(bimtests_SRCS
|
||||
bimtests/TestArchBase.py
|
||||
bimtests/TestArchRoof.py
|
||||
bimtests/TestArchSpace.py
|
||||
bimtests/TestArchWall.py
|
||||
)
|
||||
|
||||
SOURCE_GROUP("" FILES ${Arch_SRCS})
|
||||
|
||||
SET(BIMGuiIcon_SVG
|
||||
@@ -214,6 +222,7 @@ ADD_CUSTOM_TARGET(BIM ALL
|
||||
${ArchGuiIcon_SVG}
|
||||
${importers_SRCS}
|
||||
${bimcommands_SRCS}
|
||||
${bimtests_SRCS}
|
||||
${nativeifc_SRCS}
|
||||
${BIMGuiIcon_SVG}
|
||||
)
|
||||
@@ -226,6 +235,7 @@ fc_copy_sources(BIM "${CMAKE_BINARY_DIR}/Mod/BIM" ${Arch_SRCS})
|
||||
fc_copy_sources(BIM "${CMAKE_BINARY_DIR}/Mod/BIM" ${Dice3DS_SRCS})
|
||||
fc_copy_sources(BIM "${CMAKE_BINARY_DIR}/Mod/BIM" ${importers_SRCS})
|
||||
fc_copy_sources(BIM "${CMAKE_BINARY_DIR}/Mod/BIM" ${bimcommands_SRCS})
|
||||
fc_copy_sources(BIM "${CMAKE_BINARY_DIR}/Mod/BIM" ${bimtests_SRCS})
|
||||
fc_copy_sources(BIM "${CMAKE_BINARY_DIR}/Mod/BIM" ${nativeifc_SRCS})
|
||||
fc_copy_sources(BIM "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_DATADIR}/Mod/BIM" ${BIMGuiIcon_SVG})
|
||||
|
||||
@@ -273,6 +283,12 @@ INSTALL(
|
||||
DESTINATION Mod/BIM/bimcommands
|
||||
)
|
||||
|
||||
INSTALL(
|
||||
FILES
|
||||
${bimtests_SRCS}
|
||||
DESTINATION Mod/BIM/bimtests
|
||||
)
|
||||
|
||||
INSTALL(
|
||||
FILES
|
||||
${nativeifc_SRCS}
|
||||
|
||||
@@ -35,3 +35,5 @@ FreeCAD.addExportType("Collada (*.dae)","importers.importDAE")
|
||||
FreeCAD.addImportType("3D Studio mesh (*.3ds *.3DS)","importers.import3DS")
|
||||
FreeCAD.addImportType("SweetHome3D (*.sh3d)","importers.importSH3D")
|
||||
FreeCAD.addImportType("Shapefile (*.shp *.SHP)","importers.importSHP")
|
||||
|
||||
FreeCAD.__unit_test__ += ["TestArch"]
|
||||
@@ -686,6 +686,6 @@ FreeCADGui.addPreferencePage(":/ui/preferences-dae.ui", t)
|
||||
FreeCADGui.addPreferencePage(":/ui/preferences-sh3d-import.ui", t)
|
||||
|
||||
# Add unit tests
|
||||
FreeCAD.__unit_test__ += ["TestArch"]
|
||||
FreeCAD.__unit_test__ += ["TestArchGui"]
|
||||
# The NativeIFC tests require internet connection and file download
|
||||
# FreeCAD.__unit_test__ += ["nativeifc.ifc_selftest"]
|
||||
|
||||
@@ -34,352 +34,12 @@ import Sketcher
|
||||
import TechDraw
|
||||
import WorkingPlane
|
||||
|
||||
from FreeCAD import Units
|
||||
from bimtests.TestArchRoof import TestArchRoof
|
||||
from bimtests.TestArchSpace import TestArchSpace
|
||||
from bimtests.TestArchWall import TestArchWall
|
||||
|
||||
from draftutils.messages import _msg
|
||||
|
||||
if App.GuiUp:
|
||||
import FreeCADGui
|
||||
|
||||
brepArchiCAD = """
|
||||
DBRep_DrawableShape
|
||||
|
||||
CASCADE Topology V1, (c) Matra-Datavision
|
||||
Locations 3
|
||||
1
|
||||
1 0 0 0
|
||||
0 1 0 0
|
||||
0 0 1 0
|
||||
1
|
||||
0 1 0 0
|
||||
-1 0 0 0
|
||||
0 0 1 0
|
||||
2 2 -1 0
|
||||
Curve2ds 0
|
||||
Curves 12
|
||||
1 0 0 0 1 0 0
|
||||
1 3000 0 0 0 0 1
|
||||
1 3000 0 3000 -1 0 0
|
||||
1 0 0 3000 0 0 -1
|
||||
1 0 0 0 0 1 0
|
||||
1 0 5000 0 1 0 0
|
||||
1 3000 5000 0 0 -1 0
|
||||
1 3000 5000 0 0 0 1
|
||||
1 3000 5000 3000 0 -1 0
|
||||
1 3000 5000 3000 -1 0 0
|
||||
1 0 5000 3000 0 -1 0
|
||||
1 0 5000 3000 0 0 -1
|
||||
Polygon3D 0
|
||||
PolygonOnTriangulations 24
|
||||
2 1 2
|
||||
p 18.3333333333333 1 0 3000
|
||||
2 1 4
|
||||
p 18.3333333333333 1 0 3000
|
||||
2 2 3
|
||||
p 18.3333333333333 1 0 3000
|
||||
2 2 4
|
||||
p 18.3333333333333 1 0 3000
|
||||
2 3 4
|
||||
p 18.3333333333333 1 0 3000
|
||||
2 1 2
|
||||
p 18.3333333333333 1 0 3000
|
||||
2 4 1
|
||||
p 18.3333333333333 1 0 3000
|
||||
2 3 1
|
||||
p 18.3333333333333 1 0 3000
|
||||
2 1 2
|
||||
p 18.3333333333333 1 0 5000
|
||||
2 1 2
|
||||
p 18.3333333333333 1 0 5000
|
||||
2 2 3
|
||||
p 18.3333333333333 1 0 3000
|
||||
2 1 2
|
||||
p 18.3333333333333 1 0 3000
|
||||
2 3 4
|
||||
p 18.3333333333333 1 0 5000
|
||||
2 1 2
|
||||
p 18.3333333333333 1 0 5000
|
||||
2 1 3
|
||||
p 18.3333333333333 1 0 3000
|
||||
2 2 4
|
||||
p 18.3333333333333 1 0 3000
|
||||
2 3 4
|
||||
p 18.3333333333333 1 0 5000
|
||||
2 3 1
|
||||
p 18.3333333333333 1 0 5000
|
||||
2 3 4
|
||||
p 18.3333333333333 1 0 3000
|
||||
2 4 3
|
||||
p 18.3333333333333 1 0 3000
|
||||
2 4 2
|
||||
p 18.3333333333333 1 0 5000
|
||||
2 4 3
|
||||
p 18.3333333333333 1 0 5000
|
||||
2 4 2
|
||||
p 18.3333333333333 1 0 3000
|
||||
2 3 1
|
||||
p 18.3333333333333 1 0 3000
|
||||
Surfaces 6
|
||||
1 1500 0 1500 -0 -1 -0 0 0 -1 1 0 0
|
||||
1 1500 2500 0 -0 -0 -1 -1 0 0 0 1 0
|
||||
1 3000 2500 1500 1 0 0 0 0 1 0 -1 0
|
||||
1 1500 2500 3000 0 0 1 1 0 0 0 1 0
|
||||
1 0 2500 1500 -1 -0 -0 0 0 -1 0 -1 0
|
||||
1 1500 5000 1500 0 1 0 0 0 1 1 0 0
|
||||
Triangulations 6
|
||||
4 2 1 18.3333333333333
|
||||
0 0 0 3000 0 0 3000 0 3000 0 0 3000 1500 -1500 1500 1500 -1500 1500 -1500 -1500 3 4 1 2 3 1
|
||||
4 2 1 18.3333333333333
|
||||
0 0 0 0 5000 0 3000 5000 0 3000 0 0 1500 -2500 1500 2500 -1500 2500 -1500 -2500 2 3 4 2 4 1
|
||||
4 2 1 18.3333333333333
|
||||
3000 5000 0 3000 0 0 3000 5000 3000 3000 0 3000 -1500 -2500 -1500 2500 1500 -2500 1500 2500 4 2 1 4 1 3
|
||||
4 2 1 18.3333333333333
|
||||
3000 0 3000 0 0 3000 3000 5000 3000 0 5000 3000 1500 -2500 -1500 -2500 1500 2500 -1500 2500 3 2 1 3 4 2
|
||||
4 2 1 18.3333333333333
|
||||
0 0 0 0 5000 0 0 0 3000 0 5000 3000 1500 2500 1500 -2500 -1500 2500 -1500 -2500 1 3 4 1 4 2
|
||||
4 2 1 18.3333333333333
|
||||
0 5000 0 3000 5000 0 0 5000 3000 3000 5000 3000 -1500 -1500 -1500 1500 1500 -1500 1500 1500 3 2 1 4 2 3
|
||||
|
||||
TShapes 35
|
||||
Ve
|
||||
0.1
|
||||
0 0 0
|
||||
0 0
|
||||
|
||||
0101101
|
||||
*
|
||||
Ve
|
||||
0.1
|
||||
0 -3000 0
|
||||
0 0
|
||||
|
||||
0101101
|
||||
*
|
||||
Ed
|
||||
0.0001 1 1 0
|
||||
1 1 0 0 3000
|
||||
6 1 1 0
|
||||
6 2 2 0
|
||||
0
|
||||
|
||||
0101000
|
||||
+35 3 -34 3 *
|
||||
Ve
|
||||
0.1
|
||||
0 -3000 3000
|
||||
0 0
|
||||
|
||||
0101101
|
||||
*
|
||||
Ed
|
||||
0.0001 1 1 0
|
||||
1 2 0 0 3000
|
||||
6 3 1 0
|
||||
6 4 3 0
|
||||
0
|
||||
|
||||
0101000
|
||||
+34 3 -32 3 *
|
||||
Ve
|
||||
0.1
|
||||
0 0 3000
|
||||
0 0
|
||||
|
||||
0101101
|
||||
*
|
||||
Ed
|
||||
0.0001 1 1 0
|
||||
1 3 0 0 3000
|
||||
6 5 1 0
|
||||
6 6 4 0
|
||||
0
|
||||
|
||||
0101000
|
||||
+32 3 -30 3 *
|
||||
Ed
|
||||
0.0001 1 1 0
|
||||
1 4 0 0 3000
|
||||
6 7 1 0
|
||||
6 8 5 0
|
||||
0
|
||||
|
||||
0101000
|
||||
+30 3 -35 3 *
|
||||
Wi
|
||||
|
||||
0101100
|
||||
+33 0 +31 0 +29 0 +28 0 *
|
||||
Fa
|
||||
0 0.1 1 0
|
||||
2 1
|
||||
0111000
|
||||
+27 0 *
|
||||
Ve
|
||||
0.1
|
||||
5000 0 0
|
||||
0 0
|
||||
|
||||
0101101
|
||||
*
|
||||
Ed
|
||||
0.0001 1 1 0
|
||||
1 5 0 0 5000
|
||||
6 9 2 0
|
||||
6 10 5 0
|
||||
0
|
||||
|
||||
0101000
|
||||
+35 3 -25 3 *
|
||||
Ve
|
||||
0.1
|
||||
5000 -3000 0
|
||||
0 0
|
||||
|
||||
0101101
|
||||
*
|
||||
Ed
|
||||
0.0001 1 1 0
|
||||
1 6 0 0 3000
|
||||
6 11 2 0
|
||||
6 12 6 0
|
||||
0
|
||||
|
||||
0101000
|
||||
+25 3 -23 3 *
|
||||
Ed
|
||||
0.0001 1 1 0
|
||||
1 7 0 0 5000
|
||||
6 13 2 0
|
||||
6 14 3 0
|
||||
0
|
||||
|
||||
0101000
|
||||
+23 3 -34 3 *
|
||||
Wi
|
||||
|
||||
0101100
|
||||
+24 0 +22 0 +21 0 -33 0 *
|
||||
Fa
|
||||
0 0.1 2 0
|
||||
2 2
|
||||
0111000
|
||||
+20 0 *
|
||||
Ve
|
||||
0.1
|
||||
5000 -3000 3000
|
||||
0 0
|
||||
|
||||
0101101
|
||||
*
|
||||
Ed
|
||||
0.0001 1 1 0
|
||||
1 8 0 0 3000
|
||||
6 15 3 0
|
||||
6 16 6 0
|
||||
0
|
||||
|
||||
0101000
|
||||
+23 3 -18 3 *
|
||||
Ed
|
||||
0.0001 1 1 0
|
||||
1 9 0 0 5000
|
||||
6 17 3 0
|
||||
6 18 4 0
|
||||
0
|
||||
|
||||
0101000
|
||||
+18 3 -32 3 *
|
||||
Wi
|
||||
|
||||
0101100
|
||||
-21 0 +17 0 +16 0 -31 0 *
|
||||
Fa
|
||||
0 0.1 3 0
|
||||
2 3
|
||||
0111000
|
||||
+15 0 *
|
||||
Ve
|
||||
0.1
|
||||
5000 0 3000
|
||||
0 0
|
||||
|
||||
0101101
|
||||
*
|
||||
Ed
|
||||
0.0001 1 1 0
|
||||
1 10 0 0 3000
|
||||
6 19 4 0
|
||||
6 20 6 0
|
||||
0
|
||||
|
||||
0101000
|
||||
+18 3 -13 3 *
|
||||
Ed
|
||||
0.0001 1 1 0
|
||||
1 11 0 0 5000
|
||||
6 21 4 0
|
||||
6 22 5 0
|
||||
0
|
||||
|
||||
0101000
|
||||
+13 3 -30 3 *
|
||||
Wi
|
||||
|
||||
0101100
|
||||
-29 0 -16 0 +12 0 +11 0 *
|
||||
Fa
|
||||
0 0.1 4 0
|
||||
2 4
|
||||
0111000
|
||||
+10 0 *
|
||||
Ed
|
||||
0.0001 1 1 0
|
||||
1 12 0 0 3000
|
||||
6 23 5 0
|
||||
6 24 6 0
|
||||
0
|
||||
|
||||
0101000
|
||||
+13 3 -25 3 *
|
||||
Wi
|
||||
|
||||
0101100
|
||||
-24 0 -28 0 -11 0 +8 0 *
|
||||
Fa
|
||||
0 0.1 5 0
|
||||
2 5
|
||||
0111000
|
||||
+7 0 *
|
||||
Wi
|
||||
|
||||
0101100
|
||||
-22 0 -8 0 -12 0 -17 0 *
|
||||
Fa
|
||||
0 0.1 6 0
|
||||
2 6
|
||||
0111000
|
||||
+5 0 *
|
||||
Sh
|
||||
|
||||
0101100
|
||||
+26 0 +19 0 +14 0 +9 0 +6 0 +4 0 *
|
||||
So
|
||||
|
||||
0100000
|
||||
+3 0 *
|
||||
Co
|
||||
|
||||
1100000
|
||||
+2 2 *
|
||||
|
||||
+1 1
|
||||
"""
|
||||
|
||||
def like(a, b):
|
||||
return abs(a-b) < 0.001
|
||||
|
||||
def checkBB(a, b):
|
||||
return like(a.XMin, b.XMin) and like(a.YMin, b.YMin) and like(a.ZMin, b.ZMin) and like(a.XMax, b.XMax) and like(a.YMax, b.YMax) and like(a.ZMax, b.ZMax)
|
||||
|
||||
|
||||
class ArchTest(unittest.TestCase):
|
||||
|
||||
@@ -392,72 +52,11 @@ class ArchTest(unittest.TestCase):
|
||||
App.newDocument("ArchTest")
|
||||
App.setActiveDocument("ArchTest")
|
||||
|
||||
def testWall(self):
|
||||
App.Console.PrintLog ('Checking Arch Wall...\n')
|
||||
l=Draft.makeLine(App.Vector(0,0,0),App.Vector(-2,0,0))
|
||||
w = Arch.makeWall(l)
|
||||
self.assertTrue(w,"Arch Wall failed")
|
||||
|
||||
def testWallMultiMatAlign(self):
|
||||
App.Console.PrintLog ('Checking Arch Wall with MultiMaterial and 3 alignments...\n')
|
||||
matA = Arch.makeMaterial()
|
||||
matB = Arch.makeMaterial()
|
||||
matMulti = Arch.makeMultiMaterial()
|
||||
matMulti.Materials = [matA, matB]
|
||||
matMulti.Thicknesses = [100, 200] # total width different from default 200
|
||||
pts = [App.Vector( 0, 0, 0),
|
||||
App.Vector(1000, 0, 0),
|
||||
App.Vector(1000, 1000, 0),
|
||||
App.Vector(2000, 1000, 0)]
|
||||
# wall based on wire:
|
||||
wire = Draft.makeWire(pts)
|
||||
wallWire = Arch.makeWall(wire)
|
||||
wallWire.Material = matMulti
|
||||
# wall based on sketch:
|
||||
sketch = App.activeDocument().addObject('Sketcher::SketchObject','Sketch')
|
||||
sketch.addGeometry([Part.LineSegment(pts[0], pts[1]),
|
||||
Part.LineSegment(pts[1], pts[2]),
|
||||
Part.LineSegment(pts[2], pts[3])])
|
||||
wallSketch = Arch.makeWall(sketch)
|
||||
wallSketch.Material = matMulti
|
||||
|
||||
alignLst = ["Left", "Center", "Right"]
|
||||
checkLst = [[App.Vector(0, -300, 0), App.Vector(2000, 1000, 0)],
|
||||
[App.Vector(0, -150, 0), App.Vector(2000, 1150, 0)],
|
||||
[App.Vector(0, 0, 0), App.Vector(2000, 1300, 0)]]
|
||||
for i in range(3):
|
||||
wallWire.Align = alignLst[i]
|
||||
wallSketch.Align = alignLst[i]
|
||||
App.ActiveDocument.recompute()
|
||||
for box in [wallWire.Shape.BoundBox, wallSketch.Shape.BoundBox]:
|
||||
ptMin = App.Vector(box.XMin, box.YMin, 0)
|
||||
self.assertTrue(ptMin.isEqual(checkLst[i][0], 1e-8),
|
||||
"Arch Wall with MultiMaterial and 3 alignments failed")
|
||||
ptMax = App.Vector(box.XMax, box.YMax, 0)
|
||||
self.assertTrue(ptMax.isEqual(checkLst[i][1], 1e-8),
|
||||
"Arch Wall with MultiMaterial and 3 alignments failed")
|
||||
|
||||
def testStructure(self):
|
||||
App.Console.PrintLog ('Checking BIM Structure...\n')
|
||||
s = Arch.makeStructure(length=2,width=3,height=5)
|
||||
self.assertTrue(s,"BIM Structure failed")
|
||||
|
||||
def testRebar(self):
|
||||
App.Console.PrintLog ('Checking Arch Rebar...\n')
|
||||
s = Arch.makeStructure(length=2,width=3,height=5)
|
||||
sk = App.ActiveDocument.addObject('Sketcher::SketchObject','Sketch')
|
||||
sk.AttachmentSupport = (s,["Face6"])
|
||||
sk.addGeometry(Part.LineSegment(App.Vector(-0.85,1.25,0),App.Vector(0.75,1.25,0)))
|
||||
sk.addGeometry(Part.LineSegment(App.Vector(0.75,1.25,0),App.Vector(0.75,-1.20,0)))
|
||||
sk.addGeometry(Part.LineSegment(App.Vector(0.75,-1.20,0),App.Vector(-0.85,-1.20,0)))
|
||||
sk.addGeometry(Part.LineSegment(App.Vector(-0.85,-1.20,0),App.Vector(-0.85,1.25,0)))
|
||||
sk.addConstraint(Sketcher.Constraint('Coincident',0,2,1,1))
|
||||
sk.addConstraint(Sketcher.Constraint('Coincident',1,2,2,1))
|
||||
sk.addConstraint(Sketcher.Constraint('Coincident',2,2,3,1))
|
||||
sk.addConstraint(Sketcher.Constraint('Coincident',3,2,0,1))
|
||||
r = Arch.makeRebar(s,sk,diameter=.1,amount=2)
|
||||
self.assertTrue(r,"Arch Rebar failed")
|
||||
|
||||
def testFloor(self):
|
||||
App.Console.PrintLog ('Checking Arch Floor...\n')
|
||||
s = Arch.makeStructure(length=2,width=3,height=5)
|
||||
@@ -500,113 +99,6 @@ class ArchTest(unittest.TestCase):
|
||||
App.ActiveDocument.recompute()
|
||||
self.assertTrue(win, "'{}' failed".format(operation))
|
||||
|
||||
def testRoof(self):
|
||||
App.Console.PrintLog ('Checking Arch Roof...\n')
|
||||
r = Draft.makeRectangle(length=2,height=-1)
|
||||
r.recompute() # required before calling Arch.makeRoof
|
||||
ro = Arch.makeRoof(r)
|
||||
self.assertTrue(ro,"Arch Roof failed")
|
||||
|
||||
def testRoof81Permutations(self):
|
||||
"""Create 81 roofs using a range of arguments.
|
||||
"""
|
||||
operation = "Arch Roof testRoof81Permutations"
|
||||
_msg(" Test '{}'".format(operation))
|
||||
pts = [App.Vector( 0, 0, 0),
|
||||
App.Vector(2000, 0, 0),
|
||||
App.Vector(4000, 0, 0),
|
||||
App.Vector(4000, 4000, 0),
|
||||
App.Vector( 0, 4000, 0)]
|
||||
ptsMod = [App.Vector(2000, 0, 0),
|
||||
App.Vector(2000, -1000, 0),
|
||||
App.Vector(2000, 1000, 0)]
|
||||
angsMod = [[60, 60], [30, 60], [60, 30]]
|
||||
runsMod = [[500, 500], [400, 500], [500, 400]]
|
||||
overhangsMod = [[100, 100], [100, 200], [200, 100]]
|
||||
delta = 6000
|
||||
pla = App.Placement()
|
||||
for iY in range(9):
|
||||
for iX in range(9):
|
||||
pts[1] = ptsMod[iY % 3] # to get different edge angles
|
||||
angsLst = angsMod[iY // 3] + [90, 90, 90]
|
||||
runsLst = runsMod[iX % 3] + [0, 0, 0]
|
||||
overhangsLst = overhangsMod[iX // 3] + [0, 0, 0]
|
||||
pla.Base = App.Vector(iX * delta, iY * delta, 0)
|
||||
wire = Draft.makeWire(pts, closed = True)
|
||||
wire.MakeFace = False
|
||||
wire.Placement = pla
|
||||
wire.recompute() # required before calling Arch.makeRoof
|
||||
roof = Arch.makeRoof(wire,
|
||||
angles = angsLst,
|
||||
run = runsLst,
|
||||
overhang = overhangsLst)
|
||||
roof.recompute()
|
||||
self.assertFalse(roof.Shape.isNull(),
|
||||
"'{}' failed".format(operation))
|
||||
self.assertTrue(roof.Shape.isValid(),
|
||||
"'{}' failed".format(operation))
|
||||
|
||||
def testRoofAllAngles90(self):
|
||||
"""Create a roof with the angles of all segments set at 90 degrees.
|
||||
This corner case results in a flat roof.
|
||||
"""
|
||||
operation = "Arch Roof testRoofAllAngles90"
|
||||
_msg(" Test '{}'".format(operation))
|
||||
pts = [App.Vector( 0, 0, 0),
|
||||
App.Vector(2000, 0, 0),
|
||||
App.Vector(2000, 2000, 0),
|
||||
App.Vector( 0, 2000, 0)]
|
||||
|
||||
wire = Draft.makeWire(pts, closed = True)
|
||||
wire.MakeFace = False
|
||||
wire.recompute() # required before calling Arch.makeRoof
|
||||
roof = Arch.makeRoof(wire,
|
||||
angles = [90, 90, 90, 90])
|
||||
roof.recompute()
|
||||
self.assertFalse(roof.Shape.isNull(), "'{}' failed".format(operation))
|
||||
self.assertTrue(roof.Shape.isValid(), "'{}' failed".format(operation))
|
||||
|
||||
def testRoofApex(self):
|
||||
"""Create a hipped roof that relies on apex calculation. The roof has
|
||||
2 triangular segments with a single apex point.
|
||||
"""
|
||||
operation = "Arch Roof testRoofApex"
|
||||
_msg(" Test '{}'".format(operation))
|
||||
rec = Draft.makeRectangle(length = 4000,
|
||||
height = 3000,
|
||||
face = False)
|
||||
rec.recompute() # required before calling Arch.makeRoof
|
||||
roof = Arch.makeRoof(rec,
|
||||
angles = [30, 40, 50, 60],
|
||||
run = [2000, 0, 2000, 0],
|
||||
idrel = [-1, 0, -1, 0],
|
||||
thickness = [50.0],
|
||||
overhang = [100.0])
|
||||
roof.recompute()
|
||||
self.assertFalse(roof.Shape.isNull(), "'{}' failed".format(operation))
|
||||
self.assertTrue(roof.Shape.isValid(), "'{}' failed".format(operation))
|
||||
|
||||
def testRoofSingleEavePoint(self):
|
||||
"""Create a roof with a single triangular segment that has a single
|
||||
eave point.
|
||||
"""
|
||||
operation = "Arch Roof testRoofSingleEavePoint"
|
||||
_msg(" Test '{}'".format(operation))
|
||||
pts = [App.Vector( 0, 0, 0),
|
||||
App.Vector( 2000, 0, 0),
|
||||
App.Vector( 4000, 2000, 0),
|
||||
App.Vector(-2000, 2000, 0)]
|
||||
wire = Draft.makeWire(pts, closed = True)
|
||||
wire.MakeFace = False
|
||||
wire.recompute() # required before calling Arch.makeRoof
|
||||
roof = Arch.makeRoof(wire,
|
||||
angles = [45, 90, 90, 90],
|
||||
run = [1000, 0, 0, 0],
|
||||
overhang = [1000, 0, 0, 0])
|
||||
roof.recompute()
|
||||
self.assertFalse(roof.Shape.isNull(), "'{}' failed".format(operation))
|
||||
self.assertTrue(roof.Shape.isValid(), "'{}' failed".format(operation))
|
||||
|
||||
def testAxis(self):
|
||||
App.Console.PrintLog ('Checking Arch Axis...\n')
|
||||
a = Arch.makeAxis()
|
||||
@@ -617,27 +109,6 @@ class ArchTest(unittest.TestCase):
|
||||
s = Arch.makeSectionPlane([])
|
||||
self.assertTrue(s,"Arch Section failed")
|
||||
|
||||
def testSpace(self):
|
||||
App.Console.PrintLog ('Checking Arch Space...\n')
|
||||
sb = Part.makeBox(1,1,1)
|
||||
b = App.ActiveDocument.addObject('Part::Feature','Box')
|
||||
b.Shape = sb
|
||||
s = Arch.makeSpace([b])
|
||||
self.assertTrue(s,"Arch Space failed")
|
||||
|
||||
def testSpaceBBox(self):
|
||||
shape = Part.Shape()
|
||||
shape.importBrepFromString(brepArchiCAD)
|
||||
bborig = shape.BoundBox
|
||||
App.Console.PrintLog ("Original BB: "+str(bborig))
|
||||
baseobj = App.ActiveDocument.addObject("Part::Feature","brepArchiCAD_body")
|
||||
baseobj.Shape = shape
|
||||
space = Arch.makeSpace(baseobj)
|
||||
space.recompute()
|
||||
bbnew = space.Shape.BoundBox
|
||||
App.Console.PrintLog ("New BB: "+str(bbnew))
|
||||
self.assertTrue(checkBB(bborig,bbnew),"Arch Space has wrong Placement")
|
||||
|
||||
def testStairs(self):
|
||||
App.Console.PrintLog ('Checking Arch Stairs...\n')
|
||||
s = Arch.makeStairs()
|
||||
@@ -690,89 +161,6 @@ class ArchTest(unittest.TestCase):
|
||||
r = (w.Shape.Volume < 0.75)
|
||||
self.assertTrue(r,"Arch Remove failed")
|
||||
|
||||
def testBuildingPart(self):
|
||||
"""Create a BuildingPart from a wall with a window and check its shape.
|
||||
"""
|
||||
# Also regression test for:
|
||||
# https://github.com/FreeCAD/FreeCAD/issues/6178
|
||||
operation = "Arch BuildingPart"
|
||||
_msg(" Test '{}'".format(operation))
|
||||
# Most of the code below taken from testWindow function.
|
||||
line = Draft.makeLine(App.Vector(0, 0, 0), App.Vector(3000, 0, 0))
|
||||
wall = Arch.makeWall(line)
|
||||
sk = App.ActiveDocument.addObject("Sketcher::SketchObject", "Sketch001")
|
||||
sk.Placement.Rotation = App.Rotation(App.Vector(1, 0, 0), 90)
|
||||
sk.addGeometry(Part.LineSegment(App.Vector( 500, 800, 0), App.Vector(1500, 800, 0)))
|
||||
sk.addGeometry(Part.LineSegment(App.Vector(1500, 800, 0), App.Vector(1500, 2000, 0)))
|
||||
sk.addGeometry(Part.LineSegment(App.Vector(1500, 2000, 0), App.Vector( 500, 2000, 0)))
|
||||
sk.addGeometry(Part.LineSegment(App.Vector( 500, 2000, 0), App.Vector( 500, 800, 0)))
|
||||
sk.addConstraint(Sketcher.Constraint('Coincident', 0, 2, 1, 1))
|
||||
sk.addConstraint(Sketcher.Constraint('Coincident', 1, 2, 2, 1))
|
||||
sk.addConstraint(Sketcher.Constraint('Coincident', 2, 2, 3, 1))
|
||||
sk.addConstraint(Sketcher.Constraint('Coincident', 3, 2, 0, 1))
|
||||
App.ActiveDocument.recompute()
|
||||
win = Arch.makeWindow(sk)
|
||||
Arch.removeComponents(win, host=wall)
|
||||
App.ActiveDocument.recompute()
|
||||
bp = Arch.makeBuildingPart()
|
||||
|
||||
# Wall visibility works when standalone
|
||||
FreeCADGui.Selection.clearSelection()
|
||||
FreeCADGui.Selection.addSelection('ArchTest',wall.Name)
|
||||
assert wall.Visibility
|
||||
FreeCADGui.runCommand('Std_ToggleVisibility',0)
|
||||
App.ActiveDocument.recompute()
|
||||
assert not wall.Visibility
|
||||
FreeCADGui.runCommand('Std_ToggleVisibility',0)
|
||||
assert wall.Visibility
|
||||
|
||||
bp.Group = [wall]
|
||||
App.ActiveDocument.recompute()
|
||||
# Fails with OCC 7.5
|
||||
# self.assertTrue(len(bp.Shape.Faces) == 16, "'{}' failed".format(operation))
|
||||
|
||||
# Wall visibility works when inside a BuildingPart
|
||||
FreeCADGui.runCommand('Std_ToggleVisibility',0)
|
||||
App.ActiveDocument.recompute()
|
||||
assert not wall.Visibility
|
||||
FreeCADGui.runCommand('Std_ToggleVisibility',0)
|
||||
assert wall.Visibility
|
||||
|
||||
# Wall visibility works when BuildingPart Toggled
|
||||
FreeCADGui.Selection.clearSelection()
|
||||
FreeCADGui.Selection.addSelection('ArchTest',bp.Name)
|
||||
FreeCADGui.runCommand('Std_ToggleVisibility',0)
|
||||
assert not wall.Visibility
|
||||
FreeCADGui.runCommand('Std_ToggleVisibility',0)
|
||||
assert wall.Visibility
|
||||
|
||||
# Wall visibiity works inside group inside BuildingPart Toggled
|
||||
grp = App.ActiveDocument.addObject("App::DocumentObjectGroup","Group")
|
||||
grp.Label="Group"
|
||||
grp.Group = [wall]
|
||||
bp.Group = [grp]
|
||||
App.ActiveDocument.recompute()
|
||||
assert wall.Visibility
|
||||
FreeCADGui.runCommand('Std_ToggleVisibility',0)
|
||||
App.ActiveDocument.recompute()
|
||||
assert not wall.Visibility
|
||||
FreeCADGui.runCommand('Std_ToggleVisibility',0)
|
||||
App.ActiveDocument.recompute()
|
||||
assert wall.Visibility
|
||||
|
||||
def testImportSH3D(self):
|
||||
"""Import a SweetHome 3D file
|
||||
"""
|
||||
operation = "importers.importSH3D"
|
||||
_msg(" Test '{}'".format(operation))
|
||||
import BIM.importers.importSH3DHelper
|
||||
importer = BIM.importers.importSH3DHelper.SH3DImporter(None)
|
||||
importer.import_sh3d_from_string(SH3D_HOME)
|
||||
assert App.ActiveDocument.Site
|
||||
assert App.ActiveDocument.BuildingPart.Label == "Building"
|
||||
assert App.ActiveDocument.BuildingPart001.Label == "Level"
|
||||
assert App.ActiveDocument.Wall
|
||||
|
||||
def testViewGeneration(self):
|
||||
"""Tests the whole TD view generation workflow"""
|
||||
|
||||
@@ -819,173 +207,11 @@ class ArchTest(unittest.TestCase):
|
||||
App.ActiveDocument.recompute()
|
||||
assert True
|
||||
|
||||
def test_addSpaceBoundaries(self):
|
||||
"""Test the Arch.addSpaceBoundaries method.
|
||||
Create a space and a wall that intersects it. Add the wall as a boundary to the space,
|
||||
and check if the resulting space area is as expected.
|
||||
"""
|
||||
operation = " Add a wall face as a boundary to a space"
|
||||
_msg(" Test '{}'".format(operation))
|
||||
|
||||
# Create the space
|
||||
pl = App.Placement()
|
||||
pl.Rotation.Q = (0.0, 0.0, 0.0, 1.0)
|
||||
pl.Base = App.Vector(-2000.0, -2000.0, 0.0)
|
||||
rectangleBase = Draft.make_rectangle(
|
||||
length=4000.0, height=4000.0, placement=pl, face=True, support=None)
|
||||
App.ActiveDocument.recompute()
|
||||
extr = rectangleBase.Shape.extrude(App.Vector(0,0,2000))
|
||||
Part.show(extr, 'Extrusion')
|
||||
space = Arch.makeSpace(App.activeDocument().getObject('Extrusion'))
|
||||
App.ActiveDocument.recompute() # To calculate area
|
||||
|
||||
# Create the wall
|
||||
trace = Part.LineSegment(App.Vector (3000.0, 1000.0, 0.0),
|
||||
App.Vector (-3000.0, 1000.0, 0.0))
|
||||
wp = WorkingPlane.get_working_plane()
|
||||
base = App.ActiveDocument.addObject("Sketcher::SketchObject","WallTrace")
|
||||
base.Placement = wp.get_placement()
|
||||
base.addGeometry(trace)
|
||||
wall = Arch.makeWall(base,width=200.0,height=3000.0,align="Left")
|
||||
wall.Normal = wp.axis
|
||||
|
||||
# Add the boundary
|
||||
wallBoundary = [(wall, ["Face1"])]
|
||||
Arch.addSpaceBoundaries(App.ActiveDocument.Space, wallBoundary)
|
||||
App.ActiveDocument.recompute() # To recalculate area
|
||||
|
||||
# Assert if area is as expected
|
||||
expectedArea = Units.parseQuantity('12 m^2')
|
||||
actualArea = Units.parseQuantity(str(space.Area))
|
||||
|
||||
self.assertAlmostEqual(
|
||||
expectedArea.Value,
|
||||
actualArea.Value,
|
||||
msg = (f"Invalid area value. " +
|
||||
f"Expected: {expectedArea.UserString}, actual: {actualArea.UserString}"))
|
||||
|
||||
def test_SpaceFromSingleWall(self):
|
||||
"""Create a space from boundaries of a single wall.
|
||||
"""
|
||||
from FreeCAD import Units
|
||||
|
||||
operation = "Arch Space from single wall"
|
||||
_msg(f"\n Test '{operation}'")
|
||||
|
||||
# Create a wall
|
||||
wallInnerLength = 4000.0
|
||||
wallHeight = 3000.0
|
||||
wallInnerFaceArea = wallInnerLength * wallHeight
|
||||
pl = App.Placement()
|
||||
pl.Rotation.Q = (0.0, 0.0, 0.0, 1.0)
|
||||
pl.Base = App.Vector(0.0, 0.0, 0.0)
|
||||
rectangleBase = Draft.make_rectangle(
|
||||
length=wallInnerLength, height=wallInnerLength, placement=pl, face=True, support=None)
|
||||
App.ActiveDocument.recompute() # To calculate rectangle area
|
||||
rectangleArea = rectangleBase.Area
|
||||
App.ActiveDocument.getObject(rectangleBase.Name).MakeFace = False
|
||||
wall = Arch.makeWall(baseobj=rectangleBase, height=wallHeight, align="Left")
|
||||
App.ActiveDocument.recompute() # To calculate face areas
|
||||
|
||||
# Create a space from the wall's inner faces
|
||||
boundaries = [f"Face{ind+1}" for ind, face in enumerate(wall.Shape.Faces)
|
||||
if round(face.Area) == round(wallInnerFaceArea)]
|
||||
|
||||
if App.GuiUp:
|
||||
FreeCADGui.Selection.clearSelection()
|
||||
FreeCADGui.Selection.addSelection(wall, boundaries)
|
||||
|
||||
space = Arch.makeSpace(FreeCADGui.Selection.getSelectionEx())
|
||||
# Alternative, but test takes longer to run (~10x)
|
||||
# FreeCADGui.activateWorkbench("BIMWorkbench")
|
||||
# FreeCADGui.runCommand('Arch_Space', 0)
|
||||
# space = App.ActiveDocument.Space
|
||||
else:
|
||||
# Also tests the alternative way of specifying the boundaries
|
||||
# [ (<Part::PartFeature>, ["Face1", ...]), ... ]
|
||||
space = Arch.makeSpace([(wall, boundaries)])
|
||||
|
||||
App.ActiveDocument.recompute() # To calculate space area
|
||||
|
||||
# Assert if area is as expected
|
||||
expectedArea = Units.parseQuantity(str(rectangleArea))
|
||||
actualArea = Units.parseQuantity(str(space.Area))
|
||||
|
||||
self.assertAlmostEqual(
|
||||
expectedArea.Value,
|
||||
actualArea.Value,
|
||||
msg = f"Invalid area value. Expected: {expectedArea.UserString}, actual: {actualArea.UserString}")
|
||||
|
||||
def tearDown(self):
|
||||
App.closeDocument("ArchTest")
|
||||
pass
|
||||
|
||||
|
||||
SH3D_HOME = """<?xml version='1.0'?>
|
||||
<home version='7200' name='0-JoinWall.sh3d' camera='topCamera' wallHeight='250.0'>
|
||||
<property name='com.eteks.sweethome3d.SweetHome3D.CatalogPaneDividerLocation' value='327'/>
|
||||
<property name='com.eteks.sweethome3d.SweetHome3D.ColumnWidths' value='100,84,82,85,84'/>
|
||||
<property name='com.eteks.sweethome3d.SweetHome3D.FrameHeight' value='576'/>
|
||||
<property name='com.eteks.sweethome3d.SweetHome3D.FrameMaximized' value='true'/>
|
||||
<property name='com.eteks.sweethome3d.SweetHome3D.FrameWidth' value='1092'/>
|
||||
<property name='com.eteks.sweethome3d.SweetHome3D.FrameX' value='50'/>
|
||||
<property name='com.eteks.sweethome3d.SweetHome3D.FrameY' value='87'/>
|
||||
<property name='com.eteks.sweethome3d.SweetHome3D.MainPaneDividerLocation' value='441'/>
|
||||
<property name='com.eteks.sweethome3d.SweetHome3D.PlanPaneDividerLocation' value='263'/>
|
||||
<property name='com.eteks.sweethome3d.SweetHome3D.PlanScale' value='0.21343713'/>
|
||||
<property name='com.eteks.sweethome3d.SweetHome3D.PlanViewportX' value='0'/>
|
||||
<property name='com.eteks.sweethome3d.SweetHome3D.PlanViewportY' value='0'/>
|
||||
<property name='com.eteks.sweethome3d.SweetHome3D.ScreenHeight' value='720'/>
|
||||
<property name='com.eteks.sweethome3d.SweetHome3D.ScreenWidth' value='1366'/>
|
||||
<furnitureVisibleProperty name='NAME'/>
|
||||
<furnitureVisibleProperty name='WIDTH'/>
|
||||
<furnitureVisibleProperty name='DEPTH'/>
|
||||
<furnitureVisibleProperty name='HEIGHT'/>
|
||||
<furnitureVisibleProperty name='VISIBLE'/>
|
||||
<environment groundColor='FFB78744' skyColor='00CCE4FC' lightColor='00D0D0D0' ceillingLightColor='00D0D0D0' photoWidth='400' photoHeight='300' photoAspectRatio='VIEW_3D_RATIO' photoQuality='0' videoWidth='320' videoAspectRatio='RATIO_4_3' videoQuality='0' videoFrameRate='25'>
|
||||
<texture attribute='skyTexture' name='Cloudy' creator='eTeks' catalogId='eTeks#cloudy' width='100.0' height='27.6' image='0'/>
|
||||
</environment>
|
||||
<compass x='-100.0' y='50.0' diameter='100.0' northDirection='0.0' longitude='-0.06428629' latitude='0.70511305' timeZone='Europe/Madrid'/>
|
||||
<observerCamera attribute='observerCamera' lens='PINHOLE' x='50.0' y='50.0' z='170.0' yaw='5.4977875' pitch='0.19634955' fieldOfView='1.0995575' time='1729080000000'/>
|
||||
<camera attribute='topCamera' lens='PINHOLE' x='1304.082' y='1936.5889' z='1526.6199' yaw='8.98363' pitch='0.7049999' fieldOfView='1.0995575' time='1729080000000'/>
|
||||
<wall id='wall0' wallAtEnd='wall1' xStart='0.0' yStart='0.0' xEnd='100.0' yEnd='0.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall1' wallAtStart='wall0' wallAtEnd='wall2' xStart='100.0' yStart='0.0' xEnd='200.0' yEnd='0.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall2' wallAtStart='wall1' xStart='200.0' yStart='0.0' xEnd='300.0' yEnd='0.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall3' wallAtEnd='wall4' xStart='0.0' yStart='50.0' xEnd='100.0' yEnd='100.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall4' wallAtStart='wall3' wallAtEnd='wall5' xStart='100.0' yStart='100.0' xEnd='200.0' yEnd='100.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall5' wallAtStart='wall4' xStart='200.0' yStart='100.0' xEnd='300.0' yEnd='50.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall6' wallAtEnd='wall7' xStart='0.0' yStart='200.0' xEnd='100.0' yEnd='300.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall7' wallAtStart='wall6' wallAtEnd='wall8' xStart='100.0' yStart='300.0' xEnd='200.0' yEnd='300.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall8' wallAtStart='wall7' xStart='200.0' yStart='300.0' xEnd='300.0' yEnd='200.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall9' wallAtEnd='wall10' xStart='100.0' yStart='400.0' xEnd='100.0' yEnd='500.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall10' wallAtStart='wall9' wallAtEnd='wall11' xStart='100.0' yStart='500.0' xEnd='200.0' yEnd='500.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall11' wallAtStart='wall10' xStart='200.0' yStart='500.0' xEnd='200.0' yEnd='400.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall12' wallAtStart='wall14' wallAtEnd='wall13' xStart='150.0' yStart='600.0' xEnd='100.0' yEnd='700.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall13' wallAtStart='wall12' wallAtEnd='wall14' xStart='100.0' yStart='700.0' xEnd='200.0' yEnd='700.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall14' wallAtStart='wall13' wallAtEnd='wall12' xStart='200.0' yStart='700.0' xEnd='150.0' yEnd='600.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall15' wallAtEnd='wall16' xStart='400.0' yStart='150.0' xEnd='500.0' yEnd='100.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall16' wallAtStart='wall15' wallAtEnd='wall17' xStart='500.0' yStart='100.0' xEnd='600.0' yEnd='100.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall17' wallAtStart='wall16' xStart='600.0' yStart='100.0' xEnd='700.0' yEnd='50.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall18' wallAtEnd='wall19' xStart='400.0' yStart='400.0' xEnd='500.0' yEnd='300.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall19' wallAtStart='wall18' wallAtEnd='wall20' xStart='500.0' yStart='300.0' xEnd='600.0' yEnd='300.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall20' wallAtStart='wall19' xStart='600.0' yStart='300.0' xEnd='700.0' yEnd='200.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall21' wallAtEnd='wall22' xStart='400.0' yStart='600.0' xEnd='400.0' yEnd='500.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall22' wallAtStart='wall21' wallAtEnd='wall23' xStart='400.0' yStart='500.0' xEnd='600.0' yEnd='500.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall23' wallAtStart='wall22' xStart='600.0' yStart='500.0' xEnd='600.0' yEnd='400.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall24' wallAtEnd='wall25' xStart='600.0' yStart='800.0' xEnd='500.0' yEnd='700.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall25' wallAtStart='wall24' wallAtEnd='wall26' xStart='500.0' yStart='700.0' xEnd='600.0' yEnd='700.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall26' wallAtStart='wall25' xStart='600.0' yStart='700.0' xEnd='500.0' yEnd='600.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall27' wallAtStart='wall30' wallAtEnd='wall28' xStart='800.0' yStart='0.0' xEnd='1000.0' yEnd='0.0' height='250.0' thickness='10.0' arcExtent='1.0471976' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall28' wallAtStart='wall27' wallAtEnd='wall29' xStart='1000.0' yStart='0.0' xEnd='1000.0' yEnd='100.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall29' wallAtStart='wall28' wallAtEnd='wall30' xStart='1000.0' yStart='100.0' xEnd='800.0' yEnd='100.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall30' wallAtStart='wall29' wallAtEnd='wall27' xStart='800.0' yStart='100.0' xEnd='800.0' yEnd='0.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall31' wallAtEnd='wall32' xStart='800.0' yStart='400.0' xEnd='1000.0' yEnd='200.0' height='250.0' thickness='10.0' arcExtent='1.5707964' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall32' wallAtStart='wall31' wallAtEnd='wall33' xStart='1000.0' yStart='200.0' xEnd='1200.0' yEnd='400.0' height='250.0' thickness='10.0' arcExtent='1.5707964' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall33' wallAtStart='wall32' wallAtEnd='wall34' xStart='1200.0' yStart='400.0' xEnd='1000.0' yEnd='600.0' height='250.0' thickness='10.0' arcExtent='1.5707964' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall34' wallAtStart='wall33' xStart='1000.0' yStart='600.0' xEnd='800.0' yEnd='400.0' height='250.0' thickness='10.0' arcExtent='1.5707964' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall35' wallAtEnd='wall36' xStart='800.0' yStart='800.0' xEnd='900.0' yEnd='900.0' height='250.0' thickness='10.0' arcExtent='-3.1415927' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall36' wallAtStart='wall35' wallAtEnd='wall37' xStart='900.0' yStart='900.0' xEnd='1000.0' yEnd='800.0' height='250.0' thickness='10.0' arcExtent='-3.1415927' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall37' wallAtStart='wall36' wallAtEnd='wall38' xStart='1000.0' yStart='800.0' xEnd='900.0' yEnd='700.0' height='250.0' thickness='10.0' arcExtent='-3.1415927' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall38' wallAtStart='wall37' xStart='900.0' yStart='700.0' xEnd='800.0' yEnd='800.0' height='250.0' thickness='10.0' arcExtent='-3.1415927' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
</home>
|
||||
"""
|
||||
# Use the modules so that code checkers don't complain (flake8)
|
||||
True if TestArchSpace else False
|
||||
True if TestArchRoof else False
|
||||
True if TestArchWall else False
|
||||
226
src/Mod/BIM/TestArchGui.py
Normal file
226
src/Mod/BIM/TestArchGui.py
Normal file
@@ -0,0 +1,226 @@
|
||||
#***************************************************************************
|
||||
#* Copyright (c) 2013 Yorik van Havre <yorik@uncreated.net> *
|
||||
#* *
|
||||
#* This file is part of the FreeCAD CAx development system. *
|
||||
#* *
|
||||
#* This program is free software; you can redistribute it and/or modify *
|
||||
#* it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
#* as published by the Free Software Foundation; either version 2 of *
|
||||
#* the License, or (at your option) any later version. *
|
||||
#* for detail see the LICENCE text file. *
|
||||
#* *
|
||||
#* FreeCAD is distributed in the hope that it will be useful, *
|
||||
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
#* GNU Library General Public License for more details. *
|
||||
#* *
|
||||
#* You should have received a copy of the GNU Library General Public *
|
||||
#* License along with FreeCAD; if not, write to the Free Software *
|
||||
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
#* USA *
|
||||
#* *
|
||||
#***************************************************************************/
|
||||
|
||||
# Unit test for the Arch module
|
||||
|
||||
import os
|
||||
import unittest
|
||||
|
||||
import FreeCAD as App
|
||||
from FreeCAD import Units
|
||||
|
||||
import Arch
|
||||
import Draft
|
||||
import Part
|
||||
import Sketcher
|
||||
import TechDraw
|
||||
import WorkingPlane
|
||||
|
||||
from draftutils.messages import _msg
|
||||
|
||||
if App.GuiUp:
|
||||
import FreeCADGui
|
||||
|
||||
class ArchTest(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
# setting a new document to hold the tests
|
||||
if App.ActiveDocument:
|
||||
if App.ActiveDocument.Name != "ArchTest":
|
||||
App.newDocument("ArchTest")
|
||||
else:
|
||||
App.newDocument("ArchTest")
|
||||
App.setActiveDocument("ArchTest")
|
||||
|
||||
def testRebar(self):
|
||||
App.Console.PrintLog ('Checking Arch Rebar...\n')
|
||||
s = Arch.makeStructure(length=2,width=3,height=5)
|
||||
sk = App.ActiveDocument.addObject('Sketcher::SketchObject','Sketch')
|
||||
sk.AttachmentSupport = (s,["Face6"])
|
||||
sk.addGeometry(Part.LineSegment(App.Vector(-0.85,1.25,0),App.Vector(0.75,1.25,0)))
|
||||
sk.addGeometry(Part.LineSegment(App.Vector(0.75,1.25,0),App.Vector(0.75,-1.20,0)))
|
||||
sk.addGeometry(Part.LineSegment(App.Vector(0.75,-1.20,0),App.Vector(-0.85,-1.20,0)))
|
||||
sk.addGeometry(Part.LineSegment(App.Vector(-0.85,-1.20,0),App.Vector(-0.85,1.25,0)))
|
||||
sk.addConstraint(Sketcher.Constraint('Coincident',0,2,1,1))
|
||||
sk.addConstraint(Sketcher.Constraint('Coincident',1,2,2,1))
|
||||
sk.addConstraint(Sketcher.Constraint('Coincident',2,2,3,1))
|
||||
sk.addConstraint(Sketcher.Constraint('Coincident',3,2,0,1))
|
||||
r = Arch.makeRebar(s,sk,diameter=.1,amount=2)
|
||||
self.assertTrue(r,"Arch Rebar failed")
|
||||
|
||||
def testBuildingPart(self):
|
||||
"""Create a BuildingPart from a wall with a window and check its shape.
|
||||
"""
|
||||
# Also regression test for:
|
||||
# https://github.com/FreeCAD/FreeCAD/issues/6178
|
||||
operation = "Arch BuildingPart"
|
||||
_msg(" Test '{}'".format(operation))
|
||||
# Most of the code below taken from testWindow function.
|
||||
line = Draft.makeLine(App.Vector(0, 0, 0), App.Vector(3000, 0, 0))
|
||||
wall = Arch.makeWall(line)
|
||||
sk = App.ActiveDocument.addObject("Sketcher::SketchObject", "Sketch001")
|
||||
sk.Placement.Rotation = App.Rotation(App.Vector(1, 0, 0), 90)
|
||||
sk.addGeometry(Part.LineSegment(App.Vector( 500, 800, 0), App.Vector(1500, 800, 0)))
|
||||
sk.addGeometry(Part.LineSegment(App.Vector(1500, 800, 0), App.Vector(1500, 2000, 0)))
|
||||
sk.addGeometry(Part.LineSegment(App.Vector(1500, 2000, 0), App.Vector( 500, 2000, 0)))
|
||||
sk.addGeometry(Part.LineSegment(App.Vector( 500, 2000, 0), App.Vector( 500, 800, 0)))
|
||||
sk.addConstraint(Sketcher.Constraint('Coincident', 0, 2, 1, 1))
|
||||
sk.addConstraint(Sketcher.Constraint('Coincident', 1, 2, 2, 1))
|
||||
sk.addConstraint(Sketcher.Constraint('Coincident', 2, 2, 3, 1))
|
||||
sk.addConstraint(Sketcher.Constraint('Coincident', 3, 2, 0, 1))
|
||||
App.ActiveDocument.recompute()
|
||||
win = Arch.makeWindow(sk)
|
||||
Arch.removeComponents(win, host=wall)
|
||||
App.ActiveDocument.recompute()
|
||||
bp = Arch.makeBuildingPart()
|
||||
|
||||
# Wall visibility works when standalone
|
||||
FreeCADGui.Selection.clearSelection()
|
||||
FreeCADGui.Selection.addSelection('ArchTest',wall.Name)
|
||||
assert wall.Visibility
|
||||
FreeCADGui.runCommand('Std_ToggleVisibility',0)
|
||||
App.ActiveDocument.recompute()
|
||||
assert not wall.Visibility
|
||||
FreeCADGui.runCommand('Std_ToggleVisibility',0)
|
||||
assert wall.Visibility
|
||||
|
||||
bp.Group = [wall]
|
||||
App.ActiveDocument.recompute()
|
||||
# Fails with OCC 7.5
|
||||
# self.assertTrue(len(bp.Shape.Faces) == 16, "'{}' failed".format(operation))
|
||||
|
||||
# Wall visibility works when inside a BuildingPart
|
||||
FreeCADGui.runCommand('Std_ToggleVisibility',0)
|
||||
App.ActiveDocument.recompute()
|
||||
assert not wall.Visibility
|
||||
FreeCADGui.runCommand('Std_ToggleVisibility',0)
|
||||
assert wall.Visibility
|
||||
|
||||
# Wall visibility works when BuildingPart Toggled
|
||||
FreeCADGui.Selection.clearSelection()
|
||||
FreeCADGui.Selection.addSelection('ArchTest',bp.Name)
|
||||
FreeCADGui.runCommand('Std_ToggleVisibility',0)
|
||||
assert not wall.Visibility
|
||||
FreeCADGui.runCommand('Std_ToggleVisibility',0)
|
||||
assert wall.Visibility
|
||||
|
||||
# Wall visibiity works inside group inside BuildingPart Toggled
|
||||
grp = App.ActiveDocument.addObject("App::DocumentObjectGroup","Group")
|
||||
grp.Label="Group"
|
||||
grp.Group = [wall]
|
||||
bp.Group = [grp]
|
||||
App.ActiveDocument.recompute()
|
||||
assert wall.Visibility
|
||||
FreeCADGui.runCommand('Std_ToggleVisibility',0)
|
||||
App.ActiveDocument.recompute()
|
||||
assert not wall.Visibility
|
||||
FreeCADGui.runCommand('Std_ToggleVisibility',0)
|
||||
App.ActiveDocument.recompute()
|
||||
assert wall.Visibility
|
||||
|
||||
def testImportSH3D(self):
|
||||
"""Import a SweetHome 3D file
|
||||
"""
|
||||
operation = "importers.importSH3D"
|
||||
_msg(" Test '{}'".format(operation))
|
||||
import BIM.importers.importSH3DHelper
|
||||
importer = BIM.importers.importSH3DHelper.SH3DImporter(None)
|
||||
importer.import_sh3d_from_string(SH3D_HOME)
|
||||
assert App.ActiveDocument.Site
|
||||
assert App.ActiveDocument.BuildingPart.Label == "Building"
|
||||
assert App.ActiveDocument.BuildingPart001.Label == "Level"
|
||||
assert App.ActiveDocument.Wall
|
||||
|
||||
def tearDown(self):
|
||||
App.closeDocument("ArchTest")
|
||||
pass
|
||||
|
||||
|
||||
SH3D_HOME = """<?xml version='1.0'?>
|
||||
<home version='7200' name='0-JoinWall.sh3d' camera='topCamera' wallHeight='250.0'>
|
||||
<property name='com.eteks.sweethome3d.SweetHome3D.CatalogPaneDividerLocation' value='327'/>
|
||||
<property name='com.eteks.sweethome3d.SweetHome3D.ColumnWidths' value='100,84,82,85,84'/>
|
||||
<property name='com.eteks.sweethome3d.SweetHome3D.FrameHeight' value='576'/>
|
||||
<property name='com.eteks.sweethome3d.SweetHome3D.FrameMaximized' value='true'/>
|
||||
<property name='com.eteks.sweethome3d.SweetHome3D.FrameWidth' value='1092'/>
|
||||
<property name='com.eteks.sweethome3d.SweetHome3D.FrameX' value='50'/>
|
||||
<property name='com.eteks.sweethome3d.SweetHome3D.FrameY' value='87'/>
|
||||
<property name='com.eteks.sweethome3d.SweetHome3D.MainPaneDividerLocation' value='441'/>
|
||||
<property name='com.eteks.sweethome3d.SweetHome3D.PlanPaneDividerLocation' value='263'/>
|
||||
<property name='com.eteks.sweethome3d.SweetHome3D.PlanScale' value='0.21343713'/>
|
||||
<property name='com.eteks.sweethome3d.SweetHome3D.PlanViewportX' value='0'/>
|
||||
<property name='com.eteks.sweethome3d.SweetHome3D.PlanViewportY' value='0'/>
|
||||
<property name='com.eteks.sweethome3d.SweetHome3D.ScreenHeight' value='720'/>
|
||||
<property name='com.eteks.sweethome3d.SweetHome3D.ScreenWidth' value='1366'/>
|
||||
<furnitureVisibleProperty name='NAME'/>
|
||||
<furnitureVisibleProperty name='WIDTH'/>
|
||||
<furnitureVisibleProperty name='DEPTH'/>
|
||||
<furnitureVisibleProperty name='HEIGHT'/>
|
||||
<furnitureVisibleProperty name='VISIBLE'/>
|
||||
<environment groundColor='FFB78744' skyColor='00CCE4FC' lightColor='00D0D0D0' ceillingLightColor='00D0D0D0' photoWidth='400' photoHeight='300' photoAspectRatio='VIEW_3D_RATIO' photoQuality='0' videoWidth='320' videoAspectRatio='RATIO_4_3' videoQuality='0' videoFrameRate='25'>
|
||||
<texture attribute='skyTexture' name='Cloudy' creator='eTeks' catalogId='eTeks#cloudy' width='100.0' height='27.6' image='0'/>
|
||||
</environment>
|
||||
<compass x='-100.0' y='50.0' diameter='100.0' northDirection='0.0' longitude='-0.06428629' latitude='0.70511305' timeZone='Europe/Madrid'/>
|
||||
<observerCamera attribute='observerCamera' lens='PINHOLE' x='50.0' y='50.0' z='170.0' yaw='5.4977875' pitch='0.19634955' fieldOfView='1.0995575' time='1729080000000'/>
|
||||
<camera attribute='topCamera' lens='PINHOLE' x='1304.082' y='1936.5889' z='1526.6199' yaw='8.98363' pitch='0.7049999' fieldOfView='1.0995575' time='1729080000000'/>
|
||||
<wall id='wall0' wallAtEnd='wall1' xStart='0.0' yStart='0.0' xEnd='100.0' yEnd='0.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall1' wallAtStart='wall0' wallAtEnd='wall2' xStart='100.0' yStart='0.0' xEnd='200.0' yEnd='0.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall2' wallAtStart='wall1' xStart='200.0' yStart='0.0' xEnd='300.0' yEnd='0.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall3' wallAtEnd='wall4' xStart='0.0' yStart='50.0' xEnd='100.0' yEnd='100.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall4' wallAtStart='wall3' wallAtEnd='wall5' xStart='100.0' yStart='100.0' xEnd='200.0' yEnd='100.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall5' wallAtStart='wall4' xStart='200.0' yStart='100.0' xEnd='300.0' yEnd='50.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall6' wallAtEnd='wall7' xStart='0.0' yStart='200.0' xEnd='100.0' yEnd='300.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall7' wallAtStart='wall6' wallAtEnd='wall8' xStart='100.0' yStart='300.0' xEnd='200.0' yEnd='300.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall8' wallAtStart='wall7' xStart='200.0' yStart='300.0' xEnd='300.0' yEnd='200.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall9' wallAtEnd='wall10' xStart='100.0' yStart='400.0' xEnd='100.0' yEnd='500.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall10' wallAtStart='wall9' wallAtEnd='wall11' xStart='100.0' yStart='500.0' xEnd='200.0' yEnd='500.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall11' wallAtStart='wall10' xStart='200.0' yStart='500.0' xEnd='200.0' yEnd='400.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall12' wallAtStart='wall14' wallAtEnd='wall13' xStart='150.0' yStart='600.0' xEnd='100.0' yEnd='700.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall13' wallAtStart='wall12' wallAtEnd='wall14' xStart='100.0' yStart='700.0' xEnd='200.0' yEnd='700.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall14' wallAtStart='wall13' wallAtEnd='wall12' xStart='200.0' yStart='700.0' xEnd='150.0' yEnd='600.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall15' wallAtEnd='wall16' xStart='400.0' yStart='150.0' xEnd='500.0' yEnd='100.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall16' wallAtStart='wall15' wallAtEnd='wall17' xStart='500.0' yStart='100.0' xEnd='600.0' yEnd='100.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall17' wallAtStart='wall16' xStart='600.0' yStart='100.0' xEnd='700.0' yEnd='50.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall18' wallAtEnd='wall19' xStart='400.0' yStart='400.0' xEnd='500.0' yEnd='300.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall19' wallAtStart='wall18' wallAtEnd='wall20' xStart='500.0' yStart='300.0' xEnd='600.0' yEnd='300.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall20' wallAtStart='wall19' xStart='600.0' yStart='300.0' xEnd='700.0' yEnd='200.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall21' wallAtEnd='wall22' xStart='400.0' yStart='600.0' xEnd='400.0' yEnd='500.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall22' wallAtStart='wall21' wallAtEnd='wall23' xStart='400.0' yStart='500.0' xEnd='600.0' yEnd='500.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall23' wallAtStart='wall22' xStart='600.0' yStart='500.0' xEnd='600.0' yEnd='400.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall24' wallAtEnd='wall25' xStart='600.0' yStart='800.0' xEnd='500.0' yEnd='700.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall25' wallAtStart='wall24' wallAtEnd='wall26' xStart='500.0' yStart='700.0' xEnd='600.0' yEnd='700.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall26' wallAtStart='wall25' xStart='600.0' yStart='700.0' xEnd='500.0' yEnd='600.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall27' wallAtStart='wall30' wallAtEnd='wall28' xStart='800.0' yStart='0.0' xEnd='1000.0' yEnd='0.0' height='250.0' thickness='10.0' arcExtent='1.0471976' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall28' wallAtStart='wall27' wallAtEnd='wall29' xStart='1000.0' yStart='0.0' xEnd='1000.0' yEnd='100.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall29' wallAtStart='wall28' wallAtEnd='wall30' xStart='1000.0' yStart='100.0' xEnd='800.0' yEnd='100.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall30' wallAtStart='wall29' wallAtEnd='wall27' xStart='800.0' yStart='100.0' xEnd='800.0' yEnd='0.0' height='250.0' thickness='10.0' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall31' wallAtEnd='wall32' xStart='800.0' yStart='400.0' xEnd='1000.0' yEnd='200.0' height='250.0' thickness='10.0' arcExtent='1.5707964' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall32' wallAtStart='wall31' wallAtEnd='wall33' xStart='1000.0' yStart='200.0' xEnd='1200.0' yEnd='400.0' height='250.0' thickness='10.0' arcExtent='1.5707964' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall33' wallAtStart='wall32' wallAtEnd='wall34' xStart='1200.0' yStart='400.0' xEnd='1000.0' yEnd='600.0' height='250.0' thickness='10.0' arcExtent='1.5707964' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall34' wallAtStart='wall33' xStart='1000.0' yStart='600.0' xEnd='800.0' yEnd='400.0' height='250.0' thickness='10.0' arcExtent='1.5707964' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall35' wallAtEnd='wall36' xStart='800.0' yStart='800.0' xEnd='900.0' yEnd='900.0' height='250.0' thickness='10.0' arcExtent='-3.1415927' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall36' wallAtStart='wall35' wallAtEnd='wall37' xStart='900.0' yStart='900.0' xEnd='1000.0' yEnd='800.0' height='250.0' thickness='10.0' arcExtent='-3.1415927' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall37' wallAtStart='wall36' wallAtEnd='wall38' xStart='1000.0' yStart='800.0' xEnd='900.0' yEnd='700.0' height='250.0' thickness='10.0' arcExtent='-3.1415927' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
<wall id='wall38' wallAtStart='wall37' xStart='900.0' yStart='700.0' xEnd='800.0' yEnd='800.0' height='250.0' thickness='10.0' arcExtent='-3.1415927' pattern='hatchUp' topColor='FF0000FF' leftSideColor='FF00FF00' rightSideColor='FFFF0000'/>
|
||||
</home>
|
||||
"""
|
||||
@@ -150,7 +150,10 @@ class BIM_Material:
|
||||
)
|
||||
buttonMergeDupes.setIcon(QtGui.QIcon(":/icons/view-refresh.svg"))
|
||||
createButtonsLayout.addWidget(buttonMergeDupes, 1, 0)
|
||||
self.dlg.buttonMergeDupes = buttonMergeDupes
|
||||
buttonMergeDupes.clicked.connect(self.onMergeDupes)
|
||||
if len(self.dlg.materials) < 2:
|
||||
buttonMergeDupes.setEnabled(False)
|
||||
|
||||
# delete unused
|
||||
buttonDeleteUnused = QtGui.QPushButton(
|
||||
@@ -208,20 +211,15 @@ class BIM_Material:
|
||||
first = True
|
||||
for mat in self.dlg.materials:
|
||||
orig = None
|
||||
for om in mats:
|
||||
if om.Label == mat.Label:
|
||||
orig = om
|
||||
break
|
||||
else:
|
||||
if (
|
||||
mat.Label[-1].isdigit()
|
||||
and mat.Label[-2].isdigit()
|
||||
and mat.Label[-3].isdigit()
|
||||
):
|
||||
for om in self.dlg.materials:
|
||||
if om.Label == mat.Label[:-3].strip():
|
||||
orig = om
|
||||
break
|
||||
if (
|
||||
mat.Label[-1].isdigit()
|
||||
and mat.Label[-2].isdigit()
|
||||
and mat.Label[-3].isdigit()
|
||||
):
|
||||
for om in self.dlg.materials:
|
||||
if om.Label == mat.Label[:-3].strip():
|
||||
orig = om
|
||||
break
|
||||
if orig:
|
||||
for par in mat.InList:
|
||||
for prop in par.PropertiesList:
|
||||
@@ -522,6 +520,9 @@ class BIM_Material:
|
||||
i.setFlags(i.flags() | QtCore.Qt.ItemIsEditable)
|
||||
if o.Name == name:
|
||||
self.dlg.matList.setCurrentItem(i)
|
||||
if hasattr(self.dlg, "buttonMergeDupes"):
|
||||
hasMultipleMaterials = len(self.dlg.materials) > 1
|
||||
self.dlg.buttonMergeDupes.setEnabled(hasMultipleMaterials)
|
||||
|
||||
def createIcon(self, obj):
|
||||
from PySide import QtCore, QtGui
|
||||
|
||||
@@ -144,6 +144,7 @@ class BIM_ProjectManager:
|
||||
import Draft
|
||||
import FreeCADGui
|
||||
import Part
|
||||
from draftutils import params
|
||||
|
||||
vaxes = []
|
||||
haxes = []
|
||||
@@ -306,8 +307,8 @@ class BIM_ProjectManager:
|
||||
outtext = Draft.make_text(
|
||||
[buildingname],
|
||||
FreeCAD.Vector(
|
||||
Draft.getParam("textheight", 0.20) * 0.3,
|
||||
-Draft.getParam("textheight", 0.20) * 1.43,
|
||||
params.get_param("textheight") * 0.3,
|
||||
-params.get_param("textheight") * 1.43,
|
||||
0,
|
||||
),
|
||||
)
|
||||
@@ -324,8 +325,8 @@ class BIM_ProjectManager:
|
||||
axisV.Label = translate("BIM", "Vertical Axes")
|
||||
axisV.ViewObject.BubblePosition = "Both"
|
||||
axisV.ViewObject.LineWidth = self.form.lineWidth.value()
|
||||
axisV.ViewObject.FontSize = Draft.getParam("textheight", 0.20)
|
||||
axisV.ViewObject.BubbleSize = Draft.getParam("textheight", 0.20) * 1.43
|
||||
axisV.ViewObject.FontSize = params.get_param("textheight")
|
||||
axisV.ViewObject.BubbleSize = params.get_param("textheight") * 1.43
|
||||
axisV.ViewObject.LineColor = color
|
||||
axisH = None
|
||||
if self.form.countHAxes.value() and distHAxes:
|
||||
@@ -336,8 +337,8 @@ class BIM_ProjectManager:
|
||||
axisH.ViewObject.BubblePosition = "Both"
|
||||
axisH.ViewObject.NumberingStyle = "A,B,C"
|
||||
axisH.ViewObject.LineWidth = self.form.lineWidth.value()
|
||||
axisH.ViewObject.FontSize = Draft.getParam("textheight", 0.20)
|
||||
axisH.ViewObject.BubbleSize = Draft.getParam("textheight", 0.20) * 1.43
|
||||
axisH.ViewObject.FontSize = params.get_param("textheight")
|
||||
axisH.ViewObject.BubbleSize = params.get_param("textheight") * 1.43
|
||||
axisH.Placement.Rotation = FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), 90)
|
||||
axisH.ViewObject.LineColor = color
|
||||
if axisV and axisH:
|
||||
|
||||
43
src/Mod/BIM/bimtests/TestArchBase.py
Normal file
43
src/Mod/BIM/bimtests/TestArchBase.py
Normal file
@@ -0,0 +1,43 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2025 Furgo *
|
||||
# * *
|
||||
# * This file is part of FreeCAD. *
|
||||
# * *
|
||||
# * FreeCAD is free software: you can redistribute it and/or modify it *
|
||||
# * under the terms of the GNU Lesser General Public License as *
|
||||
# * published by the Free Software Foundation, either version 2.1 of the *
|
||||
# * License, or (at your option) any later version. *
|
||||
# * *
|
||||
# * FreeCAD is distributed in the hope that it will be useful, but *
|
||||
# * WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
|
||||
# * Lesser General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Lesser General Public *
|
||||
# * License along with FreeCAD. If not, see *
|
||||
# * <https://www.gnu.org/licenses/>. *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
"""Defines the base class for Arch module unit tests."""
|
||||
|
||||
import unittest
|
||||
import FreeCAD
|
||||
|
||||
class TestArchBase(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.document = FreeCAD.newDocument(self.__class__.__name__)
|
||||
|
||||
def tearDown(self):
|
||||
FreeCAD.closeDocument(self.document.Name)
|
||||
|
||||
def printTestMessage(self, text, prepend_text="Test ", end="\n"):
|
||||
"""Write messages to the console including the line ending.
|
||||
|
||||
Messages will be prepended with "Test ", unless an empty string is
|
||||
passed as the prepend_text argument
|
||||
"""
|
||||
FreeCAD.Console.PrintMessage(prepend_text + text + end)
|
||||
150
src/Mod/BIM/bimtests/TestArchRoof.py
Normal file
150
src/Mod/BIM/bimtests/TestArchRoof.py
Normal file
@@ -0,0 +1,150 @@
|
||||
#***************************************************************************
|
||||
#* Copyright (c) 2013 Yorik van Havre <yorik@uncreated.net> *
|
||||
#* *
|
||||
#* This file is part of the FreeCAD CAx development system. *
|
||||
#* *
|
||||
#* This program is free software; you can redistribute it and/or modify *
|
||||
#* it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
#* as published by the Free Software Foundation; either version 2 of *
|
||||
#* the License, or (at your option) any later version. *
|
||||
#* for detail see the LICENCE text file. *
|
||||
#* *
|
||||
#* FreeCAD is distributed in the hope that it will be useful, *
|
||||
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
#* GNU Library General Public License for more details. *
|
||||
#* *
|
||||
#* You should have received a copy of the GNU Library General Public *
|
||||
#* License along with FreeCAD; if not, write to the Free Software *
|
||||
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
#* USA *
|
||||
#* *
|
||||
#***************************************************************************/
|
||||
|
||||
# Unit tests for the Arch wall module
|
||||
|
||||
import os
|
||||
import unittest
|
||||
import Arch
|
||||
import Draft
|
||||
import Part
|
||||
import FreeCAD as App
|
||||
from bimtests import TestArchBase
|
||||
from draftutils.messages import _msg
|
||||
|
||||
class TestArchRoof(TestArchBase.TestArchBase):
|
||||
|
||||
def testRoof(self):
|
||||
operation = "Checking Arch Roof..."
|
||||
self.printTestMessage(operation)
|
||||
|
||||
r = Draft.makeRectangle(length=2,height=-1)
|
||||
r.recompute() # required before calling Arch.makeRoof
|
||||
ro = Arch.makeRoof(r)
|
||||
self.assertTrue(ro,"Arch Roof failed")
|
||||
|
||||
def testRoof81Permutations(self):
|
||||
"""Create 81 roofs using a range of arguments.
|
||||
"""
|
||||
operation = "Arch Roof testRoof81Permutations"
|
||||
self.printTestMessage(operation)
|
||||
|
||||
pts = [App.Vector( 0, 0, 0),
|
||||
App.Vector(2000, 0, 0),
|
||||
App.Vector(4000, 0, 0),
|
||||
App.Vector(4000, 4000, 0),
|
||||
App.Vector( 0, 4000, 0)]
|
||||
ptsMod = [App.Vector(2000, 0, 0),
|
||||
App.Vector(2000, -1000, 0),
|
||||
App.Vector(2000, 1000, 0)]
|
||||
angsMod = [[60, 60], [30, 60], [60, 30]]
|
||||
runsMod = [[500, 500], [400, 500], [500, 400]]
|
||||
overhangsMod = [[100, 100], [100, 200], [200, 100]]
|
||||
delta = 6000
|
||||
pla = App.Placement()
|
||||
for iY in range(9):
|
||||
for iX in range(9):
|
||||
pts[1] = ptsMod[iY % 3] # to get different edge angles
|
||||
angsLst = angsMod[iY // 3] + [90, 90, 90]
|
||||
runsLst = runsMod[iX % 3] + [0, 0, 0]
|
||||
overhangsLst = overhangsMod[iX // 3] + [0, 0, 0]
|
||||
pla.Base = App.Vector(iX * delta, iY * delta, 0)
|
||||
wire = Draft.makeWire(pts, closed = True)
|
||||
wire.MakeFace = False
|
||||
wire.Placement = pla
|
||||
wire.recompute() # required before calling Arch.makeRoof
|
||||
roof = Arch.makeRoof(wire,
|
||||
angles = angsLst,
|
||||
run = runsLst,
|
||||
overhang = overhangsLst)
|
||||
roof.recompute()
|
||||
self.assertFalse(roof.Shape.isNull(),
|
||||
"'{}' failed".format(operation))
|
||||
self.assertTrue(roof.Shape.isValid(),
|
||||
"'{}' failed".format(operation))
|
||||
|
||||
def testRoofAllAngles90(self):
|
||||
"""Create a roof with the angles of all segments set at 90 degrees.
|
||||
This corner case results in a flat roof.
|
||||
"""
|
||||
operation = "Arch Roof testRoofAllAngles90"
|
||||
self.printTestMessage(operation)
|
||||
|
||||
pts = [App.Vector( 0, 0, 0),
|
||||
App.Vector(2000, 0, 0),
|
||||
App.Vector(2000, 2000, 0),
|
||||
App.Vector( 0, 2000, 0)]
|
||||
|
||||
wire = Draft.makeWire(pts, closed = True)
|
||||
wire.MakeFace = False
|
||||
wire.recompute() # required before calling Arch.makeRoof
|
||||
roof = Arch.makeRoof(wire,
|
||||
angles = [90, 90, 90, 90])
|
||||
roof.recompute()
|
||||
self.assertFalse(roof.Shape.isNull(), "'{}' failed".format(operation))
|
||||
self.assertTrue(roof.Shape.isValid(), "'{}' failed".format(operation))
|
||||
|
||||
def testRoofApex(self):
|
||||
"""Create a hipped roof that relies on apex calculation. The roof has
|
||||
2 triangular segments with a single apex point.
|
||||
"""
|
||||
operation = "Arch Roof testRoofApex"
|
||||
self.printTestMessage(operation)
|
||||
|
||||
rec = Draft.makeRectangle(length = 4000,
|
||||
height = 3000,
|
||||
face = False)
|
||||
rec.recompute() # required before calling Arch.makeRoof
|
||||
roof = Arch.makeRoof(rec,
|
||||
angles = [30, 40, 50, 60],
|
||||
run = [2000, 0, 2000, 0],
|
||||
idrel = [-1, 0, -1, 0],
|
||||
thickness = [50.0],
|
||||
overhang = [100.0])
|
||||
roof.recompute()
|
||||
self.assertFalse(roof.Shape.isNull(), "'{}' failed".format(operation))
|
||||
self.assertTrue(roof.Shape.isValid(), "'{}' failed".format(operation))
|
||||
|
||||
def testRoofSingleEavePoint(self):
|
||||
"""Create a roof with a single triangular segment that has a single
|
||||
eave point.
|
||||
"""
|
||||
operation = "Arch Roof testRoofSingleEavePoint"
|
||||
self.printTestMessage(operation)
|
||||
|
||||
pts = [App.Vector( 0, 0, 0),
|
||||
App.Vector( 2000, 0, 0),
|
||||
App.Vector( 4000, 2000, 0),
|
||||
App.Vector(-2000, 2000, 0)]
|
||||
wire = Draft.makeWire(pts, closed = True)
|
||||
wire.MakeFace = False
|
||||
wire.recompute() # required before calling Arch.makeRoof
|
||||
roof = Arch.makeRoof(wire,
|
||||
angles = [45, 90, 90, 90],
|
||||
run = [1000, 0, 0, 0],
|
||||
overhang = [1000, 0, 0, 0])
|
||||
roof.recompute()
|
||||
self.assertFalse(roof.Shape.isNull(), "'{}' failed".format(operation))
|
||||
self.assertTrue(roof.Shape.isValid(), "'{}' failed".format(operation))
|
||||
|
||||
|
||||
500
src/Mod/BIM/bimtests/TestArchSpace.py
Normal file
500
src/Mod/BIM/bimtests/TestArchSpace.py
Normal file
@@ -0,0 +1,500 @@
|
||||
#***************************************************************************
|
||||
#* Copyright (c) 2013 Yorik van Havre <yorik@uncreated.net> *
|
||||
#* *
|
||||
#* This file is part of the FreeCAD CAx development system. *
|
||||
#* *
|
||||
#* This program is free software; you can redistribute it and/or modify *
|
||||
#* it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
#* as published by the Free Software Foundation; either version 2 of *
|
||||
#* the License, or (at your option) any later version. *
|
||||
#* for detail see the LICENCE text file. *
|
||||
#* *
|
||||
#* FreeCAD is distributed in the hope that it will be useful, *
|
||||
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
#* GNU Library General Public License for more details. *
|
||||
#* *
|
||||
#* You should have received a copy of the GNU Library General Public *
|
||||
#* License along with FreeCAD; if not, write to the Free Software *
|
||||
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
#* USA *
|
||||
#* *
|
||||
#***************************************************************************/
|
||||
|
||||
# Unit tests for the Arch space module
|
||||
|
||||
import os
|
||||
import unittest
|
||||
import Arch
|
||||
import Draft
|
||||
import Part
|
||||
import FreeCAD as App
|
||||
from FreeCAD import Units
|
||||
from bimtests import TestArchBase
|
||||
import WorkingPlane
|
||||
|
||||
def like(a, b):
|
||||
return abs(a-b) < 0.001
|
||||
|
||||
def checkBB(a, b):
|
||||
return like(a.XMin, b.XMin) and like(a.YMin, b.YMin) and like(a.ZMin, b.ZMin) and like(a.XMax, b.XMax) and like(a.YMax, b.YMax) and like(a.ZMax, b.ZMax)
|
||||
|
||||
class TestArchSpace(TestArchBase.TestArchBase):
|
||||
|
||||
def testSpace(self):
|
||||
operation = "Checking Arch Space..."
|
||||
self.printTestMessage(operation)
|
||||
|
||||
sb = Part.makeBox(1,1,1)
|
||||
b = App.ActiveDocument.addObject('Part::Feature','Box')
|
||||
b.Shape = sb
|
||||
s = Arch.makeSpace([b])
|
||||
self.assertTrue(s,"Arch Space failed")
|
||||
|
||||
def testSpaceBBox(self):
|
||||
operation = "Checking Arch Space bound box..."
|
||||
self.printTestMessage(operation)
|
||||
|
||||
shape = Part.Shape()
|
||||
shape.importBrepFromString(brepArchiCAD)
|
||||
bborig = shape.BoundBox
|
||||
App.Console.PrintLog ("Original BB: "+str(bborig))
|
||||
baseobj = App.ActiveDocument.addObject("Part::Feature","brepArchiCAD_body")
|
||||
baseobj.Shape = shape
|
||||
space = Arch.makeSpace(baseobj)
|
||||
space.recompute()
|
||||
bbnew = space.Shape.BoundBox
|
||||
App.Console.PrintLog ("New BB: "+str(bbnew))
|
||||
self.assertTrue(checkBB(bborig,bbnew),"Arch Space has wrong Placement")
|
||||
|
||||
|
||||
def test_addSpaceBoundaries(self):
|
||||
"""Test the Arch.addSpaceBoundaries method.
|
||||
Create a space and a wall that intersects it. Add the wall as a boundary to the space,
|
||||
and check if the resulting space area is as expected.
|
||||
"""
|
||||
operation = "Add a wall face as a boundary to a space"
|
||||
self.printTestMessage(operation)
|
||||
|
||||
# Create the space
|
||||
pl = App.Placement()
|
||||
pl.Rotation.Q = (0.0, 0.0, 0.0, 1.0)
|
||||
pl.Base = App.Vector(-2000.0, -2000.0, 0.0)
|
||||
rectangleBase = Draft.make_rectangle(
|
||||
length=4000.0, height=4000.0, placement=pl, face=True, support=None)
|
||||
App.ActiveDocument.recompute()
|
||||
extr = rectangleBase.Shape.extrude(App.Vector(0,0,2000))
|
||||
Part.show(extr, 'Extrusion')
|
||||
space = Arch.makeSpace(App.activeDocument().getObject('Extrusion'))
|
||||
App.ActiveDocument.recompute() # To calculate area
|
||||
|
||||
# Create the wall
|
||||
trace = Part.LineSegment(App.Vector (3000.0, 1000.0, 0.0),
|
||||
App.Vector (-3000.0, 1000.0, 0.0))
|
||||
wp = WorkingPlane.get_working_plane()
|
||||
base = App.ActiveDocument.addObject("Sketcher::SketchObject","WallTrace")
|
||||
base.Placement = wp.get_placement()
|
||||
base.addGeometry(trace)
|
||||
wall = Arch.makeWall(base,width=200.0,height=3000.0,align="Left")
|
||||
wall.Normal = wp.axis
|
||||
|
||||
# Add the boundary
|
||||
wallBoundary = [(wall, ["Face1"])]
|
||||
Arch.addSpaceBoundaries(App.ActiveDocument.Space, wallBoundary)
|
||||
App.ActiveDocument.recompute() # To recalculate area
|
||||
|
||||
# Assert if area is as expected
|
||||
expectedArea = Units.parseQuantity('12 m^2')
|
||||
actualArea = Units.parseQuantity(str(space.Area))
|
||||
|
||||
self.assertAlmostEqual(
|
||||
expectedArea.Value,
|
||||
actualArea.Value,
|
||||
msg = (f"Invalid area value. " +
|
||||
f"Expected: {expectedArea.UserString}, actual: {actualArea.UserString}"))
|
||||
|
||||
def test_SpaceFromSingleWall(self):
|
||||
"""Create a space from boundaries of a single wall.
|
||||
"""
|
||||
operation = "Arch Space from single wall"
|
||||
self.printTestMessage(operation)
|
||||
|
||||
# Create a wall
|
||||
wallInnerLength = 4000.0
|
||||
wallHeight = 3000.0
|
||||
wallInnerFaceArea = wallInnerLength * wallHeight
|
||||
pl = App.Placement()
|
||||
pl.Rotation.Q = (0.0, 0.0, 0.0, 1.0)
|
||||
pl.Base = App.Vector(0.0, 0.0, 0.0)
|
||||
rectangleBase = Draft.make_rectangle(
|
||||
length=wallInnerLength, height=wallInnerLength, placement=pl, face=True, support=None)
|
||||
App.ActiveDocument.recompute() # To calculate rectangle area
|
||||
rectangleArea = rectangleBase.Area
|
||||
App.ActiveDocument.getObject(rectangleBase.Name).MakeFace = False
|
||||
wall = Arch.makeWall(baseobj=rectangleBase, height=wallHeight, align="Left")
|
||||
App.ActiveDocument.recompute() # To calculate face areas
|
||||
|
||||
# Create a space from the wall's inner faces
|
||||
boundaries = [f"Face{ind+1}" for ind, face in enumerate(wall.Shape.Faces)
|
||||
if round(face.Area) == round(wallInnerFaceArea)]
|
||||
|
||||
if App.GuiUp:
|
||||
import FreeCADGui
|
||||
FreeCADGui.Selection.clearSelection()
|
||||
FreeCADGui.Selection.addSelection(wall, boundaries)
|
||||
|
||||
space = Arch.makeSpace(FreeCADGui.Selection.getSelectionEx())
|
||||
# Alternative, but test takes longer to run (~10x)
|
||||
# FreeCADGui.activateWorkbench("BIMWorkbench")
|
||||
# FreeCADGui.runCommand('Arch_Space', 0)
|
||||
# space = App.ActiveDocument.Space
|
||||
else:
|
||||
# Also tests the alternative way of specifying the boundaries
|
||||
# [ (<Part::PartFeature>, ["Face1", ...]), ... ]
|
||||
space = Arch.makeSpace([(wall, boundaries)])
|
||||
|
||||
App.ActiveDocument.recompute() # To calculate space area
|
||||
|
||||
# Assert if area is as expected
|
||||
expectedArea = Units.parseQuantity(str(rectangleArea))
|
||||
actualArea = Units.parseQuantity(str(space.Area))
|
||||
|
||||
self.assertAlmostEqual(
|
||||
expectedArea.Value,
|
||||
actualArea.Value,
|
||||
msg = f"Invalid area value. Expected: {expectedArea.UserString}, actual: {actualArea.UserString}")
|
||||
|
||||
|
||||
brepArchiCAD = """
|
||||
DBRep_DrawableShape
|
||||
|
||||
CASCADE Topology V1, (c) Matra-Datavision
|
||||
Locations 3
|
||||
1
|
||||
1 0 0 0
|
||||
0 1 0 0
|
||||
0 0 1 0
|
||||
1
|
||||
0 1 0 0
|
||||
-1 0 0 0
|
||||
0 0 1 0
|
||||
2 2 -1 0
|
||||
Curve2ds 0
|
||||
Curves 12
|
||||
1 0 0 0 1 0 0
|
||||
1 3000 0 0 0 0 1
|
||||
1 3000 0 3000 -1 0 0
|
||||
1 0 0 3000 0 0 -1
|
||||
1 0 0 0 0 1 0
|
||||
1 0 5000 0 1 0 0
|
||||
1 3000 5000 0 0 -1 0
|
||||
1 3000 5000 0 0 0 1
|
||||
1 3000 5000 3000 0 -1 0
|
||||
1 3000 5000 3000 -1 0 0
|
||||
1 0 5000 3000 0 -1 0
|
||||
1 0 5000 3000 0 0 -1
|
||||
Polygon3D 0
|
||||
PolygonOnTriangulations 24
|
||||
2 1 2
|
||||
p 18.3333333333333 1 0 3000
|
||||
2 1 4
|
||||
p 18.3333333333333 1 0 3000
|
||||
2 2 3
|
||||
p 18.3333333333333 1 0 3000
|
||||
2 2 4
|
||||
p 18.3333333333333 1 0 3000
|
||||
2 3 4
|
||||
p 18.3333333333333 1 0 3000
|
||||
2 1 2
|
||||
p 18.3333333333333 1 0 3000
|
||||
2 4 1
|
||||
p 18.3333333333333 1 0 3000
|
||||
2 3 1
|
||||
p 18.3333333333333 1 0 3000
|
||||
2 1 2
|
||||
p 18.3333333333333 1 0 5000
|
||||
2 1 2
|
||||
p 18.3333333333333 1 0 5000
|
||||
2 2 3
|
||||
p 18.3333333333333 1 0 3000
|
||||
2 1 2
|
||||
p 18.3333333333333 1 0 3000
|
||||
2 3 4
|
||||
p 18.3333333333333 1 0 5000
|
||||
2 1 2
|
||||
p 18.3333333333333 1 0 5000
|
||||
2 1 3
|
||||
p 18.3333333333333 1 0 3000
|
||||
2 2 4
|
||||
p 18.3333333333333 1 0 3000
|
||||
2 3 4
|
||||
p 18.3333333333333 1 0 5000
|
||||
2 3 1
|
||||
p 18.3333333333333 1 0 5000
|
||||
2 3 4
|
||||
p 18.3333333333333 1 0 3000
|
||||
2 4 3
|
||||
p 18.3333333333333 1 0 3000
|
||||
2 4 2
|
||||
p 18.3333333333333 1 0 5000
|
||||
2 4 3
|
||||
p 18.3333333333333 1 0 5000
|
||||
2 4 2
|
||||
p 18.3333333333333 1 0 3000
|
||||
2 3 1
|
||||
p 18.3333333333333 1 0 3000
|
||||
Surfaces 6
|
||||
1 1500 0 1500 -0 -1 -0 0 0 -1 1 0 0
|
||||
1 1500 2500 0 -0 -0 -1 -1 0 0 0 1 0
|
||||
1 3000 2500 1500 1 0 0 0 0 1 0 -1 0
|
||||
1 1500 2500 3000 0 0 1 1 0 0 0 1 0
|
||||
1 0 2500 1500 -1 -0 -0 0 0 -1 0 -1 0
|
||||
1 1500 5000 1500 0 1 0 0 0 1 1 0 0
|
||||
Triangulations 6
|
||||
4 2 1 18.3333333333333
|
||||
0 0 0 3000 0 0 3000 0 3000 0 0 3000 1500 -1500 1500 1500 -1500 1500 -1500 -1500 3 4 1 2 3 1
|
||||
4 2 1 18.3333333333333
|
||||
0 0 0 0 5000 0 3000 5000 0 3000 0 0 1500 -2500 1500 2500 -1500 2500 -1500 -2500 2 3 4 2 4 1
|
||||
4 2 1 18.3333333333333
|
||||
3000 5000 0 3000 0 0 3000 5000 3000 3000 0 3000 -1500 -2500 -1500 2500 1500 -2500 1500 2500 4 2 1 4 1 3
|
||||
4 2 1 18.3333333333333
|
||||
3000 0 3000 0 0 3000 3000 5000 3000 0 5000 3000 1500 -2500 -1500 -2500 1500 2500 -1500 2500 3 2 1 3 4 2
|
||||
4 2 1 18.3333333333333
|
||||
0 0 0 0 5000 0 0 0 3000 0 5000 3000 1500 2500 1500 -2500 -1500 2500 -1500 -2500 1 3 4 1 4 2
|
||||
4 2 1 18.3333333333333
|
||||
0 5000 0 3000 5000 0 0 5000 3000 3000 5000 3000 -1500 -1500 -1500 1500 1500 -1500 1500 1500 3 2 1 4 2 3
|
||||
|
||||
TShapes 35
|
||||
Ve
|
||||
0.1
|
||||
0 0 0
|
||||
0 0
|
||||
|
||||
0101101
|
||||
*
|
||||
Ve
|
||||
0.1
|
||||
0 -3000 0
|
||||
0 0
|
||||
|
||||
0101101
|
||||
*
|
||||
Ed
|
||||
0.0001 1 1 0
|
||||
1 1 0 0 3000
|
||||
6 1 1 0
|
||||
6 2 2 0
|
||||
0
|
||||
|
||||
0101000
|
||||
+35 3 -34 3 *
|
||||
Ve
|
||||
0.1
|
||||
0 -3000 3000
|
||||
0 0
|
||||
|
||||
0101101
|
||||
*
|
||||
Ed
|
||||
0.0001 1 1 0
|
||||
1 2 0 0 3000
|
||||
6 3 1 0
|
||||
6 4 3 0
|
||||
0
|
||||
|
||||
0101000
|
||||
+34 3 -32 3 *
|
||||
Ve
|
||||
0.1
|
||||
0 0 3000
|
||||
0 0
|
||||
|
||||
0101101
|
||||
*
|
||||
Ed
|
||||
0.0001 1 1 0
|
||||
1 3 0 0 3000
|
||||
6 5 1 0
|
||||
6 6 4 0
|
||||
0
|
||||
|
||||
0101000
|
||||
+32 3 -30 3 *
|
||||
Ed
|
||||
0.0001 1 1 0
|
||||
1 4 0 0 3000
|
||||
6 7 1 0
|
||||
6 8 5 0
|
||||
0
|
||||
|
||||
0101000
|
||||
+30 3 -35 3 *
|
||||
Wi
|
||||
|
||||
0101100
|
||||
+33 0 +31 0 +29 0 +28 0 *
|
||||
Fa
|
||||
0 0.1 1 0
|
||||
2 1
|
||||
0111000
|
||||
+27 0 *
|
||||
Ve
|
||||
0.1
|
||||
5000 0 0
|
||||
0 0
|
||||
|
||||
0101101
|
||||
*
|
||||
Ed
|
||||
0.0001 1 1 0
|
||||
1 5 0 0 5000
|
||||
6 9 2 0
|
||||
6 10 5 0
|
||||
0
|
||||
|
||||
0101000
|
||||
+35 3 -25 3 *
|
||||
Ve
|
||||
0.1
|
||||
5000 -3000 0
|
||||
0 0
|
||||
|
||||
0101101
|
||||
*
|
||||
Ed
|
||||
0.0001 1 1 0
|
||||
1 6 0 0 3000
|
||||
6 11 2 0
|
||||
6 12 6 0
|
||||
0
|
||||
|
||||
0101000
|
||||
+25 3 -23 3 *
|
||||
Ed
|
||||
0.0001 1 1 0
|
||||
1 7 0 0 5000
|
||||
6 13 2 0
|
||||
6 14 3 0
|
||||
0
|
||||
|
||||
0101000
|
||||
+23 3 -34 3 *
|
||||
Wi
|
||||
|
||||
0101100
|
||||
+24 0 +22 0 +21 0 -33 0 *
|
||||
Fa
|
||||
0 0.1 2 0
|
||||
2 2
|
||||
0111000
|
||||
+20 0 *
|
||||
Ve
|
||||
0.1
|
||||
5000 -3000 3000
|
||||
0 0
|
||||
|
||||
0101101
|
||||
*
|
||||
Ed
|
||||
0.0001 1 1 0
|
||||
1 8 0 0 3000
|
||||
6 15 3 0
|
||||
6 16 6 0
|
||||
0
|
||||
|
||||
0101000
|
||||
+23 3 -18 3 *
|
||||
Ed
|
||||
0.0001 1 1 0
|
||||
1 9 0 0 5000
|
||||
6 17 3 0
|
||||
6 18 4 0
|
||||
0
|
||||
|
||||
0101000
|
||||
+18 3 -32 3 *
|
||||
Wi
|
||||
|
||||
0101100
|
||||
-21 0 +17 0 +16 0 -31 0 *
|
||||
Fa
|
||||
0 0.1 3 0
|
||||
2 3
|
||||
0111000
|
||||
+15 0 *
|
||||
Ve
|
||||
0.1
|
||||
5000 0 3000
|
||||
0 0
|
||||
|
||||
0101101
|
||||
*
|
||||
Ed
|
||||
0.0001 1 1 0
|
||||
1 10 0 0 3000
|
||||
6 19 4 0
|
||||
6 20 6 0
|
||||
0
|
||||
|
||||
0101000
|
||||
+18 3 -13 3 *
|
||||
Ed
|
||||
0.0001 1 1 0
|
||||
1 11 0 0 5000
|
||||
6 21 4 0
|
||||
6 22 5 0
|
||||
0
|
||||
|
||||
0101000
|
||||
+13 3 -30 3 *
|
||||
Wi
|
||||
|
||||
0101100
|
||||
-29 0 -16 0 +12 0 +11 0 *
|
||||
Fa
|
||||
0 0.1 4 0
|
||||
2 4
|
||||
0111000
|
||||
+10 0 *
|
||||
Ed
|
||||
0.0001 1 1 0
|
||||
1 12 0 0 3000
|
||||
6 23 5 0
|
||||
6 24 6 0
|
||||
0
|
||||
|
||||
0101000
|
||||
+13 3 -25 3 *
|
||||
Wi
|
||||
|
||||
0101100
|
||||
-24 0 -28 0 -11 0 +8 0 *
|
||||
Fa
|
||||
0 0.1 5 0
|
||||
2 5
|
||||
0111000
|
||||
+7 0 *
|
||||
Wi
|
||||
|
||||
0101100
|
||||
-22 0 -8 0 -12 0 -17 0 *
|
||||
Fa
|
||||
0 0.1 6 0
|
||||
2 6
|
||||
0111000
|
||||
+5 0 *
|
||||
Sh
|
||||
|
||||
0101100
|
||||
+26 0 +19 0 +14 0 +9 0 +6 0 +4 0 *
|
||||
So
|
||||
|
||||
0100000
|
||||
+3 0 *
|
||||
Co
|
||||
|
||||
1100000
|
||||
+2 2 *
|
||||
|
||||
+1 1
|
||||
"""
|
||||
85
src/Mod/BIM/bimtests/TestArchWall.py
Normal file
85
src/Mod/BIM/bimtests/TestArchWall.py
Normal file
@@ -0,0 +1,85 @@
|
||||
#***************************************************************************
|
||||
#* Copyright (c) 2013 Yorik van Havre <yorik@uncreated.net> *
|
||||
#* *
|
||||
#* This file is part of the FreeCAD CAx development system. *
|
||||
#* *
|
||||
#* This program is free software; you can redistribute it and/or modify *
|
||||
#* it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
#* as published by the Free Software Foundation; either version 2 of *
|
||||
#* the License, or (at your option) any later version. *
|
||||
#* for detail see the LICENCE text file. *
|
||||
#* *
|
||||
#* FreeCAD is distributed in the hope that it will be useful, *
|
||||
#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
#* GNU Library General Public License for more details. *
|
||||
#* *
|
||||
#* You should have received a copy of the GNU Library General Public *
|
||||
#* License along with FreeCAD; if not, write to the Free Software *
|
||||
#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
#* USA *
|
||||
#* *
|
||||
#***************************************************************************/
|
||||
|
||||
# Unit tests for the Arch wall module
|
||||
|
||||
import os
|
||||
import unittest
|
||||
import Arch
|
||||
import Draft
|
||||
import Part
|
||||
import FreeCAD as App
|
||||
from bimtests import TestArchBase
|
||||
|
||||
|
||||
class TestArchWall(TestArchBase.TestArchBase):
|
||||
|
||||
def testWall(self):
|
||||
operation = "Checking Arch Wall..."
|
||||
self.printTestMessage(operation)
|
||||
|
||||
l=Draft.makeLine(App.Vector(0,0,0),App.Vector(-2,0,0))
|
||||
w = Arch.makeWall(l)
|
||||
self.assertTrue(w,"Arch Wall failed")
|
||||
|
||||
def testWallMultiMatAlign(self):
|
||||
operation = "Checking Arch Wall with MultiMaterial and 3 alignments..."
|
||||
self.printTestMessage(operation)
|
||||
|
||||
matA = Arch.makeMaterial()
|
||||
matB = Arch.makeMaterial()
|
||||
matMulti = Arch.makeMultiMaterial()
|
||||
matMulti.Materials = [matA, matB]
|
||||
matMulti.Thicknesses = [100, 200] # total width different from default 200
|
||||
pts = [App.Vector( 0, 0, 0),
|
||||
App.Vector(1000, 0, 0),
|
||||
App.Vector(1000, 1000, 0),
|
||||
App.Vector(2000, 1000, 0)]
|
||||
# wall based on wire:
|
||||
wire = Draft.makeWire(pts)
|
||||
wallWire = Arch.makeWall(wire)
|
||||
wallWire.Material = matMulti
|
||||
# wall based on sketch:
|
||||
sketch = App.activeDocument().addObject('Sketcher::SketchObject','Sketch')
|
||||
sketch.addGeometry([Part.LineSegment(pts[0], pts[1]),
|
||||
Part.LineSegment(pts[1], pts[2]),
|
||||
Part.LineSegment(pts[2], pts[3])])
|
||||
wallSketch = Arch.makeWall(sketch)
|
||||
wallSketch.Material = matMulti
|
||||
|
||||
alignLst = ["Left", "Center", "Right"]
|
||||
checkLst = [[App.Vector(0, -300, 0), App.Vector(2000, 1000, 0)],
|
||||
[App.Vector(0, -150, 0), App.Vector(2000, 1150, 0)],
|
||||
[App.Vector(0, 0, 0), App.Vector(2000, 1300, 0)]]
|
||||
for i in range(3):
|
||||
wallWire.Align = alignLst[i]
|
||||
wallSketch.Align = alignLst[i]
|
||||
App.ActiveDocument.recompute()
|
||||
for box in [wallWire.Shape.BoundBox, wallSketch.Shape.BoundBox]:
|
||||
ptMin = App.Vector(box.XMin, box.YMin, 0)
|
||||
self.assertTrue(ptMin.isEqual(checkLst[i][0], 1e-8),
|
||||
"Arch Wall with MultiMaterial and 3 alignments failed")
|
||||
ptMax = App.Vector(box.XMax, box.YMax, 0)
|
||||
self.assertTrue(ptMax.isEqual(checkLst[i][1], 1e-8),
|
||||
"Arch Wall with MultiMaterial and 3 alignments failed")
|
||||
|
||||
0
src/Mod/BIM/bimtests/__init__.py
Normal file
0
src/Mod/BIM/bimtests/__init__.py
Normal file
Reference in New Issue
Block a user