| Descrizione |
|---|
| Questa macro crea una curva di Hilbert in 2 o 3 dimensioni con varie iterazioni. Ultima modifica: 2021-02-13 Versione FreeCAD: 0.16 to 0.19 Download: ToolBar Icon Autore: Simone Bignetti |
| Autore |
| Simone Bignetti |
| Download |
| ToolBar Icon |
| Link |
| Raccolta di macro Come installare le macro Personalizzare la toolbar |
| Versione macro |
| 1.0 |
| Data ultima modifica |
| 2021-02-13 |
| Versioni di FreeCAD |
| 0.16 to 0.19 |
| Scorciatoia |
| Nessuna |
| Vedere anche |
| Nessuno |
Questa macro crea un wire della Curva di Hilbert in 2 or 3 dimensioni con varie iterazioni.

Puoi utilizzare una curva di Hilbert come path per uno Sweep, ma prima è meglio applicare un raggio al wire, o lo sweep sarà mal formato.

Per trovare il raggio corretto dovrai fare alcune prove. Dipende dalla lunghezza del segmento della curva e dalla forma del profilo di cui vuoi fare lo sweep.

Icona per la barra degli utensili
Macro_HilbertCurve.FCMacro
# -*- coding: utf-8 -*-
# Copyright (c) 2020 Simone Bignetti, Gottolengo Italy (simone.b)
#
# This file is part of the FreeCAD CAx development system.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
# USA
#
# You can contact me by mail at simone.bignetti@linux.it
__Name__ = 'HilbertCurve'
__Comment__ = 'This macro creates an Hilbert curve wire in 2 or 3 dimensions with many iterations.'
__Author__ = 'Simone Bignetti'
__Version__ = '1.2.0'
__Date__ = '2020-12-29'
__License__ = 'GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999'
__Web__ = 'https://wiki.freecad.org/Macro_HilbertCurve'
__Wiki__ = 'https://wiki.freecad.org/Macro_HilbertCurve'
__Icon__ = 'https://wiki.freecad.org/images/6/69/Hilbert_curve_icon.png'
__Help__ = 'Choose the dimensions of the wire, the number of the iterations and the length of the wire segment.'
__Status__ = 'Stable'
__Requires__ = ''
__Communication__ = 'https://forum.freecad.org/viewtopic.php?f=22&t=53781'
__Files__ = 'HilbertCurve.svg'
# For the wire
import FreeCAD as app
import Draft
# For the gui
from PySide import QtGui, QtCore
class HilbertCurve:
"""The class of the Hilbert curve.
By this class it's possible to create a wire
of a fractal Hilbert curve with
a fixed number of dimensions and iterations.
"""
def __init__(self, dimensions, iterations):
"""Initialize the Hilbert curve.
Args:
iterations (int): iterations to use in constructing the curve
dimensions (int): number of dimensions
"""
self.dimensions = dimensions
self.iterations = iterations
# minimum and maximum distance along curve
self.min_distance = 0
self.max_distance = 2 ** (self.iterations * self.dimensions) - 1
# minimum and maximum coordinate value in any dimension
self.min_coordinate = 0
self.max_coordinate = 2 ** self.iterations - 1
# number of points
self.number_of_points = 2 ** (self.iterations * self.dimensions)
def point_from_distance(self, distance):
"""Return a point in n-dimensional space given a distance along a the curve.
Args:
distance (int): integer distance along the curve
Returns:
point (iterable of ints): an n-dimensional vector of length dimensions where
each component value is between 0 and 2**iterations-1.
"""
bit_string = format(distance, 'b').zfill(self.iterations * self.dimensions) # zero filled binary distance
point = [int(bit_string[i::self.dimensions], 2) for i in range(self.dimensions)] # transpose of distance
# Gray decode: point = point xor (point / 2)
gray = point[self.dimensions-1] >> 1
for i in range(self.dimensions-1, 0, -1):
point[i] ^= point[i-1]
point[0] ^= gray
# Undo excess work
q = 2
while q != (2 << (self.iterations-1)):
p = q - 1
for i in range(self.dimensions-1, -1, -1):
if point[i] & q:
# invert
point[0] ^= p
else:
# exchange
gray = (point[0] ^ point[i]) & p
point[0] ^= gray
point[i] ^= gray
q <<= 1
return point
def get_min_distance(self):
"""Return the minimum distance along the curve."""
return self.min_distance
def get_max_distance(self):
"""Return the maximum distance along the curve."""
return self.max_distance
def get_min_coordinate(self):
"""Return the minimum coordinate value in any dimension."""
return self.min_coordinate
def get_max_coordinate(self):
"""Return the maximum coordinate value in any dimension."""
return self.max_coordinate
def get_number_of_points(self):
"""Return the number of points in the curve."""
return self.number_of_points
def get_points(self):
"""Return the list of points in the curve."""
points = []
for point_number in range(self.number_of_points):
points.append(self.point_from_distance(point_number))
return points
def __str__(self):
return f"HilbertCurve(dimensions={self.dimensions}, iterations={self.iterations})"
def __repr__(self):
return self.__str__()
class Hilbert_Dialog(QtGui.QDialog):
"""The dialog for the Hilbert curve
This class opens in FreeCAD a dialog to input
the number of dimensions and the number of iterations
to create the Hilbert curve.
OK creates the curve.
CANCEL quit the macro.
"""
def __init__(self):
super(Hilbert_Dialog, self).__init__()
self.setupUi()
def setupUi(self):
self.dimensions = 2
self.iterations = 3
self.setGeometry(250, 250, 400, 300) # Window definition
self.setWindowTitle("Hilbert curve Macro")
titleLabel = QtGui.QLabel("Create an Hilbert curve in two or three dimensions") # Title and subtitle
titleFont = QtGui.QFont()
titleFont.setBold(True)
titleFont.setWeight(75)
titleLabel.setFont(titleFont)
subtitleLabel = QtGui.QLabel("This macro creates a wire in the draft workbench\nwith the shape of an Hilbert curve in two or three dimensions.\nFor example, you can use this wire as a sweep path.\nIt's recommended to apply a radius at the wire,\nin order to obtain a correct sweep generation.")
titleBox = QtGui.QVBoxLayout()
titleBox.addWidget(titleLabel)
titleBox.addWidget(subtitleLabel)
titleBox.insertStretch(-1)
dimensionsLabel = QtGui.QLabel("Number of dimensions: ") # Number of dimensions
self.twoDradioButton = QtGui.QRadioButton()
self.twoDradioButton.setText("2D")
self.twoDradioButton.setChecked(True)
self.threeDradioButton = QtGui.QRadioButton()
self.threeDradioButton.setText("3D")
dimensionsBox=QtGui.QHBoxLayout()
dimensionsBox.addWidget(dimensionsLabel)
dimensionsBox.addWidget(self.twoDradioButton)
dimensionsBox.addWidget(self.threeDradioButton)
iterationsLabel = QtGui.QLabel("Iterations:") # Iterations and length spins in a grid
self.iterationsSpin = QtGui.QSpinBox()
self.iterationsSpin.setMinimum(1)
self.iterationsSpin.setMaximum(10)
lengthLabel = QtGui.QLabel("Length:")
self.lengthSpin = QtGui.QDoubleSpinBox()
self.lengthSpin.setMinimum(1.0)
self.lengthSpin.setMaximum(999999.000000000000000)
self.lengthSpin.setValue(10.000000000000000)
grid = QtGui.QGridLayout()
grid.setSpacing(10)
grid.addWidget(iterationsLabel, 1, 0)
grid.addWidget(self.iterationsSpin, 1, 1)
grid.addWidget(lengthLabel, 2, 0)
grid.addWidget(self.lengthSpin, 2, 1)
okButton = QtGui.QPushButton("OK") # Ok and Cancel Buttons at right bottom
okButton.clicked.connect(self.onOkButton)
cancelButton = QtGui.QPushButton("Cancel")
cancelButton.clicked.connect(self.onCancelButton)
buttonBox = QtGui.QHBoxLayout()
buttonBox.addStretch()
buttonBox.addWidget(okButton)
buttonBox.addWidget(cancelButton)
vbox = QtGui.QVBoxLayout()
vbox.addLayout(titleBox)
vbox.addLayout(dimensionsBox)
vbox.addLayout(grid)
vbox.addLayout(buttonBox)
vbox.setSpacing(30)
vbox.insertStretch(1)
self.setLayout(vbox)
self.show()
def onOkButton(self):
if self.twoDradioButton.isChecked():
dimensions = 2
else:
dimensions = 3
iterations = self.iterationsSpin.value()
length = self.lengthSpin.value()
HC=HilbertCurve(dimensions, iterations)
points = HC.get_points()
pl = app.Placement()
pl.Rotation.Q = (0.0, 0.0, 0.0, 1.0)
pl.Base = app.Vector(0.0, 0.0, 0.0)
vectors = []
if dimensions == 2:
for point in points:
vectors.append(app.Vector(point[0]*length, point[1]*length, 0.0))
else:
for point in points:
vectors.append(app.Vector(point[0]*length, point[1]*length, point[2]*length))
wire = Draft.makeWire(vectors, placement=pl, closed=False, face=False, support=None)
wire.Label = "Hilbert"
Draft.autogroup(wire)
self.close()
def onCancelButton(self):
self.close()
hilbert_dialog = Hilbert_Dialog()
hilbert_dialog.exec()