Руководство пользователя по OpenSCAD/Преобразования
Основное понятие
[править]Преобразование влияет на вложенные узлы и, как следует из названия, преобразует их различными способами, такими как перемещение/поворот или масштабирование вложенного узла. Вложенные преобразования используются для применения различных преобразований к конечному вложенному элементу. Вложение достигается с помощью вложенных операторов, например:
rotate([45,45,45]) translate([10,20,30]) cube(10);
Преобразования могут быть применены к группе вложенных узлов с помощью "{" и "}", чтобы заключить поддерево, например:
translate([0,0,-5]) { cube(10); cylinder(r=5,h=10); }
Преобразования записываются перед предметом, на который они влияют.
Представьте, что такие команды, как translate, mirror и scale, являются глаголами. Такие команды, как цвет, подобны прилагательным, описывающим объект.
Обратите внимание, что после команды преобразования нет точки с запятой.
Продвинутое понимание
[править]Поскольку OpenSCAD использует различные библиотеки для реализации возможностей, это может привести к некоторым несоответствиям в поведении предварительного просмотра преобразований F5. Традиционные преобразования (translate, rotate, scale, mirror и multimatrix) выполняются с использованием OpenGL в режиме предварительного просмотра, в то время как другие более продвинутые преобразования, такие как изменение размера, выполняют операцию CGAL, действуя как операция CSG, воздействующая на базовый объект, а не просто преобразующая его. В частности, это может повлиять на отображение символов-модификаторов, в частности "#" и "%", где выделение может отображаться не интуитивно, например, выделение объекта с предварительно измененным размером, но выделение объекта с последующим масштабированием. Шаблон:Incomplete
Размер
[править]scale()
изменяет размер вложенных элементов с использованием указанного вектора. Имя аргумента является необязательным.
scale(v = [x, y, z]) { ... }
Пример использования
cube(10); translate([15,0,0]) scale([0.5,1,2]) cube(10);
Изменить размер
[править]resize()
- изменяет размер вложенного предмета, чтобы он соответствовал заданным значениям x, y и z.
resize()
является операцией CGAL и, как и другие, такие как render()
, работает с полной геометрией, поэтому даже при предварительном просмотре ему требуется время для обработки.
- примеры :
// изменяет размер сферы, чтобы расширить ее в направлениях 30 в x, 60 в y и 10 в z. resize(newsize=[30,60,10]) sphere(r=10);
Если x,y, или z это 0 тогда это измерение остается как есть.
// resize the 1x1x1 cube to 2x2x1 resize([2,2,0]) cube();
Если для параметра auto
установлено значение true
, он автоматически масштабирует любые 0
-размеры для соответствия. Например.
// изменить размер куба 1x2x0.5 на 7x14x3.5 resize([7,0,0], auto=true) cube([1,2,0.5]);
Параметр auto
также можно использовать, если вы хотите автоматически масштабировать только одно измерение, а другое оставить как есть.
// изменить размер на 10x8x1. Обратите внимание, что измерение z оставлено в покое. resize([10,0,0], auto=[true,true,false]) cube([5,4,1]);
Поворот
[править]rotate()
поворачивает свой вложенный элемент 'a' на градусы вокруг оси системы координат или вокруг произвольной оси.
Имена аргументов являются необязательными, если аргументы заданы в оговоренном порядке.
//Использование: rotate(a = deg_a, v = [x, y, z]) { ... } // или rotate(deg_a, [x, y, z]) { ... } rotate(a = [deg_x, deg_y, deg_z]) { ... } rotate([deg_x, deg_y, deg_z]) { ... }
Аргумент 'a' (deg_a) может быть массивом, как указано выше в последних использованиях; когда deg_a является массивом, аргумент 'v' игнорируется. Где 'a' указывает "несколько осей", то вращение применяется в следующем порядке: x, y, z. Это означает, что код:
rotate(a=[ax,ay,az]) {...}
равнозначен:
rotate(a=[0,0,az]) rotate(a=[0,ay,0]) rotate(a=[ax,0,0]) {...}
Необязательный аргумент 'v' является вектором и позволяет задать произвольную ось, вокруг которой вращается объект.
Например, чтобы перевернуть объект вверх ногами, вы можете повернуть его на 180 градусов вокруг оси 'y'.
rotate(a=[0,180,0]) { ... }
Это часто упрощается до
rotate([0,180,0]) { ... }
При указании одной оси аргумент 'v' позволяет указать, какая ось является основой для вращения. Например, эквивалент приведенному выше, чтобы вращаться только вокруг оси y
rotate(a=180, v=[0,1,0]) { ... }
При указании одной оси, 'v' это вектор определяющий произвольную ось для вращения; это отличается от множественных осей выше. Например, поверните свой объект на 45 градусов вокруг оси, определенной вектором [1,1,0],
rotate(a=45, v=[1,1,0]) { ... }
Rotate with a single scalar argument rotates around the Z axis. This is useful in 2D contexts where that is the only axis for rotation. For example: Поворот с одним скалярным аргументом вращается вокруг оси Z. Это полезно в двумерных средах, где это единственная ось для вращения. Например:
rotate(45) square(10);
Справка по правилу поворота
[править]
Для случая:
rotate([a, b, c]) { ... };
"a" является вращением вокруг оси X, из +Y оси, по направлению к +Z оси.
"b" является вращением вокруг оси Y, из +Z оси, по направлению к +X оси.
"c" является вращением вокруг оси Z, из +X оси, по направлению к +Y оси.
Все эти случаи являются правилом захвата правой рукой. Направьте большой палец правой руки вдоль положительной оси, ваши пальцы показывают направление вращения.
Таким образом, если "a" зафиксировано на нуле, а "b" и "c" обрабатываются соответствующим образом, это сферическая система координат.
Итак, чтобы построить цилиндр от начала координат до какой-либо другой точки (x, y, z):
x= 10; y = 10; z = 10; // координаты точки конца цилиндра length = norm([x,y,z]); // радиальное расстояние b = acos(z/length); // угол наклона c = atan2(y,x); // азимутальный угол rotate([0, b, c]) cylinder(h=length, r=0.5); %cube([x,y,z]); // угол куба должен совпадать с концом цилиндра
Перенос
[править]translate()
перемещает свои вложенные предметы вдоль указанного вектора. Имя аргумента является необязательным.
Пример: translate(v = [x, y, z]) { ... }
cube(2,center = true); translate([5,0,0]) sphere(1,center = true);
Отражение
[править]mirror()
отражает вложенный предмет на плоскости, проходящей через начало координат. Аргумент для mirror()
- это вектор нормали плоскости, пересекающей начало координат, через которое должен быть отражен объект.
Сигнатура функции:
[править]mirror(v= [x, y, z] ) { ... }
Примеры
[править]Исходник находится на правой стороне. Обратите внимание, что отражение не делает копию. Подобно вращению и масштабированию, оно изменяет объект.
-
hand(); // исходник
mirror([1,0,0]) hand();
-
hand(); // исходник
mirror([1,1,0]) hand();
-
hand(); // исходник
mirror([1,1,1]) hand();
rotate([0,0,10]) cube([3,2,1]); mirror([1,0,0]) translate([1,0,0]) rotate([0,0,10]) cube([3,2,1]);
multmatrix
[править]multmatrix()
умножает геометрию всех вложенных предметов на заданную матрицей аффинного преобразования, где матрица 4×3 - вектор из 3-х строчных векторов по 4 элемента в каждом или матрица 4×4 с 4-й строкой, всегда принуждаемая к [0,0,0,1].
Использование:
multmatrix(m = [...]) { ... }
Это распределение того, что вы можете сделать с независимыми элементами в матрице (для первых трех строк):
[Масштаб X] | [Сдвиг X вдоль Y] | [Сдвиг X along Z] | [Перенести X] |
[Сдвиг Y вдоль X] | [Масштаб Y] | [Сдвиг Y вдоль Z] | [Перенести Y] |
[Сдвиг Z вдоль X] | [Сдвиг Z вдоль Y] | [Масштаб Z] | [Перенести Z] |
Четвертый ряд привидён к [0,0,0,1] и может быть опущен, если вы не объединяете матрицы перед передачей в multmatrix, так как он не обрабатывается в OpenSCAD. Каждая матрица работает с точками данной геометрии, как если бы каждая вершина представляла собой вектор из 4 элементов, состоящий из трехмерного вектора с неявным 1 в качестве его 4-го элемента, такого как v=[x, y, z, 1]. Роль неявной четвертой строки m состоит в том, чтобы сохранить неявную 1 в 4-м элементе векторов, позволяя переводам работать. Таким образом, операция multmatrix выполняет m*v для каждой вершины v. Любые элементы (кроме 4-й строки), не указанные в m, рассматриваются как нули.
Этот пример поворачивает на 45 градусов в плоскости XY и переносит на [10,20,30], т.е. то же самое, что сделали бы translate([10,20,30]) rotate([0,0,45]).
angle=45; multmatrix(m = [ [cos(angle), -sin(angle), 0, 10], [sin(angle), cos(angle), 0, 20], [ 0, 0, 1, 30], [ 0, 0, 0, 1] ]) union() { cylinder(r=10.0,h=10,center=false); cube(size=[10,10,10],center=false); }
Следующий пример представляет объединение матриц аффинного преобразования путем умножения матриц, в результате чего в окончательной версии преобразование равнозначно rotate([0, -35, 0]) translate([40, 0, 0]) Obj();. Обратите внимание, что знаки функции sin, по-видимому, расположены в другом порядке, чем в приведенном выше примере, потому что положительный знак должен быть расположен как x в y, y в z, z в x, чтобы углы поворота соответствовали повороту вокруг другой оси в правой системе координат.
y_ang=-35; mrot_y = [ [ cos(y_ang), 0, sin(y_ang), 0], [ 0, 1, 0, 0], [-sin(y_ang), 0, cos(y_ang), 0], [ 0, 0, 0, 1] ]; mtrans_x = [ [1, 0, 0, 40], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1] ]; module Obj() { cylinder(r=10.0,h=10,center=false); cube(size=[10,10,10],center=false); } echo(mrot_y*mtrans_x); Obj(); multmatrix(mtrans_x) Obj(); multmatrix(mrot_y * mtrans_x) Obj();
Этот пример искажает модель, что невозможно при других преобразованиях.
M = [ [ 1 , 0 , 0 , 0 ], [ 0 , 1 , 0.7, 0 ], // "0.7" является значением перекоса; перемещается вдоль оси y при изменении z. [ 0 , 0 , 1 , 0 ], [ 0 , 0 , 0 , 1 ] ] ; multmatrix(M) { union() { cylinder(r=10.0,h=10,center=false); cube(size=[10,10,10],center=false); } }
В этом примере показано, как вектор преобразуется с помощью вектора multmatrix, например, все точки в массиве точек (полигоне) могут быть преобразованы последовательно. Вектор (v) преобразуется с помощью матрицы вращения (m), в результате чего создается новый вектор (vtrans), который теперь вращается и перемещает куб по круговой траектории радиусом=v вокруг оси z без поворота куба.
angle=45; m=[ [cos(angle), -sin(angle), 0, 0], [sin(angle), cos(angle), 0, 0], [ 0, 0, 1, 0] ]; v=[10,0,0]; vm=concat(v,[1]); // нужно для добавления [1] vtrans=m*vm; echo(vtrans); translate(vtrans)cube();
Больше?
[править]Узнайте больше об этом здесь:
color
[править]Displays the child elements using the specified RGB color + alpha value. This is only used for the F5 preview as CGAL and STL (F6) do not currently support color. The alpha value defaults to 1.0 (opaque) if not specified.
Function signature:
[править]color( c = [r, g, b, a] ) { ... } color( c = [r, g, b], alpha = 1.0 ) { ... } color( "#hexvalue" ) { ... } color( "colorname", 1.0 ) { ... }
Note that the r, g, b, a
values are limited to floating point values in the range [0,1] rather than the more traditional integers { 0 ... 255 }. However, nothing prevents you to using R, G, B
values from {0 ... 255} with appropriate scaling: color([ R/255, G/255, B/255 ]) { ... }
Шаблон:Requires
Colors can also be defined by name (case insensitive). For example, to create a red sphere, you can write color("red") sphere(5);
. Alpha is specified as an extra parameter for named colors: color("Blue",0.5) cube(5);
Шаблон:Requires
Hex values can be given in 4 formats, #rgb
, #rgba
, #rrggbb
and #rrggbbaa
. If the alpha value is given in both the hex value and as separate alpha parameter, the alpha parameter takes precedence.
The available color names are taken from the World Wide Web consortium's SVG color list. A chart of the color names is as follows,
(note that both spellings of grey/gray including slategrey/slategray etc are valid):
|
|
|
|
|
Example
[править]Here's a code fragment that draws a wavy multicolor object
for(i=[0:36]) {
for(j=[0:36]) {
color( [0.5+sin(10*i)/2, 0.5+sin(10*j)/2, 0.5+sin(10*(i+j))/2] )
translate( [i, j, 0] )
cube( size = [1, 1, 11+10*cos(10*i)*sin(10*j)] );
}
}
↗ Being that -1<=sin(x)<=1 then 0<=(1/2 + sin(x)/2)<=1 , allowing for the RGB components assigned to color to remain within the [0,1] interval.
Chart based on "Web Colors" from Wikipedia
Example 2
[править]In cases where you want to optionally set a color based on a parameter you can use the following trick:
module myModule(withColors=false) {
c=withColors?"red":undef;
color(c) circle(r=10);
}
Setting the colorname to undef keeps the default colors.
offset
[править]Offset generates a new 2d interior or exterior outline from an existing outline. There are two modes of operation. radial and offset. The offset method creates a new outline whose sides are a fixed distance outer (delta > 0) or inner (delta < 0) from the original outline. The radial method creates a new outline as if a circle of some radius is rotated around the exterior (r>0) or interior (r<0) original outline.
The construction methods can either produce an outline that is interior or exterior to the original outline. For exterior outlines the corners can be given an optional chamfer.
Offset is useful for making thin walls by subtracting a negative-offset construction from the original, or the original from a Positive offset construction.
Offset can be used to simulate some common solid modeling operations:
- Fillet: offset(r=-3) offset(delta=+3) rounds all inside (concave) corners, and leaves flat walls unchanged. However, holes less than 2*r in diameter vanish.
- Round: offset(r=+3) offset(delta=-3) rounds all outside (convex) corners, and leaves flat walls unchanged. However, walls less than 2*r thick vanish.
- Parameters
- r
- Double. Amount to offset the polygon. When negative, the polygon is offset inward. R specifies the radius of the circle that is rotated about the outline, either inside or outside. This mode produces rounded corners.
- delta
- Double. Amount to offset the polygon. Delta specifies the distance of the new outline from the original outline, and therefore reproduces angled corners. When negative, the polygon is offset inward. No inward perimeter is generated in places where the perimeter would cross itself.
- chamfer
- Boolean. (default false) When using the delta parameter, this flag defines if edges should be chamfered (cut off with a straight line) or not (extended to their intersection).
Examples
// Example 1
linear_extrude(height = 60, twist = 90, slices = 60) {
difference() {
offset(r = 10) {
square(20, center = true);
}
offset(r = 8) {
square(20, center = true);
}
}
}
// Example 2
module fillet(r) {
offset(r = -r) {
offset(delta = r) {
children();
}
}
}
minkowski
[править]Displays the minkowski sum of child nodes.
Usage example:
Say you have a flat box, and you want a rounded edge. There are multiple ways to do this (for example, see hull below), but minkowski is elegant. Take your box, and a cylinder:
$fn=50;
cube([10,10,1]);
cylinder(r=2,h=1);
Then, do a minkowski sum of them (note that the outer dimensions of the box are now 10+2+2 = 14 units by 14 units by 2 units high as the heights of the objects are summed):
$fn=50;
minkowski()
{
cube([10,10,1]);
cylinder(r=2,h=1);
}
NB: The origin of the second object is used for the addition. If the second object is not centered, then the addition is asymmetric. The following minkowski sums are different: the first expands the original cube by 0.5 units in all directions, both positive and negative. The second expands it by +1 in each positive direction, but doesn't expand in the negative directions.
minkowski() {
cube([10, 10, 1]);
cylinder(1, center=true);
}
minkowski() {
cube([10, 10, 1]);
cylinder(1);
}
Warning: for high values of $fn the minkowski sum may end up consuming lots of CPU and memory, since it has to combine every child node of each element with all the nodes of each other element. So if for example $fn=100 and you combine two cylinders, then it does not just perform 200 operations as with two independent cylinders, but 100*100 = 10000 operations.
hull
[править]Displays the convex hull of child nodes.
Usage example:
hull() {
translate([15,10,0]) circle(10);
circle(10);
}
The Hull of 2D objects uses their projections (shadows) on the xy plane, and produces a result on the xy plane. Their Z-height is not used in the operation.
A note on limitations: Running hull() { a(); b(); }
is the same as hull() { hull() a(); hull() b(); }
so unless you accept/want hull() a();
and hull() b();
, the result will not match expectations.
Combining transformations
[править]When combining transformations, it is a sequential process, but going right-to-left. That is
rotate( ... ) translate ( ... ) cube(5) ;
would first move the cube, and then move it in an arc (while also rotating it by the same angle) at the radius given by the translation.
translate ( ... ) rotate( ... ) cube(5) ;
would first rotate the cube and then move it to the offset defined by the translate.
color("red") translate([0,10,0]) rotate([45,0,0]) cube(5); color("green") rotate([45,0,0]) translate([0,10,0]) cube(5);