From 58cbb2381bb734ec2a9ddbeb1ecde63f5db51fcb Mon Sep 17 00:00:00 2001 From: furti Date: Tue, 5 Mar 2019 17:41:33 +0100 Subject: [PATCH] Add compass to Arch Site The compass helps you to locate north in your drawings. It has the following features: - Can be hidden independently from the site. So you can still have the site without the compass. - Can be rotated relative to the site. - Also rotates with the site - Always sits 1 meter above the site geometry https://forum.freecadweb.org/viewtopic.php?f=23&t=34669 --- src/Mod/Arch/ArchSite.py | 191 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) diff --git a/src/Mod/Arch/ArchSite.py b/src/Mod/Arch/ArchSite.py index 4e1a71301a..396082d9b5 100644 --- a/src/Mod/Arch/ArchSite.py +++ b/src/Mod/Arch/ArchSite.py @@ -257,6 +257,145 @@ def makeSolarDiagram(longitude,latitude,scale=1,complete=False): numsep.addChild(item) return mastersep +# Values in mm +COMPASS_POINTER_LENGTH = 1000 +COMPASS_POINTER_WIDTH = 100 + + +class Compass(object): + def __init__(self): + self.rootNode = self.setupCoin() + + def show(self): + from pivy import coin + self.compassswitch.whichChild = coin.SO_SWITCH_ALL + + def hide(self): + from pivy import coin + self.compassswitch.whichChild = coin.SO_SWITCH_NONE + + def rotate(self, angleInDegrees): + from pivy import coin + self.transform.rotation.setValue( + coin.SbVec3f(0, 0, 1), math.radians(angleInDegrees)) + + def setZOffset(self, offsetInMillimeters): + from pivy import coin + self.transform.translation.setValue(0, 0, offsetInMillimeters) + + def setupCoin(self): + from pivy import coin + + compasssep = coin.SoSeparator() + + self.transform = coin.SoTransform() + + darkNorthMaterial = coin.SoMaterial() + darkNorthMaterial.diffuseColor.set1Value( + 0, 0.5, 0, 0) # north dark color + + lightNorthMaterial = coin.SoMaterial() + lightNorthMaterial.diffuseColor.set1Value( + 0, 0.9, 0, 0) # north light color + + darkGreyMaterial = coin.SoMaterial() + darkGreyMaterial.diffuseColor.set1Value(0, 0.9, 0.9, 0.9) # dark color + + lightGreyMaterial = coin.SoMaterial() + lightGreyMaterial.diffuseColor.set1Value( + 0, 0.5, 0.5, 0.5) # light color + + coords = self.buildCoordinates() + + # coordIndex = [0, 1, 2, -1, 2, 3, 0, -1] + + lightColorFaceset = coin.SoIndexedFaceSet() + lightColorCoordinateIndex = [4, 5, 6, -1, 8, 9, 10, -1, 12, 13, 14, -1] + lightColorFaceset.coordIndex.setValues( + 0, len(lightColorCoordinateIndex), lightColorCoordinateIndex) + + darkColorFaceset = coin.SoIndexedFaceSet() + darkColorCoordinateIndex = [6, 7, 4, -1, 10, 11, 8, -1, 14, 15, 12, -1] + darkColorFaceset.coordIndex.setValues( + 0, len(darkColorCoordinateIndex), darkColorCoordinateIndex) + + lightNorthFaceset = coin.SoIndexedFaceSet() + lightNorthCoordinateIndex = [2, 3, 0, -1] + lightNorthFaceset.coordIndex.setValues( + 0, len(lightNorthCoordinateIndex), lightNorthCoordinateIndex) + + darkNorthFaceset = coin.SoIndexedFaceSet() + darkNorthCoordinateIndex = [0, 1, 2, -1] + darkNorthFaceset.coordIndex.setValues( + 0, len(darkNorthCoordinateIndex), darkNorthCoordinateIndex) + + self.compassswitch = coin.SoSwitch() + self.compassswitch.whichChild = coin.SO_SWITCH_NONE + self.compassswitch.addChild(compasssep) + + lightGreySeparator = coin.SoSeparator() + lightGreySeparator.addChild(lightGreyMaterial) + lightGreySeparator.addChild(lightColorFaceset) + + darkGreySeparator = coin.SoSeparator() + darkGreySeparator.addChild(darkGreyMaterial) + darkGreySeparator.addChild(darkColorFaceset) + + lightNorthSeparator = coin.SoSeparator() + lightNorthSeparator.addChild(lightNorthMaterial) + lightNorthSeparator.addChild(lightNorthFaceset) + + darkNorthSeparator = coin.SoSeparator() + darkNorthSeparator.addChild(darkNorthMaterial) + darkNorthSeparator.addChild(darkNorthFaceset) + + compasssep.addChild(coords) + compasssep.addChild(self.transform) + compasssep.addChild(lightGreySeparator) + compasssep.addChild(darkGreySeparator) + compasssep.addChild(lightNorthSeparator) + compasssep.addChild(darkNorthSeparator) + + return self.compassswitch + + def buildCoordinates(self): + from pivy import coin + + coords = coin.SoCoordinate3() + + # North Arrow + coords.point.set1Value(0, 0, 0, 0) + coords.point.set1Value(1, COMPASS_POINTER_WIDTH, + COMPASS_POINTER_WIDTH, 0) + coords.point.set1Value(2, 0, COMPASS_POINTER_LENGTH, 0) + coords.point.set1Value(3, -COMPASS_POINTER_WIDTH, + COMPASS_POINTER_WIDTH, 0) + + # East Arrow + coords.point.set1Value(4, 0, 0, 0) + coords.point.set1Value( + 5, COMPASS_POINTER_WIDTH, -COMPASS_POINTER_WIDTH, 0) + coords.point.set1Value(6, COMPASS_POINTER_LENGTH, 0, 0) + coords.point.set1Value(7, COMPASS_POINTER_WIDTH, + COMPASS_POINTER_WIDTH, 0) + + # South Arrow + coords.point.set1Value(8, 0, 0, 0) + coords.point.set1Value( + 9, -COMPASS_POINTER_WIDTH, -COMPASS_POINTER_WIDTH, 0) + coords.point.set1Value(10, 0, -COMPASS_POINTER_LENGTH, 0) + coords.point.set1Value( + 11, COMPASS_POINTER_WIDTH, -COMPASS_POINTER_WIDTH, 0) + + # West Arrow + coords.point.set1Value(12, 0, 0, 0) + coords.point.set1Value(13, -COMPASS_POINTER_WIDTH, + COMPASS_POINTER_WIDTH, 0) + coords.point.set1Value(14, -COMPASS_POINTER_LENGTH, 0, 0) + coords.point.set1Value( + 15, -COMPASS_POINTER_WIDTH, -COMPASS_POINTER_WIDTH, 0) + + return coords class _CommandSite: @@ -374,6 +513,12 @@ class _Site(ArchFloor._Floor): obj.addProperty("App::PropertyVector","OriginOffset","Site",QT_TRANSLATE_NOOP("App::Property","An optional offset between the model (0,0,0) origin and the point indicated by the geocoordinates")) if not hasattr(obj,"Group"): obj.addExtension("App::GroupExtensionPython", self) + if not "Compass" in pl: + obj.addProperty("App::PropertyBool", "Compass", "Compass", QT_TRANSLATE_NOOP( + "App::Property", "Show compass or not")) + if not "CompassRotation" in pl: + obj.addProperty("App::PropertyAngle", "CompassRotation", "Compass", QT_TRANSLATE_NOOP( + "App::Property", "The rotation of the Compass relative to the Site")) self.Type = "Site" obj.setEditorMode('Height',2) @@ -577,12 +722,24 @@ class _ViewProviderSite(ArchFloor._ViewProviderFloor): self.diagramsep.addChild(self.color) vobj.Annotation.addChild(self.diagramswitch) + self.compass = Compass() + self.updateCompassVisibility(self.Object) + self.rotateCompass(self.Object) + + vobj.Annotation.addChild(self.compass.rootNode) + def updateData(self,obj,prop): if prop in ["Longitude","Latitude"]: self.onChanged(obj.ViewObject,"SolarDiagram") elif prop == "Declination": self.onChanged(obj.ViewObject,"SolarDiagramPosition") + elif prop == "Terrain": + self.updateCompassLocation(obj) + elif prop == "Compass": + self.updateCompassVisibility(obj) + elif prop == "CompassRotation": + self.rotateCompass(obj) def onChanged(self,vobj,prop): @@ -611,6 +768,40 @@ class _ViewProviderSite(ArchFloor._ViewProviderFloor): del self.diagramnode else: self.diagramswitch.whichChild = -1 + elif prop == 'Visibility': + if vobj.Visibility: + self.updateCompassVisibility(self.Object) + else: + self.compass.hide() + + def updateCompassVisibility(self, obj): + if not hasattr(self, 'compass'): + return + + show = hasattr(obj, 'Compass') and obj.Compass + + if show: + self.compass.show() + else: + self.compass.hide() + + def rotateCompass(self, obj): + if not hasattr(self, 'compass'): + return + + if hasattr(obj, 'CompassRotation'): + self.compass.rotate(obj.CompassRotation.Value) + + def updateCompassLocation(self, obj): + if not hasattr(self, 'compass'): + return + + boundBox = obj.Shape.BoundBox + pos = obj.Placement.Base + + zOffset = boundBox.ZMax = pos.z + + self.compass.setZOffset(zOffset + 1000) if FreeCAD.GuiUp: