Руководство пользователя по 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);

Изображение, показывающее результат scale() трансформации в OpenSCAD

Изменить размер

править

resize() - изменяет размер вложенного предмета, чтобы он соответствовал заданным значениям x, y и z.

resize() является операцией CGAL и, как и другие, такие как render(), работает с полной геометрией, поэтому даже при предварительном просмотре ему требуется время для обработки.

примеры :
// изменяет размер сферы, чтобы расширить ее в направлениях 30 в x, 60 в y и 10 в z.
resize(newsize=[30,60,10]) sphere(r=10);  

OpenSCAD Пример изменения размера эллипса

Если 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() в OpenSCAD

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);

Следствие поворота в OpenSCAD rotate(45) на двухмерном отображении

Справка по правилу поворота
править
Правило захвата правой рукой


Для случая:

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]); // угол куба должен совпадать с концом цилиндра

Пример функции OpenSCAD Rotate() используемой в качестве сферической системы координат.

Перенос

править

translate()перемещает свои вложенные предметы вдоль указанного вектора. Имя аргумента является необязательным.

Пример:
translate(v = [x, y, z]) { ... }
cube(2,center = true); 
translate([5,0,0]) 
   sphere(1,center = true);

изображение результата translate() в OpenSCAD

Отражение

править

mirror() отражает вложенный предмет на плоскости, проходящей через начало координат. Аргумент для mirror() - это вектор нормали плоскости, пересекающей начало координат, через которое должен быть отражен объект.

Сигнатура функции:

править
mirror(v= [x, y, z] ) { ... }

Примеры

править

Исходник находится на правой стороне. Обратите внимание, что отражение не делает копию. Подобно вращению и масштабированию, оно изменяет объект.

rotate([0,0,10]) cube([3,2,1]);
mirror([1,0,0]) translate([1,0,0]) rotate([0,0,10]) cube([3,2,1]);

изображение следствия mirror() преобразования в OpenSCAD

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(); 

Больше?

править

Узнайте больше об этом здесь:

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):

Purples
Lavender
Thistle
Plum
Violet
Orchid
Fuchsia
Magenta
MediumOrchid
MediumPurple
BlueViolet
DarkViolet
DarkOrchid
DarkMagenta
Purple
Indigo
DarkSlateBlue
SlateBlue
MediumSlateBlue
Pinks
Pink
LightPink
HotPink
DeepPink
MediumVioletRed
PaleVioletRed
Blues
Aqua
Cyan
LightCyan
PaleTurquoise
Aquamarine
Turquoise
MediumTurquoise
DarkTurquoise
CadetBlue
SteelBlue
LightSteelBlue
PowderBlue
LightBlue
SkyBlue
LightSkyBlue
DeepSkyBlue
DodgerBlue
CornflowerBlue
RoyalBlue
Blue
MediumBlue
DarkBlue
Navy
MidnightBlue
Reds
IndianRed
LightCoral
Salmon
DarkSalmon
LightSalmon
Red
Crimson
FireBrick
DarkRed
Greens
GreenYellow
Chartreuse
LawnGreen
Lime
LimeGreen
PaleGreen
LightGreen
MediumSpringGreen
SpringGreen
MediumSeaGreen
SeaGreen
ForestGreen
Green
DarkGreen
YellowGreen
OliveDrab
Olive
DarkOliveGreen
MediumAquamarine
DarkSeaGreen
LightSeaGreen
DarkCyan
Teal
Oranges
LightSalmon
Coral
Tomato
OrangeRed
DarkOrange
Orange
Yellows
Gold
Yellow
LightYellow
LemonChiffon
LightGoldenrodYellow
PapayaWhip
Moccasin
PeachPuff
PaleGoldenrod
Khaki
DarkKhaki
Browns
Cornsilk
BlanchedAlmond
Bisque
NavajoWhite
Wheat
BurlyWood
Tan
RosyBrown
SandyBrown
Goldenrod
DarkGoldenrod
Peru
Chocolate
SaddleBrown
Sienna
Brown
Maroon
Whites
White
Snow
Honeydew
MintCream
Azure
AliceBlue
GhostWhite
WhiteSmoke
Seashell
Beige
OldLace
FloralWhite
Ivory
AntiqueWhite
Linen
LavenderBlush
MistyRose
Grays
Gainsboro
LightGrey
Silver
DarkGray
Gray
DimGray
LightSlateGray
SlateGray
DarkSlateGray
Black
A 3-D multicolor sine wave

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

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.

Шаблон:Requires

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).

Шаблон:Multiple image

Examples

Example 1: Result.
// 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();
     }
   }
}


A box and a cylinder
Minkowski sum of the box and cylinder

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.

Two cylinders
Convex hull of two cylinders

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.

 
Combine two transforms
color("red")   translate([0,10,0])  rotate([45,0,0])     cube(5);
color("green") rotate([45,0,0])     translate([0,10,0])  cube(5);