Macro View Rotation/de: Difference between revisions
(Updating to match new version of source page) |
mNo edit summary |
||
(18 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
<languages/> |
|||
{{Macro/de|Icon=Text-x-python|Name=View Rotation|Name/es=View Rotation|Description=Macro provides a GUI to permit precise rotation of the objects in the view.|Author=Joe Dowsett}} |
|||
{{Macro/de |
|||
|Name=View Rotation |
|||
|Icon=Macro_View_Rotation.png |
|||
|Translate=View Rotation |
|||
|Description=Makro bietet eine grafische Benutzeroberfläche, mit der die Objekte in der Ansicht präzise gedreht werden können.<br />Download the [http://forum.freecadweb.org/download/file.php?id=453 Icon] of the macro.<br /> |
|||
|Author=Joe Dowsett |
|||
|Version=1.0 |
|||
|Date=2012-01-04 |
|||
|FCVersion=All |
|||
|Download=[http://forum.freecadweb.org/download/file.php?id=453 Icons Package]<br />[https://www.freecadweb.org/wiki/images/a/af/Macro_View_Rotation.png Icon ToolBar] |
|||
|SeeAlso=[[Macro_Rotate_View/de|Macro Rotate View]]<br />[[Macro_FCCamera/de|Macro FCCamera]] |
|||
}} |
|||
==Beschreibung== |
|||
This GUI allows the view to be rotated with more precision than when using the mouse. Rotation is according to axes fixed with respect to the user and not the objects, though the aim is that the objects rotate about their approximate shared centre rather than the view centre.<br /> |
|||
Über diese GUI kann die Ansicht präziser gedreht werden als bei Verwendung der Maus. Die Rotation richtet sich nach den Achsen, die in Bezug auf den Benutzer festgelegt sind, und nicht auf die Objekte. Das Ziel besteht jedoch darin, dass sich die Objekte um ihre ungefähre gemeinsame Mitte herum drehen, anstatt um die Ansichtsmitte |
|||
The GUI defaults to the top right of the screen, this behaviour can be changed by editing |
|||
Die GUI befindet sich standardmäßig rechts oben auf dem Bildschirm. Dieses Verhalten kann durch Bearbeiten geändert werden |
|||
{{Codeextralink|https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/master/PureGui/ViewRotation.FCMacro}} |
|||
[[File:Macro View Rotation 00.png|left|480px|Rotate view]] |
[[File:Macro View Rotation 00.png|left|480px|Rotate view]] |
||
{{clear}} |
{{clear}} |
||
Mit drei Symbolen werden die Drehrichtungen symbolisiert. Eine ZIP-Datei mit diesen Symbolen finden Sie [http://forum.freecadweb.org/download/file.php?id=453 here], die Bilder sollten sich in dem Ordner befinden, der Ihre Makros enthält. Bitte zögern Sie nicht, bessere beizutragen! |
|||
{{Code|code= |
|||
==Code== |
|||
a = QtGui.QDesktopWidget() |
|||
right = a.availableGeometry().width() |
|||
self.setGeometry(right-300, 0, 300, 150) |
|||
}} |
|||
Die neueste Version des Makros finden Sie unter [https://github.com/FreeCAD/FreeCAD-macros/blob/master/PureGui/ViewRotation.FCMacro ViewRotation.FCMacro]. Der einfachste Weg, dieses Makro zu installieren, ist das [[Addon Manager/de|Addon Manager]]. |
|||
ToolBar Icon [[Image:Macro_View_Rotation.png]] |
|||
at the end of the function 'initUI'. The first two arguments (right-300, 0) provide the position for the top left corner of the window - my experience is that the behaviour was as intended on Ubuntu but Vista positioned the window too high and the 0 needed to be changed to ~30.<br /> |
|||
Three icons are referred to to symbolise the rotation directions. A zip file containing these icons can be found [http://forum.freecadweb.org/download/file.php?id=453 here], the images should be placed in the folder containing your macros. Please feel free to contribute better ones! |
|||
'''Macro View Rotation.FCMacro''' |
|||
{{Code|code= |
{{Code|code= |
||
# -*- coding: utf-8 -*- |
|||
# |
|||
# FreeCAD macro ViewRotation. |
|||
# This GUI allows the view to be rotated with more precision than when using |
|||
# the mouse. Rotation is according to axes fixed with respect to the user and |
|||
# not the objects, though the aim is that the objects rotate about their |
|||
# approximate shared centre rather than the view centre. |
|||
# The GUI defaults to the top right of the screen, this behaviour can be |
|||
# changed by editing. |
|||
# [http://forum.freecadweb.org/viewtopic.php?f=3&t=1784&hilit=View+Rotation#p12012 View+Rotation] |
|||
from __future__ import division |
|||
__Name__ = 'View Rotation' |
|||
__Comment__ = 'This GUI allows the view to be rotated precisely' |
|||
__Author__ = 'Joe Dowsett' |
|||
__Version__ = '1.0' |
|||
__License__ = 'CC-BY-3.0' |
|||
__Web__ = 'https://www.freecadweb.org/wiki/Macro_View_Rotation' |
|||
__Wiki__ = 'https://www.freecadweb.org/wiki/Macro_View_Rotation' |
|||
__Icon__ = '' |
|||
__Help__ = 'Rotation is according to axes fixed with respect to the user.' |
|||
__Status__ = '' |
|||
__Requires__ = '' |
|||
__Files__ = 'ViewRotationOut.png,ViewRotationRight.png,ViewRotationUp.png' |
|||
import PySide |
|||
from PySide import QtGui, QtCore |
|||
from pivy import coin |
|||
from math import pi |
from math import pi |
||
import os |
|||
from PySide import QtCore |
|||
from PySide import QtGui |
|||
from pivy import coin |
|||
import FreeCAD as app |
|||
def find_centre(): |
|||
import FreeCADGui as gui |
|||
xmax = xmin = ymax = ymin = zmax = zmin = 0 |
|||
for obj in App.ActiveDocument.Objects: |
|||
if obj.TypeId[:4] == "Mesh": |
|||
box = obj.Mesh.BoundBox |
|||
elif obj.TypeId[:6] == "Points": |
|||
box = obj.Points.BoundBox |
|||
elif obj.TypeId[:4] == "Part": |
|||
box = obj.Shape.BoundBox |
|||
else: |
|||
continue |
|||
xmax = max(xmax, box.XMax) |
|||
xmin = min(xmin, box.XMin) |
|||
ymax = max(ymax, box.YMax) |
|||
ymin = min(ymin, box.YMin) |
|||
zmax = max(zmax, box.ZMax) |
|||
zmin = min(zmin, box.ZMin) |
|||
centre = FreeCAD.Vector((xmax+xmin)/2.0, (ymax+ymin)/2.0, (zmax+zmin)/2.0) |
|||
return centre |
|||
def get_macro_dir(): |
|||
"""Return the directory where macros are located""" |
|||
default_macro_dir = os.path.join(app.ConfigGet('UserAppData'), 'Macro') |
|||
return app.ParamGet('User parameter:BaseApp/Preferences/Macro').GetString('MacroPath', default_macro_dir) |
|||
def find_centre(): |
|||
class rotate_gui(QtGui.QWidget): |
|||
doc = app.activeDocument() |
|||
def __init__(self): |
|||
if doc is None: |
|||
super(rotate_gui, self).__init__() |
|||
return app.Vector(0, 0, 0) |
|||
self.initUI() |
|||
self.initRotate() |
|||
xmax = 0 |
|||
xmin = 0 |
|||
ymax = 0 |
|||
ymin = 0 |
|||
zmax = 0 |
|||
zmin = 0 |
|||
for obj in doc.Objects: |
|||
try: |
|||
if obj.TypeId[:4] == 'Mesh': |
|||
box = obj.Mesh.BoundBox |
|||
elif obj.TypeId[:6] == 'Points': |
|||
box = obj.Points.BoundBox |
|||
elif obj.TypeId[:4] == 'Part': |
|||
box = obj.Shape.BoundBox |
|||
else: |
|||
continue |
|||
except AttributeError: |
|||
continue |
|||
xmax = max(xmax, box.XMax) |
|||
xmin = min(xmin, box.XMin) |
|||
ymax = max(ymax, box.YMax) |
|||
ymin = min(ymin, box.YMin) |
|||
zmax = max(zmax, box.ZMax) |
|||
zmin = min(zmin, box.ZMin) |
|||
return app.Vector((xmax + xmin) / 2, (ymax + ymin) / 2, (zmax + zmin) / 2) |
|||
def initUI(self): |
|||
self.sld = [0,1,2] |
|||
self.tbox = [0,1,2] |
|||
path = FreeCAD.ConfigGet("UserAppData") |
|||
icon = [0,1,2] |
|||
icons = ('right.png', 'up.png', 'out.png') |
|||
for i in range(3): |
|||
self.sld[i] = QtGui.QSlider(QtCore.Qt.Horizontal, self) |
|||
self.sld[i].setFocusPolicy(QtCore.Qt.NoFocus) |
|||
self.sld[i].setSingleStep(5) |
|||
self.sld[i].setPageStep(15) |
|||
self.sld[i].setValue(0) |
|||
self.sld[i].setMaximum(180) |
|||
self.sld[i].setMinimum(-180) |
|||
self.tbox[i] = QtGui.QLineEdit(self) |
|||
self.tbox[i].setText("0") |
|||
self.tbox[i].setAlignment(QtCore.Qt.AlignRight) |
|||
icon[i] = QtGui.QLabel(self) |
|||
icon[i].setPixmap(QtGui.QPixmap(path + icons[i])) |
|||
self.sld[i].valueChanged[int].connect(self.valueChange) |
|||
self.tbox[i].returnPressed.connect(self.valueEntered) |
|||
class RotateGui(QtGui.QWidget): |
|||
resetButton = QtGui.QPushButton("Reset") |
|||
def __init__(self): |
|||
resetButton.clicked.connect(self.reset) |
|||
super(RotateGui, self).__init__() |
|||
self.init_ui() |
|||
self.init_rotate() |
|||
def init_ui(self): |
|||
okButton = QtGui.QPushButton("OK") |
|||
macro_dir = get_macro_dir() |
|||
okButton.clicked.connect(self.close) |
|||
self.sliders = [] |
|||
self.line_edits = [] |
|||
vbox = QtGui.QVBoxLayout() |
|||
cancelButton.clicked.connect(self.cancel) |
|||
icons = ('ViewRotationRight.png', 'ViewRotationUp.png', 'ViewRotationOut.png') |
|||
hbox = [0,1,2,3] |
|||
for icon in icons: |
|||
vbox = QtGui.QVBoxLayout() |
|||
slider = QtGui.QSlider(QtCore.Qt.Horizontal, self) |
|||
slider.setFocusPolicy(QtCore.Qt.NoFocus) |
|||
slider.setSingleStep(5) |
|||
slider.setPageStep(15) |
|||
slider.setValue(0) |
|||
slider.setMaximum(180) |
|||
slider.setMinimum(-180) |
|||
slider.valueChanged[int].connect(self.valueChange) |
|||
self.sliders.append(slider) |
|||
line_edit = QtGui.QLineEdit(self) |
|||
for i in range(3): |
|||
line_edit.setText('0') |
|||
hbox[i] = QtGui.QHBoxLayout() |
|||
line_edit.setAlignment(QtCore.Qt.AlignRight) |
|||
hbox[i].addWidget(icon[i],1, QtCore.Qt.AlignCenter) |
|||
line_edit.returnPressed.connect(self.valueEntered) |
|||
hbox[i].addWidget(self.sld[i],4) |
|||
self.line_edits.append(line_edit) |
|||
hbox[i].addWidget(self.tbox[i],1) |
|||
vbox.addLayout(hbox[i]) |
|||
label = QtGui.QLabel(self) |
|||
label.setPixmap(QtGui.QPixmap(os.path.join(macro_dir, icon))) |
|||
hbox[3].addWidget(resetButton,1) |
|||
hbox[3].addWidget(okButton,1) |
|||
hbox[3].addWidget(cancelButton,1) |
|||
vbox.addStretch(1) |
|||
vbox.addLayout(hbox[3]) |
|||
hbox = QtGui.QHBoxLayout() |
|||
self.setLayout(vbox) |
|||
hbox.addWidget(label, 1, QtCore.Qt.AlignCenter) |
|||
hbox.addWidget(slider, 4) |
|||
hbox.addWidget(line_edit, 1) |
|||
vbox.addLayout(hbox) |
|||
reset_button = QtGui.QPushButton('Reset') |
|||
reset_button.clicked.connect(self.reset) |
|||
right = a.availableGeometry().width() |
|||
ok_button = QtGui.QPushButton('OK') |
|||
self.setGeometry(right-300, 0, 300, 150) |
|||
ok_button.clicked.connect(self.close) |
|||
self.setWindowTitle('Rotate view...') |
|||
self.show() |
|||
cancel_button = QtGui.QPushButton('Cancel') |
|||
cancel_button.clicked.connect(self.cancel) |
|||
hbox = QtGui.QHBoxLayout() |
|||
def initRotate(self): |
|||
hbox.addWidget(reset_button, 1) |
|||
self.internal = False |
|||
hbox.addWidget(ok_button, 1) |
|||
self.current = 0 |
|||
hbox.addWidget(cancel_button, 1) |
|||
vbox.addStretch(1) |
|||
vbox.addLayout(hbox) |
|||
self.setLayout(vbox) |
|||
self.cam = Gui.ActiveDocument.ActiveView.getCameraNode() |
|||
self.centre = coin.SbVec3f(find_centre()) |
|||
self.view = self.cam.orientation.getValue() |
|||
self.pos = self.cam.position.getValue() |
|||
desktop_widget = QtGui.QDesktopWidget() |
|||
#store a copy of the original view to be restored in the case of user selecting Reset or Cancel |
|||
right = desktop_widget.availableGeometry().width() |
|||
self.original_view = coin.SbRotation(self.view.getValue()) |
|||
self.original_pos = coin.SbVec3f(self.pos.getValue()) |
|||
self.setGeometry(right - 300, 0, 300, 150) |
|||
self.config_direction(0) |
|||
self.setWindowTitle('Rotate view') |
|||
self.show() |
|||
def init_rotate(self): |
|||
self.internal = False |
|||
self.current = 0 |
|||
self.cam = gui.activeDocument().ActiveView.getCameraNode() |
|||
def reset(self): |
|||
self.centre = coin.SbVec3f(find_centre()) |
|||
#reset the view to the original one |
|||
self.view = self.cam.orientation.getValue() |
|||
self.pos = self.cam.position.getValue() |
|||
self.internal = True |
|||
for sld in self.sld: |
|||
sld.setValue(0) |
|||
self.internal = False |
|||
for tbox in self.tbox: |
|||
tbox.setText("0") |
|||
self.config_direction(0) |
|||
# Store a copy of the original view to be restored in the case of user |
|||
# selecting Reset or Cancel. |
|||
self.original_view = coin.SbRotation(self.view.getValue()) |
|||
self.original_pos = coin.SbVec3f(self.pos.getValue()) |
|||
self.config_direction(0) |
|||
def cancel(self): |
|||
self.reset() |
|||
self.close() |
|||
def reset(self): |
|||
# Reset the view to the original one. |
|||
self.cam.orientation = self.original_view |
|||
self.cam.position = self.original_pos |
|||
self.view = coin.SbRotation(self.view.getValue()) |
|||
self.internal = True |
|||
self.pos = self.cam.position.getValue() |
|||
for sld in self.sliders: |
|||
self.pos = coin.SbVec3f(self.pos.getValue()) |
|||
sld.setValue(0) |
|||
self.internal = False |
|||
for tbox in self.line_edits: |
|||
tbox.setText("0") |
|||
self.config_direction(0) |
|||
def cancel(self): |
|||
up = coin.SbVec3f(0,1,0) |
|||
self.reset() |
|||
self.close() |
|||
out = coin.SbVec3f(0,0,1) |
|||
self.out = self.view.multVec(out) |
|||
u = self.up.getValue() |
|||
o = self.out.getValue() |
|||
r = (u[1]*o[2]-u[2]*o[1], u[2]*o[0]-u[0]*o[2], u[0]*o[1]-u[1]*o[0]) |
|||
self.right = coin.SbVec3f(r) |
|||
self.direction = [self.right, self.up, self.out][i] |
|||
def config_direction(self, i): |
|||
# Evaluate the vectors corresponding to the three directions for the |
|||
#check if the direction of rotation has changed, if so then set previous slider & textbox to zero, and setup the new direction |
|||
# current view, and assign the i-th one to self.direction. |
|||
if i <> self.current: |
|||
self.view = self.cam.orientation.getValue() |
|||
self.internal = True |
|||
self.view = coin.SbRotation(self.view.getValue()) |
|||
self.pos = self.cam.position.getValue() |
|||
self.pos = coin.SbVec3f(self.pos.getValue()) |
|||
self.internal = False |
|||
self.current = i |
|||
self.config_direction(i) |
|||
up = coin.SbVec3f(0,1,0) |
|||
self.up = self.view.multVec(up) |
|||
out = coin.SbVec3f(0,0,1) |
|||
self.out = self.view.multVec(out) |
|||
u = self.up.getValue() |
|||
o = self.out.getValue() |
|||
r = (u[1]*o[2]-u[2]*o[1], u[2]*o[0]-u[0]*o[2], u[0]*o[1]-u[1]*o[0]) |
|||
self.right = coin.SbVec3f(r) |
|||
self.direction = [self.right, self.up, self.out][i] |
|||
def rotate(self, value): |
|||
#carry out the desired rotation about self.direction |
|||
val = value*pi/180.0 |
|||
rot = coin.SbRotation(self.direction, -val) |
|||
nrot = self.view*rot |
|||
prot = rot.multVec(self.pos - self.centre) + self.centre |
|||
self.cam.orientation = nrot |
|||
self.cam.position = prot |
|||
def check(self, i): |
|||
# Check if the direction of rotation has changed, if so then set |
|||
# previous slider & textbox to zero, and setup the new direction. |
|||
if i != self.current: |
|||
self.internal = True |
|||
self.sliders[self.current].setValue(0) |
|||
self.line_edits[self.current].setText("0") |
|||
self.internal = False |
|||
self.current = i |
|||
self.config_direction(i) |
|||
def rotate(self, value): |
|||
# Carry out the desired rotation about self.direction. |
|||
#respond to the change in value of a slider, update the corresponding text box, check for a direction change then rotate |
|||
val = value*pi/180.0 |
|||
#if the value was changed internally, ignore event. |
|||
rot = coin.SbRotation(self.direction, -val) |
|||
if self.internal: |
|||
nrot = self.view*rot |
|||
return |
|||
prot = rot.multVec(self.pos - self.centre) + self.centre |
|||
self.cam.orientation = nrot |
|||
self.cam.position = prot |
|||
def valueChange(self, value): |
|||
sender = self.sender() |
|||
# Respond to the change in value of a slider, update the corresponding |
|||
for i in range(3): |
|||
# text box, check for a direction change then rotate |
|||
if sender == self.sld[i]: |
|||
# if the value was changed internally, ignore event. |
|||
break |
|||
if self.internal: |
|||
self.tbox[i].setText(str(value)) |
|||
return |
|||
self.check(i) |
|||
self.rotate(value) |
|||
sender = self.sender() |
|||
for i in range(3): |
|||
if sender == self.sliders[i]: |
|||
break |
|||
self.line_edits[i].setText(str(value)) |
|||
self.check(i) |
|||
self.rotate(value) |
|||
def valueEntered(self): |
|||
# Respond to a value being entered in a text box, updating the |
|||
# corresponding slider, check for direction change then rotate. |
|||
sender = self.sender() |
|||
sender = self.sender() |
|||
for i in range(3): |
|||
for i in range(3): |
|||
if sender == self.tbox[i]: |
|||
if sender == self.line_edits[i]: |
|||
break |
|||
break |
|||
value = int(self.tbox[i].text()) |
|||
value = int(self.line_edits[i].text()) |
|||
self.internal = True |
|||
self.internal = True |
|||
self.sld[i].setValue(value) |
|||
self.sliders[i].setValue(value) |
|||
self.internal = False |
|||
self.internal = False |
|||
self.check(i) |
|||
self.check(i) |
|||
self.rotate(value) |
|||
if __name__ == '__main__': |
|||
rotate = rotate_gui() |
|||
# We need to set a variable, otherwise, the dialog doesn't appear. |
|||
rotate = RotateGui() |
|||
}} |
}} |
||
{{clear}} |
|||
== |
==Option== |
||
am Ende der Funktion 'initUI'. Die ersten beiden Argumente (rechts-300, 0) (Zeile 91) geben die Position für die obere linke Ecke des Fensters an. Ich habe die Erfahrung gemacht, dass das Verhalten auf Ubuntu wie beabsichtigt war, aber Vista positionierte das Fenster zu hoch und die 0 dazu in ~ 30 geändert werden. <br /> |
|||
[http://forum.freecadweb.org/viewtopic.php?f=3&t=1784&hilit=View+Rotation#p12012 View+Rotation] |
|||
{{Code|code= |
|||
<languages/> |
|||
self.setGeometry(right-300, 0, 300, 150) |
|||
}} |
|||
==Diskussionsseite== |
|||
[http://forum.freecadweb.org/viewtopic.php?f=3&t=1784&hilit=View+Rotation#p12012 View+Rotation] |
Revision as of 15:55, 25 July 2019
Beschreibung |
---|
Makro bietet eine grafische Benutzeroberfläche, mit der die Objekte in der Ansicht präzise gedreht werden können. Download the Icon of the macro. Versionsmakro : 1.0 Datum der letzten Änderung : 2012-01-04 FreeCAD version : All Herunterladen : Icons Package Icon ToolBar Autor: Joe Dowsett |
Autor |
Joe Dowsett |
Herunterladen |
Icons Package Icon ToolBar |
Links |
Makros Rezepte Wie installiere ich Makros So passen Sie Symbolleisten an |
Macro-Version |
1.0 |
Datum der letzten Änderung |
2012-01-04 |
FreeCAD-Version(s) |
All |
Standardverknüpfung |
None |
Siehe auch |
Macro Rotate View Macro FCCamera |
Beschreibung
Über diese GUI kann die Ansicht präziser gedreht werden als bei Verwendung der Maus. Die Rotation richtet sich nach den Achsen, die in Bezug auf den Benutzer festgelegt sind, und nicht auf die Objekte. Das Ziel besteht jedoch darin, dass sich die Objekte um ihre ungefähre gemeinsame Mitte herum drehen, anstatt um die Ansichtsmitte Die GUI befindet sich standardmäßig rechts oben auf dem Bildschirm. Dieses Verhalten kann durch Bearbeiten geändert werden
Temporary code for external macro link. Do not use this code. This code is used exclusively by Addon Manager. Link for optional manual installation: Macro
# This code is copied instead of the original macro code # to guide the user to the online download page. # Use it if the code of the macro is larger than 64 KB and cannot be included in the wiki # or if the RAW code URL is somewhere else in the wiki. from PySide import QtGui, QtCore diag = QtGui.QMessageBox(QtGui.QMessageBox.Information, "Information", "This macro must be downloaded from this link\n" "\n" "https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/master/PureGui/ViewRotation.FCMacro" + "\n" "\n" "Quit this window to access the download page") diag.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint) diag.setWindowModality(QtCore.Qt.ApplicationModal) diag.exec_() import webbrowser webbrowser.open("https://raw.githubusercontent.com/FreeCAD/FreeCAD-macros/master/PureGui/ViewRotation.FCMacro")
Mit drei Symbolen werden die Drehrichtungen symbolisiert. Eine ZIP-Datei mit diesen Symbolen finden Sie here, die Bilder sollten sich in dem Ordner befinden, der Ihre Makros enthält. Bitte zögern Sie nicht, bessere beizutragen!
Code
Die neueste Version des Makros finden Sie unter ViewRotation.FCMacro. Der einfachste Weg, dieses Makro zu installieren, ist das Addon Manager.
Macro View Rotation.FCMacro
# -*- coding: utf-8 -*-
#
# FreeCAD macro ViewRotation.
# This GUI allows the view to be rotated with more precision than when using
# the mouse. Rotation is according to axes fixed with respect to the user and
# not the objects, though the aim is that the objects rotate about their
# approximate shared centre rather than the view centre.
# The GUI defaults to the top right of the screen, this behaviour can be
# changed by editing.
# [http://forum.freecadweb.org/viewtopic.php?f=3&t=1784&hilit=View+Rotation#p12012 View+Rotation]
from __future__ import division
__Name__ = 'View Rotation'
__Comment__ = 'This GUI allows the view to be rotated precisely'
__Author__ = 'Joe Dowsett'
__Version__ = '1.0'
__License__ = 'CC-BY-3.0'
__Web__ = 'https://www.freecadweb.org/wiki/Macro_View_Rotation'
__Wiki__ = 'https://www.freecadweb.org/wiki/Macro_View_Rotation'
__Icon__ = ''
__Help__ = 'Rotation is according to axes fixed with respect to the user.'
__Status__ = ''
__Requires__ = ''
__Files__ = 'ViewRotationOut.png,ViewRotationRight.png,ViewRotationUp.png'
from math import pi
import os
from PySide import QtCore
from PySide import QtGui
from pivy import coin
import FreeCAD as app
import FreeCADGui as gui
def get_macro_dir():
"""Return the directory where macros are located"""
default_macro_dir = os.path.join(app.ConfigGet('UserAppData'), 'Macro')
return app.ParamGet('User parameter:BaseApp/Preferences/Macro').GetString('MacroPath', default_macro_dir)
def find_centre():
doc = app.activeDocument()
if doc is None:
return app.Vector(0, 0, 0)
xmax = 0
xmin = 0
ymax = 0
ymin = 0
zmax = 0
zmin = 0
for obj in doc.Objects:
try:
if obj.TypeId[:4] == 'Mesh':
box = obj.Mesh.BoundBox
elif obj.TypeId[:6] == 'Points':
box = obj.Points.BoundBox
elif obj.TypeId[:4] == 'Part':
box = obj.Shape.BoundBox
else:
continue
except AttributeError:
continue
xmax = max(xmax, box.XMax)
xmin = min(xmin, box.XMin)
ymax = max(ymax, box.YMax)
ymin = min(ymin, box.YMin)
zmax = max(zmax, box.ZMax)
zmin = min(zmin, box.ZMin)
return app.Vector((xmax + xmin) / 2, (ymax + ymin) / 2, (zmax + zmin) / 2)
class RotateGui(QtGui.QWidget):
def __init__(self):
super(RotateGui, self).__init__()
self.init_ui()
self.init_rotate()
def init_ui(self):
macro_dir = get_macro_dir()
self.sliders = []
self.line_edits = []
vbox = QtGui.QVBoxLayout()
icons = ('ViewRotationRight.png', 'ViewRotationUp.png', 'ViewRotationOut.png')
for icon in icons:
slider = QtGui.QSlider(QtCore.Qt.Horizontal, self)
slider.setFocusPolicy(QtCore.Qt.NoFocus)
slider.setSingleStep(5)
slider.setPageStep(15)
slider.setValue(0)
slider.setMaximum(180)
slider.setMinimum(-180)
slider.valueChanged[int].connect(self.valueChange)
self.sliders.append(slider)
line_edit = QtGui.QLineEdit(self)
line_edit.setText('0')
line_edit.setAlignment(QtCore.Qt.AlignRight)
line_edit.returnPressed.connect(self.valueEntered)
self.line_edits.append(line_edit)
label = QtGui.QLabel(self)
label.setPixmap(QtGui.QPixmap(os.path.join(macro_dir, icon)))
hbox = QtGui.QHBoxLayout()
hbox.addWidget(label, 1, QtCore.Qt.AlignCenter)
hbox.addWidget(slider, 4)
hbox.addWidget(line_edit, 1)
vbox.addLayout(hbox)
reset_button = QtGui.QPushButton('Reset')
reset_button.clicked.connect(self.reset)
ok_button = QtGui.QPushButton('OK')
ok_button.clicked.connect(self.close)
cancel_button = QtGui.QPushButton('Cancel')
cancel_button.clicked.connect(self.cancel)
hbox = QtGui.QHBoxLayout()
hbox.addWidget(reset_button, 1)
hbox.addWidget(ok_button, 1)
hbox.addWidget(cancel_button, 1)
vbox.addStretch(1)
vbox.addLayout(hbox)
self.setLayout(vbox)
desktop_widget = QtGui.QDesktopWidget()
right = desktop_widget.availableGeometry().width()
self.setGeometry(right - 300, 0, 300, 150)
self.setWindowTitle('Rotate view')
self.show()
def init_rotate(self):
self.internal = False
self.current = 0
self.cam = gui.activeDocument().ActiveView.getCameraNode()
self.centre = coin.SbVec3f(find_centre())
self.view = self.cam.orientation.getValue()
self.pos = self.cam.position.getValue()
# Store a copy of the original view to be restored in the case of user
# selecting Reset or Cancel.
self.original_view = coin.SbRotation(self.view.getValue())
self.original_pos = coin.SbVec3f(self.pos.getValue())
self.config_direction(0)
def reset(self):
# Reset the view to the original one.
self.cam.orientation = self.original_view
self.cam.position = self.original_pos
self.internal = True
for sld in self.sliders:
sld.setValue(0)
self.internal = False
for tbox in self.line_edits:
tbox.setText("0")
self.config_direction(0)
def cancel(self):
self.reset()
self.close()
def config_direction(self, i):
# Evaluate the vectors corresponding to the three directions for the
# current view, and assign the i-th one to self.direction.
self.view = self.cam.orientation.getValue()
self.view = coin.SbRotation(self.view.getValue())
self.pos = self.cam.position.getValue()
self.pos = coin.SbVec3f(self.pos.getValue())
up = coin.SbVec3f(0,1,0)
self.up = self.view.multVec(up)
out = coin.SbVec3f(0,0,1)
self.out = self.view.multVec(out)
u = self.up.getValue()
o = self.out.getValue()
r = (u[1]*o[2]-u[2]*o[1], u[2]*o[0]-u[0]*o[2], u[0]*o[1]-u[1]*o[0])
self.right = coin.SbVec3f(r)
self.direction = [self.right, self.up, self.out][i]
def check(self, i):
# Check if the direction of rotation has changed, if so then set
# previous slider & textbox to zero, and setup the new direction.
if i != self.current:
self.internal = True
self.sliders[self.current].setValue(0)
self.line_edits[self.current].setText("0")
self.internal = False
self.current = i
self.config_direction(i)
def rotate(self, value):
# Carry out the desired rotation about self.direction.
val = value*pi/180.0
rot = coin.SbRotation(self.direction, -val)
nrot = self.view*rot
prot = rot.multVec(self.pos - self.centre) + self.centre
self.cam.orientation = nrot
self.cam.position = prot
def valueChange(self, value):
# Respond to the change in value of a slider, update the corresponding
# text box, check for a direction change then rotate
# if the value was changed internally, ignore event.
if self.internal:
return
sender = self.sender()
for i in range(3):
if sender == self.sliders[i]:
break
self.line_edits[i].setText(str(value))
self.check(i)
self.rotate(value)
def valueEntered(self):
# Respond to a value being entered in a text box, updating the
# corresponding slider, check for direction change then rotate.
sender = self.sender()
for i in range(3):
if sender == self.line_edits[i]:
break
value = int(self.line_edits[i].text())
self.internal = True
self.sliders[i].setValue(value)
self.internal = False
self.check(i)
self.rotate(value)
if __name__ == '__main__':
# We need to set a variable, otherwise, the dialog doesn't appear.
rotate = RotateGui()
Option
am Ende der Funktion 'initUI'. Die ersten beiden Argumente (rechts-300, 0) (Zeile 91) geben die Position für die obere linke Ecke des Fensters an. Ich habe die Erfahrung gemacht, dass das Verhalten auf Ubuntu wie beabsichtigt war, aber Vista positionierte das Fenster zu hoch und die 0 dazu in ~ 30 geändert werden.
self.setGeometry(right-300, 0, 300, 150)