
Тут немного о том, как я сделал библиотеку для проектировки простой мебели из ДСП не визуальным методом, а в виде PHP-скрипта.
В далёкой-далёкой галактике...
Точно уже не помню, когда именно это произошло, но если и не 10 лет назад, то близко к этому. В какой-то момент я решил, что больше не хочу покупать себе готовую мебель из ДСП. Выбирать её слишком сложно, для этого должно сойтись очень много звёзд: она должна помещаться в квартире, но при этом быть не слишком маленькой, иметь необходимый функционал, внешний вид и цвет, а ещё вписываться в бюджет. И вот чтобы совпало всё — бывает крайне редко. Часто совпадает большая часть условий, в остальном приходится идти на компромисс. И я решил — доколе? Может и не всё, но что-то я могу сделать сам! Первые мои попытки были просты и примитивны — я просто покупал мебельные щиты и полки разных размеров в строительных магазинах и делал всё из них. Как правило, я даже ничего не проектировал, весь план был только у меня в голове. Я не заморачивался с кромками, поэтому старался приводить свои идеи к существующим размерам полок, чтобы если и требовались отрезы, то эти стороны не были бы видны снаружи. Какое-то время я делал этих квадратных несуразных Буратин, но постепенно я понял, что все мои идеи становятся заложниками этих существующих размеров полок, за которые нельзя было выходить, а вся мебель была топорно-квадратная, а иногда скругления смотрелись бы куда эстетичнее, и уже пора бы двигаться дальше. Двигаться в сторону проектирования мебели и заказа распилов тех размеров, которые мне были нужны. Отверстия для конфирмата я был в состоянии просверлить сам, а вот скругления и кромкование мне бы хотелось, чтобы было сделано за меня. Я стал искать программу для проектирования мебели и остановился на старенькой маленькой программке, которая называлась «Астра Конструктор Мебели». Но долго я на ней не задержался.
Путь к OpenSCAD
К этому времени у меня уже появился 3D-принтер, и я параллельно искал программу для проектирования моделей для него. Я перебирал множество программ для 3D-моделирования, но ни одна из них, в конечном счёте, так и не нашла во мне отклика. И вот я наткнулся на OpenSCAD. Идея рисовать 3D-модели с помощью кода показалась мне странной, но позже я осознал, что на самом деле мне это подходит больше. Я понял, что мне не нужно визуально что-то рисовать, достаточно того, чтобы я мог видеть результат. И поменять что-то в коде мне было гораздо проще, чем менять это визуально. Для себя я отметил следующие преимущества:
- Программа маленькая и не требует установки.
- Файлы текстовые и просто описывают геометрию, потому занимают мало места.
- Сложно испортить такой файл — это же просто текст. И если я что-то такое наворотил, что модель начала безбожно тормозить и с ней уже ничего не сделать, я могу просто удалить любым редактором лишний текст — и всё снова станет нормально.
Я почти никогда не печатал художку — все эти игрушки, фигурки, фанатская дребедень, кажется, я уже слишком стар для этого дерьма. А печатал я разные детали взамен сломанных, крепления, дополнения к существующим вещам, улучшения, и, работая с этим, я понял, что главное — это размеры, всё начинается с них. Они есть у всего, у каждой части есть длина, ширина, высота и координаты — вокруг этого строится всё. И очень часто с размерами промахиваешься, и хочется быстро их поменять, чтобы при этом не поехала вся остальная деталь. Поэтому-то мне и полюбился OpenSCAD, где всё строится на цифрах. Я старался для всего заводить переменные и проектировать так, чтобы потом их легко было менять, и вся модель пересчитывалась на новые параметры и строилась правильно. И вот в какой-то момент, когда нужно было в очередной раз проектировать что-то из мебели, мне пришла в голову безумная идея:

Действительно, почему бы и нет? И я написал себе библиотеку для OpenSCAD для «упрощения» проектировки мебели, в которую добавлялись детали, чтобы потом экспортировать список для распила, но пошёл я не самым простым путём. Я заложил в её работу те же принципы, что и в обычное проектирование 3D-моделей. Нужно было создать ДСП-панель заданных размеров, поместить её на нужные координаты, с нужным поворотом. И хоть я и старался во всех вычислениях использовать переменные и не вставлять «magic numbers», но всё равно, порой, код получался слишком сложным. Для меня это стало общей проблемой OpenSCAD. Пока ты варишься в этом — всё просто. Но стоит оставить проект на пару месяцев, и если там нет подробнейших комментариев, ты понимаешь, что там не просто чёрт ногу сломит, а этот самый чёрт там переломался весь и погребён в этой каше кода так, что и не найдёшь. И вот тут я понял, что мне становится тесновато в OpenSCAD. Да, я видел, что ему есть альтернативы, такие как ZenSCAD, но Python, бррр.

