Руководство пользователя по openscad

Язык сценариев OpenSCAD[править]

Общие сведения[править]

Шаблон:Incomplete

Вступление[править]


OpenSCAD это программа 2D/3D и твердотельного моделирования которая основанная на функциональном программном языке используемая для создания моделей которые можно отобразить на экране и отрэндерить в 3D сетку, что позволяет модель экспортировать в различные 2D/3D форматы файлов.

Скрипт на языке OpenSCAD используется для создания 2D или 3D моделей. Этот скрипт представляет собой свободно форматируемый список действий с выражениями.

 object();
 variable = value;
 operator()   action();
 operator() { action();    action(); }
 operator()   operator() { action(); action(); }
 operator() { operator()   action();
              operator() { action(); action(); } }
Объекты

Объекты являются строительными блоками для моделей, созданных с помощью 2D и 3D примитивов. Объекты заканчиваются точкой с запятой ‘;’.

Действия

Действия с выражениями включают создание объектов использующих примитивы и присвоение значений переменным. Действия с выражениями также заканчиваются точкой с запятой «;».

Операторы

Операторы, или преобразования, изменяют местоположение, цвет и другие свойства объектов. Операторы используют фигурные скобки «{}», когда их область действия охватывает более одного действия. Для одного действия или группы действий можно использовать более чем один оператор. Несколько операторов обрабатываются справа налево, то есть оператор, ближайший к действию, обрабатывается первым. Операторы не заканчиваются точкой с запятой «;», но отдельные действия, которые они содержат, заканчиваются.

 Примеры
  
   cube(5);
   x = 4+y;
   rotate(40) square(5,10);
   translate([10,5]) { circle(5); square(4); }
   rotate(60) color("red") { circle(5); square(4); }
   color("blue") { translate([5,3,0]) sphere(5); rotate([45,0,45]) { cylinder(10); cube([5,6,7]); } }

Комментарии[править]


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

OpenSCAD использует C++-стиль комментариев:

// Это комментарий
  
myvar = 10; // Остальная часть строки - это комментарий
  
/*
   Многострочные комментарии
   могут охватывать несколько строк.
*/

Значения и типы данных[править]


Значение в OpenSCAD — это либо число (например, 42), логическое значение (например, true), строка (например, «foo»), диапазон (например, [0:1:10]), вектор (например, [1,2,3]) или Неопределенное значение (undef). Значения могут храниться в переменных, передаваться в качестве аргументов функции и возвращаться в виде результатов функции.

[OpenSCAD — это динамически типизированный язык с фиксированным набором типов данных. Здесь нет имен типов и нет определяемых пользователем типов. Функции не являются значениями. На самом деле переменные и функции занимают непересекающиеся пространства имен.]

Числа[править]

Числа являются наиболее важным типом данных в OpenSCAD, и они записываются в привычной десятичной системе счисления, используемой в других языках. Например, -1, 42, 0,5, 2,99792458e+8. [OpenSCAD не поддерживает восьмеричную или шестнадцатеричную запись чисел.]

В дополнение к десятичным числам определены следующие имена для специальных чисел:

  • PI

В OpenSCAD есть только один тип чисел, который представляет собой 64-разрядное число IEEE с плавающей запятой. [OpenSCAD не различает целые числа и числа с плавающей запятой как два разных типа и не поддерживает комплексные числа.] Поскольку OpenSCAD использует стандарт IEEE с плавающей запятой, то существует несколько отклонений от поведения чисел в математике:

  • Мы используем двоичную систему с плавающей точкой. Дробное число не представляется точно, если только знаменатель не равен степени 2. Например, 0.2 (2/10) не имеет точного внутреннего представления, но 0.25 (1/4) и 0.125 (1/8) представлены точно.
  • Наибольшее представимое число составляет около 1e308. Если числовой результат слишком велик, то результатом может быть бесконечность (печатаемая как inf в echo).
  • Наименьшее представимое число составляет около -1e308. Если числовой результат слишком мал, то результатом может быть -бесконечность (печатаемая как -inf в echo).
  • Если числовой результат недействителен, то результат может быть не ч1ислом (англ.: Not A Number) (печатаемая как nan в echo).
  • Если ненулевой числовой результат слишком близок к нулю, чтобы быть представимым, то результат равен -0, если результат отрицательный, в противном случае он равен 0. Ноль (0) и отрицательный ноль (-0) обрабатываются как два разных числа некоторыми математическими операциями и печатаются в ‘echo’ по-разному, хотя они сравниваются как равные.

Константы «inf» и «nan» не поддерживаются OpenSCAD в качестве числовых констант, хотя вы можете вычислять числа, которые печатаются таким образом с помощью «echo». Вы можете определить переменные с этими значениями используя:

inf = 1e200 * 1e200;
nan = 0 / 0;
echo(inf,nan);

Значение ‘nan’ — это единственное значение OpenSCAD, которое не равно никакому другому значению, включая его самого. Хотя вы можете проверить, имеет ли переменная ‘x’ неопределенное значение, используя ‘x==undef’, вы не можете использовать ‘x==0/0’, чтобы проверить, не является ли x числом. Вместо этого вы должны использовать ‘x != x’, чтобы проверить, является ли x nan.

Логические значения[править]

Логические значения — это значения истинности. Существует два логических значения, а именно true (истина) и false (ложь).
Логическое значение передается в качестве аргумента условному выражению ‘if()’. условному оператору ‘? :’,
и логическим операторам ‘!’ (нет), ‘&&’ (и) и ‘||’ (или). In all of these contexts, you can actually
pass any quantity. Большинство значений преобразуются в «истину» в логическом контексте, значения, которые считаются «ложными», являются:

  • false
  • 0 and -0
  • «»
  • []
  • undef

Обратите внимание, что "false" (строка), [0] (числовой вектор),
[ [] ] (вектор, содержащий пустой вектор), [false]
(вектор, содержащий логическое значение false) и 0/0 (не число (Not A Number(nan))) все считаются истинными.

Строки[править]

Строка — это последовательность из нуля или более символов юникода. Строковые значения используются для указания имен файлов при импорте файла и для отображения текста в целях отладки при использовании echo(). Строки также можно использовать с новым примитивом text() добавленном в 2015.03.

Строковый литерал записывается как последовательность символов, заключенных в кавычки ", например: "" (пустая строка), или "это строка".

Чтобы включить символ " в строковый литерал, используйте \". Чтобы включить символ \ в строковый литерал, используйте \\. В строковых литералах можно использовать следующие escape-последовательности, начинающиеся с \:

  • \» → «
  • \\ → \
  • \t → табуляция
  • \n → новая строка
  • \r → возврат каретки
  • \u03a9 → Ω — смотри text() для получения дополнительной информации о символах юникода

Примечание: Это поведение является новым с версии OpenSCAD-2011.04. Вы можете обновить старые файлы с помощью следующей команды sed: sed ‘s/\\/\\\\/g’ non-escaped.scad > escaped.scad

 Пример:
  
 echo("The quick brown fox \tjumps \"over\" the lazy dog.\rThe quick brown fox.\nThe \\lazy\\ dog.");
  
 Результат
ECHO: "The quick brown fox jumps "over" the lazy dog. The quick brown fox. The \lazy\ dog." Старый результат
ECHO: "The quick brown fox \tjumps \"over\" the lazy dog. The quick brown fox.\nThe \\lazy\\ dog."

Диапазоны[править]

Диапазоны используются в циклах for() и в children(). У них есть 2 разновидности:

[<начало>: <конец>]
[<начало>: <прирост>: <конец>]

Хотя они заключены в квадратные скобки [], они не являются векторами. Они используют двоеточия : для разделителей, а не запятые.

r1 = [0:10];
r2 = [0.5:2.5:20];
echo(r1); // ECHO: [0: 1: 10]
echo(r2); // ECHO: [0.5: 2.5: 20]

Вам следует избегать значений шага, которые не могут быть представлены точно в виде двоичных чисел с плавающей запятой. Целые числа в порядке, как и дробные значения, знаменатель которых равен степени двух. Например, 0,25 (1/4) и 0,125 (1/8) безопасны, но следует избегать 0,2 (2/10). Проблема с этими значениями шага заключается в том, что в вашем диапазоне может быть слишком много или слишком мало элементов из-за неточной арифметики.

Пропущенный <прирост> по умолчанию равняется 1. Диапазон в форме [<начало>:<конец>] с <началом> больше, чем <конец>, генерирует предупреждение и эквивалентен [<конец>: 1: <начало>]. Диапазон в форме [<начало>:1:<конец>] с <началом> больше, чем <конец>, не генерирует предупреждение и эквивалентен []. <Приращение> в диапазоне может быть отрицательным (для версий после 2014 года).

Неопределенное Значение[править]

Неопределенное (англ.: undefined) значение — это специальное значение, записанное как undef. Это начальное значение переменной, которой не было присвоено значение, и оно часто возвращается в результате функций или операций, которым передаются недопустимые аргументы. Наконец, undef может использоваться в качестве нулевого значения, эквивалентного null или NULL на других языках программирования.

Все арифметические выражения, содержащие undef значения оцениваются как undef. В логических выражениях, undef эквивалентен false. Выражения оператора отношения с undef оцениваются как false, за исключением undef==undef, который является true.

Обратите внимание, что числовые операции могут также возвращать ‘nan’ (not-a-number(не число)), чтобы указать на недопустимый аргумент. Например, 0/false это undef, но 0/0 это ‘nan’. Операторы отношений, такие как < and > возвращают false если передаются недопустимые аргументы. Хотя undef является значением языка, ‘nan’ — нет.

Переменные[править]


Переменные OpenSCAD создаются оператором с именем или идентификатором, присваиванием с помощью выражения и точки с запятой. Роль массивов, встречающихся во многих императивных языках, обрабатывается в OpenSCAD при использовании векторов.

var = 25;
xx = 1.25 * cos(50);
y = 2*xx+var;
logic = true;
MyString = "Это строка";
a_vector = [1,2,3];
rr = a_vector[2];      // член вектора
range1 = [-1.5:0.5:3]; // for() диапазон циклов
xx = [0:5];            // альтернативный for() диапазон циклов

OpenSCAD — это функциональный язык программирования, как таковые переменные привязаны к выражениям и сохраняют одно значение в течение всего срока службы из-за требований ссылочной прозрачности. В императивных языках, таких как C, то же поведение рассматривается как константы, которые обычно противопоставляются обычным переменным.

Другими словами, переменные OpenSCAD больше похожи на константы, но с важным отличием. Если переменным присваивается значение несколько раз, во всех местах кода используется только последнее присвоенное значение. См. Дальнейшее обсуждение в Переменные устанавливаются во время компиляции, а не во время выполнения. Такое поведение связано с необходимостью для поддержки входа переменных через командную строку, с помощью параметра -D переменная=значение. В настоящее время OpenSCAD помещает это присваивание в конец исходного кода и, следовательно, должен позволять изменять значение переменной для этой цели.

Значения не могут быть изменены во время выполнения; все переменные фактически являются константами, которые не изменяются. Каждая переменная сохраняет свое последнее присвоенное значение во время компиляции в соответствии с Функциональными языками программирования. В отличие от императивных языков, таких как C, OpenSCAD iне является итеративным языком, и поэтому концепция x = x + 1 неверна. Понимание этой концепции ведет к пониманию красоты OpenSCAD.

