Macro CloneConvert: Difference between revisions

From FreeCAD Documentation
m (minor)
No edit summary
 
(53 intermediate revisions by 4 users not shown)
Line 1: Line 1:
<languages/>
{{Macro|Icon=Text-x-python|Name=Macro CloneConvert|Description=Creates a clone of the object and the converted in the chosen position and size (inch, mm, m, µm...).|Author=mario52}}
<translate>
==Description==
<!--T:1-->
Creates a clone of the object and the converted in the chosen position and size (inch, mm, m, µm...). The base object is recognized in mm (FreeCAd base)
{{Macro
==Uses==
|Name=Macro CloneConvert
Run the macro, the XYZ settings, choose a unit select your object, and click {{KEY|Ok}} button
|Icon=Macro_CloneConvert.png
|Description={{ColoredText|#ff0000|#ffffff| Latest update: GUI modified for HiDPI support (QGridLayout). Runs ≥v0.18 (PySide2 Qt5)}}<br/><br/>
For previous versions see [https://gist.githubusercontent.com/mario52a/9f2f2f6144e1307a048f1840ef99300c/raw/0a141260ad8d5f67f0fc18b9b40ef37757c06c65/Macro_CloneConvert.FCMacro Macro_CloneConvert] and install manually.<br/><br/>Creates a Clone/Copy/Compound of the object(s) and then converted into a chosen position and size (''inch, mm, m, µm''...) or free. The base object is recognized in ''mm'' (FreeCAD base).
|Author=mario52
|Version=0.15
|Date=2020-06-06
|FCVersion= ≥0.18
|Download=[https://www.freecadweb.org/wiki/images/0/0a/Macro_CloneConvert.png ToolBar Icon]
}}


==Description== <!--T:2-->
The base is the mm example with a '''1 mm''' cube of side :
Creates a clone or copy of the object and then converts it into a chosen position and size (''inch, mm, m, µm''...) or free. The base object is recognized in ''mm'' (FreeCAD base)


</translate>
Select in the comboBox '''inch''', '''1 inch = 25.4 mm''' , the fields '''"Scale free"''' automatically adjusts to 25.4 (the values ​​in '''"Scale-free"''' can be changed separately). Click {{KEY|Ok}} button, the clone created will have '''25,4 mm x 25,4 mm x 25,4 mm'''
{{Codeextralink|https://gist.githubusercontent.com/mario52a/9f2f2f6144e1307a048f1840ef99300c/raw/39bc54e90b80053a5af76b0b17694cb53697aebd/Macro_CloneConvert.FCMacro}}
<translate>


==Usage== <!--T:3-->
Predefined units are :
# Run the macro
# Set the XYZ settings
# Choose "Clone" or "Copy"
# Choose a measurement unit
# Select your object
# Click {{KEY|Ok}}


==Notes== <!--T:9-->
km, hm, dam, m, dm, cm, '''mm''', µm, nm, inch, link, foot, yard, perch, chain, furlong, mile, league, nautique.
* If no value is entered a copy or clone will be created without modification.
<br /><br />
* If no object is selected the {{KEY|Ok}} button will be colored in red.
[[File:Macro CloneConvert_01.png|220px|left|CloneConvert]]
* '''Mode'''
* '''Coordinate X :''' Coordinate placement X
* '''Coordinate Y :''' Coordinate placement Y
* '''Coordinate Z :''' Coordinate placement Z
*
* '''Scale predefined'''
* '''Scale predefined :''' predefined scales in units, km, hm, dam, m, dm, cm, '''mm''', µm, nm, inch, link, foot, yard, perch, chain, furlong, mile, league, nautique.
*
* '''Scale free'''
* '''Scale X :''' free scale , if the value is negative '''( -10)''' , the object is scaled '''x 10''' and will be reversed in the X axis, to reduce the shape give a decimal value '''(0,5)'''
* '''{{KEY|...}} :''' This button align the YZ values on the value of X if the three values are identical
* '''Scale Y :''' free scale , if the value is negative '''( -10)''' , the object is scaled '''x 10''' and will be reversed in the Y axis, to reduce the shape give a decimal value '''(0,5)'''
* '''Scale Z :''' free scale , if the value is negative '''( -10)''' , the object is scaled '''x 10''' and will be reversed in the Z axis, to reduce the shape give a decimal value '''(0,5)'''
*
* '''{{KEY|Ok}} :''' the OK button validates and launches the command
* '''{{KEY|Reset}} :''' the Reset button puts all the values to zero
* '''{{KEY|Quit}} :''' the Quit button exit the macro
{{clear}}


<!--T:10-->
==Script==
The value of the '''BoundingBox''', '''Volume''' and '''Surface''' is displayed in the [[Report_view|Report view]], in the case of '''Copy''' multiple object, the display will show BoundingBox 0.0.


<!--T:4-->
Macro_CloneConvert.FCMacro
The base is the mm example with a '''1 mm''' side of cube:


<!--T:5-->
<syntaxhighlight>
Select in the comboBox '''inch''', '''1 inch = 25.4 mm''' , the fields '''"Scale free"''' automatically adjusts to 25.4 (the values ​​in '''"Scale-free"''' can be changed separately). Click {{KEY|Ok}} button, the clone created will have '''25,4 mm x 25,4 mm x 25,4 mm'''
# -*- coding: utf-8 -*-
# CloneConvert.py
# Crée un clone de l'objet ou des objets sélectionné(s) et le met à l'échelle de la grandeur choisie
# utilisation : lancer CloneConvert sélectionnez un objet choisissez la grandeur et cliquez sur OK
#
# Creates a clone of the selected object and updates the selected size range
# use: start CloneConvert select an object choose the size and click OK
#
# OS: Windows Vista
# Platform: 32-bit
# Version: 0.14.3343 (Git)
# Branch: libpack
# Hash: 8dcb8f68cf17ef152d34d226d7699c98c5bb59fb
# Python version: 2.7.6
# Qt version: 4.8.5
# Coin version: 3.1.3
# SoQt version: 1.5.0
# OCC version: 6.7.0
#
# ver 0.1 13/04/2014


<!--T:11-->
__title__="CloneConvert"
'''150%''' = '''1,50''' in the '''"Scale free"''' fields <br />
__author__ = "mario52"
'''104%''' = '''1,04''' in the '''"Scale free"''' fields


<!--T:13-->
import Draft, Part, FreeCAD, math, PartGui, FreeCADGui, PyQt4
Inverse operation :
from math import sqrt, pi, sin, cos, asin
from FreeCAD import Base
from PyQt4 import QtCore, QtGui
from decimal import *
from FreeCAD import Vector, Rotation, Placement, Console


<!--T:14-->
If you want to reduce an object ex: a cube 25.4 mm (1 inch) in cube 1 mm sides, use the following formula, '''1 / 25.4 = 0.0393700''' and enter the value '''0,0393700''' (with comma) in the Scale field XY and Z.


<!--T:15-->
try:
In a cube of 5 mm, made​​ '''5 / 25.4 = 0.1968503''' and enter the value '''0,1968503''' (with comma) in the Scale field XY and Z.
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s


<!--T:16-->
try:
'''50%''' = '''0,50''' in the '''"Scale free"''' fields<br />
_encoding = QtGui.QApplication.UnicodeUTF8
''' 4%''' = '''0,04''' in the '''"Scale free"''' fields
def _translate(context, text, disambig):
<br />
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)


<!--T:6-->
global surface ; surface = 0.0
Predefined units are:
global volume_ ; volume_ = 0.0
km, hm, dam, m, dm, cm, '''mm''', µm, nm, inch, link, foot, yard, perch, chain, furlong, mile, league, nautique.
global boundBox_ ; boundBox_ = 0.0
<br /><br />
global boundBoxLX ; boundBoxLX = 0.0
global boundBoxLY ; boundBoxLY = 0.0
global boundBoxLZ ; boundBoxLZ = 0.0
global boundBox_S ; boundBox_S = ""
global uniteM_X ; uniteM_X = 1.0
global uniteM_Y ; uniteM_Y = 1.0
global uniteM_Z ; uniteM_Z = 1.0
global uniteM ; uniteM = 1.0
global uniteMs ; uniteMs = "mm" # default mm
global placement_X ; placement_X = 0.0
global placement_Y ; placement_Y = 0.0
global placement_Z ; placement_Z = 0.0
global oripl_X ; oripl_X = 0.0
global oripl_Y ; oripl_Y = 0.0
global oripl_Z ; oripl_Z = 0.0
global sel ; sel = ""


<!--T:7-->
class Ui_MainWindow(object):
[[File:Macro CloneConvert_01.png|350px|left|CloneConvert]]
* '''Mode'''
* '''Clone :''' The object(s) clone are create
* '''Copy :''' One copy of the objet(s) is create
* '''Comp :''' One compound of the objet(s) is create
* '''Increm. :''' incrementing the coordinates data to the original coordinates of the object (Placement, Rotation ...)<br />If this is not checked the Placement begin in coordinates 0,0,0 of FreeCAD<br />In case a compound Placement information is [0,0,0] the Placement begin in the position of object<br />If the real location is away from the base coordinates 0,0,0 use the {{KEY|ValueAt()}} button for the real Placement of the subObject selected Face, Wire, Line ....
* '''Unique :''' If this checkBox is checked and multiple object selected, the clone created is one unique object


<!--T:28-->
def __init__(self, MainWindow):
* '''Coordinates'''
# path = FreeCAD.ConfigGet("AppHomePath")
* '''{{KEY|...}} :''' This button align the YZ values on the value of X to have the same values ​​XYZ (or manually). Two click reset the coordinates values to 0.0
* '''Coordinate X :''' Move the copy to the Coordinate X selected (Base 0,0,0 if Increm. is not checked)
* '''Coordinate Y :''' Move the copy to the Coordinate Y selected (Base 0,0,0 if Increm. is not checked)
* '''Coordinate Z :''' Move the copy to the Coordinate Z selected (Base 0,0,0 if Increm. is not checked)


<!--T:29-->
global uniteMs
* '''Rotation'''
* '''{{KEY|...}} :''' This button align the Pitch and Roll values on the value of Yaw to have the same values ​​Rotation (or manually)<br />Two click reset the rotations values to 0.0
* '''Yaw (Z ) :''' Rotate the copy to the axis Z (Yaw) (Begin 0 if Increm. is not checked)
* '''Pitch ( Y ) :''' Rotate the copy to the axis Y (Pitch) (Begin 0 if Increm. is not checked)
* '''Roll ( X ) :''' Rotate the copy to the axis X (Roll) (Begin 0 if Increm. is not checked)


<!--T:30-->
self.window = MainWindow
* '''Scale predefined'''
MainWindow.setObjectName(_fromUtf8("MainWindow"))
* '''Scale predefined :''' predefined scales in units, km, hm, dam, m, dm, cm, '''mm''', µm, nm, inch, link, foot, yard, perch, chain, furlong, mile, league, nautique or choose a free value in the Scale free field.
MainWindow.resize(230, 379)
self.centralWidget = QtGui.QWidget(MainWindow)
self.centralWidget.setObjectName(_fromUtf8("centralWidget"))
self.label = QtGui.QLabel(self.centralWidget)
self.label.setGeometry(QtCore.QRect(10, 10, 191, 16))
self.label.setAlignment(QtCore.Qt.AlignCenter)
self.label.setObjectName(_fromUtf8("label"))


<!--T:31-->
self.groupBox = QtGui.QGroupBox(self.centralWidget)
* '''Number copy '''
self.groupBox.setGeometry(QtCore.QRect(10, 30, 211, 141))
* '''Number copy :''' number of copies
self.groupBox.setObjectName(_fromUtf8("groupBox"))


<!--T:32-->
self.doubleSpinBox = QtGui.QDoubleSpinBox(self.groupBox)
* '''Scale free'''
self.doubleSpinBox.setGeometry(QtCore.QRect(100, 50, 101, 22))
* '''{{KEY|...}} :''' This button align the Scales values on the value of Scale X to have the same values ​​XYZ (or manually)<br />Two click reset the scales values to 1.0
self.doubleSpinBox.setDecimals(7)
* '''Scale X :''' free scale , if the value is negative '''( -10)''' , the object is scaled '''x 10''' and will be reversed in the X axis, to reduce the shape give a decimal value '''(0,5)'''
self.doubleSpinBox.setMinimum(-10000000.0)
* '''Scale Y :''' free scale , if the value is negative '''( -10)''' , the object is scaled '''x 10''' and will be reversed in the Y axis, to reduce the shape give a decimal value '''(0,5)'''
self.doubleSpinBox.setMaximum(10000000.0)
* '''Scale Z :''' free scale , if the value is negative '''( -10)''' , the object is scaled '''x 10''' and will be reversed in the Z axis, to reduce the shape give a decimal value '''(0,5)'''
self.doubleSpinBox.setSingleStep(1.0)
self.doubleSpinBox.setProperty("value", 0.0)
self.doubleSpinBox.setObjectName(_fromUtf8("doubleSpinBox"))
self.doubleSpinBox.valueChanged.connect(self.on_doubleSpinBox_valueChanged) #connection doubleSpinBox


<!--T:33-->
self.label_2 = QtGui.QLabel(self.groupBox)
* '''{{KEY|ValueAt()}} :''' Give the valueAt() the subObject selected Face, Wire, Line ...<br />This option is useful in case a compound Placement information [0,0,0] and its real location is away from the base coordinates 0,0,0 (gives no provide information about the rotation of the object)
self.label_2.setGeometry(QtCore.QRect(10, 50, 91, 16))
* '''{{KEY|Ok}} :''' the OK button validates and launches the command, if no object is selected the {{KEY|Ok}} button will be coloured in red
self.label_2.setObjectName(_fromUtf8("label_2"))
* '''{{KEY|Reset}} :''' the Reset button puts all the values to zero

* '''{{KEY|Quit}} :''' the Quit button exit the macro
self.label_3 = QtGui.QLabel(self.groupBox)
{{clear}}
self.label_3.setGeometry(QtCore.QRect(10, 80, 91, 16))
self.label_3.setObjectName(_fromUtf8("label_3"))

self.doubleSpinBox_2 = QtGui.QDoubleSpinBox(self.groupBox)
self.doubleSpinBox_2.setGeometry(QtCore.QRect(100, 80, 101, 22))
self.doubleSpinBox_2.setDecimals(7)
self.doubleSpinBox_2.setMinimum(-10000000.0)
self.doubleSpinBox_2.setMaximum(10000000.0)
self.doubleSpinBox_2.setSingleStep(1.0)
self.doubleSpinBox_2.setProperty("value", 0.0)
self.doubleSpinBox_2.setObjectName(_fromUtf8("doubleSpinBox_2"))
self.doubleSpinBox_2.valueChanged.connect(self.on_doubleSpinBox_2_valueChanged) #connection doubleSpinBox_2

self.doubleSpinBox_3 = QtGui.QDoubleSpinBox(self.groupBox)
self.doubleSpinBox_3.setGeometry(QtCore.QRect(100, 110, 101, 22))
self.doubleSpinBox_3.setDecimals(7)
self.doubleSpinBox_3.setMinimum(-10000000.0)
self.doubleSpinBox_3.setMaximum(10000000.0)
self.doubleSpinBox_3.setSingleStep(1.0)
self.doubleSpinBox_3.setProperty("value", 0.0)
self.doubleSpinBox_3.setObjectName(_fromUtf8("doubleSpinBox_3"))
self.doubleSpinBox_3.valueChanged.connect(self.on_doubleSpinBox_3_valueChanged) #connection doubleSpinBox_3

self.label_4 = QtGui.QLabel(self.groupBox)
self.label_4.setGeometry(QtCore.QRect(10, 110, 91, 16))
self.label_4.setObjectName(_fromUtf8("label_4"))

# self.radioButton = QtGui.QRadioButton(self.groupBox)
# self.radioButton.setGeometry(QtCore.QRect(10, 20, 71, 20))
# self.radioButton.setChecked(True)
# self.radioButton.setObjectName(_fromUtf8("radioButton"))
#
# self.radioButton_2 = QtGui.QRadioButton(self.groupBox)
# self.radioButton_2.setGeometry(QtCore.QRect(100, 20, 71, 20))
# self.radioButton_2.setObjectName(_fromUtf8("radioButton_2"))

self.groupBox_2 = QtGui.QGroupBox(self.centralWidget)
self.groupBox_2.setGeometry(QtCore.QRect(10, 170, 211, 51))
self.groupBox_2.setObjectName(_fromUtf8("groupBox_2"))

self.comboBox = QtGui.QComboBox(self.groupBox_2)
self.comboBox.setGeometry(QtCore.QRect(10, 20, 191, 22))
self.comboBox.setMinimumContentsLength(0)
self.comboBox.setObjectName(_fromUtf8("comboBox"))
self.comboBox.addItem(_fromUtf8(""))
self.comboBox.addItem(_fromUtf8(""))
self.comboBox.addItem(_fromUtf8(""))
self.comboBox.addItem(_fromUtf8(""))
self.comboBox.addItem(_fromUtf8(""))
self.comboBox.addItem(_fromUtf8(""))
self.comboBox.addItem(_fromUtf8(""))
self.comboBox.addItem(_fromUtf8(""))
self.comboBox.addItem(_fromUtf8(""))
self.comboBox.addItem(_fromUtf8(""))
self.comboBox.addItem(_fromUtf8(""))
self.comboBox.addItem(_fromUtf8(""))
self.comboBox.addItem(_fromUtf8(""))
self.comboBox.addItem(_fromUtf8(""))
self.comboBox.addItem(_fromUtf8(""))
self.comboBox.addItem(_fromUtf8(""))
self.comboBox.addItem(_fromUtf8(""))
self.comboBox.addItem(_fromUtf8(""))
self.comboBox.addItem(_fromUtf8(""))
self.comboBox.setToolTip(_translate("MainWindow",u"Select unit. . .", None))
QtCore.QObject.connect(self.comboBox, QtCore.SIGNAL("currentIndexChanged(QString)"), self.SIGNAL_comboBox_Changed)

self.groupBox_3 = QtGui.QGroupBox(self.centralWidget)
self.groupBox_3.setGeometry(QtCore.QRect(10, 220, 211, 111))
self.groupBox_3.setObjectName(_fromUtf8("groupBox_3"))

self.doubleSpinBox_4 = QtGui.QDoubleSpinBox(self.groupBox_3)
self.doubleSpinBox_4.setGeometry(QtCore.QRect(100, 20, 101, 22))
self.doubleSpinBox_4.setDecimals(7)
self.doubleSpinBox_4.setMinimum(-1000000)
self.doubleSpinBox_4.setMaximum(1000000.0)
self.doubleSpinBox_4.setSingleStep(1.0)
self.doubleSpinBox_4.setProperty("value", 1.0)
self.doubleSpinBox_4.setObjectName(_fromUtf8("doubleSpinBox_4"))
self.doubleSpinBox_4.setToolTip(_translate("MainWindow", "Scale free X", None))
self.doubleSpinBox_4.valueChanged.connect(self.on_doubleSpinBox_4_valueChanged) #connection doubleSpinBox_4

self.doubleSpinBox_5 = QtGui.QDoubleSpinBox(self.groupBox_3)
self.doubleSpinBox_5.setGeometry(QtCore.QRect(100, 50, 101, 22))
self.doubleSpinBox_5.setDecimals(7)
self.doubleSpinBox_5.setMinimum(-1000000)
self.doubleSpinBox_5.setMaximum(1000000.0)
self.doubleSpinBox_5.setSingleStep(1.0)
self.doubleSpinBox_5.setProperty("value", 1.0)
self.doubleSpinBox_5.setObjectName(_fromUtf8("doubleSpinBox_5"))
self.doubleSpinBox_5.setToolTip(_translate("MainWindow", "Scale free Y", None))
self.doubleSpinBox_5.valueChanged.connect(self.on_doubleSpinBox_5_valueChanged) #connection doubleSpinBox_5

self.doubleSpinBox_6 = QtGui.QDoubleSpinBox(self.groupBox_3)
self.doubleSpinBox_6.setGeometry(QtCore.QRect(100, 80, 101, 22))
self.doubleSpinBox_6.setDecimals(7)
self.doubleSpinBox_6.setMinimum(-1000000)
self.doubleSpinBox_6.setMaximum(1000000.0)
self.doubleSpinBox_6.setSingleStep(1.0)
self.doubleSpinBox_6.setProperty("value", 1.0)
self.doubleSpinBox_6.setObjectName(_fromUtf8("doubleSpinBox_6"))
self.doubleSpinBox_6.setToolTip(_translate("MainWindow", "Scale free Z", None))
self.doubleSpinBox_6.valueChanged.connect(self.on_doubleSpinBox_6_valueChanged) #connection doubleSpinBox_6

self.label_5 = QtGui.QLabel(self.groupBox_3)
self.label_5.setGeometry(QtCore.QRect(10, 20, 53, 16))
self.label_5.setObjectName(_fromUtf8("label_5"))

self.label_6 = QtGui.QLabel(self.groupBox_3)
self.label_6.setGeometry(QtCore.QRect(10, 50, 53, 16))
self.label_6.setObjectName(_fromUtf8("label_6"))

self.label_7 = QtGui.QLabel(self.groupBox_3)
self.label_7.setGeometry(QtCore.QRect(10, 80, 53, 16))
self.label_7.setObjectName(_fromUtf8("label_7"))

self.pushButton_3 = QtGui.QPushButton(self.groupBox_3)
self.pushButton_3.setGeometry(QtCore.QRect(70, 20, 21, 21))
self.pushButton_3.setToolTip(_fromUtf8(""))
self.pushButton_3.setObjectName(_fromUtf8("pushButton_3"))
self.pushButton_3.clicked.connect(self.on_pushButton03_clicked) #connection pushButton03 "..." align YZ to X

self.pushButton_2 = QtGui.QPushButton(self.centralWidget)
self.pushButton_2.setGeometry(QtCore.QRect(152, 340, 71, 28))
self.pushButton_2.setObjectName(_fromUtf8("pushButton_2"))
self.pushButton_2.clicked.connect(self.on_pushButton02_clicked) #connection pushButton02 "Quitter"

self.pushButton_1 = QtGui.QPushButton(self.centralWidget)
self.pushButton_1.setGeometry(QtCore.QRect(10, 340, 71, 28))
self.pushButton_1.setObjectName(_fromUtf8("pushButton_1"))
self.pushButton_1.clicked.connect(self.on_pushButton01_clicked) #connection pushButton01 "OK"

self.pushButton = QtGui.QPushButton(self.centralWidget)
self.pushButton.setGeometry(QtCore.QRect(90, 340, 51, 28))
self.pushButton.setObjectName(_fromUtf8("pushButton"))
self.pushButton.clicked.connect(self.on_pushButton00_clicked) #connection pushButton00 "Reset"

MainWindow.setCentralWidget(self.centralWidget)

self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)

def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(_translate("MainWindow", "CloneConvert", None))
MainWindow.setWindowFlags(PyQt4.QtCore.Qt.WindowStaysOnTopHint) # cette fonction met la fenêtre en avant
self.label.setText(_translate("MainWindow", "Object converter", None))
self.groupBox.setTitle(_translate("MainWindow", "Mode", None))
# self.radioButton.setText(_translate("MainWindow", "Clone", None))
# self.radioButton_2.setText(_translate("MainWindow", "Copy", None))
self.doubleSpinBox.setToolTip(_translate("MainWindow", "Placement coordinate X", None))
self.label_2.setText(_translate("MainWindow", "Coordinate X", None))
self.label_3.setText(_translate("MainWindow", "Coordinate Y", None))
self.doubleSpinBox_2.setToolTip(_translate("MainWindow", "Placement coordinate Y", None))
self.doubleSpinBox_3.setToolTip(_translate("MainWindow", "Placement coordinate Z", None))
self.label_4.setText(_translate("MainWindow", "Coordinate Z", None))
self.groupBox_2.setTitle(_translate("MainWindow", "Scale predefined", None))
self.comboBox.setToolTip(_translate("MainWindow", "Convert to . . .", None))
self.comboBox.setCurrentIndex(6)
self.comboBox.setItemText(0, _translate("MainWindow", "km", None)) #km # = 1000000
self.comboBox.setItemText(1, _translate("MainWindow", "hm", None)) #hm # = 100000
self.comboBox.setItemText(2, _translate("MainWindow", "dam", None)) #dam# = 10000
self.comboBox.setItemText(3, _translate("MainWindow", "m", None)) #m # = 1000
self.comboBox.setItemText(4, _translate("MainWindow", "dm", None)) #dm # = 100
self.comboBox.setItemText(5, _translate("MainWindow", "cm", None)) #cm # = 10
self.comboBox.setItemText(6, _translate("MainWindow", "mm", None)) #mm # = 1 #####
self.comboBox.setItemText(7, _translate("MainWindow", "µm", None)) #µm # micro = 0.001
self.comboBox.setItemText(8, _translate("MainWindow", "nm", None)) #nm # nano = 0.000001
self.comboBox.setItemText(9, _translate("MainWindow", "inch", None)) #in # inch pouce = 25.400
self.comboBox.setItemText(10, _translate("MainWindow", "link", None)) #lk # link chaînon = 201.168
self.comboBox.setItemText(11, _translate("MainWindow", "foot", None)) #ft # foot pied = 304.800
self.comboBox.setItemText(12, _translate("MainWindow", "yard", None)) #yd # yard verge = 914.400
self.comboBox.setItemText(13, _translate("MainWindow", "perch", None)) #rd # rod ou perch perche = 5029.200
self.comboBox.setItemText(14, _translate("MainWindow", "chain", None)) #ch # chain chaîne = 20116.800
self.comboBox.setItemText(15, _translate("MainWindow", "furlong", None)) #fur# furlong = 201168
self.comboBox.setItemText(16, _translate("MainWindow", "mile", None)) #mi # mile = 1609344
self.comboBox.setItemText(17, _translate("MainWindow", "league", None)) #lea# league lieue = 4828032
self.comboBox.setItemText(18, _translate("MainWindow", "nautique", None)) #nmi# mile nautique = 1852000
self.groupBox_3.setTitle(_translate("MainWindow", "Scale free", None))
self.label_5.setText(_translate("MainWindow", "Scale X", None))
self.label_6.setText(_translate("MainWindow", "Scale Y", None))
self.label_7.setText(_translate("MainWindow", "Scale Z", None))
self.pushButton_3.setToolTip(_translate("MainWindow", "Align the YZ scale values ​​to X scale value ", None))
self.pushButton_3.setText(_translate("MainWindow", "...", None))
self.pushButton_2.setToolTip(_translate("MainWindow", "Quit the macro", None))
self.pushButton_2.setText(_translate("MainWindow", "Quit", None))
self.pushButton_1.setToolTip(_translate("MainWindow", "Ok Convert and copy", None))
self.pushButton_1.setText(_translate("MainWindow", "Ok", None))
self.pushButton.setToolTip(_translate("MainWindow", "Reset", None))
self.pushButton.setText(_translate("MainWindow", "Reset", None))

def SIGNAL_comboBox_Changed(self,text):
global uniteM_X
global uniteM_Y
global uniteM_Z
global uniteM
global uniteMs

text = unicode(text, 'ISO-8859-1').encode('UTF-8')
if text == "km": # = 1000000
uniteM = uniteM_X = uniteM_Y = uniteM_Z = 1000000.0
uniteMs= "km"
elif text == "hm": # = 100000
uniteM = uniteM_X = uniteM_Y = uniteM_Z = 100000.0
uniteMs= "hm"
elif text == "dam": # = 10000
uniteM = uniteM_X = uniteM_Y = uniteM_Z = 10000.0
uniteMs= "dam"
elif text == "m": # = 1000
uniteM = uniteM_X = uniteM_Y = uniteM_Z = 1000.0
uniteMs= "m"
elif text == "dm": # = 100
uniteM = uniteM_X = uniteM_Y = uniteM_Z = 100.0
uniteMs= "dm"
elif text == "cm": # = 10
uniteM = uniteM_X = uniteM_Y = uniteM_Z = 10.0
uniteMs= "cm"
elif text == "mm": # = 1 ###############################
uniteM = uniteM_X = uniteM_Y = uniteM_Z = 1.0
uniteMs= "mm"
elif text == "µm": # = 1000
uniteM = uniteM_X = uniteM_Y = uniteM_Z = 1.0/1000.0
uniteMs= u"µm"
elif text == "nm": # = 1000000
uniteM = uniteM_X = uniteM_Y = uniteM_Z = 1.0/1000000.0
uniteMs= u"nm"
elif text == "inch": # inch = 25.400
uniteM = uniteM_X = uniteM_Y = uniteM_Z = 25.400
uniteMs= "in"
elif text == "link": # link = 201.168
uniteM = uniteM_X = uniteM_Y = uniteM_Z = 201.168
uniteMs= "lk"
elif text == "foot": # foot = 304.800
uniteM = uniteM_X = uniteM_Y = uniteM_Z = 304.800
uniteMs= "ft"
elif text == "yard": # yard = 914.400
uniteM = uniteM_X = uniteM_Y = uniteM_Z = 914.400
uniteMs= "yd"
elif text == "perch": #rd # rod perche = 5029.200
uniteM = uniteM_X = uniteM_Y = uniteM_Z = 5029.200
uniteMs= "rd"
elif text == "chain": # chain = 20116.800
uniteM = uniteM_X = uniteM_Y = uniteM_Z = 20116.800
uniteMs= "ch"
elif text == "furlong": # furlong= 201168
uniteM = uniteM_X = uniteM_Y = uniteM_Z = 201168
uniteMs= "fur"
elif text == "mile": # mile = 1609344
uniteM = uniteM_X = uniteM_Y = uniteM_Z = 1609344
uniteMs= "mi"
elif text == "league": # league = 4828032
uniteM = uniteM_X = uniteM_Y = uniteM_Z = 4828032
uniteMs= "lea"
elif text == "nautique": # nautique = 1852000
uniteM = uniteM_X = uniteM_Y = uniteM_Z = 1852000
uniteMs= "nmi"
else: # mm = 1
uniteM = uniteM_X = uniteM_Y = uniteM_Z = 1.0
uniteMs= "mm"
self.doubleSpinBox_4.setProperty("value", uniteM_X)
self.doubleSpinBox_5.setProperty("value", uniteM_Y)
self.doubleSpinBox_6.setProperty("value", uniteM_Z)

def on_doubleSpinBox_valueChanged(self,value): # doubleSpinbox X
global placement_X
placement_X = value

def on_doubleSpinBox_2_valueChanged(self,value): # doubleSpinbox Y
global placement_Y
placement_Y = value

def on_doubleSpinBox_3_valueChanged(self,value): # doubleSpinbox Z
global placement_Z
placement_Z = value

def on_doubleSpinBox_4_valueChanged(self,value): # doubleSpinbox free X
global uniteM_X
uniteM_X = value
if uniteM_X == 0:
uniteM_X = 1

def on_doubleSpinBox_5_valueChanged(self,value): # doubleSpinbox free Y
global uniteM_Y
uniteM_Y = value
if uniteM_Y == 0:
uniteM_Y = 1

def on_doubleSpinBox_6_valueChanged(self,value): # doubleSpinbox free Z
global uniteM_Z
uniteM_Z = value
if uniteM_Z == 0:
uniteM_Z = 1

def on_pushButton03_clicked(self): # Bouton ... (align)
global uniteM_X
global uniteM_Y
global uniteM_Z
global uniteM
global uniteMs
uniteM_Y = uniteM_Z = uniteM_X
self.doubleSpinBox_5.setProperty("value", uniteM_X)
self.doubleSpinBox_6.setProperty("value", uniteM_X)


==Script== <!--T:8-->
def on_pushButton00_clicked(self): # Bouton Reset
The icon [[Image:Macro_CloneConvert.png]]
global uniteM_X
global uniteM_Y
global uniteM_Z
global uniteM
global uniteMs
global placement_X
global placement_Y
global placement_Z
global oripl_X
global oripl_Y
global oripl_Z


<!--T:18-->
oripl_X = oripl_Y = oripl_Z = 0.0
'''Macro_CloneConvert.FCMacro'''


<!--T:34-->
self.comboBox.setCurrentIndex(6)
Download the macro to Gist [https://gist.github.com/mario52a/9f2f2f6144e1307a048f1840ef99300c Macro_CloneConvert.FCMacro]
self.doubleSpinBox.setProperty("value", 0.0)
self.doubleSpinBox_2.setProperty("value", 0.0)
self.doubleSpinBox_3.setProperty("value", 0.0)


==Revision== <!--T:19-->
placement_X = placement_Y = placement_Z = 0.0


<!--T:41-->
self.doubleSpinBox_4.setProperty("value", 1.0)
06/06/2020 ver 0.15 = icon
self.doubleSpinBox_5.setProperty("value", 1.0)
self.doubleSpinBox_6.setProperty("value", 1.0)


<!--T:40-->
uniteM = uniteM_X = uniteM_Y = uniteM_Z = 1.0
20/05/2020 ver 0.14 = grid layout PySide2 Qt5
uniteMs= "mm"
uniteM = 1


<!--T:39-->
def on_pushButton01_clicked(self): # Bouton OK
15/09/2019 ver 0.13 = replace the grec sign micro to "um", replace all "_translate("MainWindow", "mm", None)" to "mm" and comment line "text.encode('utf-8')" cause not work with FC 0.19 18.213
global surface
global volume_
global boundBox
global boundBoxLX
global boundBoxLY
global boundBoxLZ
global boundBox_S
global uniteM_X
global uniteM_Y
global uniteM_Z
global uniteM
global uniteMs
global placement_X
global placement_Y
global placement_Z
global oripl_X
global oripl_Y
global oripl_Z
global sel


<!--T:38-->
sel = FreeCADGui.Selection.getSelection()
01/06/2019 ver 0.12 = adapted for 0.19 et correction "Copy:legacy=True" and ShapeColor .....


<!--T:37-->
if len(sel) != 0:
30/03/2018 ver 0.11 = odd checkBox, if multi selection the clone are object unique or object separate
# surface
try:
surface = sel[0].Shape.Area
except:
surface = 0.0
# volume
try:
volume_ = sel[0].Shape.Volume
except:
volume_ = 0.0


<!--T:35-->
# boundinbox (dimensions hors tout)
07/06/2017 ver 0.10 = replace Draft...Copy to Part..Shape cause section Copy : not draw copy scaled of object but copy not scaled ??
try:
boundBox_ = sel[0].Shape.BoundBox
boundBoxLX = boundBox_.XLength
boundBoxLY = boundBox_.YLength
boundBoxLZ = boundBox_.ZLength
except:
boundBox_ = 0.0
boundBoxLX = 0.0
boundBoxLY = 0.0
boundBoxLZ = 0.0
boundBox_S = ""


<!--T:36-->
boundBox_S = "[X: "+str(boundBoxLX)+" mm] x [Y: "+str(boundBoxLY)+" mm] x [Z:"+str(boundBoxLZ)+" mm]"
14/06/2016 ver 0.9 = adding the choice of number of copies and labels optimization
App.Console.PrintMessage("Original boundBox : "+boundBox_S+"\r\n")
App.Console.PrintMessage("Original volume_ : "+str(volume_)+" mm3"+"\r\n")
App.Console.PrintMessage("Original surface : "+str(surface)+" mm2"+"\r\n")
App.Console.PrintMessage("- - - - - - - - - -"+"\r\n")


<!--T:27-->
oripl_X = sel[0].Placement.Base[0]
31/01/2016 ver 0.8 = modify the buttons reset section for two click for reset (in case modification the value)
oripl_Y = sel[0].Placement.Base[1]
oripl_Z = sel[0].Placement.Base[2]


<!--T:20-->
#### ici avec tous les objets sélectionné plus placement et rotation si un seul objet
30/01/2016 ver 0.7 = rewriting code with Placement and Increment and adding buttons Compound, Increment, ValueAt(),
obj=Draft.clone(sel)
if len(sel) > 1:
obj.Placement=App.Placement(App.Vector(placement_X,placement_Y,placement_Z), App.Rotation(App.Vector(0,0,1),0), App.Vector(0,0,0))
else:
obj.Placement=App.Placement(App.Vector(oripl_X + placement_X,oripl_Y + placement_Y,oripl_Z + placement_Z), App.Rotation(sel[0].Placement.Rotation), App.Vector(0,0,0))
obj.Scale = (uniteM_X, uniteM_Y, uniteM_Z)
FreeCAD.ActiveDocument.recompute()
####


<!--T:21-->
# surface
26/01/2016 ver 0.6 = correction placement with many objets Copy
try:
surface = obj.Shape.Area
except:
surface = 0.0
# volume
try:
volume_ = obj.Shape.Volume
except:
volume_ = 0.0
# boundinbox (dimensions hors tout)
try:
boundBox_ = obj.Shape.BoundBox
boundBoxLX = boundBox_.XLength
boundBoxLY = boundBox_.YLength
boundBoxLZ = boundBox_.ZLength
except:
boundBox_ = 0.0
boundBoxLX = 0.0
boundBoxLY = 0.0
boundBoxLZ = 0.0


<!--T:22-->
App.Console.PrintMessage("Convert mm in ' "+uniteMs+" ' (1 "+uniteMs+" = "+str(uniteM)+" mm)"+"\r\n")
26/07/2015 ver 0.5 = correction rotate many objects Function Copy
App.Console.PrintMessage("Clone boundBox_X : "+str(boundBoxLX)+" mm"+"\r\n")
App.Console.PrintMessage("Clone boundBox_Y : "+str(boundBoxLY)+" mm"+"\r\n")
App.Console.PrintMessage("Clone boundBox_Z : "+str(boundBoxLZ)+" mm"+"\r\n")
App.Console.PrintMessage("Clone volume : "+str(volume_)+" mm3 ("+str(len(sel))+" element(s))"+"\r\n")#
App.Console.PrintMessage("Clone surface : "+str(surface)+" mm2 ("+str(len(sel))+" element(s))"+"\r\n")#
App.Console.PrintMessage("___________________"+"\r\n")
else:
FreeCAD.Console.PrintError("Select an object"+"\r\n") #App.Console.PrintMessage
sel = ""


<!--T:23-->
def on_pushButton02_clicked(self): # Bouton Quitter
25/07/2015 ver 0.4 = adding rotation
App.Console.PrintMessage("End CloneConvert\r\n")
self.window.hide()


<!--T:24-->
sel = FreeCADGui.Selection.getSelection()
11/08/2014 replace "AttributeError" to "Exception"


<!--T:25-->
MainWindow = QtGui.QMainWindow()
02/07/2014 ver. 0.3 = modified to operate PyQt4 and PySide
ui = Ui_MainWindow(MainWindow)
MainWindow.show()


<!--T:26-->
</syntaxhighlight>
09/05/2014 ver. 0.2 = adding function "Copy"
</translate>

Latest revision as of 16:02, 20 May 2021

Other languages:

Macro CloneConvert

Description
Latest update: GUI modified for HiDPI support (QGridLayout). Runs ≥v0.18 (PySide2 Qt5)

For previous versions see Macro_CloneConvert and install manually.

Creates a Clone/Copy/Compound of the object(s) and then converted into a chosen position and size (inch, mm, m, µm...) or free. The base object is recognized in mm (FreeCAD base).

Macro version: 0.15
Last modified: 2020-06-06
FreeCAD version: ≥0.18
Download: ToolBar Icon
Author: mario52

Author
mario52
Download
ToolBar Icon
Links
Macro Version
0.15
Date last modified
2020-06-06
FreeCAD Version(s)
≥0.18
Default shortcut
None
See also
None

Description

Creates a clone or copy of the object and then converts it into a chosen position and size (inch, mm, m, µm...) or free. The base object is recognized in mm (FreeCAD base)

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://gist.githubusercontent.com/mario52a/9f2f2f6144e1307a048f1840ef99300c/raw/39bc54e90b80053a5af76b0b17694cb53697aebd/Macro_CloneConvert.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://gist.githubusercontent.com/mario52a/9f2f2f6144e1307a048f1840ef99300c/raw/39bc54e90b80053a5af76b0b17694cb53697aebd/Macro_CloneConvert.FCMacro")


Usage

  1. Run the macro
  2. Set the XYZ settings
  3. Choose "Clone" or "Copy"
  4. Choose a measurement unit
  5. Select your object
  6. Click Ok

Notes

  • If no value is entered a copy or clone will be created without modification.
  • If no object is selected the Ok button will be colored in red.

The value of the BoundingBox, Volume and Surface is displayed in the Report view, in the case of Copy multiple object, the display will show BoundingBox 0.0.

The base is the mm example with a 1 mm side of cube:

Select in the comboBox inch, 1 inch = 25.4 mm , the fields "Scale free" automatically adjusts to 25.4 (the values ​​in "Scale-free" can be changed separately). Click Ok button, the clone created will have 25,4 mm x 25,4 mm x 25,4 mm

150% = 1,50 in the "Scale free" fields
104% = 1,04 in the "Scale free" fields

Inverse operation :

If you want to reduce an object ex: a cube 25.4 mm (1 inch) in cube 1 mm sides, use the following formula, 1 / 25.4 = 0.0393700 and enter the value 0,0393700 (with comma) in the Scale field XY and Z.

In a cube of 5 mm, made​​ 5 / 25.4 = 0.1968503 and enter the value 0,1968503 (with comma) in the Scale field XY and Z.

50% = 0,50 in the "Scale free" fields
4% = 0,04 in the "Scale free" fields

Predefined units are: km, hm, dam, m, dm, cm, mm, µm, nm, inch, link, foot, yard, perch, chain, furlong, mile, league, nautique.

CloneConvert
CloneConvert
  • Mode
  • Clone  : The object(s) clone are create
  • Copy  : One copy of the objet(s) is create
  • Comp  : One compound of the objet(s) is create
  • Increm. : incrementing the coordinates data to the original coordinates of the object (Placement, Rotation ...)
    If this is not checked the Placement begin in coordinates 0,0,0 of FreeCAD
    In case a compound Placement information is [0,0,0] the Placement begin in the position of object
    If the real location is away from the base coordinates 0,0,0 use the ValueAt() button for the real Placement of the subObject selected Face, Wire, Line ....
  • Unique  : If this checkBox is checked and multiple object selected, the clone created is one unique object
  • Coordinates
  • ... : This button align the YZ values on the value of X to have the same values ​​XYZ (or manually). Two click reset the coordinates values to 0.0
  • Coordinate X : Move the copy to the Coordinate X selected (Base 0,0,0 if Increm. is not checked)
  • Coordinate Y : Move the copy to the Coordinate Y selected (Base 0,0,0 if Increm. is not checked)
  • Coordinate Z : Move the copy to the Coordinate Z selected (Base 0,0,0 if Increm. is not checked)
  • Rotation
  • ... : This button align the Pitch and Roll values on the value of Yaw to have the same values ​​Rotation (or manually)
    Two click reset the rotations values to 0.0
  • Yaw (Z )  : Rotate the copy to the axis Z (Yaw) (Begin 0 if Increm. is not checked)
  • Pitch ( Y ) : Rotate the copy to the axis Y (Pitch) (Begin 0 if Increm. is not checked)
  • Roll ( X )  : Rotate the copy to the axis X (Roll) (Begin 0 if Increm. is not checked)
  • Scale predefined
  • Scale predefined : predefined scales in units, km, hm, dam, m, dm, cm, mm, µm, nm, inch, link, foot, yard, perch, chain, furlong, mile, league, nautique or choose a free value in the Scale free field.
  • Number copy
  • Number copy : number of copies
  • Scale free
  • ... : This button align the Scales values on the value of Scale X to have the same values ​​XYZ (or manually)
    Two click reset the scales values to 1.0
  • Scale X : free scale , if the value is negative ( -10) , the object is scaled x 10 and will be reversed in the X axis, to reduce the shape give a decimal value (0,5)
  • Scale Y : free scale , if the value is negative ( -10) , the object is scaled x 10 and will be reversed in the Y axis, to reduce the shape give a decimal value (0,5)
  • Scale Z : free scale , if the value is negative ( -10) , the object is scaled x 10 and will be reversed in the Z axis, to reduce the shape give a decimal value (0,5)
  • ValueAt() : Give the valueAt() the subObject selected Face, Wire, Line ...
    This option is useful in case a compound Placement information [0,0,0] and its real location is away from the base coordinates 0,0,0 (gives no provide information about the rotation of the object)
  • Ok : the OK button validates and launches the command, if no object is selected the Ok button will be coloured in red
  • Reset : the Reset button puts all the values to zero
  • Quit : the Quit button exit the macro

Script

The icon

Macro_CloneConvert.FCMacro

Download the macro to Gist Macro_CloneConvert.FCMacro

Revision

06/06/2020 ver 0.15 = icon

20/05/2020 ver 0.14 = grid layout PySide2 Qt5

15/09/2019 ver 0.13 = replace the grec sign micro to "um", replace all "_translate("MainWindow", "mm", None)" to "mm" and comment line "text.encode('utf-8')" cause not work with FC 0.19 18.213

01/06/2019 ver 0.12 = adapted for 0.19 et correction "Copy:legacy=True" and ShapeColor .....

30/03/2018 ver 0.11 = odd checkBox, if multi selection the clone are object unique or object separate

07/06/2017 ver 0.10 = replace Draft...Copy to Part..Shape cause section Copy : not draw copy scaled of object but copy not scaled ??

14/06/2016 ver 0.9 = adding the choice of number of copies and labels optimization

31/01/2016 ver 0.8 = modify the buttons reset section for two click for reset (in case modification the value)

30/01/2016 ver 0.7 = rewriting code with Placement and Increment and adding buttons Compound, Increment, ValueAt(),

26/01/2016 ver 0.6 = correction placement with many objets Copy

26/07/2015 ver 0.5 = correction rotate many objects Function Copy

25/07/2015 ver 0.4 = adding rotation

11/08/2014 replace "AttributeError" to "Exception"

02/07/2014 ver. 0.3 = modified to operate PyQt4 and PySide

09/05/2014 ver. 0.2 = adding function "Copy"