Мне хотелось сделать что-то своё, удобное именно мне.
include <../lib/export-details.scad>
EdgeThick = 0.4;
Thick = 16;
ClosetInsideHeight = 800;
ClosetInsideMirrorWidth = 400;
ClosetInsideShelfWidth = 200;
ClosetDeep = 140;
ShelfCount = 2;
BoxesCount = 3;
BoxRailingThick = 13;
BoxSpaceWidth = 460;
BoxFasadeWidth = 486;
BoxFasadeHeight = 230;
BoxDeep = 400;
BoxBottomHeight = 4;
BoxWidth = BoxSpaceWidth - BoxRailingThick * 2;
BoxHeight = BoxFasadeHeight - 16 - BoxBottomHeight;
BoxesSpace = 2;
CablesHolderWidth = 86 * 3;
CablesHolderHeight = 150;
CablesHolderDepth = 80;
CablesHolderUpHeight = 70;
translate([0, 0, 0]) rotate([90, 0, 90]) detail([ClosetDeep, ClosetInsideHeight + Thick * 2, Thick], "Шкафчик: правая стенка", [EdgeThick, EdgeThick, EdgeThick, EdgeThick]);
translate([Thick * 2 + ClosetInsideMirrorWidth + ClosetInsideShelfWidth, 0, 0]) rotate([90, 0, 90]) detail([ClosetDeep, ClosetInsideHeight + Thick * 2, Thick], "Шкафчик: левая стенка", [EdgeThick, EdgeThick, EdgeThick, EdgeThick]);
translate([ClosetInsideMirrorWidth + Thick, 0, Thick]) rotate([90, 0, 90]) detail([ClosetDeep, ClosetInsideHeight, Thick], "Шкафчик: средняя стенка", [EdgeThick, EdgeThick, EdgeThick, EdgeThick]);
translate([Thick, ClosetDeep, 0]) rotate([0, 0, -90]) detail([ClosetDeep, ClosetInsideMirrorWidth + ClosetInsideShelfWidth + Thick, Thick], "Шкафчик: дно", [EdgeThick, EdgeThick, EdgeThick, EdgeThick]);
translate([Thick, ClosetDeep, ClosetInsideHeight + Thick]) rotate([0, 0, -90]) detail([ClosetDeep, ClosetInsideMirrorWidth + ClosetInsideShelfWidth + Thick, Thick], "Шкафчик: верх", [EdgeThick, EdgeThick, EdgeThick, EdgeThick]);
translate([ClosetInsideMirrorWidth + Thick * 2, 0, Thick])
for (i = [1 : ShelfCount]) {
translate([0, 0, i * (ClosetInsideHeight / (ShelfCount + 1))]) rotate([0, 0, 0]) detail([ClosetInsideShelfWidth, ClosetDeep, Thick], "Шкафчик: полка", [EdgeThick, EdgeThick, EdgeThick, EdgeThick]);
}
translate([ClosetInsideMirrorWidth + Thick, ClosetDeep, Thick]) rotate([90, -90, 00]) detail([ClosetInsideHeight, ClosetInsideMirrorWidth, Thick], "Шкафчик: зад", [EdgeThick, EdgeThick, EdgeThick, EdgeThick]);
translate ([ClosetInsideHeight + 400, 0, 0])
for (i = [0 : BoxesCount - 1]) {
translate ([0, 0, i * (BoxFasadeHeight + BoxesSpace)]) {
translate([BoxRailingThick, 0, 0]) {
translate([0, 0, 0]) rotate([90, 0, 90]) detail([BoxDeep, BoxHeight, Thick], "Ящик: правая стенка", [EdgeThick, EdgeThick, EdgeThick, EdgeThick]);
translate([BoxWidth - Thick, 0, 0]) rotate([90, 0, 90]) detail([BoxDeep, BoxHeight, Thick], "Ящик: левая стенка", [EdgeThick, EdgeThick, EdgeThick, EdgeThick]);
translate([Thick, Thick, 0]) rotate([90, 0, 0]) detail([BoxWidth - Thick * 2, BoxHeight, Thick], "Ящик: левая стенка", [EdgeThick, EdgeThick, EdgeThick, EdgeThick]);
translate([Thick, BoxDeep, 0]) rotate([90, 0, 0]) detail([BoxWidth - Thick * 2, BoxHeight, Thick], "Ящик: левая стенка", [EdgeThick, EdgeThick, EdgeThick, EdgeThick]);
translate([0, 0, -BoxBottomHeight]) color([1,0.9,0.7]) cube([BoxWidth, BoxDeep,BoxBottomHeight]);
//translate([0, 20, BoxHeight]) cube([BoxWidth, 10,10]);
}
translate([-(BoxFasadeWidth - BoxSpaceWidth) / 2, 0, -BoxBottomHeight]) rotate([90, 0, 0]) detail([BoxFasadeWidth, BoxFasadeHeight, Thick], "Ящик: фасад", [EdgeThick, EdgeThick, EdgeThick, EdgeThick]);
}
}
translate ([ClosetInsideHeight + 1000, 0, 0]) {
translate([0, 0, 0]) rotate([90, 0, 90]) detail([CablesHolderDepth, CablesHolderHeight, Thick], "Для проводов: левая стенка", [EdgeThick, EdgeThick, EdgeThick, EdgeThick]);
translate([CablesHolderWidth + Thick, 0, 0]) rotate([90, 0, 90]) detail([CablesHolderDepth, CablesHolderHeight, Thick], "Для проводов: правая стенка", [EdgeThick, EdgeThick, EdgeThick, EdgeThick]);
translate([0, 0, ]) rotate([90, 0, 0]) detail([CablesHolderWidth + Thick * 2, CablesHolderHeight, Thick], "Для проводов: фасад", [EdgeThick, EdgeThick, EdgeThick, EdgeThick]);
translate([Thick, CablesHolderDepth, 0]) rotate([0, 0, -90]) detail([CablesHolderDepth, CablesHolderWidth, Thick], "Для проводов: дно", [EdgeThick, EdgeThick, EdgeThick, EdgeThick]);
translate([0, CablesHolderDepth, CablesHolderHeight * 1.5]) rotate([90, 0, 0]) detail([CablesHolderWidth + Thick * 2, CablesHolderUpHeight, Thick], "Для проводов: фасад", [EdgeThick, EdgeThick, EdgeThick, EdgeThick]);
}
PHP.SCAD
Прошло чуток времени, и я, наконец, понял, чего мне не хватало в OpenSCAD при создании 3D-моделей. Слоёв. Можно из одной фигуры вырезать другую, но иногда бывает, что мне нужно вырезать отверстие через большую часть модели, куда входит много различных элементов, и все они раскиданы по коду в файле. Всё это как-то нужно сгруппировать, чтобы сделать такой вырез, но специфика OpenSCAD такая, что это больше декларативный язык, нельзя создать модели, присвоить их переменным и потом провести действия над группой переменных. Там это немного сложнее, и каша кода от этого становится ещё наваристей. Было бы здорово, если бы я мог сказать, что вырезаю на слое 10, и это бы значило, что вырез будет через всё на слоях с 1 по 9, а на слои, начиная с 11 и выше вырез не распространяется. Но средствами OpenSCAD это было не сделать, вносить правки в сам OpenSCAD мне совершенно не хотелось, как и придумывать свой альтернативный язык программирования, чтобы сделать свой SCAD, этих языков и так развелось больше, чем хотелось бы. Поэтому я решил написать библиотеку для другого, существующего языка, которая реализует все нужные мне функции из OpenSCAD, добавляет то, чего мне не хватало, а на выходе будет генерировать файл формата OpenSCAD. И выбор мой пал на PHP. Вообще, PHP чаще используется для web-разработок, говорят даже, что он как рок, мёртв, но я не из тех, кто так быстро закапывает стюардесс, и я продолжаю его использовать для написания любых скриптов в системе. Почему всё-таки не Python? Он, казалось бы, сейчас более популярен. Не люблю я его, субъективно. Я привык к тому, что отступы — это просто форматирование текста, и мне не нравится идея того, что то, как будут стоять отступы в коде, будет как-то влиять на работу самой программы. И хоть иногда и приходится на нём что-то писать, делал я это всегда без любви и удовольствия. Поэтому я выбрал PHP. Чтобы работа была удобнее, я настроил VSCode так, чтобы по F5 он выполнял мой скрипт, который в свою очередь при выполнении обновляет SCAD-файл, а OpenSCAD довольно умный, и когда он видит, что файл изменился даже извне, он моментально его перезагружает и обновляет картинку. Поэтому работать удобно, F5 — и ты сразу видишь, что наворотил.

