Macro Center Align Objects with Faces or Edges: Difference between revisions
(added Macro code inside the Macros recipes page) |
m (png to svg) |
||
(29 intermediate revisions by 5 users not shown) | |||
Line 1: | Line 1: | ||
<languages/> |
|||
<translate> |
<translate> |
||
<!--T:16--> |
|||
{{VeryImportantMessage|These tools are now included in the [[Manipulator Workbench|Manipulator Workbench]]. Install this workbench for the latest updates on these tools.}} |
|||
<!--T:1--> |
<!--T:1--> |
||
{{Macro |
|||
{{Macro|Icon=Macro_Center_Align_Objects_with_Faces_or_Edges|Name=Center Faces of Parts|Description=This macro Aligns Objects through Faces or Edges constraints|Author=easyw-fc|Version=0.32 (11.2016)}} |
|||
|Name=Center Faces of Parts |
|||
|Icon=Macro_Center_Align_Objects_with_Faces_or_Edges.svg |
|||
|Description=This macro Aligns Objects through Faces or Edges constraints. These tools are now included in the [https://github.com/easyw/Manipulator Manipulator Workbench]. Install this workbench for the latest updates on these tools. |
|||
|Author=easyw-fc |
|||
|Version=1.5.3 |
|||
|Date=2017-10-01 |
|||
|FCVersion=All |
|||
|Download=[https://www.freecadweb.org/wiki/images/e/ee/Macro_Center_Align_Objects_with_Faces_or_Edges.svg ToolBar Icon]<br/>[https://www.freecadweb.org/wiki/images/3/3d/Manipulator_Mover.svg Mover-icon]<br/>[https://www.freecadweb.org/wiki/images/1/10/Manipulator_Caliper.svg Caliper-icon] |
|||
}} |
|||
==Description== <!--T:2--> |
==Description== <!--T:2--> |
||
This macro |
This macro Aligns Objects through Faces or Edges constraints |
||
<br /> - Concentric constraint among non cylindrical parts; |
|||
</translate> |
|||
<br /> - Constraint on center Faces and/or Edges. |
|||
{{Codeextralink|https://raw.githubusercontent.com/easyw/FreeCAD_Macros/master/Align%20Objects/CenterAlignObjectswFacesEdges.py}} |
|||
<translate> |
|||
== Tools == <!--T:8--> |
|||
<!--T:9--> |
|||
'''Aligner''' [[File:Macro_Center_Align_Objects_with_Faces_or_Edges.svg|32px]]: a set of tools to move and align 3D parts |
|||
<!--T:10--> |
|||
'''Mover''' [[File:Manipulator_Mover.svg|32px]]: a set of tools to move and rotate 3D parts on different Axis |
|||
<!--T:11--> |
|||
'''Measure''' [[File:Manipulator_Caliper.svg|32px]]: a set of tools to measure 3D parts, with some Snap facility and Radius, Length, Angle measurements. |
|||
<!--T:12--> |
|||
These helpers work with '''Part, App::Part and Body objects'''. |
|||
Each Tool can be '''Floating''' or '''Docked Left or Right'''. |
|||
<!--T:13--> |
|||
---- |
|||
== OLD References == <!--T:14--> |
|||
<!--T:15--> |
|||
This macro covers the following constraints: |
|||
* Concentric constraint among non cylindrical parts; |
|||
* Constraint on center Faces and/or Edges. |
|||
* It works also with the new Body and App::Part containers, as well as with STEP hierarchy. |
|||
</translate> |
</translate> |
||
{{clear}} |
|||
[[File:Center-align-faces.png ]] |
[[File:Center-align-faces.png ]] |
||
{{clear}} |
|||
[[File:center-align-faces-in-action.gif]] |
[[File:center-align-faces-in-action.gif]] |
||
{{clear}} |
|||
[[File:center-align-Body-objects.gif]] |
|||
[[File:utube-alignment-tool-tutorial.png]] |
[[File:utube-alignment-tool-tutorial.png]] |
||
{{clear}} |
|||
[https://youtu.be/qzixT157jJU Aligning tool video tutorial] |
[https://youtu.be/qzixT157jJU Aligning tool video tutorial] |
||
{{clear}} |
|||
[[File:utube-alignment-STEP-models.png]] |
|||
[https://youtu.be/aQcPqhlgHBU Aligning STEP models video tutorial] |
|||
<translate> |
<translate> |
||
== |
==Usage== <!--T:3--> |
||
Faces or Edges constraint among non cylindrical parts: Just open a FC document, launch the Macro and select two or more Faces/Edges to be aligned. Click on Align button and that's it! |
Faces or Edges constraint among non cylindrical parts: Just open a FC document, launch the Macro and select two or more Faces/Edges to be aligned. Click on Align button and that's it! |
||
Line 27: | Line 73: | ||
<!--T:5--> |
<!--T:5--> |
||
'''CenterAlignObjectswFacesEdges.py''' |
|||
Macro Center Faces of Parts.FCMacro |
|||
<!--T:6--> |
<!--T:6--> |
||
Line 33: | Line 79: | ||
GitHub page |
GitHub page |
||
<br /> |
<br /> |
||
https://github.com/easyw/FreeCAD_Macros/ |
https://github.com/easyw/FreeCAD_Macros/tree/master/Align%20Objects |
||
<br /> |
<br /> |
||
code: |
code: |
||
Line 42: | Line 88: | ||
<br /> |
<br /> |
||
[[How to install macros|How to install macros]] |
[[How to install macros|How to install macros]] |
||
<br /> |
|||
{{Code|code= |
|||
# -*- coding: utf-8 -*- |
|||
# evolution of Macro_CenterFace |
|||
# some part of Macro WorkFeature |
|||
# and assembly2 |
|||
# |
|||
# center objs faces/closed_edges to first obj face/closed_edge |
|||
# |
|||
__title__ = "Center Faces of Parts" |
|||
__author__ = "maurice" |
|||
__url__ = "kicad stepup" |
|||
__version__ = "0.38" #undo alignement |
|||
__date__ = "09.2017" |
|||
## todo |
|||
## align edges when are just a line |
|||
## use faces when available? |
|||
## make Undo doing opposite Moved, Rotated on objs (prob it is enough the Rotation plus actual undo) |
|||
## align PartDN and Body using simplecopy plcm of faces |
|||
# * (C) Maurice easyw-fc 2016 |
|||
# * This program is free software; you can redistribute it and/or modify * |
|||
# * it under the terms of the GNU Library General Public License (LGPL) * |
|||
# * as published by the Free Software Foundation; either version 2 of * |
|||
# * the License, or (at your option) any later version. * |
|||
# * for detail see the LICENCE text file. * |
|||
## done case: invert normal and standard when already aligned planes |
|||
## done works for Bodys on FC 0.17 |
|||
import FreeCAD, FreeCADGui, Draft, Part, DraftTools |
|||
from FreeCAD import Base |
|||
import sys |
|||
testing=False #true for showing helpers |
|||
# Form implementation generated from reading ui file 'C:\Cad\Progetti_K\3D-FreeCad-tools\CenterAlignObjectswFacesEdges.ui' |
|||
# |
|||
# Created: Wed Sep 13 22:20:26 2017 |
|||
# by: pyside-uic 0.2.15 running on PySide 1.2.2 |
|||
# |
|||
# WARNING! All changes made in this file will be lost! |
|||
from PySide import QtCore, QtGui |
|||
class Ui_CenterAlignObjectsFacesEdges(object): |
|||
def setupUi(self, CenterAlignObjectsFacesEdges): |
|||
CenterAlignObjectsFacesEdges.setObjectName("CenterAlignObjectsFacesEdges") |
|||
CenterAlignObjectsFacesEdges.setWindowModality(QtCore.Qt.NonModal) |
|||
CenterAlignObjectsFacesEdges.resize(475, 351) |
|||
CenterAlignObjectsFacesEdges.setFocusPolicy(QtCore.Qt.NoFocus) |
|||
self.verticalLayout = QtGui.QVBoxLayout(CenterAlignObjectsFacesEdges) |
|||
self.verticalLayout.setObjectName("verticalLayout") |
|||
self.verticalLayout_2 = QtGui.QVBoxLayout() |
|||
self.verticalLayout_2.setObjectName("verticalLayout_2") |
|||
self.lbl_info = QtGui.QLabel(CenterAlignObjectsFacesEdges) |
|||
font = QtGui.QFont() |
|||
font.setWeight(75) |
|||
font.setBold(True) |
|||
self.lbl_info.setFont(font) |
|||
self.lbl_info.setObjectName("lbl_info") |
|||
self.verticalLayout_2.addWidget(self.lbl_info) |
|||
self.horizontalLayout = QtGui.QHBoxLayout() |
|||
self.horizontalLayout.setObjectName("horizontalLayout") |
|||
self.groupBox = QtGui.QGroupBox(CenterAlignObjectsFacesEdges) |
|||
self.groupBox.setObjectName("groupBox") |
|||
self.rb_bb = QtGui.QRadioButton(self.groupBox) |
|||
self.rb_bb.setGeometry(QtCore.QRect(11, 20, 241, 20)) |
|||
self.rb_bb.setChecked(True) |
|||
self.rb_bb.setObjectName("rb_bb") |
|||
self.rb_mass = QtGui.QRadioButton(self.groupBox) |
|||
self.rb_mass.setGeometry(QtCore.QRect(300, 20, 181, 20)) |
|||
self.rb_mass.setObjectName("rb_mass") |
|||
self.horizontalLayout.addWidget(self.groupBox) |
|||
self.verticalLayout_2.addLayout(self.horizontalLayout) |
|||
self.verticalLayout.addLayout(self.verticalLayout_2) |
|||
self.hLayout2 = QtGui.QHBoxLayout() |
|||
self.hLayout2.setObjectName("hLayout2") |
|||
self.groupBox_2 = QtGui.QGroupBox(CenterAlignObjectsFacesEdges) |
|||
self.groupBox_2.setObjectName("groupBox_2") |
|||
self.rb_centers = QtGui.QRadioButton(self.groupBox_2) |
|||
self.rb_centers.setGeometry(QtCore.QRect(20, 20, 261, 20)) |
|||
self.rb_centers.setObjectName("rb_centers") |
|||
self.rb_planes = QtGui.QRadioButton(self.groupBox_2) |
|||
self.rb_planes.setGeometry(QtCore.QRect(20, 50, 261, 20)) |
|||
self.rb_planes.setObjectName("rb_planes") |
|||
self.rb_centers_planes = QtGui.QRadioButton(self.groupBox_2) |
|||
self.rb_centers_planes.setGeometry(QtCore.QRect(20, 80, 301, 20)) |
|||
self.rb_centers_planes.setChecked(True) |
|||
self.rb_centers_planes.setObjectName("rb_centers_planes") |
|||
self.cb_x = QtGui.QCheckBox(self.groupBox_2) |
|||
self.cb_x.setGeometry(QtCore.QRect(370, 40, 41, 20)) |
|||
self.cb_x.setChecked(True) |
|||
self.cb_x.setObjectName("cb_x") |
|||
self.cb_y = QtGui.QCheckBox(self.groupBox_2) |
|||
self.cb_y.setGeometry(QtCore.QRect(370, 60, 41, 20)) |
|||
self.cb_y.setChecked(True) |
|||
self.cb_y.setObjectName("cb_y") |
|||
self.cb_z = QtGui.QCheckBox(self.groupBox_2) |
|||
self.cb_z.setGeometry(QtCore.QRect(370, 80, 41, 20)) |
|||
self.cb_z.setChecked(True) |
|||
self.cb_z.setObjectName("cb_z") |
|||
self.label_2 = QtGui.QLabel(self.groupBox_2) |
|||
self.label_2.setGeometry(QtCore.QRect(350, 20, 61, 16)) |
|||
self.label_2.setObjectName("label_2") |
|||
self.hLayout2.addWidget(self.groupBox_2) |
|||
self.verticalLayout.addLayout(self.hLayout2) |
|||
self.verticalLayout_3 = QtGui.QVBoxLayout() |
|||
self.verticalLayout_3.setObjectName("verticalLayout_3") |
|||
self.cb_inv_normals = QtGui.QCheckBox(CenterAlignObjectsFacesEdges) |
|||
self.cb_inv_normals.setObjectName("cb_inv_normals") |
|||
self.verticalLayout_3.addWidget(self.cb_inv_normals) |
|||
self.line = QtGui.QFrame(CenterAlignObjectsFacesEdges) |
|||
self.line.setFrameShape(QtGui.QFrame.HLine) |
|||
self.line.setFrameShadow(QtGui.QFrame.Sunken) |
|||
self.line.setObjectName("line") |
|||
self.verticalLayout_3.addWidget(self.line) |
|||
self.label = QtGui.QLabel(CenterAlignObjectsFacesEdges) |
|||
self.label.setObjectName("label") |
|||
self.verticalLayout_3.addWidget(self.label) |
|||
self.hLayout1 = QtGui.QHBoxLayout() |
|||
self.hLayout1.setObjectName("hLayout1") |
|||
self.btnAlign = QtGui.QPushButton(CenterAlignObjectsFacesEdges) |
|||
self.btnAlign.setObjectName("btnAlign") |
|||
self.hLayout1.addWidget(self.btnAlign) |
|||
self.btnMove = QtGui.QPushButton(CenterAlignObjectsFacesEdges) |
|||
self.btnMove.setObjectName("btnMove") |
|||
self.hLayout1.addWidget(self.btnMove) |
|||
self.btnUndoMove = QtGui.QPushButton(CenterAlignObjectsFacesEdges) |
|||
self.btnUndoMove.setObjectName("btnUndoMove") |
|||
self.hLayout1.addWidget(self.btnUndoMove) |
|||
self.verticalLayout_3.addLayout(self.hLayout1) |
|||
self.verticalLayout.addLayout(self.verticalLayout_3) |
|||
self.retranslateUi(CenterAlignObjectsFacesEdges) |
|||
QtCore.QMetaObject.connectSlotsByName(CenterAlignObjectsFacesEdges) |
|||
def retranslateUi(self, CenterAlignObjectsFacesEdges): |
|||
CenterAlignObjectsFacesEdges.setWindowTitle(QtGui.QApplication.translate("CenterAlignObjectsFacesEdges", "Center Align Faces/Edges", None, QtGui.QApplication.UnicodeUTF8)) |
|||
self.lbl_info.setText(QtGui.QApplication.translate("CenterAlignObjectsFacesEdges", "<html><head/><body><p>Select [Ctrl+Click] multiple face(s) or closed Edges and click Align</p></body></html>", None, QtGui.QApplication.UnicodeUTF8)) |
|||
self.groupBox.setTitle(QtGui.QApplication.translate("CenterAlignObjectsFacesEdges", "reference", None, QtGui.QApplication.UnicodeUTF8)) |
|||
self.rb_bb.setText(QtGui.QApplication.translate("CenterAlignObjectsFacesEdges", "Center of Bounding Box", None, QtGui.QApplication.UnicodeUTF8)) |
|||
self.rb_mass.setText(QtGui.QApplication.translate("CenterAlignObjectsFacesEdges", "Center of Mass", None, QtGui.QApplication.UnicodeUTF8)) |
|||
self.groupBox_2.setTitle(QtGui.QApplication.translate("CenterAlignObjectsFacesEdges", "aligning", None, QtGui.QApplication.UnicodeUTF8)) |
|||
self.rb_centers.setText(QtGui.QApplication.translate("CenterAlignObjectsFacesEdges", "Align Faces/Edges Centers", None, QtGui.QApplication.UnicodeUTF8)) |
|||
self.rb_planes.setText(QtGui.QApplication.translate("CenterAlignObjectsFacesEdges", "Align Faces/Edges Planes", None, QtGui.QApplication.UnicodeUTF8)) |
|||
self.rb_centers_planes.setText(QtGui.QApplication.translate("CenterAlignObjectsFacesEdges", "Align Faces/Edges Centers and Planes", None, QtGui.QApplication.UnicodeUTF8)) |
|||
self.cb_x.setText(QtGui.QApplication.translate("CenterAlignObjectsFacesEdges", "x", None, QtGui.QApplication.UnicodeUTF8)) |
|||
self.cb_y.setText(QtGui.QApplication.translate("CenterAlignObjectsFacesEdges", "y", None, QtGui.QApplication.UnicodeUTF8)) |
|||
self.cb_z.setText(QtGui.QApplication.translate("CenterAlignObjectsFacesEdges", "z", None, QtGui.QApplication.UnicodeUTF8)) |
|||
self.label_2.setText(QtGui.QApplication.translate("CenterAlignObjectsFacesEdges", "center on:", None, QtGui.QApplication.UnicodeUTF8)) |
|||
self.cb_inv_normals.setText(QtGui.QApplication.translate("CenterAlignObjectsFacesEdges", "invert Normal for Plane", None, QtGui.QApplication.UnicodeUTF8)) |
|||
self.label.setText(QtGui.QApplication.translate("CenterAlignObjectsFacesEdges", "<html><b>First Face/Edge is the Reference for alignment</b> <u>vers. 0.38</u>", None, QtGui.QApplication.UnicodeUTF8)) |
|||
self.btnAlign.setToolTip(QtGui.QApplication.translate("CenterAlignObjectsFacesEdges", "select Faces or Edges (Ctrl+LBM) and click button to Apply", None, QtGui.QApplication.UnicodeUTF8)) |
|||
self.btnAlign.setText(QtGui.QApplication.translate("CenterAlignObjectsFacesEdges", "Align", None, QtGui.QApplication.UnicodeUTF8)) |
|||
self.btnMove.setToolTip(QtGui.QApplication.translate("CenterAlignObjectsFacesEdges", "select an Object and click button to Move it", None, QtGui.QApplication.UnicodeUTF8)) |
|||
self.btnMove.setText(QtGui.QApplication.translate("CenterAlignObjectsFacesEdges", "Move", None, QtGui.QApplication.UnicodeUTF8)) |
|||
self.btnUndoMove.setToolTip(QtGui.QApplication.translate("CenterAlignObjectsFacesEdges", "select Faces / Edges and click to show Normals", None, QtGui.QApplication.UnicodeUTF8)) |
|||
self.btnUndoMove.setText(QtGui.QApplication.translate("CenterAlignObjectsFacesEdges", "undo", None, QtGui.QApplication.UnicodeUTF8)) |
|||
### ------------------------------------------------------------------------------------ ### |
|||
### ---------code to be inserted and remove from new generation------------------------- ### |
|||
### ------------------------------------------------------------------------------------ ### |
|||
self.btnAlign.clicked.connect(self.onAlign) |
|||
self.btnMove.clicked.connect(self.onMove) |
|||
self.btnUndoMove.clicked.connect(self.onUndo) |
|||
def onAlign(self): |
|||
say("Align clicked") |
|||
normal=0;type=0;mode=0 |
|||
if self.cb_inv_normals.isChecked(): |
|||
say("Align Normal Inverted") |
|||
normal=1 |
|||
if self.rb_bb.isChecked(): |
|||
say("centering on Bounding Boxes") |
|||
else: |
|||
say("centering on Center of Mass") |
|||
type=1 |
|||
if self.rb_centers_planes.isChecked(): |
|||
say("Centering and aligning Planes") |
|||
elif self.rb_centers.isChecked(): |
|||
say("Centering Faces/Edges") |
|||
mode=1 |
|||
else: |
|||
say("Aligning Planes") |
|||
mode=2 |
|||
cx=0;cy=0;cz=0 |
|||
if self.cb_x.isChecked(): |
|||
cx=1 |
|||
if self.cb_y.isChecked(): |
|||
cy=1 |
|||
if self.cb_z.isChecked(): |
|||
cz=1 |
|||
Align(normal,type,mode,cx,cy,cz) |
|||
def onMove(self): |
|||
say("Move clicked") |
|||
Move() |
|||
say("Move clicked2") |
|||
def onUndo(self): |
|||
say("Undo clicked") |
|||
Undo() |
|||
say("Undo clicked2") |
|||
############################################################## |
|||
global initial_placement, last_selection |
|||
global moving, rotating |
|||
#init |
|||
initial_placement = FreeCAD.Placement(App.Vector(0,0,0), App.Rotation(0,0,0), App.Vector(0,0,0)) #Placement [Pos=(0,0,0), Yaw-Pitch-Roll=(0,0,0)] |
|||
moving = [] #[App.Vector(0,0,0)] |
|||
rotating = [] #[0, App.Vector(0,0,0), App.Vector(0,0,0)] |
|||
#Draft.rotate(objs[j],-rot_angle,rot_center,rot_axis) |
|||
#rotating=[rot_angle,rot_center,rot_axis] |
|||
last_selection = [] |
|||
def say(msg): |
|||
FreeCAD.Console.PrintMessage(msg) |
|||
FreeCAD.Console.PrintMessage('\n') |
|||
def sayw(msg): |
|||
FreeCAD.Console.PrintWarning(msg) |
|||
FreeCAD.Console.PrintWarning('\n') |
|||
def sayerr(msg): |
|||
FreeCAD.Console.PrintError(msg) |
|||
FreeCAD.Console.PrintWarning('\n') |
|||
def make_string(input): |
|||
if (sys.version_info > (3, 0)): #py3 |
|||
if isinstance(input, str): |
|||
return input |
|||
else: |
|||
input = input.encode('utf-8') |
|||
return input |
|||
else: #py2 |
|||
if type(input) == unicode: |
|||
input = input.encode('utf-8') |
|||
return input |
|||
else: |
|||
return input |
|||
def singleInstance(): |
|||
app = QtGui.qApp |
|||
for i in app.topLevelWidgets(): |
|||
if i.objectName() == "CenterAlignObjectsFacesEdges": |
|||
i.deleteLater() |
|||
else: |
|||
pass |
|||
# t=FreeCADGui.getMainWindow() |
|||
# dw=t.findChildren(QtGui.QDockWidget) |
|||
# #print str(dw) |
|||
# for i in dw: |
|||
# print str(i.objectName()) |
|||
# if str(i.objectName()) == "CenterAlignObjectsFacesEdges": #"kicad StepUp 3D tools": |
|||
# i.deleteLater() |
|||
# else: |
|||
# pass |
|||
## assigning DisplayModeBody to Tip to attach Facebinder to Body |
|||
doc=FreeCAD.ActiveDocument |
|||
#Init |
|||
singleInstance() |
|||
CenterAlignObjectsFacesEdges = QtGui.QWidget() |
|||
ui = Ui_CenterAlignObjectsFacesEdges() |
|||
ui.setupUi(CenterAlignObjectsFacesEdges) |
|||
#CenterAlignObjectsFacesEdges.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint) |
|||
CenterAlignObjectsFacesEdges.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint & QtCore.Qt.WindowTitleHint & QtCore.Qt.WindowMinimizeButtonHint & QtCore.Qt.WindowSystemMenuHint & QtCore.Qt.CustomizeWindowHint | QtCore.Qt.WindowStaysOnTopHint); |
|||
## CenterAlignObjectsFacesEdges.setWindowFlags(CenterAlignObjectsFacesEdges.windowFlags() & QtCore.Qt.CustomizeWindowHint) |
|||
#CenterAlignObjectsFacesEdges.setWindowModality(QtCore.Qt.ApplicationModal) |
|||
#self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint) |
|||
#CenterAlignObjectsFacesEdges.setWindowFlags(CenterAlignObjectsFacesEdges.windowFlags() & QtCore.Qt.WindowStaysOnTopHint) |
|||
CenterAlignObjectsFacesEdges.show() |
|||
# def center(self): |
|||
# frameGm = self.frameGeometry() |
|||
# screen = QtGui.QApplication.desktop().screenNumber(QtGui.QApplication.desktop().cursor().pos()) |
|||
# #say(screen) |
|||
# centerPoint = QtGui.QApplication.desktop().screenGeometry(screen).center() |
|||
# #say(centerPoint) |
|||
# frameGm.moveCenter(centerPoint) |
|||
# self.move(frameGm.center) |
|||
#center(CenterAlignObjectsFacesEdges) |
|||
CenterAlignObjectsFacesEdges.move(100,100) |
|||
##CenterAlignObjectsFacesEdges.move(500,100) |
|||
## to do: |
|||
## ok single instance |
|||
## - always on top |
|||
## - no maximize |
|||
### ------------------------------------------------------------------------------------ ### |
|||
### ---------code to be inserted and remove from new generation------------------------- ### |
|||
### ------------------------------------------------------------------------------------ ### |
|||
def Undo(): |
|||
say('Undo') |
|||
global initial_placement, last_selection |
|||
global moving, rotating |
|||
global objs, objs_plc |
|||
if len(last_selection) == 1: |
|||
obj = last_selection[0].Object |
|||
say ('last selection: ' + obj.Name) |
|||
obj.Placement.Base =initial_placement |
|||
FreeCAD.ActiveDocument.recompute() |
|||
objs = [] |
|||
last_selection = [] |
|||
elif len (objs) > 1: |
|||
say ('Moving: ' + str(moving)) |
|||
say ('Rotating: ' + str(rotating)) |
|||
i=0 |
|||
for o in objs: |
|||
say ('obj: ' + o.Name) |
|||
if i != 0: |
|||
#o.Placement.Base = objs_plc [i] |
|||
if rotating[i][0]!=0: |
|||
sayw('restoring rotation') |
|||
o.Placement.move(App.Vector(-moving[i][0],-moving[i][1],-moving[i][2])) |
|||
Draft.rotate(o,rotating[i][0],rotating[i][1],rotating[i][2]) |
|||
else: |
|||
sayw('restoring position') |
|||
o.Placement.Base = objs_plc [i] |
|||
#o.Placement=rtg.multiply(o.Placement) #incremental Placement |
|||
#o.Placement=moving.multiply(o.Placement) #incremental Placement |
|||
#else: |
|||
# o.Placement.Base = objs_plc [i] |
|||
say ('Placement: ' + str(objs_plc [i])) |
|||
i=i+1 |
|||
objs = [] |
|||
last_selection = [] |
|||
FreeCAD.ActiveDocument.recompute() |
|||
def Move(): |
|||
global initial_placement, last_selection |
|||
global objs, objs_plc |
|||
say('Move') |
|||
selection = [s for s in FreeCADGui.Selection.getSelectionEx() if s.Document == FreeCAD.ActiveDocument ] |
|||
if len(selection) == 1: |
|||
objs = [] |
|||
last_selection = selection |
|||
say('Move2') |
|||
PartMover( FreeCADGui.activeDocument().activeView(), selection[0].Object ) |
|||
say('starting '+str(initial_placement)) |
|||
else: |
|||
PartMoverSelectionObserver() |
|||
class PartMover: |
|||
global initial_placement |
|||
def __init__(self, view, obj): |
|||
global initial_placement |
|||
self.obj = obj |
|||
self.initialPosition = self.obj.Placement.Base |
|||
initial_placement = self.initialPosition |
|||
#sayw('init '+str(initial_placement)) |
|||
self.copiedObject = False |
|||
self.view = view |
|||
self.callbackMove = self.view.addEventCallback("SoLocation2Event",self.moveMouse) |
|||
self.callbackClick = self.view.addEventCallback("SoMouseButtonEvent",self.clickMouse) |
|||
self.callbackKey = self.view.addEventCallback("SoKeyboardEvent",self.KeyboardEvent) |
|||
def moveMouse(self, info): |
|||
newPos = self.view.getPoint( *info['Position'] ) |
|||
# debugPrint(5, 'new position %s' % str(newPos)) |
|||
self.obj.Placement.Base = newPos |
|||
def removeCallbacks(self): |
|||
self.view.removeEventCallback("SoLocation2Event",self.callbackMove) |
|||
self.view.removeEventCallback("SoMouseButtonEvent",self.callbackClick) |
|||
self.view.removeEventCallback("SoKeyboardEvent",self.callbackKey) |
|||
def clickMouse(self, info): |
|||
global initial_placement |
|||
# debugPrint(4, 'clickMouse info %s' % str(info)) |
|||
if info['Button'] == 'BUTTON1' and info['State'] == 'DOWN': |
|||
if not info['ShiftDown'] and not info['CtrlDown']: |
|||
say('releasing obj') |
|||
FreeCAD.ActiveDocument.recompute() |
|||
#sayw('releasing\ninitial p: '+ str( initial_placement )) |
|||
#sayw('final p: '+str(self.obj.Placement.Base)) |
|||
self.removeCallbacks() |
|||
elif info['ShiftDown']: #copy object |
|||
self.obj = duplicateImportedPart( self.obj ) |
|||
self.copiedObject = True |
|||
elif info['CtrlDown']: |
|||
azi = ( numpy.random.rand() - 0.5 )*numpy.pi*2 |
|||
ela = ( numpy.random.rand() - 0.5 )*numpy.pi |
|||
theta = ( numpy.random.rand() - 0.5 )*numpy.pi |
|||
axis = azimuth_and_elevation_angles_to_axis( azi, ela ) |
|||
self.obj.Placement.Rotation.Q = quaternion( theta, *axis ) |
|||
def KeyboardEvent(self, info): |
|||
# debugPrint(4, 'KeyboardEvent info %s' % str(info)) |
|||
if info['State'] == 'UP' and info['Key'] == 'ESCAPE': |
|||
if not self.copiedObject: |
|||
self.obj.Placement.Base = self.initialPosition |
|||
else: |
|||
FreeCAD.ActiveDocument.removeObject(self.obj.Name) |
|||
self.removeCallbacks() |
|||
class PartMoverSelectionObserver: |
|||
def __init__(self): |
|||
FreeCADGui.Selection.addObserver(self) |
|||
FreeCADGui.Selection.removeSelectionGate() |
|||
def addSelection( self, docName, objName, sub, pnt ): |
|||
# debugPrint(4,'addSelection: docName,objName,sub = %s,%s,%s' % (docName, objName, sub)) |
|||
FreeCADGui.Selection.removeObserver(self) |
|||
obj = FreeCAD.ActiveDocument.getObject(objName) |
|||
view = FreeCADGui.activeDocument().activeView() |
|||
PartMover( view, obj ) |
|||
# class MovePartCommand: |
|||
# say('Move') |
|||
# def Activated(self): |
|||
# selection = [s for s in FreeCADGui.Selection.getSelectionEx() if s.Document == FreeCAD.ActiveDocument ] |
|||
# if len(selection) == 1: |
|||
# say('Move2') |
|||
# PartMover( FreeCADGui.activeDocument().activeView(), selection[0].Object ) |
|||
# else: |
|||
# PartMoverSelectionObserver() |
|||
#FreeCADGui.addCommand('assembly2_movePart', MovePartCommand()) |
|||
def duplicateImportedPart( part ): |
|||
nameBase = part.Label |
|||
while nameBase[-1] in '0123456789' and len(nameBase) > 0: |
|||
nameBase = nameBase[:-1] |
|||
try: |
|||
newObj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", findUnusedObjectName(nameBase)) |
|||
except UnicodeEncodeError: |
|||
safeName = findUnusedObjectName('import_') |
|||
newObj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", safeName) |
|||
newObj.Label = findUnusedLabel( nameBase ) |
|||
newObj.addProperty("App::PropertyFile", "sourceFile", "importPart").sourceFile = part.sourceFile |
|||
newObj.addProperty("App::PropertyFloat", "timeLastImport","importPart").timeLastImport = part.timeLastImport |
|||
newObj.setEditorMode("timeLastImport",1) |
|||
newObj.addProperty("App::PropertyBool","fixedPosition","importPart").fixedPosition = False# part.fixedPosition |
|||
newObj.addProperty("App::PropertyBool","updateColors","importPart").updateColors = getattr(part,'updateColors',True) |
|||
newObj.Shape = part.Shape.copy() |
|||
for p in part.ViewObject.PropertiesList: #assuming that the user may change the appearance of parts differently depending on their role in the assembly. |
|||
if hasattr(newObj.ViewObject, p) and p not in ['DiffuseColor','Proxy']: |
|||
setattr(newObj.ViewObject, p, getattr( part.ViewObject, p)) |
|||
newObj.ViewObject.DiffuseColor = copy.copy( part.ViewObject.DiffuseColor ) |
|||
newObj.Proxy = Proxy_importPart() |
|||
newObj.ViewObject.Proxy = ImportedPartViewProviderProxy() |
|||
newObj.Placement.Base = part.Placement.Base |
|||
newObj.Placement.Rotation = part.Placement.Rotation |
|||
return newObj |
|||
def Align(normal,type,mode,cx,cy,cz): |
|||
global initial_placement, last_selection |
|||
global objs, objs_plc |
|||
global moving, rotating |
|||
objs = [] ; objs_plc = [] |
|||
#cx = 1 # center x -> 1 |
|||
#cy = 1 # center y -> 1 |
|||
#cz = 1 # center z -> 1 |
|||
say(str(cx)+str(cy)+str(cz)) |
|||
create_points=False |
|||
use_bb = True #align center based on bounding boxes or center of mass |
|||
if type==1: |
|||
use_bb = False #align center based on bounding boxes or center of mass |
|||
sel = FreeCADGui.Selection.getSelection() |
|||
selEx = FreeCADGui.Selection.getSelectionEx() |
|||
if len(selEx) < 2: |
|||
return |
|||
last_selection = [] |
|||
say("number of objects: "+ str(len(selEx))) |
|||
objs = [selobj.Object for selobj in selEx] |
|||
#k=0 |
|||
for o in objs: |
|||
say ('obj: ' + o.Name) |
|||
objs_plc.append(o.Placement.Base) |
|||
say ('Placement: ' + str(o.Placement.Base)) |
|||
moving.append([App.Vector(0,0,0)]) |
|||
rotating.append([0, App.Vector(0,0,0), App.Vector(0,0,0)]) |
|||
#k=k+1 |
|||
#objs_plc = [selobj.Object.Placement.Base for selobj in selEx] |
|||
#say(objs) |
|||
#sayw(objs_plc) |
|||
#stop |
|||
#def say(msg): |
|||
# FreeCAD.Console.PrintMessage(msg) |
|||
# FreeCAD.Console.PrintMessage('\n') |
|||
# |
|||
#def sayw(msg): |
|||
# FreeCAD.Console.PrintWarning(msg) |
|||
# FreeCAD.Console.PrintWarning('\n') |
|||
def edgeToVector(edge): |
|||
""" Return a vector from an edge or a Part.line. |
|||
""" |
|||
if isinstance(edge,Part.Shape): |
|||
return edge.Vertexes[-1].Point.sub(edge.Vertexes[0].Point) |
|||
elif isinstance(edge,Part.Line): |
|||
return edge.EndPoint.sub(edge.StartPoint) |
|||
else: |
|||
sayw("Error in edgeToVector(edge) : not a good type of input" + str(type(edge))) |
|||
return None |
|||
def centerLinePoint(edge,info=0): |
|||
""" Return the center point of the Line. |
|||
""" |
|||
center = None |
|||
#VVector_A=edge.valueAt( 0.0 ) |
|||
Vector_A = edge.Vertexes[0].Point |
|||
if info != 0: |
|||
say("Origin of line selected is : "+str(Vector_A)) |
|||
#Vector_B=edge.valueAt( edge.Length ) |
|||
Vector_B = edge.Vertexes[-1].Point |
|||
if info != 0: |
|||
say("End of line selected is : "+str(Vector_B)) |
|||
Vector_MidPoint = Vector_B + Vector_A |
|||
center = Vector_MidPoint.multiply(0.5) |
|||
if info != 0: |
|||
say("Center of line selected is : "+str(center)) |
|||
return center |
|||
def object_alignEdges(): |
|||
""" |
|||
Align the Edge(s) from selected object(s) to the last Edge selected. |
|||
- Click first to select an Edge of an object or several Edges from several objects. |
|||
- Click second to select an Edge to align to. |
|||
NB: |
|||
The center of rotation is the center of the bounbing box if possible or |
|||
the center of the Edge. |
|||
if the Edge of the object selected is already aligned to the last one, |
|||
a rotation of 180 deg is applied to the object. |
|||
In this case the Axis of rotation is Z vector : Base.Vector(0, 0, 1) |
|||
Two clicks will rotate by 180 deg. |
|||
""" |
|||
msg=verbose |
|||
error_msg =\ |
|||
"INCORRECT Object(s) Selection :\n" +\ |
|||
"You Must Select at least two(2) Edges (from two objects) !\n" +\ |
|||
"All Edges will be aligned to the last one !" |
|||
Selection = get_SelectedObjectsWithParent(info=msg, printError=False) |
|||
m_actDoc=get_ActiveDocument(info=1) |
|||
Selection2 = Gui.Selection.getSelectionEx(m_actDoc.Name) |
|||
try: |
|||
SelectedObjects = Selection |
|||
Number_of_Edges = SelectedObjects[1] |
|||
if msg!=0: |
|||
print_msg("Number_of_Edges=" + str(Number_of_Edges)) |
|||
if Number_of_Edges >= 2 : |
|||
Edge_List = SelectedObjects[4] |
|||
if msg != 0: |
|||
print_msg(" Edge_List=" + str(Edge_List)) |
|||
# Get the Reference Edge : last of the selected |
|||
Ref_Edge_dict = Edge_List[-1] |
|||
for Selected_Edge, Parent_Edge in Ref_Edge_dict.iteritems(): |
|||
Edge_ref = Selected_Edge |
|||
del Edge_List[-1] |
|||
for Selected_Edge_dict in Edge_List: |
|||
if msg != 0: |
|||
print_msg("Selected_Edge_dict = " + str(Selected_Edge_dict)) |
|||
for Selected_Edge, Parent_Edge in Selected_Edge_dict.iteritems(): |
|||
if msg != 0: |
|||
print_msg("Selected_Edge = " + str(Selected_Edge)) |
|||
print_msg("Parent = " + str(Parent_Edge)) |
|||
try: |
|||
Edge_Point = Parent_Edge.Shape.BoundBox.Center |
|||
except: |
|||
Edge_Point = centerLinePoint(Selected_Edge,info=0) |
|||
if msg != 0: |
|||
print_point(Edge_Point, msg="Edge_Point = ") |
|||
Edge = Selected_Edge |
|||
if colinearEdges(Edge, Edge_ref, info=msg , tolerance=1e-12): |
|||
rot_axis = Base.Vector(0, 0, 1).cross(edgeToVector(Edge)) |
|||
rot_center = Edge_Point |
|||
rot_angle = 180. + m_angleAlignEdges |
|||
Draft.rotate(Parent_Edge,rot_angle,rot_center,rot_axis) |
|||
else: |
|||
m_angle, m_angle_rad = angleBetween(Edge,Edge_ref) |
|||
print_msg("m_angle = " + str(m_angle)) |
|||
rot_axis = edgeToVector(Edge).cross(edgeToVector(Edge_ref)) |
|||
print_msg("rot_axis = " + str(rot_axis)) |
|||
rot_center = Edge_Point |
|||
rot_angle = m_angle + m_angleAlignEdges |
|||
Draft.rotate(Parent_Edge,rot_angle,rot_center,rot_axis) |
|||
# Reset the selection changed by Draft.rotate |
|||
reset_SelectedObjects(Selection2, info=0) |
|||
else: |
|||
sayerr(error_msg) |
|||
except: |
|||
sayerr(error_msg) |
|||
def angleBetween(e1, e2): |
|||
""" Return the angle (in degrees) between 2 edges. |
|||
""" |
|||
if isinstance(e1,Part.Edge) and isinstance(e2,Part.Edge): |
|||
# Create the Vector for first edge |
|||
v1 = e1.Vertexes[-1].Point |
|||
v2 = e1.Vertexes[0].Point |
|||
ve1 = v1.sub(v2) |
|||
# Create the Vector for second edge |
|||
v3 = e2.Vertexes[-1].Point |
|||
v4 = e2.Vertexes[0].Point |
|||
ve2 = v3.sub(v4) |
|||
elif isinstance(e1,Base.Vector) and isinstance(e2,Base.Vector): |
|||
ve1 = e1 |
|||
ve2 = e2 |
|||
elif isinstance(e1,Part.Edge) and isinstance(e2,Base.Vector): |
|||
v1 = e1.Vertexes[-1].Point |
|||
v2 = e1.Vertexes[0].Point |
|||
ve1 = v1.sub(v2) |
|||
ve2 = e2 |
|||
elif isinstance(e1,Base.Vector) and isinstance(e2,Part.Edge): |
|||
ve1 = e1 |
|||
v3 = e2.Vertexes[-1].Point |
|||
v4 = e2.Vertexes[0].Point |
|||
ve2 = v3.sub(v4) |
|||
else: |
|||
return |
|||
angle = ve1.getAngle(ve2) |
|||
import math |
|||
return math.degrees(angle), angle |
|||
def colinearVectors(A, B, C, info=0, tolerance=1e-12): |
|||
""" Return true if the 3 points are aligned. |
|||
""" |
|||
Vector_1 = B - A |
|||
Vector_2 = C - B |
|||
#if info != 0: |
|||
# print_point(Vector_1, msg="Vector_1 : ") |
|||
# print_point(Vector_2, msg="Vector_2 : ") |
|||
Vector_3 = Vector_1.cross(Vector_2) |
|||
#if info != 0: |
|||
# print_point(Vector_3, msg="Vector_1.cross(Vector_2) : ") |
|||
if abs(Vector_3.x) <= tolerance and abs(Vector_3.y) <= tolerance and abs(Vector_3.z) <= tolerance: |
|||
if info != 0: |
|||
sayw("Colinear Vectors !") |
|||
return True |
|||
else: |
|||
if info != 0: |
|||
sayw("NOT Colinear Vectors !") |
|||
return False |
|||
return |
|||
coords = [] |
|||
normals = [] |
|||
coordPs = [] |
|||
sEdge = [] |
|||
j = 0 |
|||
# .BoundBox.Center |
|||
#align faces |
|||
if (len(selEx) > 1) and (len(selEx)==len(sel)): |
|||
#s = obj.Shape |
|||
last_selection = [] #removing old Move object |
|||
for fc in selEx: |
|||
say ("j= "+str(j)) |
|||
say("len selEx "+str(len(selEx))) |
|||
s=fc |
|||
#selectedEdge = FreeCADGui.Selection.getSelectionEx()[j].SubObjects[0] # select one element SubObjects |
|||
selectedEdge = selEx[j].SubObjects[0] # select one element SubObjects |
|||
sEdge.append(selectedEdge) |
|||
pad=0 |
|||
if str(fc.SubObjects[0])[1:5] != "Face": #edge |
|||
# try: |
|||
# Edge_Point = centerLinePoint(selectedEdge,info=1) |
|||
# except: |
|||
# stop |
|||
try: |
|||
wire = Part.Wire(selectedEdge) |
|||
fw = Part.Face(wire) |
|||
except: |
|||
sayerr('edge non closed to be managed') |
|||
Edge_Point = centerLinePoint(selectedEdge,info=0) |
|||
reply = QtGui.QMessageBox.information(None,"info", "edge(s) non closed are not managed atm\n") |
|||
stop |
|||
#Part.show(fw) |
|||
f=FreeCAD.ActiveDocument.addObject("Part::Feature","Facebinder") |
|||
f.Shape=fw |
|||
pad=1 |
|||
#FreeCAD.ActiveDocument.recompute() |
|||
say("Label : "+ make_string(sel[j].Label)) # extract the Label |
|||
say("Name : "+ str(sel[j].Name)) # extract the Name |
|||
say( "Center Face Binder "+str(0)+" "+str(FreeCAD.ActiveDocument.getObject(f.Name).Shape.Faces[0].CenterOfMass)) # Vector center mass to face |
|||
say( "Center Face Binder bb "+str(0)+" "+str(FreeCAD.ActiveDocument.getObject(f.Name).Shape.Faces[0].BoundBox.Center)) # Vector center mass to face |
|||
else: #face |
|||
pad=0 |
|||
f=Draft.makeFacebinder(s) |
|||
say("Label : "+ make_string(sel[j].Label)) # extract the Label |
|||
say("Name : "+ str(sel[j].Name)) # extract the Name |
|||
say( "Center Face Binder "+str(0)+" "+str(f.Shape.Faces[0].CenterOfMass)) # Vector center mass to face |
|||
say( "Center Face Binder bb "+str(0)+" "+str(f.Shape.Faces[0].BoundBox.Center)) # Vector center mass to face |
|||
# LineColor |
|||
red = 1.0 # 1 = 255 |
|||
green = 0.0 # |
|||
blue = 0.0 # |
|||
if create_points: |
|||
if pad==0: |
|||
if use_bb: |
|||
Draft.makePoint(f.Shape.Faces[0].BoundBox.Center.x,f.Shape.Faces[0].BoundBox.Center.y,f.Shape.Faces[0].BoundBox.Center.z) # create a point |
|||
else: |
|||
Draft.makePoint(f.Shape.Faces[0].CenterOfMass.x,f.Shape.Faces[0].CenterOfMass.y,f.Shape.Faces[0].CenterOfMass.z) # create a point |
|||
FreeCADGui.activeDocument().activeObject().PointColor = (red, green, blue) |
|||
else: |
|||
if use_bb: |
|||
Draft.makePoint(FreeCAD.ActiveDocument.getObject(f.Name).Shape.Faces[0].BoundBox.Center.x,FreeCAD.ActiveDocument.getObject(f.Name).Shape.Faces[0].CenterOfMass.y,FreeCAD.ActiveDocument.getObject(f.Name).Shape.Faces[0].CenterOfMass.z) # create a point |
|||
else: |
|||
Draft.makePoint(FreeCAD.ActiveDocument.getObject(f.Name).Shape.Faces[0].CenterOfMass.x,FreeCAD.ActiveDocument.getObject(f.Name).Shape.Faces[0].CenterOfMass.y,FreeCAD.ActiveDocument.getObject(f.Name).Shape.Faces[0].CenterOfMass.z) # create a point |
|||
FreeCADGui.activeDocument().activeObject().PointColor = (red, green, blue) |
|||
if pad==0: |
|||
if use_bb: |
|||
coordNx = f.Shape.Faces[0].BoundBox.Center.x |
|||
coordNy = f.Shape.Faces[0].BoundBox.Center.y |
|||
coordNz = f.Shape.Faces[0].BoundBox.Center.z |
|||
coordP = f.Shape.Faces[0].BoundBox.Center |
|||
else: |
|||
coordNx = f.Shape.Faces[0].CenterOfMass.x |
|||
coordNy = f.Shape.Faces[0].CenterOfMass.y |
|||
coordNz = f.Shape.Faces[0].CenterOfMass.z |
|||
coordP = f.Shape.Faces[0].CenterOfMass |
|||
else: |
|||
if use_bb: |
|||
coordNx = FreeCAD.ActiveDocument.getObject(f.Name).Shape.Faces[0].BoundBox.Center.x |
|||
coordNy = FreeCAD.ActiveDocument.getObject(f.Name).Shape.Faces[0].BoundBox.Center.y |
|||
coordNz = FreeCAD.ActiveDocument.getObject(f.Name).Shape.Faces[0].BoundBox.Center.z |
|||
coordP = FreeCAD.ActiveDocument.getObject(f.Name).Shape.Faces[0].BoundBox.Center |
|||
else: |
|||
coordNx = FreeCAD.ActiveDocument.getObject(f.Name).Shape.Faces[0].CenterOfMass.x |
|||
coordNy = FreeCAD.ActiveDocument.getObject(f.Name).Shape.Faces[0].CenterOfMass.y |
|||
coordNz = FreeCAD.ActiveDocument.getObject(f.Name).Shape.Faces[0].CenterOfMass.z |
|||
coordP = FreeCAD.ActiveDocument.getObject(f.Name).Shape.Faces[0].CenterOfMass |
|||
coords.append ([coordNx,coordNy,coordNz]) |
|||
coordPs.append (coordP) |
|||
#norm = f.Shape.Faces[0].normalAt(0,0) |
|||
if j==0: |
|||
if normal==1: |
|||
norm = f.Shape.Faces[0].normalAt(0,0)*-1 |
|||
else: |
|||
norm = f.Shape.Faces[0].normalAt(0,0) |
|||
else: |
|||
norm = f.Shape.Faces[0].normalAt(0,0) |
|||
#else: |
|||
# norm = f.Shape.Faces[0].normalAt(0,0) |
|||
say (norm) |
|||
normals.append (norm) |
|||
FreeCAD.ActiveDocument.removeObject(f.Name) |
|||
if j>0: |
|||
pos=App.Vector(-coords[j][0]+coords[0][0],-coords[j][1]+coords[0][1],-coords[j][2]+coords[0][2]) |
|||
## objs[j].Placement.move(pos) |
|||
m_angle, m_angle_rad = angleBetween(normals[0],normals[j]) |
|||
say (m_angle) |
|||
Origin = Base.Vector(0, 0, 0) |
|||
copl=0 |
|||
if colinearVectors(normals[0], Origin, normals[j], info=1, tolerance=1e-12): |
|||
rot_axis = Base.Vector(0, 0, 1).cross(normals[0]) |
|||
if rot_axis==FreeCAD.Vector (0.0, 0.0, 0.0): |
|||
rot_axis=Base.Vector(0, 1, 0).cross(normals[0]) |
|||
rot_center = coordPs[j] |
|||
if normal==1: |
|||
rot_angle = 180. # + m_angleAlignFaces |
|||
else: |
|||
rot_angle=0. |
|||
copl=1 |
|||
#Draft.rotate(Parent_Plane,rot_angle,rot_center,rot_axis) |
|||
else: |
|||
#m_angle, m_angle_rad = angleBetween(Plane_Normal,Plane_Normal_ref) |
|||
rot_axis = normals[0].cross(normals[j]) |
|||
rot_center = coordPs[j] |
|||
rot_angle = m_angle # + m_angleAlignFaces |
|||
#Draft.rotate(Parent_Plane,rot_angle,rot_center,rot_axis) |
|||
#rot_axis = normals[0].cross(normals[j]) |
|||
#rot_center = coordPs[j] |
|||
#rot_angle = m_angle # + m_angleAlignFaces |
|||
sayw("axis,center,angle") |
|||
say(rot_axis) |
|||
say(rot_center) |
|||
say(rot_angle) |
|||
if rot_angle!=0: # and rot_axis!=FreeCAD.Vector (0.0, 0.0, 0.0): |
|||
if mode==0 or mode==2: |
|||
if rot_axis!=FreeCAD.Vector (0.0, 0.0, 0.0): |
|||
Draft.rotate(objs[j],-rot_angle,rot_center,rot_axis) |
|||
rotating[j] = [rot_angle,rot_center,rot_axis] |
|||
say("Rotated : angle "+str(-rot_angle)+" center "+str(rot_center)+" axis "+str(rot_axis)) |
|||
else: |
|||
rotating[j] = [0, App.Vector(0,0,0), App.Vector(0,0,0)] |
|||
else: |
|||
rotating[j] = [0, App.Vector(0,0,0), App.Vector(0,0,0)] |
|||
j=j+1 |
|||
coords = [] |
|||
normals = [] |
|||
coordPs = [] |
|||
j = 0 |
|||
#align centers |
|||
if (len(selEx) >= 1) and (len(selEx)==len(sel)): |
|||
#s = obj.Shape |
|||
for fc in selEx: |
|||
s=fc |
|||
print j |
|||
#selectedEdge = FreeCADGui.Selection.getSelectionEx()[j].SubObjects[0] # select one element SubObjects |
|||
selectedEdge = sEdge[j] # select one element SubObjects |
|||
pad=0 |
|||
if str(fc.SubObjects[0])[1:5] != "Face": |
|||
wire = Part.Wire(selectedEdge) |
|||
fw = Part.Face(wire) |
|||
if testing: |
|||
Part.show(fw) |
|||
f=FreeCAD.ActiveDocument.addObject("Part::Feature","Facebinder") |
|||
f.Shape=fw |
|||
pad=1 |
|||
#FreeCAD.ActiveDocument.recompute() |
|||
else: |
|||
pad=0 |
|||
f=Draft.makeFacebinder(s) |
|||
say("Label : "+ make_string(sel[j].Label)) # extract the Label |
|||
say("Name : "+ str(sel[j].Name)) # extract the Name |
|||
say( "Center Face Binder "+str(0)+" "+str(f.Shape.Faces[0].CenterOfMass)) # Vector center mass to face |
|||
say( "Center Face Binder bb "+str(0)+" "+str(f.Shape.Faces[0].BoundBox.Center)) # Vector center mass to face |
|||
# LineColor |
|||
red = 1.0 # 1 = 255 |
|||
green = 0.0 # |
|||
blue = 0.0 # |
|||
if create_points: |
|||
if pad==0: |
|||
Draft.makePoint(f.Shape.Faces[0].CenterOfMass.x,f.Shape.Faces[0].CenterOfMass.y,f.Shape.Faces[0].CenterOfMass.z) # create a point |
|||
FreeCADGui.activeDocument().activeObject().PointColor = (red, green, blue) |
|||
else: |
|||
Draft.makePoint(FreeCAD.ActiveDocument.getObject(f.Name).Shape.Faces[0].CenterOfMass.x,FreeCAD.ActiveDocument.getObject(f.Name).Shape.Faces[0].CenterOfMass.y,FreeCAD.ActiveDocument.getObject(f.Name).Shape.Faces[0].CenterOfMass.z) # create a point |
|||
FreeCADGui.activeDocument().activeObject().PointColor = (red, green, blue) |
|||
if pad==0: |
|||
if use_bb: |
|||
coordNx = f.Shape.Faces[0].BoundBox.Center.x |
|||
coordNy = f.Shape.Faces[0].BoundBox.Center.y |
|||
coordNz = f.Shape.Faces[0].BoundBox.Center.z |
|||
coordP = f.Shape.Faces[0].BoundBox.Center |
|||
else: |
|||
coordNx = f.Shape.Faces[0].CenterOfMass.x |
|||
coordNy = f.Shape.Faces[0].CenterOfMass.y |
|||
coordNz = f.Shape.Faces[0].CenterOfMass.z |
|||
coordP = f.Shape.Faces[0].CenterOfMass |
|||
norm = f.Shape.Faces[0].normalAt(0,0) |
|||
else: |
|||
if use_bb: |
|||
coordNx = FreeCAD.ActiveDocument.getObject(f.Name).Shape.Faces[0].BoundBox.Center.x |
|||
coordNy = FreeCAD.ActiveDocument.getObject(f.Name).Shape.Faces[0].BoundBox.Center.y |
|||
coordNz = FreeCAD.ActiveDocument.getObject(f.Name).Shape.Faces[0].BoundBox.Center.z |
|||
coordP = FreeCAD.ActiveDocument.getObject(f.Name).Shape.Faces[0].BoundBox.Center |
|||
else: |
|||
coordNx = FreeCAD.ActiveDocument.getObject(f.Name).Shape.Faces[0].CenterOfMass.x |
|||
coordNy = FreeCAD.ActiveDocument.getObject(f.Name).Shape.Faces[0].CenterOfMass.y |
|||
coordNz = FreeCAD.ActiveDocument.getObject(f.Name).Shape.Faces[0].CenterOfMass.z |
|||
coordP = FreeCAD.ActiveDocument.getObject(f.Name).Shape.Faces[0].CenterOfMass |
|||
norm = FreeCAD.ActiveDocument.getObject(f.Name).Shape.Faces[0].normalAt(0,0) |
|||
coords.append ([coordNx,coordNy,coordNz]) |
|||
coordPs.append (coordP) |
|||
say (norm) |
|||
normals.append (norm) |
|||
FreeCAD.ActiveDocument.removeObject(f.Name) |
|||
if j>0: |
|||
pos=App.Vector((-coords[j][0]+coords[0][0])*cx,(-coords[j][1]+coords[0][1])*cy,(-coords[j][2]+coords[0][2])*cz) |
|||
if mode==0 or mode==1: |
|||
objs[j].Placement.move(pos) |
|||
moving[j] = pos |
|||
say("Moved : "+str(coordNx-coords[0][0])+" "+str(coordNy-coords[0][1])+" "+str(coordNz-coords[0][2])) |
|||
else: |
|||
moving[j] = App.Vector(0,0,0) |
|||
j=j+1 |
|||
FreeCAD.ActiveDocument.recompute() |
|||
for obj in objs: |
|||
FreeCADGui.Selection.removeSelection(obj) |
|||
# except: |
|||
# App.Console.PrintError( "select a face"+"\n") |
|||
}} |
|||
{{clear}} |
|||
==Link== <!--T:7--> |
==Link== <!--T:7--> |
||
Line 947: | Line 94: | ||
</translate> |
</translate> |
||
{{clear}} |
{{clear}} |
||
<languages/> |
Latest revision as of 02:31, 28 February 2020
Description |
---|
This macro Aligns Objects through Faces or Edges constraints. These tools are now included in the Manipulator Workbench. Install this workbench for the latest updates on these tools. Macro version: 1.5.3 Last modified: 2017-10-01 FreeCAD version: All Download: ToolBar Icon Mover-icon Caliper-icon Author: easyw-fc |
Author |
easyw-fc |
Download |
ToolBar Icon Mover-icon Caliper-icon |
Links |
Macros recipes How to install macros How to customize toolbars |
Macro Version |
1.5.3 |
Date last modified |
2017-10-01 |
FreeCAD Version(s) |
All |
Default shortcut |
None |
See also |
None |
Description
This macro Aligns Objects through Faces or Edges constraints
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/easyw/FreeCAD_Macros/master/Align%20Objects/CenterAlignObjectswFacesEdges.py" + "\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/easyw/FreeCAD_Macros/master/Align%20Objects/CenterAlignObjectswFacesEdges.py")
Tools
Aligner : a set of tools to move and align 3D parts
Mover : a set of tools to move and rotate 3D parts on different Axis
Measure : a set of tools to measure 3D parts, with some Snap facility and Radius, Length, Angle measurements.
These helpers work with Part, App::Part and Body objects. Each Tool can be Floating or Docked Left or Right.
OLD References
This macro covers the following constraints:
- Concentric constraint among non cylindrical parts;
- Constraint on center Faces and/or Edges.
- It works also with the new Body and App::Part containers, as well as with STEP hierarchy.
Aligning STEP models video tutorial
Usage
Faces or Edges constraint among non cylindrical parts: Just open a FC document, launch the Macro and select two or more Faces/Edges to be aligned. Click on Align button and that's it!
Script
CenterAlignObjectswFacesEdges.py
After downloading the file here
GitHub page
https://github.com/easyw/FreeCAD_Macros/tree/master/Align%20Objects
code:
https://github.com/easyw/FreeCAD_Macros/raw/master/Align%20Objects/CenterAlignObjectswFacesEdges.py
you need to copy the file to your macro directory.
How to install macros
Link
Forum : Faces or Edges constraint among non cylindrical parts Macro