До версии 2015.03

Невозможно было выполнять назначения в любом месте, кроме верхнего уровня файла и верхнего уровня модуля. Внутри if/else  или for  цикла, assign() был необходим.

Начиная с версии 2015.03

Переменные теперь можно назначать в любой области. Обратите внимание, что назначения допустимы только в той области, в которой они определены — вам по-прежнему не разрешается передавать значения во внешнюю область. См. Область действия переменных для получения более подробной информации.

a=0;
if (a==0) 
  {
 a=1; //  до 2015.03 эта строка будет выдавать Ошибку Компиляции
      //  с 2015.03 больше не является ошибкой, но значение a=1 ограничено фигурными скобками {}
  }

Неопределенная переменная[править]

Неназначенная переменная имеет специальное значение undef.
Он может быть проверен в условном выражении и возвращен функцией.

 Пример:
  
 echo("Переменная a", a);                        // Переменная a не определена
 if (a==undef) {
   echo("Переменная a является неопределенной"); // Переменная a является неопределенной
 }

Область действия переменных[править]

Когда такие операторы, как translate() и color(), должны охватывать более одного действия (действия заканчиваются на ;), фигурные скобки {} необходимы для группировки действий, создавая новую внутреннюю область.
Когда есть только одна точка с запятой, фигурные скобки обычно необязательны.

Каждая пара фигурных скобок создает новую область внутри области, в которой они используются. Начиная с 2015.03, в этой новой области можно создавать новые переменные. Новые значения могут быть присвоены переменным, которые были созданы во внешней области.
Эти переменные и их значения также доступны для других внутренних областей, созданных в этой области, но «недоступны» для чего-либо за пределами этой области. Переменные по-прежнему содержат только последнее значение, присвоенное в пределах области.

                       // область 1
 a = 6;                // создать a
 echo(a,b);            //                6, undef
 translate([5,0,0]){   // область 1.1
   a= 10;
   b= 16;              // создать b
   echo(a,b);          //              100, 16   a=10; был переопределен более поздним a=100;
   color("blue") {     // область 1.1.1
     echo(a,b);        //              100, 20
     cube();
     b=20;
   }                   // возврат в 1.1
   echo(a,b);          //              100, 16
   a=100;              // переопределить a в 1.1
 }                     // возврат в 1   
 echo(a,b);            //                6, undef
 color("red"){         // область 1.2
   cube();
   echo(a,b);          //                6, undef
 }                     // возврат в 1
 echo(a,b);            //                6, undef
  
 //В этом примере области 1 и 1.1 являются внешними областями для 1.1.1, а 1.2 - нет.
Анонимные области не считаются областями:
 {
   angle = 45;
 }
 rotate(angle) square(10);

Циклы for() не являются исключением из правила о переменных, имеющих только одно значение в области видимости. Для каждого прохода создается копия содержимого цикла. Каждому проходу присваивается своя область действия, что позволяет любым переменным иметь уникальные значения для этого прохода. Нет, вы все еще не можете сделать a=a+1;

Переменные задаются во время компиляции, а не во время выполнения[править]

Поскольку OpenSCAD вычисляет значения своих переменных во время компиляции, а не во время выполнения, последнее назначение переменной в области применяется везде в этой области или ее внутренних областях. Возможно, было бы полезно думать о них как о переопределяемых константах, а не как о переменных.

// Значение 'a' отражает только последнее установленное значение
   a = 0;
   echo(a);  // 5
   a = 3;
   echo(a);  // 5
   a = 5;

Хотя это кажется нелогичным, это позволяет вам делать некоторые интересные вещи: например, если вы настроили файлы общей библиотеки так, чтобы значения по умолчанию определялись как переменные на их корневом уровне, когда вы включаете этот файл в свой собственный код, вы можете ‘переопределить’ эти константы, просто присвоив им новое значение. Таким образом, изменение постоянных значений дает вам больше гибкости. Если константы никогда не изменятся, конечно, вы всегда можете быть уверены, что у вас есть значение, которое вы видите в любом определении константы. Здесь все не так. Если вы видите определение постоянного значения в любом другом месте, его значение может быть другим. Это очень гибкий подход.

Специальные переменные[править]

Специальные переменные предоставляют альтернативные средства передачи аргументов модулям и функциям.
Все переменные, начинающиеся с ‘$’ являются специальными переменными, подобными специальным переменным в lisp.
Как таковые, они более динамичны, чем обычные переменные.
(для получения более подробной информации см. Другие языковые функции)

Векторы[править]


Вектор или список — это последовательность из нуля или более значений OpenSCAD. Векторы представляют собой набор числовых или логических значений, переменных, векторов, строк или любой их комбинации. Они также могут быть выражениями, которые оценивают одно из них. Векторы выполняют роль массивов, найденных во многих императивных языках.
Приведенная здесь информация также относится к спискам и таблицам, которые используют векторы для своих данных.

Вектор имеет квадратные скобки, [] заключающие ноль или более элементов (элементов или членов), разделенных запятыми. Вектор может содержать векторы, которые содержат векторы и т.д.

Примеры:
   [1,2,3]
   [a,5,b]
   []
   [5.643]
   ["a","b","string"]
   [[1,r],[x,y,z,4,5]]
   [3, 5, [6,7], [[8,9],[10,[11,12],13], c, "string"]
   [4/3, 6*1.5, cos(60)]

использование в OpenSCAD:

  cube( [width,depth,height] );           // дополнительные пробелы, показанны для ясности
  translate( [x,y,z] )
  polygon( [ [x0,y0],  [x1,y1],  [x2,y2] ] );
Создание

Векторы создаются путем написания списка элементов, разделенных запятыми и заключенных в квадратные скобки. Переменные заменяются их значениями.

  cube([10,15,20]);
  a1 = [1,2,3];
  a2 = [4,5];
  a3 = [6,7,8,9];
  b  = [a1,a2,a3];    // [ [1,2,3], [4,5], [6,7,8,9] ]  обратите внимание на увеличенную глубину вложенности
Индексирование элементов в векторах[править]

Элементы в векторах пронумерованы от 0 до n-1, где n — длина, возвращаемая len().
Адреса элементов внутри векторов со следующем обозначением:

e[5]           // элемент № 5 (шестой)      1-го уровня вложенности
e[5][2]        // элемент 2 элемента 5      2-го уровня вложенности
e[5][2][0]     // элемент 0 из 2 из 5       3-го уровня вложенности
e[5][2][0][1]  // элемент 1 из 0 из 2 из 5  4-го уровня вложенности

примеры элементов с длинами из len()

e = [ [1], [], [3,4,5], "string", "x", [[10,11],[12,13,14],[[15,16],[17]]] ];  // length 6

адрес         длина   элемент
e[0]          1       [1]
e[1]          0       []
e[5]          3       [ [10,11], [12,13,14], [[15,16],[17]] ]
e[5][1]       3       [ 12, 13, 14 ]
e[5][2]       2       [ [15,16], [17] ]
e[5][2][0]    2       [ 15, 16 ]
e[5][2][0][1] undef   16
    
e[3]          6       "string"
e[3 ][2]      1       "r"
  
s = [2,0,5]; a = 2;
s[a]          undef   5
e[s[a]]       3       [ [10,11], [12,13,14], [[15,16],[17]] ]
Индексация точечных обозначений[править]

К первым трем элементам вектора можно получить доступ с помощью альтернативной точечной нотации:

e.x    //равнозначно e[0]
e.y    //равнозначно e[1]
e.z    //равнозначно e[2]
Векторные операторы[править]

concat[править]

Шаблон:Requires

concat() cобъединяет элементы 2 или более векторов в один вектор. Никаких изменений в уровне вложенности не делается.

 vector1 = [1,2,3]; vector2 = [4]; vector3 = [5,6];
 new_vector = concat(vector1, vector2, vector3); // [1,2,3,4,5,6]
  
 string_vector = concat("abc","def");                 // ["abc", "def"]
 one_string = str(string_vector[0],string_vector[1]); // "abcdef"
len[править]

len() это функция, которая возвращает длину векторов или строк.
Индексы элементов находятся в диапазоне от [0] до [длина-1].

вектор

Возвращает количество элементов на этом уровне.
Единичные значения, которые являются не not векторами, возвращает undef.
строка

Возвращает количество символов в строке.
 a = [1,2,3]; echo(len(a));   //  3

См. Примеры элементов с длиной

Матрица[править]

Матрица — это вектор векторов.

Пример, который определяет двумерную матрицу вращения
mr = [
     [cos(angle), -sin(angle)],
     [sin(angle),  cos(angle)]
    ];

Получение входных данных[править]


Теперь у нас есть переменные, было бы неплохо иметь возможность вводить их вместо того, чтобы задавать значения из кода. Существует несколько функций для чтения данных из файлов DXF, или вы можете установить переменную с помощью переключателя -D в командной строке.

Получение точки из рисунка

Получение точки полезно для считывания исходной точки в 2D-виде на техническом чертеже. Функция dxf_cross считывает пересечение двух линий на указанном вами слое и возвращает точку пересечения. Это означает, что точка должна быть задана двумя строками в файле DXF, а не точечным объектом.

OriginPoint = dxf_cross(file="drawing.dxf", layer="SCAD.Origin", 
                        origin=[0, 0], scale=1);

Получение значения измерения

Вы можете прочитать размеры из технического чертежа. Это может быть полезно для считывания угла поворота, высоты выдавливания или расстояния между деталями. На чертеже создайте размер, в котором отображается не значение размера, а идентификатор. Чтобы прочитать значение, вы указываете этот идентификатор в своей программе:

TotalWidth = dxf_dim(file="drawing.dxf", name="TotalWidth",
                        layer="SCAD.Origin", origin=[0, 0], scale=1);

Для наглядного примера обеих функций см. Example009 и изображение на домашней странице OpenSCAD.

Примитивы объемных тел[править]

Куб[править]


cube() создает куб в первом октанте. Когда параметр center=true куб центрируется в начале координат.
Имена аргументов являются необязательными, если они заданы в указанном здесь порядке.

cube(size = [x,y,z], center = true/false);
cube(size =  x ,     center = true/false);
Параметры :
size

одно значение, куб со всеми сторонами этой длины
массив из 3-х значений [x, y, z], куб с размерами x, y и z.
center

false (по умолчанию), 1-й (положительный) октант, первый угол находится на (0,0,0)
true, куб центрирован на (0,0,0)
значения по умолчанию:  cube();   выводит:  cube(size = [1, 1, 1], center = false);
примеры :

равнозначные описания для этого примера
 cube(size = 18);
 cube(18);
 cube([18,18,18]);
 .
 cube(18,false);
 cube([18,18,18],false);
 cube([18,18,18],center=false);
 cube(size = [18,18,18], center = false);
 cube(center = false,size = [18,18,18] );

равнозначные описания для этого примера
 cube([18,28,8],true);
 box=[18,28,8];cube(box,true);

Сфера[править]


Создает сферу в начале системы координат. Имя аргумента r является необязательным. Чтобы использовать d вместо r, d должен быть назван.

Параметры

r
Радиус. Это радиус сферы. Разрешение сферы зависит от размера сферы и переменных $fa, $fs и $fn. Для получения дополнительной информации об этих специальных переменных смотрите: OpenSCAD_User_Manual/Other_Language_Features
d
Диаметр. Это диаметр сферы.
$fa
Угол наклона фрагмента в градусах
$fs
Размер фрагмента в миллиметрах
$fn
Разрешение
 значения по умолчанию:  sphere();   выводит:   sphere($fn = 0, $fa = 12, $fs = 2, r = 1);

Примеры использования

sphere(r = 1);
sphere(r = 5);
sphere(r = 10);
sphere(d = 2);
sphere(d = 10);
sphere(d = 20);
// результатом будет сфера радиусом 2мм, с поверхностью высокого разрешения
sphere(2, $fn=100); 
// также создается сфера радиусом 2мм, с поверхностью высокого разрешения, но у этой
// не так много маленьких треугольников на полюсах сферы
sphere(2, $fa=5, $fs=0.1); 

Sample OpenSCAD spheres, showing clearly the difference in scale.

Цилиндр[править]


cylinder() создает цилиндр или конус с центром вокруг оси z. Если значение center равно true, оно также центрируется вертикально вдоль оси z.

Имена параметров являются необязательными, если они заданы в указанном здесь порядке. Если параметр получил имя, то все следующие параметры также должны быть поименованы.

ПРИМЕЧАНИЕ: Если используются r, d, d1 или d2, они должны быть названы.

cylinder(h = height, r1 = BottomRadius, r2 = TopRadius, center = true/false);
Параметры
h : высота цилиндра или конуса
r : радиус цилиндра. r1 = r2 = r.
r1 : радиус, нижней части конуса.
r2 : радиус, верхней части конуса.
d : диаметр цилиндра. r1 = r2 = d / 2. Шаблон:Требуется
d1 : диаметр, нижней части конуса. r1 = d1 / 2. Шаблон:Требуется
d2 : диаметр, верхней части конуса. r2 = d2 / 2. Шаблон:Требуется
center

false (по умолчанию), z в диапозоне от 0 до h
true, z в диапозоне от -h/2 до +h/2
$fa : минимальный угол (в градусах) каждого фрагмента.
$fs : минимальная длина окружности каждого фрагмента.
$fn : исправлено количество фрагментов в 360 градусах. Значения 3 или более переопределяют значения $fa и $fs

$fa, $fs и $fn должны быть именованными параметрами. нажмите здесь для получения более подробной информации.
значения по умолчанию: cylinder();  выводит: cylinder($fn = 0, $fa = 12, $fs = 2, h = 1, r1 = 1, r2 = 1, center = false);

равнозначные описания для этого примера
 cylinder(h=15, r1=9.5, r2=19.5, center=false);
 cylinder(  15,    9.5,    19.5, false);
 cylinder(  15,    9.5,    19.5);
 cylinder(  15,    9.5, d2=39  );
 cylinder(  15, d1=19,  d2=39  );
 cylinder(  15, d1=19,  r2=19.5);

равнозначные описания для этого примера
 cylinder(h=15, r1=10, r2=0, center=true);
 cylinder(  15,    10,    0,        true);
 cylinder(h=15, d1=20, d2=0, center=true);
  • center = false

    center = false

  • center = true

    center = true

равнозначные описания для этого примера
 cylinder(h=20, r=10, center=true);
 cylinder(  20,   10, 10,true);
 cylinder(  20, d=20, center=true);
 cylinder(  20,r1=10, d2=20, center=true);
 cylinder(  20,r1=10, d2=2*10, center=true);
использование $fn

Большие значения $fn создают более гладкие, более круглые поверхности за счет увеличения времени рендеринга. Некоторые используют средние значения во время разработки для более быстрого рендеринга, а затем меняют значение на большое для окончательного рендеринга F6.

Однако использование малых значений может привести к появлению некоторых интересных некруглых объектов. Здесь показано несколько примеров:

описания для этих примеров
 cylinder(20,20,20,$fn=3);
 cylinder(20,20,00,$fn=4);
 cylinder(20,20,10,$fn=4);
отверстия меньшего размера

Используя cylinder() с difference() для размещения отверстий в объектах, создаются отверстия меньшего размера. Это происходит потому, что круговые пути аппроксимируются многоугольниками, вписанными внутри круга. Точки многоугольника находятся на окружности, но прямые линии между ними находятся внутри. Чтобы все отверстия были больше истинного круга, многоугольник должен лежать полностью за пределами круга (описанного). Модули для описанных отверстий

описание для этого примера
 poly_n = 6;
 color("blue") translate([0, 0, 0.02]) linear_extrude(0.1) circle(10, $fn=poly_n);
 color("green") translate([0, 0, 0.01]) linear_extrude(0.1) circle(10, $fn=360);
 color("purple") linear_extrude(0.1) circle(10/cos(180/poly_n), $fn=poly_n);

Многогранник[править]


Многогранник — это наиболее общее трехмерное простейшее твердое тело. Его можно использовать для создания любой правильной или неправильной фигуры, в том числе с вогнутыми и выпуклыми частями. Изогнутые поверхности аппроксимируются несколькими плоскими поверхностями.

polyhedron( points = [ [X0, Y0, Z0], [X1, Y1, Z1], ... ], triangles = [ [P0, P1, P2], ... ], convexity = N);        // до 2014.03
polyhedron( points = [ [X0, Y0, Z0], [X1, Y1, Z1], ... ], faces = [ [P0, P1, P2, P3, ...], ... ], convexity = N);   // 2014.03 & позже 
Параметры

points

Вектор 3d точек или вершин. Каждая точка, в свою очередь, является вектором [x, y, z] своих координат.
Точки могут быть определены в любом порядке. N точек указываются в оределённом порядке, от 0 до N-1.
triangles Шаблон:OpenSCAD User Manual/Deprecated

Вектор граней, которые в совокупности охватывают твердое тело. Каждая грань представляет собой вектор, содержащий индексы (на основе 0) 3 точек из вектора точек.
faces Шаблон:Требует

Вектор граней, которые в совокупности охватывают твердое тело. Каждая грань представляет собой вектор, содержащий индексы (на основе 0) 3 или более точек из вектора точек.
Грани могут быть определены в любом порядке. Определите достаточное количество граней, чтобы полностью охватить твердое тело без перекрытия.
Если точки, описывающие одну грань, не находятся в одной плоскости, грань автоматически разбивается на треугольники по мере необходимости.
convexity

Целое число. Параметр выпуклости указывает максимальное количество граней, через которые может пройти луч, пересекающий объект. Этот параметр необходим только для корректного отображения объекта в режиме предварительного просмотра OpenCSG. Это никак не влияет на рендеринг многогранника. При проблемах с отображением значение 10 должно работать нормально в большинстве случаев.
 значения по умолчанию: polyhedron(); выводит: polyhedron(points = undef, faces = undef, convexity = 1);

Вы можете начать с любой точки, но все грани должны иметь точки, расположенные в одном и том же направлении. OpenSCAD предпочитает по часовой стрелке, когда смотрит на каждую грань снаружи внутрь. Задняя часть просматривается сзади, нижняя часть снизу и т.д. Еще один способ запомнить это требование к порядку — использовать правило правой руки. Используя правую руку, поднимите большой палец вверх и согните пальцы, как бы показывая большой палец вверх, направьте большой палец в грань и расположите точки в направлении, в котором сгибаются ваши пальцы. Попробуйте сделать это на примере ниже.

Пример 1 Использование многогранника для создания куба( [ 10, 7, 5 ] );

номера точек у куба
развернутые грани куба
CubePoints = [
  [  0,  0,  0 ],  //0
  [ 10,  0,  0 ],  //1
  [ 10,  7,  0 ],  //2
  [  0,  7,  0 ],  //3
  [  0,  0,  5 ],  //4
  [ 10,  0,  5 ],  //5
  [ 10,  7,  5 ],  //6
  [  0,  7,  5 ]]; //7
  
CubeFaces = [
  [0,1,2,3],  // bottom
  [4,5,1,0],  // front
  [7,6,5,4],  // top
  [5,6,2,1],  // right
  [6,7,3,2],  // back
  [7,4,0,3]]; // left
  
polyhedron( CubePoints, CubeFaces );
равнозначные описания нижней грани
  [0,1,2,3],
  [0,1,2,3,0],
  [1,2,3,0],
  [2,3,0,1],
  [3,0,1,2],
  [0,1,2],[2,3,0],   // 2 треугольника без перекрытия
  [1,2,3],[3,0,1],
  [1,2,3],[0,1,3],
Пример 2 Пирамида с квадратным основанием:

Простая многогранная пирамида с квадратным основанием
polyhedron(
  points=[ [10,10,0],[10,-10,0],[-10,-10,0],[-10,10,0], // четыре точки в основании
           [0,0,10]  ],                                 // точка вершины 
  faces=[ [0,1,4],[1,2,4],[2,3,4],[3,0,4],              // все стороны треугольников
              [1,0,3],[2,1,3] ]                         // два триугольника для квадратного основания
 );
Пример 3 Треугольная призма:

Многогранная треугольная призма
   module prism(l, w, h){
       polyhedron(
               points=[[0,0,0], [l,0,0], [l,w,0], [0,w,0], [0,w,h], [l,w,h]],
               faces=[[0,1,2,3],[5,4,3,2],[0,4,5,1],[0,3,4],[5,2,1]]
               );
       
       // предварительный просмотр развернутый (не включайте в свою функцию)
       z = 0.08;
       separation = 2;
       border = .2;
       translate([0,w+separation,0])
           cube([l,w,z]);
       translate([0,w+separation+w+border,0])
           cube([l,h,z]);
       translate([0,w+separation+w+border+h+border,0])
           cube([l,sqrt(w*w+h*h),z]);
       translate([l+border,w+separation+w+border+h+border,0])
           polyhedron(
                   points=[[0,0,0],[h,0,0],[0,sqrt(w*w+h*h),0], [0,0,z],[h,0,z],[0,sqrt(w*w+h*h),z]],
                   faces=[[0,1,2], [3,5,4], [0,3,4,1], [1,4,5,2], [2,5,3,0]]
                   );
       translate([0-border,w+separation+w+border+h+border,0])
           polyhedron(
                   points=[[0,0,0],[0-h,0,0],[0,sqrt(w*w+h*h),0], [0,0,z],[0-h,0,z],[0,sqrt(w*w+h*h),z]],
                   faces=[[1,0,2],[5,3,4],[0,1,4,3],[1,2,5,4],[2,0,3,5]]
                   );
       }
   
   prism(10, 5, 3);

Отладка многогранников[править]


Ошибки при определении многогранников включают в себя отсутствие всех граней с одинаковым порядком, перекрытие граней и отсутствие граней или частей граней. Как правило, грани многогранника также должны удовлетворять нескольким условиям:

  • ровно две грани должны встретиться на любом ребре многогранника.
  • Если две грани имеют общую вершину, то они должны быть в в том же цикле грань-ребра вокруг вершины.

Первое правило исключает многогранники, такие как два куба с общим ребром, а не герметичные модели; второе исключает многогранники, такие как два куба с общей вершиной.

При взгляде снаружи точки, описывающие каждую грань, должны располагаться в одном и том же порядке. OpenSCAD предпочитает CW (clockwise — по Часовой Стрелке) и предоставляет механизм для обнаружения CCW (counterclockwise — Против Часовой Стрелки).
Когда комбинированный вид (F12) используется с F5, грани ПЧС (CCW) отображаются розовым цветом. Измените порядок точек для неправильных граней. Поверните объект, чтобы просмотреть все грани. Розовый вид можно отключить с помощью F10.

OpenSCAD позволяет временно закомментировать часть описаний граней, чтобы отображались только оставшиеся грани. Используйте //, чтобы закомментировать остальную часть строки. Используйте /* и */, чтобы начать и закончить блок комментариев. Это может быть частью строки или распространяться на несколько строк. Просмотр только части граней может быть полезным при определении правильных точек для отдельной грани. Обратите внимание, что твердое тело не отображается, только грани. При использовании F12 все грани имеют одну розовую сторону. Комментирование некоторых граней помогает также показать любое внутреннюю грань.

пример 1, показывающий только 2 грани
CubeFaces = [
/* [0,1,2,3],  // bottom
   [4,5,1,0],  // front */
   [7,6,5,4],  // top
/* [5,6,2,1],  // right
   [6,7,3,2],  // back */
   [7,4,0,3]]; // left

После определения многогранника его предварительный просмотр может показаться правильным. Один только многогранник может даже хорошо отрисоваться. Однако, чтобы убедиться, что это допустимое множество и что оно может генерировать допустимый файл STL, объедините его с любым кубом и визуализируйте его (F6). Если многогранник исчезает, это означает, что он неправильный. Пересмотрите порядок намотки всех граней и два правила, изложенные выше.

Неправильно направленные грани[править]


Пример 4 более сложный многогранник с неправильно упорядоченными гранями

Если вы выберете ‘Всё вместе (Thrown together) [F12]’ в меню Вид (View) и скомпилируйте дизайн [F5] (не компелировать и рендер! [F6]) предварительный просмотр покажет выделением неправильно направленные полигоны. К сожалению, это выделение невозможно в режиме предварительного просмотра OpenCSG, поскольку это помешало бы реализации режима предварительного просмотра OpenCSG.

Ниже вы можете увидеть код и изображение такого проблемного многогранника, плохие полигоны (грани или сочетания граней) окрашены в розовый цвет.

// Плохой многогранник
polyhedron
    (points = [
	       [0, -10, 60], [0, 10, 60], [0, 10, 0], [0, -10, 0], [60, -10, 60], [60, 10, 60], 
	       [10, -10, 50], [10, 10, 50], [10, 10, 30], [10, -10, 30], [30, -10, 50], [30, 10, 50]
	       ], 
     faces = [
		  [0,2,3],   [0,1,2],  [0,4,5],  [0,5,1],   [5,4,2],  [2,4,3],
                  [6,8,9],  [6,7,8],  [6,10,11], [6,11,7], [10,8,11],
		  [10,9,8], [0,3,9],  [9,0,6], [10,6, 0],  [0,4,10],
                  [3,9,10], [3,10,4], [1,7,11],  [1,11,5], [1,7,8],  
                  [1,8,2],  [2,8,11], [2,11,5]
		  ]
     );

Многогранник с плохо направленными многоугольниками

Правильный многогранник был бы следующим:

polyhedron
    (points = [
	       [0, -10, 60], [0, 10, 60], [0, 10, 0], [0, -10, 0], [60, -10, 60], [60, 10, 60], 
	       [10, -10, 50], [10, 10, 50], [10, 10, 30], [10, -10, 30], [30, -10, 50], [30, 10, 50]
	       ], 
     faces = [
		  [0,3,2],  [0,2,1],  [4,0,5],  [5,0,1],  [5,2,4],  [4,2,3],
                  [6,8,9],  [6,7,8],  [6,10,11],[6,11,7], [10,8,11],
		  [10,9,8], [3,0,9],  [9,0,6],  [10,6, 0],[0,4,10],
                  [3,9,10], [3,10,4], [1,7,11], [1,11,5], [1,8,7],  
                  [2,8,1],  [8,2,11], [5,11,2]
		  ]
     );
Совет для начинающих

Если вы действительно не понимаете «ориентацию», попробуйте определить неправильно ориентированные розовые грани, а затем перевернуть последовательность ссылок на векторы точек, пока не получите правильное отображение. К примеру, в приведенном выше примере третий треугольник([0,4,5]) был неправильным, и мы исправили это так [4,0,5]. Помните, что список граней — это круговой список. Кроме того, вы можете выбрать «Показать ребра» в меню «Вид», распечатать снимок экрана и пронумеровать как точки, так и грани. В нашем примере точки помечены черным цветом, а грани — синим. Переверните объект и при необходимости сделайте вторую копию с обратной стороны. Таким путём вы сможете держать верное направление (This way you can keep track).

Техника по часовой стрелке

Ориентация определяется круговым указанием по часовой стрелке. Это означает, что если вы смотрите на треугольник (в этом случае [4,0,5]) снаружи вы увидите, что путь проходит по часовой стрелке вокруг центра грани. Порядок намотки [4,0,5] по часовой стрелке и, следовательно, хорошо. Порядок намотки [0,4,5] против часовой стрелки и, следовательно, плохо. Аналогично, любой другой порядок по часовой стрелке [4,0,5] работает: [5,4,0] и [0,5,4] тоже хорошо. Если вы используете технику по часовой стрелке, ваши грани всегда будут снаружи (за пределами OpenSCAD, хотя другие программы используют против часовой стрелки в качестве внешней стороны).

Думайте об этом как о Правиле Левой Руки:

Если вы положите левую руку на грань, согнув пальцы в направлении порядка точек, ваш большой палец должен быть направлен наружу. Если ваш большой палец указывает внутрь, вам нужно изменить порядок намотки.

Многогранник с плохо ориентированными многоугольниками

Краткое описание ‘Многогранника’

* Точки определяют все точки/вершины фигуры.
* Грани - это список плоских многоугольников, соединяющих точки/вершины. 

Каждая точка в списке точек определяется с помощью 3-мерной x,y,z характеристики положения. Точки в списке точек автоматически перечисляются, начиная с нуля, для использования в списке граней (0,1,2,3,… и т.д.).

Каждая грань в списке граней определяется путем выбора 3 или более точек (с использованием порядкового номера точек) из списка точек.

например, faces=[ [0,1,2] ] определяет треугольник из первой точки (точки равны нулю) ко второй точке, а затем к третьей точке.

При взгляде на любую грань снаружи, на ней должны быть перечислены все точки в порядке по часовой стрелке.

Повторения точек в списке точек многогранника[править]

Список точек определения многогранника может содержать повторы. Когда две или более точки имеют одинаковые координаты, они считаются одной и той же вершиной многогранника. Итак, следующий многогранник:

points = [[ 0, 0, 0], [10, 0, 0], [ 0,10, 0],
          [ 0, 0, 0], [10, 0, 0], [ 0,10, 0],
          [ 0,10, 0], [10, 0, 0], [ 0, 0,10],
          [ 0, 0, 0], [ 0, 0,10], [10, 0, 0],
          [ 0, 0, 0], [ 0,10, 0], [ 0, 0,10]];
polyhedron(points, [[0,1,2], [3,4,5], [6,7,8], [9,10,11], [12,13,14]]);

опишет тот же тетраэдр, что и:

points = [[0,0,0], [0,10,0], [10,0,0], [0,0,10]];
polyhedron(points, [[0,2,1], [0,1,3], [1,2,3], [0,3,2]]);

OpenSCAD Tutorial

Table of Contents

  1. Chapter 1: A few words about OpenSCAD and getting started with the first object
  2. Chapter 2: Scaling the model and first steps for parameterizing models
  3. Chapter 3: Resizing models and more ways of combining objects
  4. Chapter 4: Introducing modules to organize the code
  5. Chapter 5: Using multiple scripts and libraries
  6. Chapter 6: Control flow, conditional creation of objects
  7. Chapter 7: Loops and creating more complex patterns
  8. Chapter 8: Extruding 2D shapes into 3D objects
  9. Chapter 9: Math, calculations and low level geometry creation

OpenSCAD User Manual

Table of Contents

  1. Introduction
  2. First Steps
  3. User Interface
  4. Input Devices
  5. Customizer
  6. Import and Export
  7. Commented Example Projects
  8. Paths
  9. Using an external Editor with OpenSCAD
  10. Using OpenSCAD in a command line environment
  11. Building OpenSCAD from Sources
  12. FAQ
  13. Libraries
  14. Tips and Tricks
  15. Glossary

OpenSCAD Language Reference

Table of Contents

  1. The OpenSCAD Language — General
  2. 3D Objects,
    Projection
  3. 2D Objects,
    Primitives,
    Text,
    Extrusion to 3D
  4. Transformations
  5. Boolean operations
  6. Conditional and iterator functions
  7. Mathematical operators
  8. Mathematical functions
  9. String functions
  10. Type test functions
  11. List comprehensions
  12. Other language features
  13. User defined functions and modules
  14. Debugging aids — modifier characters
  15. Importing geometry,
    Exporting geometry

Cheat Sheet


Содержание

  • 1 Создание простейшего модуля
    • 1.1 Компиляция и визуализация нашей первой модели
  • 2 Открытие существующей учебной модели
  • 3 Позиционирование объекта
    • 3.1 Отсутствие точки с запятой после команды переноса
  • 4 Изменение цвета объекта
  • 5 Режимы просмотра
    • 5.1 OpenCGS
    • 5.2 CGAL-поверхности
    • 5.3 Только CGAL-сетка
    • 5.4 Предварительный просмотр

Создание простейшего модуля[править]

В качестве нашей первой модели мы создадим простой 2 х 3 х 4 кубоид. В OpenSCAD-редакторе наберите следующую команду:

Пример 1 — простой кубоид:

Простейший кубоид в OpenSCAD

Компиляция и визуализация нашей первой модели[править]

Теперь кубоид может быть скомпилирован и визуализирован нажатием клавиши F6 в активном окне OpenSCAD-редактора.

Открытие существующей учебной модели[править]

Откройте один из множества примеров, которые идут с OpenSCAD (File, Examples, и, например, example002.scad). Или Вы можете скопировать и вставить этот простой пример в окно OpenSCAD-редактора:

Пример 1 — example002.scad:
difference() {
 	cube(30, center=true);
 	sphere(20);
 }
 translate([0, 0, 30]) {
 	cylinder(h=40, r=10);
 }

OpenSCAD после вставки кода примера и нажатия F5

Когда нажмете F5, то получите графическое представление сценария, набранного в окне OpenSCAD-редактора.

Вам доступны три типа перемещений в окне предпросмотра:

  1. Перетаскивание левой кнопкой мыши для вращения модели. В нижней строке окна будет меняться величина rotate.
  2. Перетаскивание правой кнопкой мыши для перемещения модели. В нижней строке окна будет меняться величина translate.
  3. Использование колеса прокрутки мыши для приближения и удаления модели. В нижней строке окна будет меняться величина distance.

Позиционирование объекта[править]

Мы уже увидели как создать простой кубоид. Наша следующая задача состоит в размещении идентичного кубоида по соседству с уже существующим:

Пример 1 — позиционирование объекта:
cube([2,3,4]);
translate([3,0,0])
cube([2,3,4]);

Позиционирование объекта в OpenSCAD

Отсутствие точки с запятой после команды переноса[править]

Обратите внимание на отсутствие точки с запятой после команды переноса (translate). Это связано с тем, что команда переноса связана со следующим объектом. Если точка с запятой не будет пропущена, то эффект смены позиции прекратится и второй кубоид будет размещен на той же позиции, что и первый.

Изменение цвета объекта[править]

Мы можем изменять цвет объекта, передавая команде color RGB-значение цвета. Вместо традиционных RGB-значений от 0 до 255 используются значения с плавающей точкой от 0.0 до 1.0 (результат деления традиционного RGB-значения на 255).

Пример 1 — изменение цвета объекта:
color([1,0,0]) cube([2,3,4]);
translate([3,0,0])
color([0,1,0]) cube([2,3,4]);
translate([6,0,0])
color([0,0,1]) cube([2,3,4]);

OpenSCAD меняет цвет объекта

Режимы просмотра[править]

Окно просмотра OpenSCAD предлагает пользователю различные режимы просмотра, которые влияют на отображение модели.

OpenCGS[править]

Данный режим просмотра (View -> OpenCGS) будет использовать библиотеку OpenCGS (открытая библиотека конструктивной сплошной геометрии) для генерации представления модели с применением OpenGL. Если библиотека OpenCGS не доступна или видеокарта/драйвер не поддерживают OpenGL, то в этом режиме модель не будет отображена.

CGAL-поверхности[править]

Режим CGAL-поверхности (View -> CGAL Surfaces) это базовый режим просмотра модели, в котором отображается модель при нажатии клавиши F6 (Компиляция и построение).

Только CGAL-сетка[править]

Режим Только CGAL-сетка (View -> CGAL Grid Only) позволяет увидеть модель, составленную только из ребер — эдаких строительных лесов на которые впоследствии «натягивается» поверхность.

Предварительный просмотр[править]

В режиме Предварительного просмотр (View -> Trown Together) модель строится и отображается очень быстро, но не всегда верно: какие-то грани или поверхности могут отображаться, хотя при полноценном построении должны быть удалены. Именно в этом режиме отображается модель при нажатии клавиши F5 (Компиляция и предварительный просмотр).

Introduction: OpenSCAD: Introduction and Notes

This started out as a way of me putting some notes online for the kind of things I found myself regularly searching for, mainly for personal use. It’s grown to a bit more of an introduction to OpenSCAD than I was planning so I thought I’d publish here and I hope it is of use to anyone interested in the area. If you have questions I’ll try and answer them in the comments bellow.

Intro

OpenSCAD is a free opensource CAD program, it runs on Windows, Mac and Linux.

Like many CAD packages an easy way to start is to build your object from 3D ‘primitive’ shapes, e.g. cubes, cylinders and spheres. A little different from many other packages it’s not directly interactive, you can’t grab a point or edge and drag it out. Instead you describe thing programmatically and OpenSCAD interprets your code. This may take a little getting used to but it means if you want an obscure feature you can just write it!

First two go-to references are:

  • OpenSCAD user manual wiki book
  • OpenSCAD cheat sheet

Instructables already has several guides including some some useful specifics such as:

  • Animating with OpenScad
  • Loft in OpenSCAD

If you find (or have written) others please message me and I’ll add to the list.

Step 1: Some Basics

A few quick basics…

  • Primitives
  • Comments
  • Modules & functions

Primitives

The three basic 3D primitives are:

  • Cube
  • Cylinder
  • Sphere

Sizes and co-ordinates are given ([X, Y, Z]) and each instruction ends with a semi-colon.

F5 shows a preview of your object and F6 will do a full render, I only do a full render when I’m exporting for 3D printing or laser cutting, it can take a little while based on the complexity of you object and the power of your machine.

A full description (and useful reference for all things OpenSCAD) can be found at: OpenSCAD user manual the section on primitives is at: Primitives.

Sphere

The simplest of the primitive shapes, pass it a size, either radius or diameter and press F5 to preview.

— Note: On a mac air it needs fn+F5 to preview.

sphere(d=10);

This preview doesn’t look very smooth, we can set the number of faces on an object with ‘$fn=’ inside the brackets. If you place a ‘$fn’ at the start of a project all objects after will aim for that number of faces unless specified otherwise.

sphere(d=10, $fn=200);

You can set this as high or as low as you want but be aware that calculating millions of faces will take much longer!

Cube

A cube can be described with:

cube(10);

This would be a cube, 10mm on each side. Pressing F5 will show a preview of the cube.

Alternatively you could use:

cube([10,20,30]);

This would make a cuboid with X=10mm, Y= 20mm and Z=30mm.

You will notice one corner is at 0,0,0. We can center any primitive with:

cube([10,20,30], center = true);

In this case the center of the cube is now at 0,0,0.

Cylinder

A cylinder can be described with using ‘r’ for the radius or, ‘d’ for the diameter. you also need to give it a height ‘h’.

cylinder(d = 10, h  = 10);

Again, this preview doesn’t look very smooth, we can set the number of faces on an object with $fn= inside the brackets.

cylinder(d = 10, h  = 10, $fn = 250);

You can also set it lower than the default, for example:

cylinder(d = 10, h  = 10, $fn = 3);

This gives a triangular prism. It’s maybe not quite the size you want but we can sort that kind of thing out in the modules section.

Cylinder — cone

You can give a cylinder two diameters to make a cone, d1 is the lower and d2 the upper.

cylinder (d1=40, d2=20, h=20);

Comments

It’s always handy to leave a few hints as to what you were aiming to do, OpenSCAD allows commenting in the code with either ‘//’ for one line or block commenting with ‘/* …… */’

// Single line commented out
/* Large block

removed from preview

and render */

Modules & functions

A handy way to organise code, make parts and reuse code is to use modules and functions, OpenSCADs name for reusable blocks of code. Enclosed in curly brackets and end with a semi colon.

I use modules to make up parts of a large objects, this means once I’m happy with a final assembly I can the use the module for printing or laser cutting etc.

module test_part(){

};

When you want to use the module call it with:

test_part();

A module will make a part (or sub-part etc.) but doesn’t return anything. OpenSCAD can also do functions, these will return a value, e.g doing a calculation.

function sine_vec_func (range)= [for (x = range) [ x, sin(x)]];

This world generate a list of vector point ([x,y}), we could check the out put with an echo:

sin_vector = sine_vec_func([0:180]);
echo (sin_vector);

So I assign the output of the function to a variable called sin_vector, by calling it and passing a range. Then I echo (print to terminal) the variable to check it’s what I think it should be.

Step 2: Moving Things Around

With a few basic shapes we now want to position and manipulate them. The main functions for this are:

  • Translate
  • Rotate
  • Scale

Translate

This moves the object to the co-ordinates X, Y, Z.

translate([10,20,0]) sphere(d=10);

So the center of the sphere is off set from 0,0,0 by 10 in the x axis, 20 in the y axis and 0 in the z axis.

Rotate

This rotates about an axis, X, Y, Z.

rotate([0,20,45]) cube([10,20,30);

Scale

This will scale your object along the X,Y or Z axis. This is a relative scaling, so ‘1’ is the original size, and e.g. ‘2’ double and ‘0.5’ would be half the original size.

scale([1,1,2]) sphere(d=10);

Step 3: Difference

This is possibly the most important function! It allows you to remove one shape from another.

An example would be adding a hole for a bolt:

difference(){
cube([30,30,3]);
translate([15,15,-0.1]) cylinder(d=3.2, h=3.2);
};

The syntax is that the first shape has all following shapes removed, in the above case a 30x30x3mm plate has a 3.2mm hole through the middle. To keep things neat, the object being remove should sit proud of the surfaces it is cutting though, in the above case I used a cylinder of 3.2mm to go though a 3mm plate, offsetting by 0.1mm so that the cylinder removed is 0.1mm above and bellow the plate. The second picture has a 3mm cylinder removed from a 3mm plate, as you can see there isn’t a hole. I think it’s left an infinitely thin surface because the command is unclear.

It’s also easy to do a difference with multiple shapes:

difference(){
cube([30,30,3]);
translate([15,15,-0.1]) cylinder(d=3.2, h=3.2);
translate([5,5,-0.1]) cube([2,3,3.2]);
translate([23,22,-0.1]) cube([2,3,3.2]);
};

If you are having problems getting an object in the correct place then ‘#’ will highlight it, this will make an object being differenced appear as an opaque red making easier to see where it is:

difference(){
cube([30,30,3]);
translate([15,15,-0.1]) cylinder(d=3.2, h=3.2);
translate([5,5,-0.1]) cube([2,3,3.2]);
#translate([23,22,2]) cube([2,3,3.2]);
};

Step 4: Importing Models

You may want to use an existing model such as an .stl or .dxf:

import("path/to.yourfile.stl", convexity = 3);

You can also drag your file into the code window to generate this.

The you can apply any functions you need, such as difference, scale and intersection.

Step 5: Modules I Use…

The more I use OpenSCAD the more I reused solutions from previous designs, my original aim for these notes was to share some of these modules, so here is a collection of things I’ve found or written which now make drawing quicker and easier:

Copy Mirror

This is from the OpenSCAD forum from Greg Frost, it copies and mirrors the part follows the function.

module copy_mirror(vec=[0,1,0]){
children();
mirror(vec) children();
};

This is one of my go-to functions for anything symmetrical. You can change the axis around which the copy is mirrored by changing the ‘vec’, leaving it empty will mirror along the Y axis. A quick use example would if I have four mount points arranged around a center I can draw one, mirror it across the Y axis then mirror this pair across the X axis.

Copy translate

Based on Greg’s module this will clone the original part and move it to the desired vector.

module copy_translate(vec=[0,0,0]){
children(); // This maintains the original part
translate(vec) children();
};

So to copy a part an move it 50mm along the X axis you would use:

copy_translate([50,0,0]) cube(20);

This is quick and useful for cloning once or twice, if I was doing more I’d probably use a for loop.

For loops

This idea of using a module part to clone a part can be built on with a for loop to repeat a part many times:

for (i=[0:20:100]){
translate([i,0,0]) part();
};

So this would make ‘part()’ and place it at 0, 20, 40, 60, 80 and 100 along the X axis.

The ‘for loop’ outputs the value ‘i’, this is each value in the range 0:100 with a step size of 20. The value of ‘i’ is then used as the x value of a translate. The value of ‘i’ could be used for anything, scale, rotate, translate. It can also be changed e.g. multiplied by 10 ( i*10).

Rounded boxes

This takes a little longer to render than a plain cube but looks a bit nicer is some places.

module rounded_edge_box(x_dim, y_dim, z_dim, radius){
hull(){
//Bottom
translate([radius,radius,radius]) sphere(radius);
translate([x_dim-radius,radius,radius]) sphere(radius);
translate([radius,y_dim-2*radius,radius]) sphere(radius);
translate([x_dim-radius,y_dim-2*radius,radius]) sphere(radius);

//Top
translate([radius,radius,z_dim-radius]) sphere(radius);
translate([x_dim-radius,radius,z_dim-radius]) sphere(radius);
translate([radius,y_dim-2*radius,z_dim-radius]) sphere(radius);
translate([x_dim-radius,y_dim-2*radius,z_dim-radius]) sphere(radius);
};
};

There was an excellent video by MakersMuse on the pros and cons of chamfer and filleted edges for 3D printing.

Ruler

I like to pull in an object to show scale of a design, one of my preferred items is a 30cm ruler (or 12″ if you are that way inclined). I have a ruler of these dimensions to hand in the real world and I can use it to double check I’ve got critical dimensions right.

module ruler(ruler_length = 300, ruler_thickness = 2, ruler_height = 20){

translate([0,0,ruler_thickness])rotate([-90,0,0])difference(){
union(){
cube([ruler_length, ruler_thickness, ruler_height]);
translate([ruler_length,ruler_thickness,ruler_height/2])rotate([90,0,0]) linear_extrude(height = ruler_thickness)circle(r=ruler_height/2);
};
translate([ruler_length+5,ruler_thickness+0.5,ruler_height/2])rotate([90,0,0])color("Gainsboro")cylinder(r=2, h= ruler_thickness+1, $fn=24);
// Measurement ticks long
for (i = [0 : 10 : ruler_length]){
translate([i, -0.05, 0]) {
color("Gray")cube([0.1, 0.1, ruler_height]);
};
};

// Measurement ticks short
for (i = [0 : 1 : ruler_length]){
translate([i, -0.05, 0]) {
color("Gray")cube([0.1, 0.1, 5]);
//translate([0,0,12]) color("Gray")cube([0.1, 0.1, 5]);
};
};

// Measurement ticks v.short
for (i = [0 : 0.5 : 50]){
translate([i, -0.05, 0]) {
color("Gray")cube([0.1, 0.1, 2.5]);
};
};

// Measurement Numbers
for (i = [10 : 10 : ruler_length]){
translate([i, -0.05, 0]) {
color("Black")translate([0,ruler_thickness,10.25]) rotate([90,0,0]) linear_extrude(height = 2.2)text(str(i), size=2, halign = "center");
};
};
};
};

Protractor

Similar to the ruler, this is great for scale and allows me to double check I’ve got angles correct.

module protractor(){
translate([0,0,1]) difference(){
color("Gainsboro", 0.5)cylinder(r=50, h= 2, center= true, $fn=128);
color("Gainsboro", 0.5)translate([0,-25,0])cube([100, 50, 4], center= true);

// Ruler long ticks & Numbers
for (i = [10 : 10 : 90]){
translate([-50+i, -0.05, 1.01])rotate([-90,0,0])color("Gray")cube([0.1, 0.1, 5]);
color("Black")translate([-50+i, 5.5, -0.01]) rotate([0,0,0]) linear_extrude(height = 1.05)text(str(i), size=2, halign = "center");
};

// Ruler short ticks
for (i = [0 : 5 : 95]){
translate([-50+i, -0.05, 1.01])rotate([-90,0,0])color("Gray")cube([0.1, 0.1, 2.5]);
};
for (i = [0 : 1 : 99]){
translate([-50+i, -0.05, 1.01])rotate([-90,0,0])color("Gray")cube([0.1, 0.1, 1]);
};

// Protractor Large ticks and numbers
for (i = [10 : 10 : 170]){
rotate([0,0,90-i])translate([0,5+42.5,1])color("Gray")cube([0.1, 5, 1.1], center = true);
color("Black")rotate([0,0,90-i])translate([0,42.5,0])linear_extrude(height = 1.05)text(str(i), size=2, halign = "center");
rotate([0,0,90-i])translate([0,5+22.5,1])color("Gray")cube([0.1, 25, 1.1], center = true);
};
// Protractor small ticks
for (i = [5 : 5 : 175]){
rotate([0,0,90-i])translate([0,5+44,1])color("Gray")cube([0.1, 2.5, 1.1], center = true);
};
// Protractor v.small ticks
for (i = [1 : 1 : 179]){
rotate([0,0,90-i])translate([0,5+45,1])color("Gray")cube([0.1, 1, 1.1], center = true);
};
};
};

Nut/Bolt head

This is just a simple way to take an edge-to-edge size and get the diameter of the circle needed, then doing a 6 faced cylinder (well 8 with top and bottom). It may or may not be easier to extrude a polygon but I like doing this way…

function indiameter_to_diameter(d) = d/(sqrt(3)/2);
module hexagon(indiameter, height = 2){
diameter = indiameter_to_diameter(indiameter);
translate([0,0,0]) cylinder(d=diameter, h = height, $fn=6);
};

So an M3 bolt has a 5.5mm head so I would do hexagon(5.5); most of the time I make a bolt module or a lookup so an M3 bolt has the right size shaft, head etc.

module M3_nut(){
difference(){
hexagon(indiameter = 5.5, height = 3);
translate([0,0,-1])cylinder(d=3, h=4);
};

Standoff

Using the hexagon module and indiameter function. Being able to reuse code to quick make new objects is one of the major strengths of OpenSCAD!

module M3_standoff(body_height=5, screw_height=5){<br>    body_size = 5.5;
bolt_diameter = 3;

hexagon(indiameter = body_size, height = body_height);
translate([0,0,-screw_height])cylinder(d=bolt_diameter, h=screw_height);
};

I could (and perhaps should) have made a universal standoff module then specific modules for the sizes I have.

Torus

A doughnut shape, sometimes handy particularly if you want a lip on a curved edge. It’s based on the information in the wiki: OpenSCAD User Manual/2D to 3D Extrusion

module torus(thickness = 2, diameter = 20){
rotate_extrude(convexity = 10, $fn = 100)
translate([diameter/2 - thickness/2, 0, 0])
circle(d = thickness, $fn = 100);
};

There’s some defaults set just so it makes something as you are building your parts.

Different views

It depends on what you are building and how it will be used. For me most of my drawings will eventually be 3D printed or laser cut. So I make multiple modules of different part layouts. The first one I call «design_view()» this lays out parts as they will be used when they exist, showing each part in the finial layout. I make another called «print_layout()» which has the parts spaced orientated for printing. This allows me to quickly move from seeing (or exporting pictures) of a design to something I can send to print.

I’ll add to this as I find or make useful things. I have a load of old designs I need to dig through, I’m getting better (I think) so many of the older ones aren’t great and i only tend to update them if I encounter a similar problem again.

Step 6: A Worked Example — Lamp

There’s a nice lamp in the fusion 360 tutorial, this is sort of similar. There will be other ways to make the shapes, many of them much better, I’m trying to give an examples for people to play with. If you know of a better way add it to the comments!

Shade

The fusion tutorial uses a 2d shape with a rotate extrude so I will do something similar. OpenScad has three 2D primitives, circle, square and polygon. We could build the shade from scaled circles but I want to try plotting it as a curve. One way to do this is to use a function:

function sine_vec_points (range)= [for (x = range) [ x, sin(x*1.25)*100]];

This will return a set of vector co-ordinates for the range given. So for every value in ‘range’ we return [ x (i.e the value), and f(x) which in this case is sin(x) with a multiplier. The advantage of this is that we can swap, change or reuse my curve more easily.

Next we use the vector to plot a 2D curve. The vector points are made and used to plot a polygon. This module has a default value for range given [0:180], if you call the module with a range it overrides this.

module shade_base_2d(range = [0:180]){
curve_vec_points = sine_vec_points(range);
rotate([0,0,21]) polygon(points=curve_vec_points);
};

The base shape of the lamp is a rotate_extrude of the curve…

module shade_base(range = [0:180]){
curve_vec_points = sine_vec_points(range);
rotate_extrude(angle = 360, convexity = 4) rotate([0,0,21]) polygon(points=curve_vec_points);
};

The lamp shade is made from differencing two of the extrusions off set by -2mm and making a hole in the middle for an LED or bulb:

module shade(){<br>    difference(){
shade_base();
translate([0,0,-2])shade_base();
translate([0,0,0]) cylinder(d=50, h=150);
};
};

Base

Starting with the back foot, make a hull between two spheres.

module base(){

// Back leg
hull(){
translate([0,0,20]) sphere(d=20);
translate([-50,0,5]) sphere(d=10);
};
};
base();

To make the foot a little more streamlined, scale the sphere:

module base(){

// Back leg
hull(){
translate([0,0,20]) sphere(d=20);
translate([-50,0,5]) scale([1,0.75,1]) sphere(d=10);
};
};
base();

Next add two front feet in a similar manner, make two spheres and hull between them:

module base(){
// Back leg
hull(){
translate([0,0,20]) sphere(d=20);
translate([-50,0,5]) scale([1,0.75,1]) sphere(d=10);
};
// Front left
hull(){
translate([0,0,20]) sphere(d=20);
translate([60,-40,5]) rotate([0,0,-30]) scale([1,0.5,1]) sphere(d=10);
};
// Front right
hull(){
translate([0,0,20]) sphere(d=20);
translate([60,40,5]) rotate([0,0,30]) scale([1,0.5,1]) sphere(d=10);
};
};
base();

This time I’ve rotated the scaled spheres a little.

Arm

Most of the dimensions for the arm were set by how I laid out the base and shade. The lower arm is a cylinder, scaled 1.5 fold along the x axis to make it oval. The upper arm is two parallel scaled cylinders.

I made a joining plate for articulation:

module plate(){
rotate([90,0,0]) difference(){
hull(){
translate([0,10,0]) cylinder(d=10, h=3);
translate([10,0,0]) cylinder(d=10, h=3);
translate([-10,0,0]) cylinder(d=10, h=3);
};

translate([0,10,-1]) cylinder(d=3, h=6);
translate([10,0,-1]) cylinder(d=3, h=6);
translate([-10,0,-1]) cylinder(d=3, h=6);
};
};

This used a hull on three cylinders, the same co-ordinates were used to difference out some bolt holes.

Assembly

With the parts all sorted it’s now time to put them together, I’ve also coloured them at this stage. Here the lengths and angles of the arm parts are tweaked to make everything join. There’s a nice color table in the wiki book to help get things looking nice in the preview.

module design_view(){
translate([55,0,120]) rotate([0,-30,0]) scale([0.25,0.25,0.25]) color("WhiteSmoke") shade();
translate([0,0,20]) rotate([0,0,0]) arm();
translate([0,0,0]) rotate([0,0,0]) color("DimGray") base();
};

Step 7: Exporting for the Real World

3D Printing

To export an object you need to first render it with F6. This can take a little while depending on the complexity of your design, how it’s been made ($fn, hull etc.) and your hardware.

Once rendered the object can be exported as an .stl and then imported into your favorite slicer!

With most (all?) of the printers I’ve used so far I find smaller holes (M2 and M3) need to be made a smidge bigger for printing, It’s worth trying a quick test print early on. For my Ender3 I use 3.5mm as an M3 through hole (it should be 3.4mm) because I get a little slump and would need to use a needle file to get things perfect.

Laser cutting

Exporting for laser cutting needs an extra couple of steps.

BE AWARE: OpenSCAD is inherently dimensionless, most packages assume you are working in mm but every so often you find one which doesn’t. I had an issue with a another package reading my dimensions as px, using 72px inch and making everything tiny, and I heard a horror story of a drawing being imported with dimensions treated as inches not mm and it wasn’t caught until after manufacture.

I make all my parts as modules so once the design is finished I make a cube the size of the stock (e.g. 500mm x 500mm acrylic) then lay out my parts inside the boundaries. Once I’m happy I’ve got the best/most efficient use of material then I do a projection. This make a 2D version of your 3D parts.

This works really well for sheet material, I then do a projection through it to give a 2D shape with all the holes, cut outs etc.

projection() part();

So an example would be a 5mm sheet with a few holes:

difference(){    
cube([100,100,5]);
for (i = [10:10:90]){
translate([i,50,-1]) cylinder(d=3.4, h=7);
};
};

Then the projection would be a 2D object which could be exported:

projection(cut=true) difference(){
cube([100,100,5]);
for (i = [10:10:90]){
translate([i,50,-1]) cylinder(d=3.4, h=7);
};
};

The pictures look similar but the first one has thickness, the second one is 2D.

On my system this projection takes a lot of thinking about once parts get complex.

For some laser cutting services you sometimes need to change the colour of the lines, red for cut though and green for engraving, so I export the projection as an svg file (scalable vector graphic) then open and edit in Inkscape.

Other places prefer .dxf, so far every time I’ve imported a .dxf it’s asked about the scaling to mm and all has been good.

Введение

В настоящие время существует большой выбор мощных, универсальных 3D-редакторов для создания и анимирования 3D-сцен, которые в подавляющим случае можно отнести к программам с графическим интерфейсом. Такой подход к созданию 3D сцен имеет одновременно как большое преимуществом так и серьезный недостаток, заключающийся в том, что с одной стороны вам доступны сотни различных объектов и манипуляций над ним, а с другой стороны для качественной работы их все нужно знать и использовать, что требует весьма длительного времени на обучение.

В основу 3D-script редактора OpenSCAD положена абсолютно обратная парадигма, в данном редакторе полностью отсутствует какой либо графический интерфейс для создания 3D-объектов, нет ни одной «кнопки» или пункта «меню» при помощи которого вы могли бы создать какой либо графический примитив и произвести над ним какую либо манипуляцию. Создание всех объектов в OpenSCAD и манипуляции над ними происходят только посредством заранее подготовленного script-кода.

Предлагаю Вам самим ознакомиться с представленным ниже руководством и самому решить оправдан либо такой подход к созданию и анимации 3D-сцен.

Вы можете скачать OpenSCAD, либо воспользоваться его ONLINE версией, но учтите что она немного отличаются в синтаксисе от представленных ниже примеров.

Инструкция по скачиванию, установке и настройки программы не прилагается, подразумевается что если вы решили овладеть OpenScad, то значит вы достаточно технически грамотны чтобы разобраться в таких вопросах самостоятельно.

Данное пособие рассчитано на читателей минимально знакомых с синтаксисом си-подобных языков.

1. Графические примитивы

Напишем две строки кода первой сцены/программы:

$fn = 32;
sphere();

Запустим их на исполнение и получим картинку примерно следующего вида:

Очевидно что строка-2 отвечает за создание сферы, а поскольку никакие параметры, при создании сферы, не были явно указаны, она была создана с параметрами по умолчанию.

Значение первой строки это специальная переменная (Special variables), о чем свидетельствует символ доллара, определяющая на сколько секторов будет разбита любая окружность. Как видно мы установили ее значение равным 32 для большей визуальной гладкости криволинейных поверхностей.

Не стоит беспокоиться о необходимости запоминания сотен специальных переменных, их всего 10 штук, следующих типов:

  • $fa, $fs, $fn гладкость криволинейных поверхностей;

  • $t время;

  • $vpr, $vpt,, $vpd,, $vpf место расположения и ориентация камеры;

  • $children номер «наследника/последователя»;

  • $preview выбор кнопки рендера

Напишим новый код и запустим его:

$fn = 32;
cylinder();

Как можно заметить поведение цилиндра более сложно чем сферы, во первых он считает своей осью симметрии исключительноось-Z, а во вторых располагает одну из своих торцевых поверхностей в плоскости-XY с центром в начале координат.

Задействуем теперь все доступные параметры примитива, которых не так и много, чтобы увидить все доступные модификации по умолчанию:

$fn = 32;
cylinder(h = 3, d1 = 2, d2 = 1, center = true);

Как можно заметить, цилиндр поддерживает крайне небольшое количество модификаторов параметров, среди которых даже нету модификатора координат.

Для полноты картины расмотрим третий графический примитив cube().

$fn = 32;
cube([3,2,1],  center = true)

Кроме выше указанных графических примитивов существуют еще несколько графических примитивов 3D и 2D, расматривать которые в данной статье мы не будем.

2. Манипуляторы примитивы

Добавте в код манипулятор translate() и самостоятельно измените его параметры отслеживая изменения. Обратите внимание что параметры должны быть не только переданы модификатору, посредством размещения внутри оператора(), но и быль заключены в оператор[] который преобразует три одиночных числа x,y,z в вектор вида [x,y,z], принимаемый на входе модификатор translate(). Если нарушить данное правило, то модификатор translate() расширит первое одиночное число X до вектора [x,0,0].

$fn = 32;
translate([3,2,1])
    cylinder(h = 3, d1 = 2, d2 = 1, center = true); 

Обратите внимание, что после модификатора translate() не нужно указывать оператор; это вызвано тем, что модификатор оказывает воздействие на первый же примитив следующий за ним, если же за модификатором будет следовать следующий модификатор, то их общее действие сложиться и будет применено к первому же примитиву, следующему за цепочкой модификаторов.

Добавим в код второй манитулятор rotate(), и попробуем две различных комбинации их сочетания:

$fn = 32;
rotate([90, 0, 0])
    translate([3,2,1])
        cylinder(h = 3, d1 = 2, d2 = 1, center = true);
        
translate([3,2,1])
    rotate([90, 0, 0])
        cylinder(h = 3, d1 = 2, d2 = 1, center = true);

Как видно, два абсолютно одинаковых модификатора, но в разном последовательности оказывают различное воздействие на графический примитив. Это естественное следствие векторных вычислений, где в отличии от скалярного, результат меняется в зависимости от перестановки слагаемых.

Поэкспериментируйте с параметрами и сочетаниями модификаторов самостоятельно, чтобы понять как и в какой последовательности они воздействуют друг на друга.

3. Составные объекты (модули)

Напишем код создающий объект состоящий из трех примитивов, моделирующий стержень круглого сечения и переменного диаметра.

$fn = 32;
cylinder(h = 3, d = 2);     
translate([0, 0, 3])
    cylinder(h = 2, d1 = 2, d2 = 1);
translate([0, 0, 3 + 2])
    cylinder(h = 1, d = 1);

Обратите внимание что поскольку действие модификаторов распространяется только на примитив который следует за ним и заканчивается при достижении ;. в строке-5 было необходимо сложить высоту первого и второго цилиндра, для того чтобы третий оказался выше них обоих.

Изменим код чтобы продемонстрировать как можно распространить действие одного модификатора на несколько примитивов.

$fn = 32;
cylinder(h = 3, d = 2);     
translate([0, 0, 3]) {
    cylinder(h = 2, d1 = 2, d2 = 1);
    translate([0, 0, 2])
        cylinder(h = 1, d = 1);
};

Заключение группы модификаторов и примитивов в один блок, посредством фигурных скобок, позволяет оперировать ими как одним целым.

Введем в код символьные константы, для придания ему большей читабельности и облегчения его дальнейшего совершенствования.

Стоит отметить что хотя в англоязычном руководстве символьные константы называются переменными, фактически это константы значение которым можно присвоить только при инициализации.

$fn = 32;

diam1 = 2;
diam2 = 1;
heig1 = 3;
heig2 = 2;
heig3 = 1;

cylinder(h = heig1, d = diam1);     
translate([0, 0, heig1]) {
    cylinder(h = heig2, d1 = diam1, d2 = diam2);
    translate([0, 0, heig2])
        cylinder(h = heig3, d = diam2);
};

Прорисовка объекта совершенно не изменилась, но зато теперь мы можем изменять его весь целиком меняя значения всего лишь нескольких констант.

Инкапсулируем фигуру, сделав из нее «шаблон», для будущего применения изменив код следующим образом.

$fn = 32;

module Arm(diam1 = 2, diam2 = 1, heig1 = 3, heig2 = 2, heig3 = 1) {
    cylinder(h = heig1, d = diam1);     
    translate([0, 0, heig1]) {
        cylinder(h = heig2, d1 = diam1, d2 = diam2);
        translate([0, 0, heig2])
            cylinder(h = heig3, d = diam2);
    };
};

Как можно заметить после этих изменений объект пропал. Это произошло потому что теперь код лишь «описывает» объект, но не создает его, добавим в самый конец файла еще одну строку и повторим рендер.

Arm();

Стоит заметить что мы не только определили символические имена констант, но и присвоили им значения по умолчанию, что позволяет нам создавать объект с параметрами по умолчанию.

4. Проверка типа параметра

Напишем код для создания стержня который может опционально заканчиваться «втулкой», внесем изменение в код в два этапа, для реализации указанного функционала.

$fn = 32;

module Arm(list = [[1,2],[1,2,3]]) {
    echo(Arm = list);
    diam =  list[0];
    heig =  list[1];
    
    cylinder(h = heig[0], d = diam[0]);     
    translate([0, 0, heig[0]]) {
        cylinder(h = heig[1], d1 = diam[0], d2 = diam[1]);
        translate([0, 0, heig[1]])
            cylinder(h = heig[2], d = diam[1]);
    };
};

Arm();

В указанном коде количество передаваемых параметров сократилось до одного, которому присвоено символическое имя list, но одновременно указанный параметр представляет собой сложным вектором, состоящим из двух простых векторов.

В начала модуля мы раскладываем сложный вектор на два простых, с символическими более простыми и понятными именами diam, heig, и осуществляем все дальнейщие посроения и манипуляции уже посредством этих векторов.

Под термином сложный/простой подразумевается содержит ли вектор в себе подвекторы или состоит только из чисел.

Особо стоит отметить модификатор echo, как несложно догадаться он выводит в консоль содержимое вектора list. Сейчас значение list известно нам заранее, но в будущем при отладке более сложного кода всегда полезно видеть входные параметры.

Найдите консоль и посмотрите что было передано.

Напишем дополнительные элементы кода для реализующими требуемого функционала.

$fn = 32;

module Arm(list = [[[1,2],[1,2,3]], 3, 2]) {
    echo(Arm = list);
    diam =  list[0][0];
    heig =  list[0][1];
    fork = [list[1], list[2]];
    
    if (is_num(fork[0]))
        rotate([0, 90])
            cylinder(h = fork[0], d = diam[0], center = true);
            
    cylinder(h = heig[0], d = diam[0]);     
    translate([0, 0, heig[0]]) {
        cylinder(h = heig[1], d1 = diam[0], d2 = diam[1]);
        translate([0, 0, heig[1]]) {
            cylinder(h = heig[2], d = diam[1]);
            
            if (is_num(fork[1]))
                translate([0, 0, heig[2]])
                    rotate([0, 90])
                        cylinder(h = fork[1], d = diam[2], center = true);
        };
    };
};

Arm();

В строке-9 и строке-19, посредством оператора is_num мы проводим проверку определен ли параметр фактически и является ли он числом, и если параметр определен производим отрисовку дополнительных элементов объекта.

5. Рекурсивный вызов и передача объектов по вектору

Напишем код для создания стержня состоящего из пяти участков и имеющий три различных диаметра. На первый взгляд имеющийся на данный момент код в принципе не соответствует такой задаче и нужно написать новый, но давайте не будем выбрасывать существующий код, а попробуем его усовершенствовать.

$fn = 32;

module Arm(list = [[[1,2],[1,2,3],[1,[2,1],undef]], undef, 2]) {
    echo( Arm = list);
    diam =  list[0][0];
    heig =  list[0][1];
    next =  list[0][2];
    fork = [list[1], list[2]];
    
    if (is_num(fork[0]))
        rotate([0, 90])
            cylinder(h = fork[0], d = diam[0], center = true);
    
    cylinder(h = heig[0], d = diam[0]);     
    translate([0, 0, heig[0]]) {
        cylinder(h = heig[1], d1 = diam[0], d2 = diam[1]);
        translate([0, 0, heig[1]])
        
        if (is_list(next)) {
            diam = [diam[1],next[0]];
            heig = [heig[2],next[1][0],next[1][1]];
            next =  next[2];
            Arm([[diam,heig,next],undef,fork[1]]);
        }
        else {
            cylinder(h = heig[2], d = diam[1]);
            
            if (is_num(fork[1]))
                translate([0, 0, heig[2]])
                    rotate([0, 90])
                        cylinder(h = fork[1], d = diam[1], center = true);
        };
    };
};

Arm();

Применив в строке-23 рекурсивный вызов модуля Arm можно создавать объекты состоящие из неограниченного числа однотипных блоков.

6. Вложенные модули и сокрытие имен

Напишем код для создания плоской закругленной пластины Slab, с возможностью рекурсивного вызова для добавления дополнительных звений. Поскольку код Slab аналогичен коду Arm, предлагаю читателю разобраться с ним самостоятельно.

$fn = 32;

module Slab (list = [3,1,.5,[30,30],[2,30,undef]]) {
    echo(Slab = list);
    length    = list[0];
    diameter  = list[1];
    thickness = list[2];
    angle     = is_list(list[3]) ? list[3]:
                 is_num(list[3]) ? [0, list[3]]: [0,0];
    next      = list[4];
    
    rotate([0, 0, angle[0]]) {
        cylinder(h = thickness, d = diameter, center = true);
        translate([length / 2, 0, 0])
            cube([length, diameter, thickness], center = true);
        translate([length, 0, 0])
            if (is_list(next))
                rotate([0, 0, angle[1]])
                    Slab([next[0], diameter, thickness, next[1], next[2]]);
            else
                cylinder(h = thickness, d = diameter, center = true);
    };
};

Slab();

Стоит обратить внимание что значение константы angle, определяемое в строках-8,9, зависит от того является ли переданный параметр вектором.

Напишем теперь код создающий две параллельных пластинки Fork, которые в последствии применим в Arm.

module Fork (list = [1,[1,1,.5,[30,30],[2,30,[1,-30]]]]) {
    echo(Fork = list);
    gap       = list[0];
    thickness = list[1][2];
    slab      = list[1];
        
    translate([0, 0,  (thickness + gap) / 2])
        Slab(slab);
    translate([0, 0, -(thickness + gap) / 2])
        Slab(slab);
};
Fork();

Как легко заметить для создания модуля Fork, необходим модуль Slab. При этом модуль Slab имеет глобальную видимость и доступен для всех прочих модулей, что может создать конфликт имен. Инкапсулируем модуль Slab внутри модуля Fork.

$fn = 32;

module Fork (list = [1,[1,1,.5,[30,30],[2,30,[1,-30]]]]) {
    echo(Fork = list);
    gap       = list[0];
    thickness = list[1][2];
    slab      = list[1];
        
    translate([0, 0,  (thickness + gap) / 2])
        Slab(slab);
    translate([0, 0, -(thickness + gap) / 2])
        Slab(slab);
    
    module Slab (list = [3,1,.5,[30,30],[2,30,undef]]) {
        echo(Slab = list);
        length    = list[0];
        diameter  = list[1];
        thickness = list[2];
        angle     = is_list(list[3]) ? list[3]:
                     is_num(list[3]) ? [0, list[3]]: [0,0];
        next      = list[4];
        
        rotate([0, 0, angle[0]]) {
            cylinder(h = thickness, d = diameter, center = true);
            translate([length / 2, 0, 0])
                cube([length, diameter, thickness], center = true);
            translate([length, 0, 0])
                if (is_list(next))
                    rotate([0, 0, angle[1]])
                        Slab([next[0], diameter, thickness, next[1], next[2]]);
                else
                    cylinder(h = thickness, d = diameter, center = true);
        };
    };
};
Fork();

Теперь попытка создания модуля Slab за пределами модуля Fork будет приводить к ошибке.

По умолчанию все символические имена существуют только в пределах объявленного блока, а при совпадении имен более «нижний» уровень перекрывает более «высокий».

7. Подключение дополнительных файлов

Сохраним код содержащий определение Fork в отдельном файле с именем Fork.scad

Напишем код который позволит нам присоединить к «верхнему» концу Arm вилку Fork применив директиву include.

$fn = 32;

module Arm(list = [[[1,2],[1,2,3],[1,[2,1],undef]],
                  undef, 
                  [1,[1,1,.5,[-30,30],[1,30,[1,-30,undef]]]]]) {
    echo( Arm = list);
    diam =  list[0][0];
    heig =  list[0][1];
    next =  list[0][2];
    fork = [list[1], list[2]];
    
    if (is_num(fork[0]))
        rotate([0, 90])
            cylinder(h = fork[0], d = diam[0], center = true);
    
    cylinder(h = heig[0], d = diam[0]);     
    translate([0, 0, heig[0]]) {
        cylinder(h = heig[1], d1 = diam[0], d2 = diam[1]);
        translate([0, 0, heig[1]])
        
        if (is_list(next)) {
            diam = [diam[1],next[0]];
            heig = [heig[2],next[1][0],next[1][1]];
            next =  next[2];
            Arm([[diam,heig,next],undef,fork[1]]);
        }
        else {
            cylinder(h = heig[2], d = diam[1]);
            
            if (!is_undef(fork[1]))
                translate([0, 0, heig[2]])
                    rotate([0, -90])
                        if (is_list(fork[1])) {
                            heig = fork[1][0];
                            cylinder(h = heig, d = diam[1], center = true);
                            Fork(fork[1]); 
                        }
                        else
                            cylinder(h = diam[1], d = diam[1], center = true);
        };
    };
    include<Fork.scad>;
};

Arm();

8. Наследование

Предположим необходимо создать двухзвенный манипулятор, текущая версия модуля Arm вполне работоспособна и позволяет создать два звена манипулятора, но она не позволяет объединить их в один объект посредством какой либо простой манипуляции.

При попытки создать два звена манипулятора, они будут сгенерированы каждый сам по себе и совершенно не будут учитывать факт существования друг друга, а также какой либо иерархии, когда одно звено должно быть главным и способным перемещаться самостоятельно, а второе зависимым и учитывать перемещение главного.

Реализуем требуемый функционал посредством технологии наследования реализованной в операторе children, добавив его в существующий код.

$fn = 32;

module Arm(list = [[[1,2],[1,2,3],[1,[2,1],undef]],
                  1, 
                  [1,[1,1,.5,[-30,30],[2,30,[1,-30]]]]]) {
    echo( Arm = list);
    diam =  list[0][0];
    heig =  list[0][1];
    next =  list[0][2];
    fork = [list[1], list[2]];
    
    if (is_num(fork[0]))
        rotate([0, 90])
            cylinder(h = fork[0], d = diam[0], center = true);
    
    cylinder(h = heig[0], d = diam[0]);     
    translate([0, 0, heig[0]]) {
        cylinder(h = heig[1], d1 = diam[0], d2 = diam[1]);
        translate([0, 0, heig[1]])
        
        if (is_list(next)) {
            diam = [diam[1],next[0]];
            heig = [heig[2],next[1][0],next[1][1]];
            next =  next[2];
            Arm([[diam,heig,next],undef,fork[1]])
                children();
        }
        else {
            cylinder(h = heig[2], d = diam[1]);
            translate([0, 0, heig[2]])      
                if (is_undef(fork[1])) 
                    children();
                else {
                    if (is_list(fork[1])) {
                        heig = fork[1][0];
                        rotate([0, -90])
                            cylinder(h = heig, d = diam[1], center = true);
                        Fork(fork[1])
                            children();
                    }
                    else {
                        rotate([0, -90])
                            cylinder(h = diam[1], d = diam[1], center = true);
                        children();
                    };
                };
        };
    };
    include<Fork.scad>;
};

Arm() Arm();

Добавление в оператора children() позволила разместить второе звено манипулятора на месте второй, зависимой оси первого манипулятора.

Впрочем полученный код не полон, в случае попытки добавить манипулятору вилку, не важно на каком конце, второе звено манипулятора разместиться не на конце вилки, а на оси втулки. Так происходит потому что код вилки не имеет функционал наследования, добавим его и модернизируем код Arm для поддержки нового функционала.

$fn = 32;

module Fork (list = [1,[1,1,.5,[30,30],[2,30,[1,-30]]]]) {
    echo(Fork = list);
    gap       = list[0];
    thickness = list[1][2];
    slab      = list[1];
        
    rotate([0, -90]) {
        translate([0, 0,  (thickness + gap) / 2])
            Slab(slab);
        translate([0, 0, -(thickness + gap) / 2])
            Slab(slab)
                translate([0, 0,  (thickness + gap) / 2])
                    rotate([0, 90])
                        children();
    };
    
    module Slab (list = [3,1,.5,[30,30],[2,30,undef]]) {
        echo(Slab = list);
        length    = list[0];
        diameter  = list[1];
        thickness = list[2];
        angle     = is_list(list[3]) ? list[3]:
                     is_num(list[3]) ? [0, list[3]]: [0,0];
        next      = list[4];
        
        rotate([0, 0, angle[0]]) {
            cylinder(h = thickness, d = diameter, center = true);
            translate([length / 2, 0, 0])
                cube([length, diameter, thickness], center = true);
            translate([length, 0, 0]) {
                if (is_list(next)) {
                    rotate([0, 0, angle[1]])
                        Slab([next[0], diameter, thickness, next[1], next[2]])
                            children();
                }
                else {
                    cylinder(h = thickness, d = diameter, center = true);
                    children();
                };
            };
        };
    };
};

0. Анимация

Это маленькая затравка для подогрева интереса к следующему посту. Замените последнию строку кода в файл Arm.scad, создающию два объекта Arm, на строку указанную ниже и запустите анимацию.

rotate([$t * 360]) Arm() rotate([$t * 360]) Arm();

Послесловие

Данный пост абсолютно не претендует на полное и сичерпывающие описание OpenSCAD, пишите вопросы в комментариях и я постораюсь дать ответы. Небольшая шпаргалка для самостоятельного изучения.

Понравилась статья? Поделить с друзьями:
  • Руководство по эксплуатации опель фронтера а дизель
  • Мануал toyota corolla 2007
  • Нафталановая мазь для суставов инструкция по применению цена
  • Gold egf eye spot patch инструкция по применению
  • Поворотники на ардуино нано пошаговая инструкция