{
"configurations": [
{
"name": "F5 Anything",
"type": "f5anything",
"request": "launch",
"command": "c:/Projects/Bin/php7/php.exe ${file}",
}
]
}
Не скажу, что это решило проблему каши в коде, но сильно всё упростило и принесло мне нормальную работу переменных и функций (кто не знает, как это работает в OpenSCAD, то скажу так, специфически). Но я эту поделку никуда не выкладывал, и описываю её только как промежуточный шаг на пути к тому, что было дальше.
PHP.MEBEL.SCAD :)
Что? Mebel? Серьёзно? Да. Я знаю, что по-английски это будет furniture, но в русском языке есть слово фурнитура и у него немного другое значение, не хотелось путаницы, поэтому долго я не думал:

Но прежде чем сделать эту библиотеку, я решил переосмыслить саму концепцию проектирования мебели кодом. Мне не хотелось повторять то, что было сделано в виде библиотеки для OpenSCAD, где надо было размещать каждую доску, задавая ей смещения по 3м осям и углы поворота. Это всё громоздко и не слишком удобно и трудно читаемо в будущем. Я хотел чего-то нового. И в этом случае у нас есть два пути:
- Изучить то, что уже сделано в этом направлении, и адаптировать под свои нужды.
- Ничего не изучать и сразу начать изобретать свой велосипед.
А что тут думать? Конечно же, второй пункт! Ещё чего-то изучать я буду, делать мне больше нечего! Но если серьёзно, то в этом есть свои плюсы и минусы. Минусы в том, что я могу «изобрести» то, что уже давным-давно изобретено до меня, причём изобрести не в лучшем виде. Или изобрести что-то мертворождённое, что не приведёт меня ни к чему, кроме понимания того, что эта идея была плохая. Но плюсы в том, что так я думаю сам, и это иногда приводит к хорошим оригинальным решениям. Если я посмотрю, как сделали другие, мне будет гораздо сложнее потом придумать что-то своё, кардинально от этого отличающееся. Мозг зацепляется за протоптанную тропинку и не хочет топтать новую. Поэтому я ничего не изучал, да и вообще, не думаю, что в мире есть еще хоть один псих, который решит проектировать мебель PHP-скриптом. А если он есть, я бы предпочёл держаться от него подальше, мало ли что ему ещё в голову взбредёт? И вот я просто ходил и думал. И что-то придумал. Квадрат! Точнее, нет — куб. Всё — куб. А еще точнее, всё — параллелепипед. И немного из HTML/CSS разметки. Так, наверное это надо как-то объяснить) Сейчас попробую, итак, в отличие от произвольных 3D-моделей, мебель из ДСП в 99% случаев строится по одному принципу: панель ложится либо горизонтально, либо вертикально, без хитрых углов и причудливых форм, она сама параллелепипед и стыкуется с другими параллелепипедами. И в результате образуется другой большой параллелепипед (один или много). Сейчас покажу наглядно, и станет понятно о чём я и что у меня вышло.
Итак, сначала был размер.
Всё всегда начинается с размера, место в которое нужно эту мебель поставить, и оно ограничено. (Сразу буду писать на PHP.MEBEL.SCAD и визуализировать)
И создал я пространство!
require_once "scad.mebel.php";
$box = box(500, 800, 600);
draw_box($box);
render_scad();

Вот он, этот параллелепипед гражданской наружности шириной 500мм, высотой 800мм, глубиной 600мм. Я сразу решил оперировать не x,y,z, а более человеческими — ширина (h, он же horizontal), высота (v, он же vertical) и глубина (d, он же depth). Дальше я совместил трёхмерное пространство и принцип html/css разметки, когда у нас есть div фиксированного размера, у которого есть border или padding, который его уменьшает и дочерние элементы остаются уже в меньшем прямоугольнике.
Далее создал я полку сверху и понял, что не плохо это:
require_once "scad.mebel.php";
$box = box(500, 800, 600);
$box = wall_top($box, "Мебель: %W");
render_scad();

Панель примагнитилась к верхней грани параллелепипеда, а сам параллелепипед уменьшился на толщину этой панели. Нам не нужно указывать размеры панели, мы только указываем сторону параллелепипеда, размеры она возьмёт по размеру прямоугольника этой стороны (ну ладно, мы можем задать padding или размер для панели, но это не обязательно).
И создал я вторую полку снизу, и понравилось это мне:
require_once "scad.mebel.php";
$box = box(500, 800, 600);
$box = wall_top($box, "Мебель: %W");
$box = wall_bottom($box, "Мебель: %W");
render_scad();

Теперь то же самое произошло снизу, параллелепипед уменьшается, создавая каркас будущего изделия.
И создал я стенки боковые, как опоры меж полок горизонтальных:
require_once "scad.mebel.php";
$box = box(500, 800, 600);
$box = wall_top($box, "Мебель: %W");
$box = wall_bottom($box, "Мебель: %W");
$box = wall_left($box, "Мебель: %W");
$box = wall_right($box, "Мебель: %W");
render_scad();

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

Но если поменять местами порядок создания стенок, то будет так:
require_once "scad.mebel.php";
$box = box(500, 800, 600);
$box = wall_left($box, "Мебель: %W");
$box = wall_right($box, "Мебель: %W");
$box = wall_top($box, "Мебель: %W");
$box = wall_bottom($box, "Мебель: %W");
render_scad();

И разбил я пространство оставшееся на несколько частей равных:
require_once "scad.mebel.php";
$box = box(500, 800, 600);
$box = wall_top($box, "Мебель: %W");
$box = wall_bottom($box, "Мебель: %W");
$box = padding($box, "front=16");
$box = wall_left($box, "Мебель: %W");
$box = wall_right($box, "Мебель: %W");
$box = wall_back($box, "Мебель: %W");
$boxes = split_vertical($box, "*,*,*,*,*", 16);
foreach ($boxes as $b) {
if (is_part($b)) {
draw_box($b);
}
}
render_scad();

Здесь они разбиты на равные интервалы с пропуском в 16 мм, это не случайно, а чтобы при сборке ящиков класть между ними обрезок ДСП, и так их будет не нужно выравнивать. Разбиение задано "*,*,*,*,*", но можно вместо * задавать либо % от всего пространства, либо размеры в мм. Сначала вычисляются все фиксированные значения, а оставшееся пространство делится между *.
И закрыл я каждую из полученных частей каркасом деревянным:
require_once "scad.mebel.php";
$box = box(500, 800, 600);
$box = wall_top($box, "Мебель: %W");
$box = wall_bottom($box, "Мебель: %W");
$box = wall_left($box, "Мебель: %W");
$box = wall_right($box, "Мебель: %W");
$box = wall_back($box, "Мебель: %W");
$boxes = split_vertical($box, "*,*,*,*,*", 16);
foreach ($boxes as $b) {
if (is_part($b)) {
$b = padding($b, "left=10,right=10,back=5");
$b = wall_front($b, "Ящик: %W");
$b = wall_bottom($b, "Ящик: %W");
$b = wall_back($b, "Ящик: %W");
$b = wall_left($b, "Ящик: %W");
$b = wall_right($b, "Ящик: %W");
}
}
render_scad();

