BIM: Fix BIM_Box command

Fixes #14823.

Depending on the order and location of the picked points, the Placement of the Box could be unexpected. The Height value was always positive if points were picked, a negative Height entered in the input box would lead to errors.

Additonally:
* Avoided some code duplication.
* Added a proper transaction to make the command undoable.
This commit is contained in:
Roy-043
2024-07-01 23:47:10 +02:00
committed by Yorik van Havre
parent c60b4dbd1f
commit ea7a68dfe1
2 changed files with 97 additions and 120 deletions

View File

@@ -66,6 +66,7 @@ class BIM_Box:
)
def MoveCallback(self, point, snapinfo):
import DraftGeomUtils
import DraftVecUtils
self.currentpoint = point
@@ -73,7 +74,7 @@ class BIM_Box:
# we have the base point already
self.Length.setText(
FreeCAD.Units.Quantity(
str(self.points[-1].sub(point).Length) + "mm"
self.points[-1].sub(point).Length, FreeCAD.Units.Length
).UserString
)
self.Length.selectAll()
@@ -91,20 +92,20 @@ class BIM_Box:
self.cubetracker[0].p3(p)
self.Width.setText(
FreeCAD.Units.Quantity(
str(self.cubetracker[0].getSize()[1]) + "mm"
self.cubetracker[0].getSize()[1], FreeCAD.Units.Length
).UserString
)
self.Width.selectAll()
self.Width.setFocus()
elif len(self.points) == 3:
# we must first find our height point by projecting on the normal
w = DraftVecUtils.project(point.sub(self.cubetracker[0].p3()), self.normal)
h = DraftGeomUtils.distance_to_plane(point, self.cubetracker[0].p3(), self.normal)
w = self.normal * h
# then we update all rectangles
self.cubetracker[1].p3((self.cubetracker[0].p2()).add(w))
self.cubetracker[2].p3((self.cubetracker[0].p4()).add(w))
self.cubetracker[3].p1((self.cubetracker[0].p1()).add(w))
self.cubetracker[3].p3((self.cubetracker[0].p3()).add(w))
self.Height.setText(FreeCAD.Units.Quantity(str(w.Length) + "mm").UserString)
self.Height.setText(FreeCAD.Units.Quantity(h, FreeCAD.Units.Length).UserString)
self.Height.selectAll()
self.Height.setFocus()
@@ -120,6 +121,7 @@ class BIM_Box:
if len(self.points) == 0:
# this is our first clicked point, nothing to do just yet
self.points.append(point)
FreeCADGui.Snapper.getPoint(
last=point,
callback=self.PointCallback,
@@ -128,70 +130,17 @@ class BIM_Box:
)
elif len(self.points) == 1:
# this is our second point
# we turn on only one of the rectangles
baseline = point.sub(self.points[0])
self.cubetracker[0].setPlane(baseline)
self.cubetracker[0].p1(self.points[0])
self.cubetracker[0].on()
FreeCADGui.Snapper.getPoint(
last=point,
callback=self.PointCallback,
movecallback=self.MoveCallback,
extradlg=self.taskbox(),
)
self.points.append(point)
self._setupForWidthInput(baseline)
elif len(self.points) == 2:
# this is our third point
# we can get the cubes Z axis from our first rectangle
self.normal = self.cubetracker[0].getNormal()
# we can therefore define the (u,v) planes of all rectangles
u = self.cubetracker[0].u
v = self.cubetracker[0].v
self.cubetracker[1].setPlane(u, self.normal)
self.cubetracker[2].setPlane(u, self.normal)
self.cubetracker[3].setPlane(u, v)
# and the origin points of the vertical rectangles
self.cubetracker[1].p1(self.cubetracker[0].p1())
self.cubetracker[2].p1(self.cubetracker[0].p3())
# finally we turn all rectangles on
for r in self.cubetracker:
r.on()
if hasattr(FreeCAD, "DraftWorkingPlane"):
FreeCAD.DraftWorkingPlane.save()
FreeCAD.DraftWorkingPlane.position = self.cubetracker[0].p3()
FreeCAD.DraftWorkingPlane.u = (
self.cubetracker[0].p4().sub(self.cubetracker[0].p3())
).normalize()
FreeCAD.DraftWorkingPlane.v = FreeCAD.Vector(self.normal).normalize()
FreeCAD.DraftWorkingPlane.axis = (
self.cubetracker[0].p2().sub(self.cubetracker[0].p3())
).normalize()
FreeCADGui.Snapper.setGrid()
FreeCADGui.Snapper.getPoint(
last=self.cubetracker[0].p3(),
callback=self.PointCallback,
movecallback=self.MoveCallback,
extradlg=self.taskbox(),
)
self.points.append(point)
self._setupForHeightInput()
elif len(self.points) == 3:
# finally we have all our points. Let's create the actual cube
cube = FreeCAD.ActiveDocument.addObject("Part::Box", "Cube")
cube.Length = self.LengthValue
cube.Width = self.WidthValue
cube.Height = self.HeightValue
# we get 3 points that define our cube orientation
p1 = self.cubetracker[0].p1()
p2 = self.cubetracker[0].p2()
p3 = self.cubetracker[0].p4()
import WorkingPlane
cube.Placement = WorkingPlane.getPlacementFromPoints([p1, p2, p3])
if hasattr(FreeCAD, "DraftWorkingPlane"):
FreeCAD.DraftWorkingPlane.restore()
FreeCADGui.Snapper.setGrid()
for c in self.cubetracker:
c.off()
FreeCAD.ActiveDocument.recompute()
self.points.append(point)
self._makeBox()
self._finish()
def taskbox(self):
"sets up a taskbox widget"
@@ -254,15 +203,7 @@ class BIM_Box:
baseline.multiply(self.LengthValue)
p2 = self.points[0].add(baseline)
self.points.append(p2)
self.cubetracker[0].setPlane(baseline)
self.cubetracker[0].p1(self.points[0])
self.cubetracker[0].on()
FreeCADGui.Snapper.getPoint(
last=p2,
callback=self.PointCallback,
movecallback=self.MoveCallback,
extradlg=self.taskbox(),
)
self._setupForWidthInput(baseline)
def setWidthUI(self):
if (len(self.points) == 2) and self.currentpoint and self.WidthValue:
@@ -275,57 +216,93 @@ class BIM_Box:
p2 = self.points[1].add(n)
self.cubetracker[0].p3(p2)
self.points.append(p2)
u = self.cubetracker[0].u
v = self.cubetracker[0].v
self.cubetracker[1].setPlane(u, self.normal)
self.cubetracker[2].setPlane(u, self.normal)
self.cubetracker[3].setPlane(u, v)
self.cubetracker[1].p1(self.cubetracker[0].p1())
self.cubetracker[2].p1(self.cubetracker[0].p3())
for r in self.cubetracker:
r.on()
if hasattr(FreeCAD, "DraftWorkingPlane"):
FreeCAD.DraftWorkingPlane.save()
FreeCAD.DraftWorkingPlane.position = self.cubetracker[0].p3()
FreeCAD.DraftWorkingPlane.u = (
self.cubetracker[0].p4().sub(self.cubetracker[0].p3())
).normalize()
FreeCAD.DraftWorkingPlane.v = self.normal
FreeCAD.DraftWorkingPlane.axis = (
self.cubetracker[0].p2().sub(self.cubetracker[0].p3())
).normalize()
FreeCADGui.Snapper.setGrid()
FreeCADGui.Snapper.getPoint(
last=p2,
callback=self.PointCallback,
movecallback=self.MoveCallback,
extradlg=self.taskbox(),
)
self._setupForHeightInput()
def setHeightUI(self):
if (len(self.points) == 3) and self.HeightValue:
cube = FreeCAD.ActiveDocument.addObject("Part::Box", "Cube")
cube.Length = self.LengthValue
cube.Width = self.WidthValue
cube.Height = self.HeightValue
# we get 3 points that define our cube orientation
p1 = self.cubetracker[0].p1()
p2 = self.cubetracker[0].p2()
p3 = self.cubetracker[0].p4()
FreeCADGui.Snapper.off()
import WorkingPlane
self._makeBox()
self._finish()
cube.Placement = WorkingPlane.getPlacementFromPoints([p1, p2, p3])
if hasattr(FreeCAD, "DraftWorkingPlane"):
FreeCAD.DraftWorkingPlane.restore()
def _setupForWidthInput(self, baseline):
# we turn on only one of the rectangles
self.cubetracker[0].setPlane(baseline)
self.cubetracker[0].p1(self.points[0])
self.cubetracker[0].on()
FreeCADGui.Snapper.getPoint(
last=self.points[-1],
callback=self.PointCallback,
movecallback=self.MoveCallback,
extradlg=self.taskbox(),
)
def _setupForHeightInput(self):
# we can get the cubes Z axis from our first rectangle
self.normal = self.cubetracker[0].getNormal()
# we can therefore define the (u,v) planes of all rectangles
u = self.cubetracker[0].u
v = self.cubetracker[0].v
self.cubetracker[1].setPlane(u, self.normal)
self.cubetracker[2].setPlane(u, self.normal)
self.cubetracker[3].setPlane(u, v)
# and the origin points of the vertical rectangles
self.cubetracker[1].p1(self.cubetracker[0].p1())
self.cubetracker[2].p1(self.cubetracker[0].p3())
# finally we turn all rectangles on
for r in self.cubetracker:
r.on()
if hasattr(FreeCAD, "DraftWorkingPlane"):
FreeCAD.DraftWorkingPlane.save()
FreeCAD.DraftWorkingPlane.position = self.cubetracker[0].p3()
FreeCAD.DraftWorkingPlane.u = (
self.cubetracker[0].p3().sub(self.cubetracker[0].p4())
).normalize()
FreeCAD.DraftWorkingPlane.v = self.normal
FreeCAD.DraftWorkingPlane.axis = (
self.cubetracker[0].p2().sub(self.cubetracker[0].p3())
).normalize()
FreeCADGui.Snapper.setGrid()
for c in self.cubetracker:
c.off()
FreeCADGui.Snapper.getPoint()
FreeCADGui.Snapper.off()
if hasattr(FreeCADGui, "draftToolBar"):
FreeCADGui.draftToolBar.offUi()
FreeCAD.ActiveDocument.recompute()
FreeCADGui.Snapper.getPoint(
last=self.cubetracker[0].p3(),
callback=self.PointCallback,
movecallback=self.MoveCallback,
extradlg=self.taskbox(),
)
def _makeBox(self):
import DraftGeomUtils
p1 = self.cubetracker[0].p1()
p2 = self.cubetracker[0].p2()
p3 = self.cubetracker[0].p4()
pla = DraftGeomUtils.placement_from_points(p1, p2, p3)
if self.normal.isEqual(pla.Rotation.multVec(FreeCAD.Vector(0, 0, 1)), 1e-6):
if self.HeightValue < 0.0:
pla = DraftGeomUtils.placement_from_points(p1, p3, p2)
self.LengthValue, self.WidthValue = self.WidthValue, self.LengthValue
else:
if self.HeightValue > 0.0:
pla = DraftGeomUtils.placement_from_points(p1, p3, p2)
self.LengthValue, self.WidthValue = self.WidthValue, self.LengthValue
doc = FreeCAD.ActiveDocument
doc.openTransaction(translate("Arch","Create Box"))
cube = doc.addObject("Part::Box", "Cube")
cube.Placement = pla
cube.Length = self.LengthValue
cube.Width = self.WidthValue
cube.Height = abs(self.HeightValue)
doc.commitTransaction()
doc.recompute()
def _finish(self):
FreeCADGui.Snapper.getPoint()
FreeCADGui.Snapper.off()
for c in self.cubetracker:
c.finalize()
if hasattr(FreeCADGui, "draftToolBar"):
FreeCADGui.draftToolBar.offUi()
if hasattr(FreeCAD, "DraftWorkingPlane"):
FreeCAD.DraftWorkingPlane.restore()
FreeCADGui.Snapper.setGrid()
FreeCADGui.addCommand("BIM_Box", BIM_Box())

View File

@@ -288,7 +288,7 @@ class rectangleTracker(Tracker):
self.v = v
else:
norm = self._get_wp().axis
self.v = self.u.cross(norm)
self.v = norm.cross(self.u)
def p1(self, point=None):
"""Set or get the base point of the rectangle."""