| Descrizione |
|---|
| Questa macro aggiunge una vista ausiliaria a una pagina TechDraw Versione macro: 0.02 Ultima modifica: 27/06/2025 Autore: FBXL5 |
| Autore |
| FBXL5 |
| Download |
| Link |
| Raccolta di macro Come installare le macro Personalizzare la toolbar |
| Versione macro |
| 0.02 |
| Data ultima modifica |
| 27/06/2025 |
| Versioni di FreeCAD |
| Scorciatoia |
| Nessuna |
| Vedere anche |
Non tutti coloro che devono consegnare un disegno insieme al proprio modello si accontentano di sole tre viste principali (viste primarie) e delle relative sezioni parallele. Per rappresentare un modello da qualsiasi angolazione possibile, i progettisti si affidano a viste ausiliarie (viste secondarie) che vengono posizionate sulla pagina di disegno in un ordine specifico, in modo da poter ricostruire la sequenza di definizione di ciascuna vista. Viste non correlate, definite nello spazio 3D e posizionate casualmente sulla pagina di disegno, non rappresentano un valido sostituto per le viste ausiliarie correttamente ordinate.
Per ora questa pagina ospita solo una macro che funge da prova di concetto e dimostra che è possibile definire una vista ausiliaria all'interno di una vista di base senza dover passare attraverso lo spazio 3D.
La Macro TechDraw AuxiliaryView aggiunge una vista ausiliaria (oggetto AuxView) a una pagina TechDraw. Si tratta di una vista semplice definita in una vista di base anziché nello spazio 3D.
AuxView definita dalla linea rossa nella vista base a destra
Si supponga di avere una vista parallela alla griglia e di voler sviluppare altre viste per visualizzare le forme reali degli elementi geometrici che si desidera quotare.
L'idea alla base è quella di scegliere una linea retta in una vista di base e definire una vista ausiliaria perpendicolare ad essa; questa sarà la vista di base per un'altra vista ausiliaria lungo la stessa linea retta. Si possono concatenare le viste ausiliarie fino a creare tutte e tre le viste principali dell'oggetto e una lungo la sua sottoforma cilindrica:
La linea retta posizionata arbitrariamente (rossa) nella vista iniziale verrà proiettata come una linea di lunghezza reale in AuxView X e come un punto in AuxView Y, dove si può anche vedere la larghezza e lo spessore reali della piastra di base. AuxView Z è definita perpendicolarmente alla piastra di base e presenta la forma reale della piastra di base e dei suoi fori. AuxView R è perpendicolare al lato più lungo della piastra di base e mostra gli angoli reali della faccia superiore e inferiore della sottoforma cilindrica e come questa si adatta alla piastra di base. L'ultima, AuxView S, è definita lungo l'asse del cilindro e mostra il diametro e lo spessore della sottoforma cilindrica.
Disegnare manualmente le viste ausiliarie richiede una seconda vista di base per accedere alle altezze rispetto al piano della vista di base, ma poiché FreeCAD si occupa di tutte le proiezioni, ci si può concentrare esclusivamente sulla direzione della vista.
Premere il pulsante Macro... e crea una nuova macro. Copiare e incollare la macro qui sotto nell'editor delle macro.
#! python
# -*- coding: utf-8 -*-
"""
This script creates an Auxiliary View from two selectec vertices
of one base view.
What is required: an active document, a drawing page containing one
or more views with a projection of a shape.
A possible workflow:
1. Extract base view from selection (two vertices)
2. Extract work page from app objects
3. Add a new view
4. Link base view from selection to new view
5. Link base view source to new view source
6. Retrieve new view's x direction from base view's x direction
7. calculate new view's z direction from new view's x direction
and base view's z direction
8. Set new view rotation including base view rotation
9. (Add annotations etc.)
I have tried to follow this naming rule:
class names: CamelCase
function names: mixedCase
constant names: ALL_CAPITAL + underscore
variable names: lower_case + underscore
"""
__Name__= ""
__Comment__ = ""
__Author__ = "FBXL5"
__Version__ = "00.02"
__Date__ = "2025-06-27"
__License__ = "LGPL-2.0-or-later"
__Web__ = ""
__Wiki__ = ""
__Icon__ = ""
__IconW__ = ""
__Help__ = ""
__Status__ = "Alpha"
__Requires__ = "FreeCAD >= 1.0 + Python3"
__Communication__ = "https://www.freecad.org/wiki/index.php?title=User: FBXL5"
__Files__ = ""
import math # to use some predefined conversions
from PySide.QtGui import (QMessageBox)
ARROW = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns="http://www.w3.org/2000/svg" version="1.1"
width ="16.8mm"
height="2.8mm"
viewBox=" 0 -1.4 16.8 2.8">
<g id="ArrowHead"
style="fill:#000;fill-opacity:1;stroke:#000;stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;font-size:5.0;text-anchor:middle;font-family:osifont">
<path d="m 0.3 0.0 h 16 " />
<path d="m 0.3 0.0 l 8.0 1.05 v -2.1 z " />
</g>
</svg>
"""
def displayMessage(title,message):
'''
displayMessage('Title','Messagetext')
'''
message_box = QMessageBox()
message_box.setText(message)
message_box.setWindowTitle(title)
message_box.exec()
def getActiveDocument():
'''
Returns the active document or sends a message
'''
ado = App.activeDocument()
if ado is not None:
return ado
displayMessage("AuxView", "No active document available!")
return False
# (borrowed from TechDraw sources)
def getSelView(nSel=0):
'''
view = getSelView()
nSel=0 ... number of selected view, 0 = first selected
Return selected view, otherwise return False
'''
if not Gui.Selection.getSelection():
view = None
displayMessage('AuxView','No view selected')
else:
view = Gui.Selection.getSelection()[nSel]
return view
# (borrowed from TechDraw sources)
def getSelVertexes(nVertex=1, nSel=0):
'''
vertexes = getSelVertexes(nVertex)
nVertex=1 ... min. number of selected vertexes
nSel=0 ... number of selected view, 0 = first selected
Return a list of selected vertexes if at least nVertex vertexes are selected, otherwise return False
'''
if getSelView(nSel):
view = getSelView(nSel)
else:
return False
if not Gui.Selection.getSelectionEx():
displayMessage('AuxView','No vertex selected')
return False
objectList = Gui.Selection.getSelectionEx()[nSel].SubElementNames
vertexes = []
for objectString in objectList:
if objectString[0:6] == 'Vertex':
vertexes.append(view.getVertexBySelection(objectString))
if (len(vertexes) < nVertex):
displayMessage('AuxView','Select at least '+
str(nVertex)+' vertices')
return False
else:
return vertexes
def getPageOfSelection(doc, b_view):
'''Retrieves the Page that holds the selected elements'''
#- Find an object starting with 'Page' that contains the selected object
for each in doc.Objects:
if each.Name.startswith("Page"): # [0:4] == 'Page':
for item in each.OutList: # Search items belonging to a Page object
if item.Name.startswith("ProjGroup"): # Look into projection groups
for view in item.OutList: # Search views belonging to a ProjGroup object
if view.Name == b_view.Name:
return each
else:
if item.Name == b_view.Name:
return each
return False
def getCcwAngle(vertex1,vertex2,view_rotation):
'''Creates 3D vectors to calculate the 2D angle towards the x direction of the
base view which is parallel to the page view's x direction.
The direction of the XDirection property is not parallel to the view's
x direction if the view is rotated! This angle also has to be taken into
account to calculate the 3D angle'''
#- Extract position vectors from the points
vector_start = App.Vector(vertex1.X, vertex1.Y, vertex1.Z)
vector_end = App.Vector(vertex2.X, vertex2.Y, vertex2.Z)
#- Calculate the 2D Direction vector from start vertex to end vertex
# on the XY plane of the base view/work page (z = 0)
direction = vector_end.sub(vector_start)
x_direction = App.Vector(1, 0, 0)
angle_x = math.degrees(direction.getAngle(x_direction))
# getAngle() returns positive (absolute) values only (in rad)
# -> convert to degrees and check orientation
if vertex1.Y > vertex2.Y:
angle_x *= -1 # switches angle orientation
#- Turn back the base view rotation
# angle_x is a float value now but view_rotation is deg
#print('a. angle_x: ', angle_x)
#print('b. view_rotation: ', float(view_rotation))
angle_x -= float(view_rotation)
return angle_x
def symbolAngle(vertex1,vertex2):
'''
Creates 3D vectors to calculate the 2D angle towards the x direction of the
base view
'''
#- Extract position vectors from the points
vector_start = FreeCAD.Vector(vertex1.X, vertex1.Y, vertex1.Z)
vector_end = FreeCAD.Vector(vertex2.X, vertex2.Y, vertex2.Z)
#- Calculate the 2D Direction vector from start vertex to end vertex
# on the XY plane of the base view/work page (z = 0)
direction = vector_end.sub(vector_start)
y_direction = FreeCAD.Vector(0, -1, 0)
angle_y = math.degrees(direction.getAngle(y_direction))
# getAngle() returns positive (absolute) values only (in rad)
# -> convert to degrees and check orientation
if vertex1.X > vertex2.X:
angle_y *= -1 # switches angle orientation
return angle_y
def main():
''' The main section, no more, no less '''
# Operations are performed in the active document of the application
#- Retrieve the active document
active_doc = getActiveDocument()
if not active_doc: # (active_doc is None/False)
return
#- Retrieve the selection view and selected vertices
if getSelView() and getSelVertexes(2):
base_view = getSelView()
vertices = getSelVertexes(2) # required number of vertices
else:
return
#- Retrieve the page that holds the view
work_page = getPageOfSelection(active_doc, base_view)
if not work_page:
# this should always be true as selected vertices are already checked
return
# At this point the input elements are gathered:
# active_doc, work_page, base_view, and vertices
#- Create a new view
new_view = active_doc.addObject('TechDraw::DrawViewPart', 'AuxView')
#- Add the new view to the page
work_page.addView(new_view)
#- Add a BaseView property to the new view
new_view.addProperty('App::PropertyLink','BaseView')
#- Link the BaseView object to the BaseView property
new_view.BaseView = active_doc.getObject(base_view.Name)
#- Hand over the source objects
new_view.Source = new_view.BaseView.Source
#- 2D: Calculate the ccw angle between the x axes of base view and new view
turn_ccw = getCcwAngle(vertices[0],vertices[1],new_view.BaseView.Rotation)
# Returns a float value representing degrees
# 3D: Turn base_view.XDirection around base_view.Direction to get
# new_view.XDirection
#- Create a rotation, angle input in float (for degrees), stored in rad
around_direction = App.Rotation(new_view.BaseView.Direction, turn_ccw)
#- Apply rotation to the base_view.XDirection
new_view.XDirection = around_direction.multVec(new_view.BaseView.XDirection)
#- The cross-product of base view Z and new view X gives new view Z direction
new_view.Direction = new_view.BaseView.Direction.cross(new_view.XDirection)
# 2D: Take base_view.Rotation into account, it has to be converted
# to float since it is stored in deg
#- Add the rotation of the base view to the angle between the x axes
new_view.Rotation = turn_ccw + float(new_view.BaseView.Rotation)
Gui.runCommand('TechDraw_RedrawPage',0)
# At this point the Auxiliary View is complete
#- Create an arrow symbol
new_symbol = active_doc.addObject('TechDraw::DrawViewSymbol', 'Symbol')
new_symbol.Symbol = ARROW
new_symbol.Owner = base_view
new_symbol.Rotation = symbolAngle(vertices[0],vertices[1])
#- Add the new symbol to the page
work_page.addView(new_symbol)
#- Create a direction tag
dir_tag = active_doc.addObject('TechDraw::DrawViewAnnotation', 'DirTag')
dir_tag.Text = "X"
dir_tag.Owner = new_symbol
#- Add the new symbol to the page
work_page.addView(dir_tag)
#- Create a view tag
view_tag = active_doc.addObject('TechDraw::DrawViewAnnotation', 'ViewTag')
view_tag.Text = "AuxView X"
view_tag.Owner = new_view
#- Add the new symbol to the page
work_page.addView(view_tag)
FreeCADGui.runCommand("TechDraw_RedrawPage",0)
FreeCADGui.runCommand("TechDraw_RedrawPage",0)
return
if __name__ == "__main__":
# This will be true only if the file is "executed"
# but not if imported as module
main()