И нарёк я тумбою изделие своё, но сперва облагородил её незначительно:
require_once "scad.mebel.php";
$box = box(500, 800, 600);
$box["closed"]["b"] = true;
$box = wall_top($box, "Мебель: %W");
$box = wall_bottom($box, "Мебель: %W");
$box = padding($box, "front=16");
$box = wall_left($box, "Мебель: %W");
$box = wall_right($box, "Мебель: %W");
$box = wall_back($box, "Мебель: %W");
$box = padding($box, "top=10,bottom=10");
$boxes = split_vertical($box, "*,*,*,*,*", 16);
foreach ($boxes as $b) {
if (is_part($b)) {
wall_front($b, "door=1,edge=f", "Ящик: %W", "front=-16,left=-16,right=-16,top=-6,bottom=-6");
$b = padding($b, "left=10,right=10,back=5");
$b = wall_front($b, "Ящик: %W");
$b = wall_bottom($b, "Ящик: %W");
$b = wall_back($b, "Ящик: %W");
$b = wall_left($b, "Ящик: %W");
$b = wall_right($b, "Ящик: %W");
}
}
render_scad();


Вот так просто мы создали тумбочку. И именно этот принцип проектирования пришёл мне в голову. Мы не работаем со стенками по отдельности, мы всегда работаем с параллелепипедом. Мы можем сами резать его на несколько параллелепипедов, уменьшать или увеличивать. А потом заполнять нужные нам стенки панелями. И нам не нужно держать кучу цифр в голове, какого размера будет эта панель, как её повернуть. Всё будет сделано за нас. Также библиотека пытается предугадать, где нужна кромка, а где нет. Иногда она ошибается, но мы можем ей помочь сделать вручную. Все края, на которых нет кромок, специально показываются красным цветом, чтобы сразу было видно, где косяк:

Если мы хотим посмотреть картинку в разрезе, добавим команду:
view_cut_front(400);
И рассёк я пространство, чтобы все могли лицезреть срез творения моего

И вот она в разрезе (OpenSCAD не всегда правильно отображает такие разрезы в реальном времени, но после рендеринга (F6) всё становится как надо, а рендеринг тут почти мгновенный).
Добавив строчку
render_parts_list();
мы получим рядом с нашим файлом с кодом csv-файл с частями для распила:

Но это всё баловство, давайте посмотрим на реальные проекты, которые я не только нарисовал, но и собрал.
Реальные проекты
▍ Стол-стеллаж
Идея была в том, что над столом часто пропадает пространство, а можно сделать там стеллаж, и оно будет использоваться с пользой.
require_once "scad.mebel.php";
$box = box(1400, 780 + 1516, 600);
list($tableBox, $upperBox) = split_vertical($box, "780,*");
$thick = 24;
$tableBox = set_thick($tableBox, $thick);
$tableBox = set_edge_thick($tableBox, 2);
$tableBox = wall_top($tableBox, "edge=f,round-front-left=100,round-front-right=100", "Стол: %W");
$tableBox = padding($tableBox, "left=16,right=16,front=100");
$tableBox = wall_left($tableBox, "", "Стол: %W");
$tableBox = wall_right($tableBox, "", "Стол: %W");
$tableBox = padding($tableBox, "bottom=200");
$tableBox = wall_back($tableBox, "", "Стол: %W");
$shelfBox = split_vertical($tableBox, "*,200")[1];
$shelfBox = split_horizontal($shelfBox, "25%,*")[1];
$shelfBox = split_depth($shelfBox, "200,*")[0];
$shelfBox = wall_bottom($shelfBox, "", "Полка: %W");
$shelfBox = wall_left($shelfBox, "", "Полка: %W");
$thick = 16;
$upperBox = set_thick($upperBox, $thick);
$upperBox = set_edge_thick($upperBox, 0.4);
list($upperBottomBox, $upperTopBox) = split_vertical($upperBox, "600,*");
$upperBottomBox = split_depth($upperBottomBox, "300,*")[0];
$upperBottomBox = wall_left($upperBottomBox, "", "Опоры стеллажа: %W");
$upperBottomBox = wall_right($upperBottomBox, "", "Опоры стеллажа: %W");
$upperTopBox = split_depth($upperTopBox, "400,*")[0];
$upperTopBox = wall_top($upperTopBox, "", "Стеллаж: %W");
$upperTopBox = wall_left($upperTopBox, "round-front-bottom=100", "Стеллаж: %W");
$upperTopBox = wall_right($upperTopBox, "round-front-bottom=100", "Стеллаж: %W");
$upperTopBox = padding($upperTopBox, "bottom=100,front=$thick");
$upperTopShelfBoxes = split_vertical($upperTopBox, "*,*,*");
$n = 0;
foreach ($upperTopShelfBoxes as $shelfBox) {
$shelfBox = wall_bottom($shelfBox, "edge-back=0", "Полка стеллажа");
$splitBox = split_horizontal($shelfBox, ($n % 2 == 0 ? "58%,*" : "*,58%"))[1];
$splitBox = wall_left($splitBox, "edge-bottom=0,edge-top=0,edge-back=0", "Перегородка стеллажа");
$n++;
}
render_scad();
render_parts_list();
Рендер:

В жизни (требует обязательного крепления верхней части к стене):

