import numpy import traceback import FreeCAD as App import FreeCAD, FreeCADGui, Part, os from PySide import QtGui, QtCore, QtSvg from .svgLib import SvgTextRenderer, SvgTextParser from .py3_helpers import encode_if_py2 __dir__ = os.path.dirname(os.path.dirname(__file__)) iconPath = os.path.join( __dir__, 'Gui','Resources', 'icons' ) path_dd_resources = os.path.join( __dir__, 'Gui', 'Resources', 'dd_resources.rcc') resourcesLoaded = QtCore.QResource.registerResource(path_dd_resources) assert resourcesLoaded def debugPrint( level, msg ): if level <= debugPrint.level: App.Console.PrintMessage(msg + '\n') debugPrint.level = 3 if hasattr(os,'uname') and os.uname()[1].startswith('antoine') else 2 def findUnusedObjectName(base, counterStart=1, fmt='%03i'): i = counterStart objName = '%s%s' % (base, fmt%i) while hasattr(App.ActiveDocument, objName): i = i + 1 objName = '%s%s' % (base, fmt%i) return objName def errorMessagebox_with_traceback(title='Error'): 'for also those PySide linked codes where the Python debugger does not work...' App.Console.PrintError(traceback.format_exc()) QtGui.QMessageBox.critical( QtGui.QApplication.activeWindow(), title, traceback.format_exc(), ) notDrawingPage_title = "Current Window not showing a Drawing Page" notDrawingPage_msg = "Drawing Dimensioning tools are for page objects generated using the Drawing workbench. Aborting operation." def getDrawingPageGUIVars(): ''' Get the FreeCAD window, graphicsScene, drawing page object, ... ''' # get the active window mw = QtGui.QApplication.activeWindow() MdiArea = [c for c in mw.children() if isinstance(c,QtGui.QMdiArea)][0] try: subWinMW = MdiArea.activeSubWindow().children()[3] except AttributeError: QtGui.QMessageBox.information( QtGui.QApplication.activeWindow(), notDrawingPage_title, notDrawingPage_msg ) raise ValueError(notDrawingPage_title) # The drawing 'page' is really a group in the model tree # The objectName for the group object is not the same as the name shown in # the model view, this is the 'Label' property, it *should* be unique. # To find the page we are on, we get all the pages which have the same label as # the current object. In theory there should therefore only be one page in the list # returned by getObjectsByLabel, so we'll just take the first in the list pages = App.ActiveDocument.getObjectsByLabel( encode_if_py2(subWinMW.objectName()) ) # raise an error explaining that the page wasn't found if the list is empty if len(pages) != 1: QtGui.QMessageBox.information( QtGui.QApplication.activeWindow(), notDrawingPage_title, notDrawingPage_msg ) raise ValueError(notDrawingPage_title) # get the page from the list page = pages[0] try: graphicsView = [ c for c in subWinMW.children() if isinstance(c,QtGui.QGraphicsView)][0] except IndexError: QtGui.QMessageBox.information( QtGui.QApplication.activeWindow(), notDrawingPage_title, notDrawingPage_msg ) raise ValueError(notDrawingPage_title) graphicsScene = graphicsView.scene() pageRect = graphicsScene.items()[0] #hope this index does not change! width = pageRect.rect().width() height = pageRect.rect().height() #ViewResult has an additional tranform on it [VRT]. #if width > 1400: #then A3 # or == 1488 in FreeCAD v 0.15 # VRT_scale = width / 420.0 #VRT = view result transform, where 420mm is the width of an A3 page. #else: #assuming A4 # VRT_scale = width / 297.0 VRT_scale = 3.542 #i wonder where this number comes from VRT_ox = pageRect.rect().left() / VRT_scale VRT_oy = pageRect.rect().top() / VRT_scale transform = QtGui.QTransform() transform.translate(VRT_ox, VRT_oy) transform.scale(VRT_scale, VRT_scale) return DrawingPageGUIVars(locals()) class DrawingPageGUIVars: "for coding convience, wrt v.transform instead of v['transform']" def __init__(self, data): self.__dict__.update(data) def recomputeWithOutViewReset( drawingVars ): ''' By default app.recompute() resets the drawing view, which can be rather frustrating... ''' printGraphicsViewInfo( drawingVars ) gV = drawingVars.graphicsView T = gV.transform() scale = T.m11() ##attempting to find centre of view #dx = gV.mapToScene( 0,0).x() #dy = gV.mapToScene( 0,0).y() ## now scene_x = view_x/scale + dx; so #centerView = [ # 0.5*gV.width(), # 0.5*gV.height(), # ] #centerScene = gV.mapToScene( *centerView ) #centerOn approach did not work rather using scroll bars. h_scrollValue = gV.horizontalScrollBar().value() v_scrollValue = gV.verticalScrollBar().value() from . import selectionOverlay selectionOverlay.hideSelectionGraphicsItems() drawingVars.page.touch() App.ActiveDocument.recompute() gV.scale( scale , scale ) #scale correction for i in range(3): scale_actual = gV.transform().m11() debugPrint(4, 'scale_desired %1.3f scale_actual %1.3f' % (scale, scale_actual)) s_correction = scale / scale_actual gV.scale( s_correction, s_correction ) gV.horizontalScrollBar().setValue( h_scrollValue ) gV.verticalScrollBar().setValue( v_scrollValue ) printGraphicsViewInfo( drawingVars ) def printGraphicsViewInfo( drawingVars ): ''' A PySide.QtGui.QTransform object contains a 3 x 3 matrix. The m31 (dx ) and m32 (dy ) elements specify horizontal and vertical translation. The m11 and m22 elements specify horizontal and vertical scaling. The m21 and m12 elements specify horizontal and vertical shearing . And finally, the m13 and m23 elements specify horizontal and vertical projection, with m33 as an additional projection factor. This function was written help restore the view transform after App.ActiveDocument.recompute(); example of how to get T, T= preview.drawingVars.graphicsView.transform() DrawingView.cpp: line134: s->setSceneRect(m_outlineItem->boundingRect().adjusted(-10, -10, 10, 10)); # s is QGraphicsScene used for scroll bars! ''' T = drawingVars.graphicsView.transform() sx, sy, dx, dy = T.m11(), T.m22(), T.m31(), T.m32() debugPrint(4,'graphicsView transform info: sx %1.2f, sy %1.2f, dx %1.2f, dy %1.2f' % (sx, sy, dx, dy) ) debugPrint(4,' [ %1.2f %1.2f %1.2f ]' % (T.m11(), T.m12(), T.m13() )) debugPrint(4,'M = [ %1.2f %1.2f %1.2f ]' % (T.m21(), T.m22(), T.m23() )) debugPrint(4,' [ %1.2f %1.2f %1.2f ]' % (T.m31(), T.m32(), T.m33() )) #r = preview.drawingVars.graphicsView.sceneRect() #seems to be used for scroll bars, not for anything else #debugPrint(2,'graphicsView.sceneRect info: topLeft.x %3.2f, topLeft.y %3.2f, bottomRight.x %3.2f, bottomRight.y %3.2f' \ # % (r.topLeft().x(), r.topLeft().y(), r.bottomRight().x(), r.bottomRight().y() ) ) #T = drawingVars.graphicsView.viewportTransform() #sx, sy, dx, dy = T.m11(), T.m22(), T.m31(), T.m32() #debugPrint(2,'viewPort transform info: sx %1.2f, sy %1.2f, dx %1.2f, dy %1.2f' % (sx, sy, dx, dy) ) #debugPrint(4,' [ %1.2f %1.2f %1.2f ]' % (T.m11(), T.m12(), T.m13() )) #debugPrint(4,'M = [ %1.2f %1.2f %1.2f ]' % (T.m21(), T.m22(), T.m23() )) #debugPrint(4,' [ %1.2f %1.2f %1.2f ]' % (T.m31(), T.m32(), T.m33() )) class helpCommand: def Activated(self): QtGui.QMessageBox.information( QtGui.QApplication.activeWindow(), 'Drawing Dimensioning Help', '''For help getting started, please refer to the following YouTube video tutorials: - https://www.youtube.com/watch?v=CTEPu50bG4U - https://www.youtube.com/watch?v=ztMTLp4wZx4 ''' ) def GetResources(self): return { 'Pixmap' : ':/dd/icons/help.svg', 'MenuText': 'Help', 'ToolTip': 'Help' } FreeCADGui.addCommand('dd_help', helpCommand()) def dimensionableObjects ( page ): 'commonly used code in Activate, exclude centerlines' from .unfold import Proxy_unfold drawingViews = [] for obj in page.Group: if hasattr(obj, 'ViewResult'): if hasattr(obj, 'Proxy'): if isinstance( obj.Proxy, Proxy_unfold ): drawingViews.append( obj ) else: #assuming some kind of drawing view ... drawingViews.append( obj ) return drawingViews