diff --git a/ahb_cmd_new_step.py b/ahb_cmd_new_step.py index 4b29f4b..074ea8e 100644 --- a/ahb_cmd_new_step.py +++ b/ahb_cmd_new_step.py @@ -1,6 +1,7 @@ import FreeCADGui as Gui import FreeCAD as App +import ahb_utils class AHB_New_Step: def GetResources(self): return {"MenuText": "New Step", @@ -9,7 +10,7 @@ class AHB_New_Step: } def IsActive(self): - return True + return ahb_utils.getCurrentView() is not None def Activated(self): import re diff --git a/ahb_cmd_view_annotate.py b/ahb_cmd_view_annotate.py index bc63c3d..90d8641 100644 --- a/ahb_cmd_view_annotate.py +++ b/ahb_cmd_view_annotate.py @@ -1,6 +1,9 @@ +import math import FreeCADGui as Gui import FreeCAD as App +import ahb_utils + class AHB_View_Annotate: def GetResources(self): return {"MenuText": "Annotate view", @@ -67,9 +70,75 @@ class AHB_View_Annotate: doc.removeObject(balloon.Name) for partLink in view.XSource: - workbench.techDrawExtensions.add_or_update_balloon(view, partLink, '') - + balloonsCreated = workbench.techDrawExtensions.add_or_update_balloon(view, partLink, '') + if len(balloonsCreated) > 0: + regroupedBalloons = self.RegroupNearestSimilarBalloons(balloonsCreated) + self.PlaceBalloonsInCircle(regroupedBalloons) + #self.PlaceBalloonsInCircle(balloonsCreated) + workbench.techDrawExtensions.refreshOverlays(page) + + def CalculatePointsCenter(self, balloons): + totalX = 0 + totalY = 0 + for balloon in balloons: + realBalloon = balloon[0] if type(balloon) is list else balloon + totalX = totalX + int(realBalloon.OriginX) + totalY = totalY + int(realBalloon.OriginY) + return App.Base.Vector2d(totalX / len(balloons), totalY / len(balloons)) + + def IsSimilarBalloonNear(self, balloonA, balloonB): + MAX_DISTANCE_BETWEEN_REGROUPED_BALLOONS = 50 + if balloonA.Text == balloonB.Text: + pos = App.Base.Vector2d(balloonA.OriginX, balloonA.OriginY) + dist = pos.distance(App.Base.Vector2d(balloonB.OriginX, balloonB.OriginY)) + return dist < MAX_DISTANCE_BETWEEN_REGROUPED_BALLOONS + else: + return False + + def RegroupNearestSimilarBalloons(self, balloons): + regroupedBalloons = [] + for balloon in balloons: + nearestBalloons = [] + for otherBalloon in balloons: + if otherBalloon != balloon and self.IsSimilarBalloonNear(balloon, otherBalloon): + nearestBalloons.append(otherBalloon) + balloons.remove(otherBalloon) + if len(nearestBalloons) == 0: + regroupedBalloons.append(balloon) + else: + nearestBalloons.append(balloon) + regroupedBalloons.append(nearestBalloons) + return regroupedBalloons + + def PlaceBalloonsInCircle(self, balloons): + center = self.CalculatePointsCenter(balloons) + nbBalloons = len(balloons) + balloonPosStep = (math.pi * 2) / nbBalloons + for i in range(nbBalloons): + xPos = round(center.x + 600 * math.cos(balloonPosStep * i)) + yPos = round(center.y + 600 * math.sin(balloonPosStep * i)) + balloonPos = App.Base.Vector2d(xPos, yPos) + # Find nearest arrow to avoid arrow crossing each other + smallestDistance = 0 + balloonToUse = None + for balloon in balloons: + realBalloon = balloon[0] if type(balloon) is list else balloon + dist = balloonPos.distance(App.Base.Vector2d(realBalloon.OriginX, realBalloon.OriginY)) + if smallestDistance == 0 or dist < smallestDistance: + smallestDistance = dist + balloonToUse = balloon + + if balloonToUse is not None: + balloons.remove(balloonToUse) + if type(balloonToUse) is list: + for realBalloon in balloonToUse: + realBalloon.X = balloonPos.x + realBalloon.Y = balloonPos.y + else: + balloonToUse.X = balloonPos.x + balloonToUse.Y = balloonPos.y + from ahb_command import AHB_CommandWrapper AHB_CommandWrapper.addGuiCommand('AHB_view_annotate', AHB_View_Annotate()) diff --git a/ahb_cmd_view_edit_source_parts.py b/ahb_cmd_view_edit_source_parts.py index e0747aa..b03c318 100644 --- a/ahb_cmd_view_edit_source_parts.py +++ b/ahb_cmd_view_edit_source_parts.py @@ -1,6 +1,8 @@ import FreeCADGui as Gui import FreeCAD as App +import ahb_utils + class AHB_EditViewSourceParts: def GetResources(self): return {"MenuText": "Edit view source parts", @@ -19,9 +21,7 @@ class AHB_EditViewSourceParts: def Activated(self): workbench = Gui.getWorkbench("AssemblyHandbookWorkbench") #: :type workbench: AssemblyHandbookWorkbench - view = None - if len(Gui.Selection.getSelection()) == 1 and Gui.Selection.getSelection()[0].TypeId == 'TechDraw::DrawViewPart': - view = Gui.Selection.getSelection()[0] + view = ahb_utils.getCurrentView() workbench.techDrawExtensions.toggleEditViewSourceParts(view) class AHB_AddSourcePartsToView: diff --git a/ahb_cmd_view_set_direction.py b/ahb_cmd_view_set_direction.py index d657491..c839e54 100644 --- a/ahb_cmd_view_set_direction.py +++ b/ahb_cmd_view_set_direction.py @@ -1,6 +1,7 @@ import FreeCADGui as Gui import FreeCAD as App +import ahb_utils class AHB_SetViewDirection: def GetResources(self): return {"MenuText": "Set view direction", @@ -9,22 +10,15 @@ class AHB_SetViewDirection: } def IsActive(self): - view = self._get_view() - return view is not None + return ahb_utils.getCurrentView() is not None def Activated(self): workbench = Gui.getWorkbench("AssemblyHandbookWorkbench") #: :type workbench: AssemblyHandbookWorkbench - view = self._get_view() + view = ahb_utils.getCurrentView() if view is None: raise Exception("Please select a TechDraw view") workbench.techDrawExtensions.setCurrentViewDirection(view) - def _get_view(self): - view = None if len(Gui.Selection.getSelection()) == 0 else Gui.Selection.getSelection()[0] - if view is not None and view.TypeId != 'TechDraw::DrawViewPart': - view = None - return view - from ahb_command import AHB_CommandWrapper AHB_CommandWrapper.addGuiCommand('AHB_view_set_direction', AHB_SetViewDirection()) diff --git a/ahb_techdraw_extensions.py b/ahb_techdraw_extensions.py index c57e86d..7336d69 100644 --- a/ahb_techdraw_extensions.py +++ b/ahb_techdraw_extensions.py @@ -457,6 +457,7 @@ class TechDrawExtensions: self.updating_balloon = False def add_or_update_balloon(self, view, part, parent_path): + balloonsCreated = [] page = self.getViewPage(view) overlay_view = self.getOverlayView(view) doc = page.Document @@ -498,13 +499,14 @@ class TechDrawExtensions: self.updateBalloon(balloon) - balloon.X = int(balloon.OriginX) + 20 - balloon.Y = int(balloon.OriginY) + 20 - if not self.isNewPartInView(view, part): balloon.ViewObject.Visibility = False + else: + balloonsCreated.append(balloon) else: self.updateBalloon(balloon) + + return balloonsCreated def updateBalloon(self, balloon): workbench = Gui.getWorkbench("AssemblyHandbookWorkbench") #: :type workbench: AssemblyHandbookWorkbench @@ -524,7 +526,7 @@ class TechDrawExtensions: balloon.ViewObject.Font = 'DejaVu Sans' balloon.ViewObject.Fontsize = 4 balloon.BubbleShape = 'Inspection' - balloon.EndTypeScale = 1 + balloon.EndTypeScale = 0.5 def getBalloonSourcePart(self, balloon): try: diff --git a/ahb_utils.py b/ahb_utils.py new file mode 100644 index 0000000..6d66ff1 --- /dev/null +++ b/ahb_utils.py @@ -0,0 +1,8 @@ +import FreeCADGui as Gui + +def getCurrentView(): + currentSel = Gui.Selection.getSelection() + if len(currentSel) == 1 and currentSel[0].TypeId == 'TechDraw::DrawViewPart': + return currentSel[0] + else: + return None \ No newline at end of file