▍ Франкенштейн из стола-стеллажа
Продолжение стола-стеллажа, сделано место под компьютер и сзади отступ на 10 см, чтобы там пустить все провода и закрыть это крышкой внизу.
require_once "scad.mebel.php";
$railsThick = 10;
$box = box(1500, 780 + 1516, 600, 1600);
$box["closed"]["b"] = true;
list($tableBox, $upperBox) = split_vertical($box, "780,*");
$thick = 24;
$tableBox = set_thick($tableBox, $thick);
$tableBox = set_edge_thick($tableBox, 2);
$tableBox = wall_top($tableBox, "edge=f,edge-back=0,round-front-left=100,round-front-right=100", "Стол: %W");
$tableBox = padding($tableBox, "left=230,front=100");
list($tableBox, $computerBox) = split_horizontal($tableBox, "*,230");
$tableBox = padding($tableBox, "back=100");
$tableBox = wall_left($tableBox, "", "Стол: %W");
$tableBox = wall_right($tableBox, "", "Стол: %W");
$computerBox = wall_bottom($computerBox, "edge-left=0", "Стол: Под компьютер" );
list($tableCloseBox,$tablePartBox) = split_vertical($tableBox, "360,*");
$tableCloseBox = wall_back($tableCloseBox, "edge=f", "Стол: закрывашка");
$tablePartBox = wall_back($tablePartBox, "", "Стол: %W");
$thick = 16;
$upperBox = set_thick($upperBox, $thick);
$upperBox = set_edge_thick($upperBox, 0.4);
list($upperBottomBox, $upperTopBox) = split_vertical($upperBox, "600,*");
$upperBottomBox = split_depth($upperBottomBox, "300,*")[0];
$upperBottomBox = wall_left($upperBottomBox, "", "Опоры стеллажа: %W");
$upperBottomBox = wall_right($upperBottomBox, "", "Опоры стеллажа: %W");
$upperTopBox = split_depth($upperTopBox, "400,*")[0];
$upperTopBox = wall_top($upperTopBox, "", "Стеллаж: %W");
$upperTopBox = wall_left($upperTopBox, "round-front-bottom=100", "Стеллаж: %W");
$upperTopBox = wall_right($upperTopBox, "round-front-bottom=100", "Стеллаж: %W");
$upperTopBox = padding($upperTopBox, "bottom=100,front=$thick");
$upperTopShelfBoxes = split_vertical($upperTopBox, "*,*,*");
$n = 0;
foreach ($upperTopShelfBoxes as $shelfBox) {
$shelfBox = wall_bottom($shelfBox, "edge-back=0", "Полка стеллажа");
$splitBox = split_horizontal($shelfBox, ($n % 2 == 1 ? "60%,*" : "*,60%"))[1];
$splitBox = wall_left($splitBox, "edge-bottom=0,edge-top=0,edge-back=0", "Перегородка стеллажа");
$n++;
}
$box = box(1830, 780 - 24, 500);
$box["closed"]["b"] = true;
$box = wall_top($box, "edge-right=0", "Центральная часть: %W");
$box = padding($box, "front=$thick");
list($boxesBox, $centerBox) = split_horizontal($box, "400,*");
$boxesBox = wall_left($boxesBox, "", "Под ящики: %W");
$boxesBox = wall_right($boxesBox, "", "Под ящики: %W");
$boxesBox = wall_bottom($boxesBox, "edge-left=0", "Под ящики: %W");
$thick2 = $thick / 2;
$space = $thick - 4;
$space2 = $space / 2;
$boxesBoxes = split_vertical(padding($boxesBox, "top=4"), "*,*,*,*,*", $thick);
foreach ($boxesBoxes as $boxBox) {
if (is_part($boxBox)) {
wall_front($boxBox, "door=1,edge=f", "Ящик: %W", "front=-$thick,left=-$thick,right=-$thick,bottom=-$space");
$boxBox = padding($boxBox, "left=$railsThick,right=$railsThick,back=5");
$boxBox = wall_front($boxBox, "", "Ящик: %W");
$boxBox = wall_bottom($boxBox, "", "Ящик: %W");
$boxBox = wall_back($boxBox, "", "Ящик: %W");
$boxBox = wall_left($boxBox, "", "Ящик: %W");
$boxBox = wall_right($boxBox, "", "Ящик: %W");
}
}
$centerBox = wall_bottom($centerBox, "edge-left=0,edge-right=0", "Центральная часть: %W");
list($bottomCenterBox, $upperCenterBox) = split_vertical($centerBox, "320,*");
$upperCenterBox = wall_bottom($upperCenterBox, "edge-left=0,edge-right=0", "Центральная часть: Вертикальный разделитель");
wall_left(split_horizontal($upperCenterBox, "*,*", $thick)[1], "", "Центральная часть: Верхний горизонтальный разделитель");
list($bottomCenterLeftBox, $bottomCenterSplitBox, $bottomCenterRightBox) = split_horizontal($bottomCenterBox, "*,*", $thick);
wall_left($bottomCenterSplitBox, "", "Центральная часть: Нижний горизонтальный разделитель");
$bottomCenterLeftBox = wall_front($bottomCenterLeftBox, "edge=f", "Центральная часть: Левая крышка", "front=-$thick,top=-$thick,bottom=-$space,left=2,right=-$space2");
$bottomCenterRightBox = wall_front($bottomCenterRightBox, "edge=f", "Центральная часть: Правая крышка", "front=-$thick,top=-$thick,bottom=-$space,right=2,left=-$space2");
render_scad();
render_parts_list();
Рендер:


В жизни (требует обязательного крепления верхней части к стене):

▍ Стол на кухню
Основная мысль была в том, чтобы за ним можно было нормально сидеть с любой из трёх сторон, и ноги не упирались ни во что, а табуретки убирались под него и получалось компактнее кухонных уголков.
require_once "scad.mebel.php";
$thick = 24;
$edgeThick = 2;
setEdgeThick($edgeThick);
setThick($thick);
$tableBox = box(1200, 742, 800);
$tableBox = wall_top($tableBox, "round-right-front=100,round-right-back=100", "Столешница");
$tableBox = padding($tableBox, "left=30,right=400,front=50,back=50");
$tableBox = wall_left($tableBox, "", "Стол: %W");
$tableBox = padding($tableBox, "front=110,back=110");
$tableBox = wall_right($tableBox, "", "Стол: %W");
$tableBox = split_vertical($tableBox, "*,250")[1];
$tableBox = wall_back(split_depth($tableBox, "*,*", $thick)[1], "", "Стол: Перегородка");
for ($i = 0; $i < 2; $i++) {
for ($j = 0; $j < 2; $j++) {
$chairBox = box(350, 452, 350, 60 + $i * 355, 0, $j * 450);
$chairBox = wall_top($chairBox, "round=100", "Табуретка: Сиденье");
$chairBox = padding($chairBox, "left=60,right=60,back=60,front=60");
$chairBox = wall_left($chairBox, "", "Табуретка: %W");
$chairBox = wall_right($chairBox, "", "Табуретка: %W");
$chairBox = split_vertical($chairBox, "*,200")[1];
$chairBox = wall_back(split_depth($chairBox, "*,*", $thick)[1], "", "Табуретка: Перегородка");
}
}
render_scad();
render_parts_list();
Рендер:

В жизни:



И резюмирую
Если вдруг вам захотелось делать мебель также безумно, как это делаю я, вот что нужно:
- OpenSCAD — рекомендую не стабильный билд, а найтли, он намного быстрее.
- PHP — я использую 7.2. Но все будет работать и на последней на сегодняшний день — 8.4
- Любой редактор, я использую VSCode с плагином для PHP, а также плагин F5 Anything, чтобы по F5 выполнять скрипт. Он создаёт файл с таким же названием и расширением .scad. Его надо открыть в OpenSCAD. Каждый раз, когда будете нажимать F5 в VSCode, он будет видеть, что scad файл изменился и сразу же отображать изменения.
- Сама библиотека и документация всех функций: https://github.com/CodeName33/php.mebel.scad
Ну и как обычно всё MIT, делайте с этим чего хотите.
© 2025 ООО «МТ ФИНАНС»
Telegram-канал со скидками, розыгрышами призов и новостями IT ?

Комментарии (44)
DDroll
17.05.2025 15:04Ну, главное, результат есть, руки более чем прямые) А так, как то сложно выглядит. Не проще ли было запустить SketchUp?)) В свое время ремонт квартиры проектировал в связке SketchUp -> blender -> UE4 -> HTC Vive. Стены, мебель схематично по размерам - в скетче, материалы-текстуры, подгонки моделей - блендер; освещение, запуск ВР режиме - анриал. Был забавный момент - в анриале можно выставить свет в соответствии с географией и временем, я выставил по панорамной фотке, которую юзал для вида за окном, и почему-то в двух комнатах получился разный по яркости свет, в одной было прямо сильно темнее. Думал артефакт, а в реальности так и оказалось - сыграл козырек балкона при определенном положении солнца.
Antra
17.05.2025 15:04Что на выходе в SketchUp будет? Если только ренедер, для планирования ремонта - да, хорош, но для проектирования мебели со множеством деталей маловато будет.
Pro100 (выше уже назвали, и вроде я как раз в нем после переезда много лет назад делал) экспортирует все в виде, удобном для разных контор по изготовлению деталей, кромкованию и т.п.
И расположение деталей на листах для уменьшения количества закупаемых листов, и еще много такого нужного. Помнится, я выбрал на 1 см уменьшить высоту стеллажа, и существенно на этом сэкономил...
dot22
17.05.2025 15:04https://docs.opencutlist.org/ - Для скетчапа есть расширение OpenCutList, которое предназначено именно для решения таких вопросов
OpenCutList Cutting Diagram sizeg
17.05.2025 15:04Распил самое лёгкое. Нужно указать кромки, отверстия, проставить размеры. Вот это настоящий головняк.
CBET_TbMbI
17.05.2025 15:04Такую мебель на бумаге будет "спроектировать" быстрее. Или в любой рисовальной программе.
А тут даже ничего не сказано про крепления, полозья и прочую фурнитуру.
CodeName33 Автор
17.05.2025 15:04Я никогда не заказываю отверстия для конфирмата при распиле, это бессмысленно удорожает заказ, их я делаю сам и сразу по месту, поэтому не вижу смысла вносить это в проект. С фурнитурой также.
CBET_TbMbI
17.05.2025 15:04Так для себя надо знать, где и что сверлить. Подогнать точно дверцу под шкаф гораздо труднее, чем тупо выбрать размеры досок для этого шкафа.
CodeName33 Автор
17.05.2025 15:04Не сталкивался с такой проблемой. Обычно, пока задней части нет, приложил снаружи дверцу, как должна быть, зафиксировал, изнутри прикрутил петлю.
Pondesss
17.05.2025 15:04В открытом виде приставил фасад, прикрутил, отрепетировал, забыл. Кстати если от руки рисовать на бумаге, то такой стол для пк с тумбой под ТВ пеналом и антресолями был нарисован и посчитан (ну еще придуман естессно) минут за 30 с перекурами. В спец программах с нормальными БД будет естессно быстрее, но мне лень, у меня лапки)))
pnmv
17.05.2025 15:04Так, ну, в наши то непростые времена, понятное дело, но десять то лет назад, ну икея же вовсю трудилась, предоставляя полный фарш, из этого вашего дсп...
Ладно бы, там, из цельного дуба...
MountainGoat
17.05.2025 15:04Тем временем FreeCAD такой: ну да, ну да....
CodeName33 Автор
17.05.2025 15:04Несколько раз пытался и удалял его) Не мое)
MountainGoat
17.05.2025 15:04Обычно дело в цветовой теме. Дело в том, что FreeCAD все сложные штуки здорово выделяет цветом, но только вот цвета подсветки от основных почти не отличаются. Я сам это узнал только когда тёмную тему включил.
devlev
17.05.2025 15:04Как же это близко и лампово)) Но писать кодом это конечно мощно! Тут выше написали про sketchup.
Лет 10 назад его освоил и с тех пор все модели в нем рисую. Т.е. рисую сразу по тем размерам которые нужны мне. В своем городе нашел компанию, которая потом все мои идеи перерисовывает уже в своей специальной распиловочной программе, а там сама расставляет присадки. Плюс кромка бывает тоже разной. Использую в основном 2мм а например при распиле ящиков это нужно учитывать чтобы присадки совпали. Программа распиловщика это все учитывает. Так что это их головная боль, не моя.
Так же можно кучу времени потратить на подгонку к направляющим. Ладно если это просто шариковые 8мм. А если хочется скрытого монтажа, то тут вручную все это предусмотреть может быть не просто. А так фабрика сразу размечает места под будущие крепления, только саморез закрути.
CodeName33 Автор
17.05.2025 15:04Мне sketchup тоже не зашел в свое время, я его тоже пробовал. Наверное у меня такое мышление, что код мне понятнее)
У меня кромка всегда уменьшает деталь. Т.е. работает как padding в css, сохраняя внешний размер делали. А с направляющими на ящиках - я просто делаю между ними зазор в 16мм, чтобы на предыдущий ящик положить лист дсп и следующий на своем месте. А фасады уже потом, закрывают лишние зазоры.
sajtim
17.05.2025 15:04Можно дополнить, что зарабатывают не столько освоив сами программы, сколько накопив, освоив и сохранив сильных решений в своих библиотеках.
psiklop
17.05.2025 15:04Я люблю свою работу! Я приду сюда в субботу.. Не понятно, для чего этот пост, но будь здоров.
BSOZ
17.05.2025 15:04Очень похоже на мой проект для научного общества учащихся лет 25 назад, я тогда на VB6 писал. Штука считала материал для ремонта, всякий там плинтус и обои. Была какая-то мало-мальская визуализация. Я ещё в каком-то классе школы учился.
shushu
17.05.2025 15:04PHP — я использую 7.2.
Судя по коду, я думал PHP 4 :)
PHP End of Life support: https://www.php.net/eol.php PHP 7.2: 30 Nov 2020
А если серьезно - то хорошее начало, лучший метод изучать что-то - это пробовать решать реальные задачи. Теория немного хромает, я бы рекомендовал изучить немного про ООП, composer.
Также, необходимо разделить логику от рендеринга. А то у вас там все смешалось
CodeName33 Автор
17.05.2025 15:04Осталась такая плохая (или наоборот хорошая) привычка использовать старые версии языка, поскольку он интерпретируемый, не факт, что там где понадобится, чтобы твой код работал будет стоять новая версия. В свое время несколько раз на этом обжигался, с тех пор я, как тот кот которому крышка унитаза упала по спине, и он продолжал ходить в туалет забираясь на унитаз, то исключительно лицом к крышке)
А логика объединенная с рендером - это принцип OpenSCAD, это иногда причиняет боль, а иногда удобнее, я взял что-то среднее оттуда, ориентируясь на собственное удобство. ООП, где все будет объектом и будет что-то типа куб->доскаСверху(), мне не зашло потому, что при этом исходный куб должен уменьшится, но так не всегда нужно, показалось что функциональное программирование тут будет проще, когда функция всегда возвращает измененный куб, а уж присваивать его той же переменной или другой - это я буду решать в зависимости от задачи.
FanatPHP
17.05.2025 15:04Для не самых новых версий это правда. Но вот для ископаемых ситуация меняется на противоположную - как раз их-то и не найдёшь. Плюс стон стоит на весь интернет, когда такие вот сидельцы рыдают, что хостер насильно обновил версию пхп до минимально приемлемой и их говнокод перестал работать. Это всё равно что рекомендовать Питон 2.
Да и чисто технически, в чём смысл зачем рекомендовать 7.2 и давать ссылку, по которой эту версию скачать невозможно. Плюс в целом непонятно, зачем вообще рекомендовать какую-то конкретную версию, если никакие специфические для этой версии возможности языка не используются, а не оставить версию на выбор читателя.
CodeName33 Автор
17.05.2025 15:04Я 7.2 не рекомендовал, я написал ту, на которой делал сам, подразумевая, что это минимум на котором я проверял, будет ли все работать на более ранних, я не знаю. Но это не значит, что на версии 8.4 работать не будет, оно там прекрасно работает. Но вы правы, я подумал ,что это само собой разумеющееся, а на самом деле это следовало указать.
denizkino_mesto
17.05.2025 15:04Открой рег.ру, арендуй на месяц хостинг их за 411 рублей, там доступны все версии php с 5.3 до 8.4, любые на одном хостинге для разных папок с сайтами можешь свою версию php использовать, вот mysql одной только версии они предоставляют на весь хостинг либо 5.7, либо 8.
Главное ты сам такую программу напиши, после написания покажи, а мы оценим.
Я php разработчик с 15 летним стажем, в основном работаю с проектами на битриксе, могу сказать, что огромное множество проектов до сих пор работают у компаний крупных причём на php 5.6 и php 7.2.
sajtim
17.05.2025 15:04Картинка заглавная сделала это воскресенье, ( ᵔ▽ᵔ)_b спасибо! По поводу проектирования
мебеливообще квартиры, как по мне, пока не прикрыли, blender может всё.denizkino_mesto
17.05.2025 15:04Блендер слишком сложный, проблемный и может далеко не всё. Основное преимущество, человек может на удалённый сервер к своему проекту на php обратиться практически с любого устройства, а вот блендер работает иначе, плюс в блендере постоянно есть проблемы несовместимости версий, сделали модель на новой версии и не сказали на какой, у тебя заведомо более старая установлена при попытке открыть проект просто вылетает блендер и все дела.
sajtim
17.05.2025 15:04Согласен с тем, что вопрос зависимости от разработчика автором статьи решён, для себя точно. Поэтому и отметил, что блендер хорош на данном этапе. Могут и прикрыть или создать некоторые неудобства, не спорю. Но, освоив, для собственного планирования, мебели в том числе пока другого не надо. К примеру, на скрине подоконник-столешница, со всеми размерами, фасками, вырезами и т.д.
KMiNT21
17.05.2025 15:04Когда я 5 лет назад попробовал OpenSCAD, я тоже проникся. :) Даже пост написал:
После нескольких подходов к "Fusion 360", в котором я каждый раз тонул в перегруженном интерфейсе, словно маленький кораблик, решивший пересечь океан, я, вдруг, открыл для себя "OpenSCAD".
Эти ощущения похожи на те, которые вы получаете ступив на твердую землю после того, как вас укачало на волнах. К счастью, меня не успело вывернуть, ведь Fusion все равно еще понадобится. (не понадобился, пользовался потом другим)
Но вот подход к созданию [параметрических] 3D-моделей в виде последовательного описания отдельных графических примитивов меня просто вдохновил вчера!
Это просто чистое программерское удовольствие. Никаких тебе тяганий мышки по углам и прочих пиксельхантингов.
Написал, например, cylinder(d=10, h=100) - будет тебе цилиндр. Написал difference() { cylinder(d=10, h=100); cylinder(d=8, h=100); } - будет тебе труба (в хорошем смысле ).
Весь объект описывается таким образом. И все всегда будет стоять на своих местах. Как в том анекдоте про девочку и бант.
В общем, рекомендую!
AllySanders
17.05.2025 15:04Да уж, вот что получается, когда макеты рисует программист, а не дизайнер, функционально, но глаз совсем не радуется
Ole
17.05.2025 15:04Это футуристический дизайн. Современные дизайнеры пока ещё не доросли до его понимания.
serafims
17.05.2025 15:04А есть ли где-то, может, встречал кто-нибудь, чек-лист для чайников в проектировании опилочной мебели, что надо учесть при расчете листов? Условно шаг петель, нагрузка на петлю, типовые крепления, какие кромки и т.п.?
Serpentine
17.05.2025 15:04Шаг петель и нагрузку смотреть надо на сайтах производителей, зачастую там можно скачать pdf-файл с каталогом, где нарисовано сколько и на каком расстоянии надо их крепить в зависимости от веса фасада и его размеров (вес считается исходя из плотности материала, у МДФ она больше, чем у ЛДСП), там же иногда пишут зазоры.
Та же история с направляющими для ящиков, подъемными механизмами, да и вообще прочей фурнитуре — смотрим инструкции от производителя. Например, посудосушитель в базу 600мм — значит внешняя ширина корпуса (независимо от толщины ДСП 16/18мм) должна быть 600мм. Бутылочница 150 или 200мм — ширина корпуса должна быть 150 или 200мм соответственно.
Ну и еще добавлю пару мыслей от себя:
Крепеж
Крепежные элементы основные: евровинт 7х50 (он же конфирмат, можно взять еще несколько 7х70 если накосячил и 50-й стал прокручиваться), эксцентриковая стяжка (два исполнения) (см. по ссылке с поз.4). Прочность соединения ±одинаковая. На особо важных участках можно заморочиться, добавить шканты и проклеить торец в месте стыка.
Саморезы по дереву (для уголков, петель, фурнитуры и для накладной задней стенки или дна ящика из ДВП, ходовой размер 3,5х16). Гвозди мебельные для задней стенки и дна, используются наверное сейчас редко, но в целом можно.
Заглушки для эксцентриков/евровинтов есть пластиковые (выпуклые, цвета ограничены, иногда держатся не очень) и самоклеящиеся (можно иногда подобрать точно в цвет с ЛДСП, держатся хорошо, если клеить аккуратно).
Задние стенки / донца ящиков из ДВП можно как набивать/прикручивать, так и садить в паз (ширина 4мм делается на форматно-раскроечном станке, глубина около 5-10мм (не помню точно) отступ от края около 10мм) дополнительно можно зафиксировать уголком для ДВП под паз с саморезом.
Кромка
Меламиновая (утюгом которая клеится) используется наверное уже редко, также редко встречаются канты мебельные накладные и врезные.
Кромка ABS клеится на станке или кромочной линии специальным клеем (иногда клей наносят на кромку и с помощью фена приклеивают к детали, но это не так часто. Например, запилили деталь по месту уже на адресе и приклеили кромку).
Ходовые размеры ABS кромок (ширина/толщина): 19/0,4мм и 19/2мм (для 16/18 плит), 25/2мм или 35/2мм (для 22 плиты или «сэндвича» 32мм).
Кромка 0,4мм в раскрое детали не учитывается, а если толщина 2мм — придется вычитать из размера детали. Есть еще кромка толщиной 1мм, но я не работал с ней, в целом, ее можно для внутрянки использовать вместо 0,4.
Особенность кромки 2мм (для видимых лицевых частей изделия (если не закрыты фасадом) и самих фасадов) — снимается закругленная фаска (поэтому, когда делаем, например, открытый стеллаж для книг, то «утапливаем» полку на 2 мм, чтобы не было некрасивых переходов на стыке полки и стенки — т.е. если глубина стеллажа (его боковой стенки) 350мм, то глубина полки тогда будет 348мм).
Что кромить?
По ГОСТу по крайней мере детали детской мебели не должны иметь торцов без кромки (напр., стенка выдвижного ящика должна кромиться сверху (понятно дело, ее видно) и сзади (а это редко кто делает, ее не видно), а снизу (набивается ДВП) и спереди (прикручивается фасад) она не кромится.
Но по общему правилу (не по ГОСТу), что не видим, то не кромим, за исключением внешних частей, например, которые будут соприкасаться с полом или стеной, если не набиваем ДСП.
На кухонном гарнитуре можно заморочиться и закромить вкруговую всю деталь, даже там где она будет стыковаться с другой (присадку делаем уже на закромленной детали, понятное дело).
Неприятности с кромкой.
Иногда на светлых деталях может быть виден черный клеевой шов (зависит от оборудования и от толщины нанесенного клея).
Иногда кромка 2мм со временем отклеивается на деталях с вырезанным внутренним радиусом (обычно на столешницах) или на небольших (менее 50мм) внешних радиусах.
Отдельные замечания.
Полка из ЛДСП обычно провисает под собственным весом при ширине от 900мм (нужно дополнительное крепление по центру или поперечная стойка, или т.н. ребро/царга сзади).
Дно большого ящика следует делать из ЛДСП (или если хранить легкие предметы, то можно и из ДВП, но с дополнительной поперечной стенкой). Вес пустого и нагруженного ящика тоже учитываем при выборе направляющих (роликовые уже не подойдут).
Минимальная ширина детали около 70мм (касается в основном стяжек и цоколей), т.к. кромочные линии обычно меньшие размеры не обклеивают (тут следует уточнять на производстве, могут просто закромить подороже на ручном станке).
Фасады из МДФ, покрытые эмалью (крашенные) лучше заказывать толщиной 19мм, а не 16. Неприятность может случиться при присадке под чашку петли — будет видна своеобразная вмятина.
Nuflyn
17.05.2025 15:04Отдаю должно основательному подходу автора. Сам я в свое время озаботившись темой кастомной мебели и сознавая кривизну собственных рук обратился к отличному столяру, который и сваял все требуемое из натурального дерева.
Roland21
Eсть же программа pro100 - которая и для частника (сам делал в ней мебель на всю квартиру) и для небольших фирм ок...
CodeName33 Автор
Наверное, проблема во мне) я эту программу пробовал много лет назад, тогда не зашло
Serpentine
PRO100 сейчас не продается на территории РФ, а цена вроде как была от 20К руб./мес. или от 60К руб. до 130К руб. за лицензию. Демо-версия не позволяет печатать/сохранять проекты если что.
Работал раньше с ней (4 и 5 версия) лет пять назад. Для эскизов — самое то, быстро/красиво. Но вот напрямую в производство/раскрой выхлоп из этой программы (или, не дай Бог, чужие проекты) без проверки с калькулятором и карандашом я никогда бы не отправил.
releyshic
ниужели в ней столько багов?
Serpentine
Дело не в багах, а в прокладке между монитором и креслом (при мне увольняли конструктора, который доверял всему, что эта программа выдавала по его же кривым проектам). Сама программа (я про 4 или 5 версию, т.к. с 6 не работал) рассчитана на то, что проекты может составлять любой без особой подготовки просто «тяхая мЫшей» при подгонке деталей.
Отсюда самые частые косяки — деталь меньше (недотянули) или больше (перетянули, при неправильном пересечении деталей их размер можно сделать каким угодно), еще возможны варианты с неправильной толщиной (18мм вместо 16) и неправильной ориентацией (рисунка) ламината.
Самый злостный косяк, который я встречал, когда из этой программы отправили размеры фасадов на производство в другой город без учета зазоров и пр. Если корпуса еще в собственном цехе могут перепроверить перед раскроем и переделают, то фасады приедут ровно такие, какие заказывали :) А тут проблема такая — один неправильный фасад → перезаказывай весь комплект, т.к. даже мизерное отличие в тоне будет резать глаз заказчику.
Плюсом ко всему никакого учета кромок, фасок и пазов в тех версиях не было.
Но повторюсь, для салонов/дизайнеров (где точность ±50мм простительна и нужна просто красивая картинка без лишних сложностей) эта программа лучше, чем более тяжеловесные аналоги. Хотя лично я, будучи конструктором, ее использовал чисто для эскизов, а деталировку для карт кроя считал вручную или в Exel с последующей перегонкой в Cutting2 (ну это когда на Базис-Мебельщик контора еще не разорилась).
CodeName33 Автор
Дополню еще немного о том, почему мне удобней делать все это кодом. Потому, что когда я начинаю проектировать, я не всегда знаю заранее, что должно быть на выходе, нужно посмотреть покрутить, делать много изменений (особенно когда делаешь не только для себя, но и с кем-то надо согласовать, особенно, если это женщина). И вот взять тумбу из примера статьи и внезапно, что если сделать не 5 ящиков, а 4, но побольше? В этих всех программах обычно, надо выделять ящик, удалять его, пропорционально изменять размер других. А у меня просто убрать одну "*," и все посчитается само:
$boxes = split_vertical($box, "*,*,*,*", 16);
А теперь что если нижние два ящика объединить в 1?
Вот так:
$boxes = split_vertical($box, "50%,*,*", 16);
А что если внезапно нужна тумба побольше и пошире, с двумя большими ящиками и двумя маленькими (это уже комод теперь). Просто поменять 2 строчки:
$box = box(800, 1200, 600);
...
$boxes = split_vertical($box, "400,400,*,*", 16);
Я меняю внешние размеры, а внутри все пересчитывается автоматически в соответствии с правилами, можно задать четко размер для любой части, можно в процентах от общего пространства, можно равномерно разделить оставшееся свободное место. Добавить/убрать ящик/полку - одна строчка в коде. Что-то меняешь серьезнее, закоментарил старый код, и всегда видишь, как было и можешь к этому вернуться.