[Python, CAD/CAM, Промышленное программирование, Прототипирование, Визуальное программирование] Slicer: нарезка твердотельных объектов под раскрой
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Извините, данный ресурс не поддреживается. :( Всем привет. Красивая фэшн мебель, предметы роскоши и интересный интерьер - это то, что позволяет пустить пыль в глаза вашим гостям и прослыть интересными людьми. Но как все это раздобыть, если у вас ипотека и бюджет ограничен? Этими вопросами я и задался, когда решил построить свой личный CNC станок.Если конкретнее, я увидел на Pinterest всяческие модные штуки типа этой:
себестоимость материала - 3 копейкиВоссоздать такую красоту нам поможет формула волны, известная из школьного курса y=sin(x), правда я модифицировал ее, добавив затухание, и спустя пару часов с момента, как я впервые увидел язык ruby, в редакторе SketchUp у меня оформился вот такой результат (листинг рассмотрим в другой раз):
данный код уже не работает в SketchUp, они плевать хотели на обратную совместимостьНо, если речь идет об объектах серьезных размеров, хотелось бы как-то сократить количество материала. Посмотрите на следующий объект:
это мебель, или просто часть стены?..Здесь появляется следующая проблема: как преобразовать 3D объект в каркас из листового материала, части которого стыкуются между собой, желательно без крепежа, паз в паз? Не секрет, что на рынке игрушек есть разнообразные конструкторы, разработчики которых решили эту проблему:
наивный байесовский оленьв открытом виде такой код мне обнаружить не удалось, поэтому пришлось писать свой собственный высококачественный лапшекод, за который "coder-nazi" накидают мне минусов в карму, думая что этого достаточно для его автоматического улучшения. Перед тем как вы это увидите, отвлекитесь от детских конструкторов и взгляните, что могут сделать толковые ребята в более серьезных масштабах:
И наконец, его величество код! Исполнять в консоли редактора FreeCad.
App.ActiveDocument.addObject("Part::Sphere","Sphere")
App.ActiveDocument.ActiveObject.Label = "Sphere"
s_offset = 200
App.ActiveDocument.Sphere.Radius = s_offset
#App.ActiveDocument.Sphere.Placement = App.Placement(App.Vector(500,500,500),App.Rotation(App.Vector(0,0,1),0))
App.ActiveDocument.recompute()
def isEmpty(sh):
if sh == None:
return True
if sh.Shape.BoundBox.ZMin == sys.float_info.max and sh.Shape.BoundBox.ZMax == -sys.float_info.max:
return True
return False
def slice(name):
if name == "":
name = "Sphere"
sx = 1310
sy = 1510
offset = 10000
rHeigth = 1400
rThickness = 4
rLength = 1500
stepx = 80
stepy = 80
dx = 10
dy = 10
mx = {}
my = {}
n = 0
copy = FreeCAD.ActiveDocument.copyObject(FreeCAD.activeDocument().getObject(name),False)
copy.Placement = App.Placement(App.Vector(s_offset,offset+s_offset,s_offset),App.Rotation(App.Vector(0,0,1),0))
while dx < sx:
box = App.ActiveDocument.addObject("Part::Box","Box"+str(n))
box.Length=rThickness
box.Width=rLength
box.Height=rHeigth
box.Placement=App.Placement(App.Vector(dx,offset,0),App.Rotation(App.Vector(0,0,1),0))
common = App.activeDocument().addObject("Part::MultiCommon","CommonX"+str(n))
common.Shapes = [copy,box]
#common.Placement=App.Placement(App.Vector(0,0,0),App.Rotation(App.Vector(0,0,1),0))
#copy.Visibility=False
#box.Visibility=False
#common.ShapeColor=copy.ShapeColor
#common.DisplayMode=copy.DisplayMode
mx[n] = common
dx = dx + stepx
n = n + 1
colx = n
n = 0
while dy < sy:
box = App.ActiveDocument.addObject("Part::Box","Box"+str(n))
box.Length=rLength
box.Width=rThickness
box.Height=rHeigth
box.Placement=App.Placement(App.Vector(0,offset+dy,0),App.Rotation(App.Vector(0,0,1),0))
common = App.activeDocument().addObject("Part::MultiCommon","CommonY"+str(n))
common.Shapes = [copy,box]
#common.Placement=App.Placement(App.Vector(0,0,0),App.Rotation(App.Vector(0,0,1),0))
#copy.Visibility=False
#box.Visibility=False
#common.ShapeColor=copy.ShapeColor
#common.DisplayMode=copy.DisplayMode
my[n] = common
dy = dy + stepy
n = n + 1
coly = n
print("!!!---")
App.ActiveDocument.recompute()
inter = {}
for i in range(0,colx):
for j in range(0,coly):
if not (isEmpty(mx[i]) or isEmpty(my[j])):
common = App.activeDocument().addObject("Part::MultiCommon","ComX"+str(i)+"Y"+str(j))
common.Shapes = [mx[i],my[j]]
inter[(i,j)] = common
#print(str(i)+" "+ str(j)+" " + str(common.Shape.BoundBox.ZMax)+" "+str(common.Shape.BoundBox.ZMax))
App.ActiveDocument.recompute()
for i in range(0,colx):
for j in range(0,coly):
if not isEmpty(inter.get((i,j))):
com = inter.get((i,j))
d = (com.Shape.BoundBox.ZMax - com.Shape.BoundBox.ZMin)/2
box = App.ActiveDocument.addObject("Part::Box","Box"+str(n))
box.Length= com.Shape.BoundBox.XMax - com.Shape.BoundBox.XMin
box.Width= com.Shape.BoundBox.YMax - com.Shape.BoundBox.YMin
box.Height=d+rThickness/2
box.Placement=App.Placement(App.Vector(com.Shape.BoundBox.XMin,com.Shape.BoundBox.YMin,com.Shape.BoundBox.ZMin),App.Rotation(App.Vector(0,0,1),0))
box1 = App.ActiveDocument.copyObject(box, False)
box1.Placement=App.Placement(App.Vector(com.Shape.BoundBox.XMin,com.Shape.BoundBox.YMin,com.Shape.BoundBox.ZMin+d-rThickness/2),App.Rotation(App.Vector(0,0,1),0))
com2 = App.activeDocument().addObject("Part::MultiCommon","com2_")
com2.Shapes = [com,box]
com3 = App.activeDocument().addObject("Part::MultiCommon","com3_")
com3.Shapes = [com,box1]
comX = App.activeDocument().addObject("Part::Cut","CutX"+str(i))
comX.Base = mx[i]
comX.Tool = com2
mx[i] = comX
comY = App.activeDocument().addObject("Part::Cut","CutY"+str(j))
comY.Base = my[j]
comY.Tool = com3
my[j] = comY
#print(str(i)+" "+ str(j))
App.ActiveDocument.recompute()
for i in range(0,colx):
if not (isEmpty(mx[i])):
mx[i].Placement=App.Placement(App.Vector(stepx*i,20000,0),App.Rotation(App.Vector(0,1,0),90))
for j in range(0,coly):
if not (isEmpty(my[j])):
my[j].Placement=App.Placement(App.Vector(20000,stepy*j,0),App.Rotation(App.Vector(1,0,0),90))
#App.ActiveDocument.addObject('Part::Feature','Line002').Shape=App.ActiveDocument.Line002.Shape.removeSplitter()
#App.ActiveDocument.Common.Shape.BoundBox.ZMax
App.ActiveDocument.recompute()
x1=rThickness
y1=rThickness
yMax = 0
#from typing import Dict, List
all = list()#List[DocumentObject]
for i in range(0,colx):
if not (isEmpty(mx[i])):
if (x1+(mx[i].Shape.BoundBox.XMax-mx[i].Shape.BoundBox.XMin)) > sx:
x1 = 0
y1 = yMax+rThickness*3
x=mx[i].Shape.BoundBox.XMin
y=mx[i].Shape.BoundBox.YMin
z=mx[i].Shape.BoundBox.ZMin
mx[i].Placement.move(FreeCAD.Base.Vector(-x+x1+rThickness*3,-y+y1,-z))
x1=mx[i].Shape.BoundBox.XMax
if (mx[i].Shape.BoundBox.YMax>yMax):
yMax = mx[i].Shape.BoundBox.YMax
all.append(App.activeDocument().getObject(mx[i].Name))
for j in range(0,coly):
if not (isEmpty(my[j])):
if (x1+(my[j].Shape.BoundBox.XMax-my[j].Shape.BoundBox.XMin)) > sx:
x1 = 0
y1 = yMax+rThickness*3
x=my[j].Shape.BoundBox.XMin
y=my[j].Shape.BoundBox.YMin
z=my[j].Shape.BoundBox.ZMin
my[j].Placement.move(FreeCAD.Base.Vector(-x+x1+rThickness*3,-y+y1,-z))
#App.ActiveDocument.recompute()
x1=my[j].Shape.BoundBox.XMax
#print "--"+str(x1)
#y1=my[j].Shape.BoundBox.YMax
if (my[j].Shape.BoundBox.YMax>yMax):
yMax = my[j].Shape.BoundBox.YMax
all.append(App.activeDocument().getObject(my[j].Name))
#print all
Gui.activeDocument().getObject(name).Visibility=False
App.activeDocument().addObject("Part::Compound","Compound")
App.activeDocument().Compound.Links = all
App.ActiveDocument.recompute()
return ""
slice("")
Для начала, создается сфера (App.ActiveDocument.addObject("Part::Sphere","Sphere"))
Далее, она нарезается горизонтально решеткой рассекающих Box'ов:
Особенность ее - в том, что на половине высоты каждого пересечения у продольных и поперечных ребер вырезается паз. Так как у меня фрезер, а не лазерный станок, пазы следует увеличить, иначе за счет радиуса фрезы при вставке деталей будет пазы окажутся недостаточными. Но ребра еще предстоит разложить на листе материала:
На основе этого compaund'а из всех деталей можно построить программу для станка. Программно я этого сделать не смог (может, кто-то подскажет как это сделать), поэтому следует вручную добавить Job, выставить параметры фрезы, и добавить тех. операцию profile (к которой было бы неплохо добавить "Перемычки для удержания деталей в заготовке", иначе детали разбросает после отделения от листа):
Отсюда уже можно экспортировать G-код для станка:
Видео-версия:Извините, данный ресурс не поддреживается. :(
===========
Источник:
habr.com
===========
Похожие новости:
- [Python, Программирование, Машинное обучение, Natural Language Processing] Как новый метод упаковки в BERT ускоряет обработку естественного языка в 2 раза (перевод)
- [Open source, Алгоритмы, Машинное обучение] Open source в Университете ИТМО: фреймворк для AutoML и библиотека алгоритмов выбора признаков
- [Программирование, Звук] Книги о цифровой обработке сигналов и звуковом синтезе
- [Программирование, Анализ и проектирование систем, Совершенный код, Проектирование и рефакторинг, ООП] OCP против YAGNI (перевод)
- [Python] Алгебраические типы данных и Python
- [Python, Машинное обучение, Разработка на Raspberry Pi, TensorFlow] Как на Raspberry Pi запустить модель ML и сэкономить пространство одноплатника (перевод)
- [Python, Программирование, C++, Алгоритмы] Оптимизация на простых типах данных. Часть №2 «Числа»
- [Тестирование IT-систем, Python, Разработка под Windows] Десктопизация по-питоновски. Инструменты для создания автотестов
- [Python, Профессиональная литература] Книга «Python, например»
- [Системное программирование] Домен, поддомен, ограниченный контекст, пространство задач/решений в DDD: четко определены (перевод)
Теги для поиска: #_python, #_cad/cam, #_promyshlennoe_programmirovanie (Промышленное программирование), #_prototipirovanie (Прототипирование), #_vizualnoe_programmirovanie (Визуальное программирование), #_python, #_cnc, #_cad, #_freecad, #_programmirovanie (программирование), #_promyshlennyj_dizajn (промышленный дизайн), #_stanki (станки), #_stanki_s_chpu (станки с чпу), #_krasivye_shtuki (красивые штуки), #_interer (интерьер), #_python, #_cad/cam, #_promyshlennoe_programmirovanie (
Промышленное программирование
), #_prototipirovanie (
Прототипирование
), #_vizualnoe_programmirovanie (
Визуальное программирование
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 07:14
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Извините, данный ресурс не поддреживается. :( Всем привет. Красивая фэшн мебель, предметы роскоши и интересный интерьер - это то, что позволяет пустить пыль в глаза вашим гостям и прослыть интересными людьми. Но как все это раздобыть, если у вас ипотека и бюджет ограничен? Этими вопросами я и задался, когда решил построить свой личный CNC станок.Если конкретнее, я увидел на Pinterest всяческие модные штуки типа этой:
себестоимость материала - 3 копейкиВоссоздать такую красоту нам поможет формула волны, известная из школьного курса y=sin(x), правда я модифицировал ее, добавив затухание, и спустя пару часов с момента, как я впервые увидел язык ruby, в редакторе SketchUp у меня оформился вот такой результат (листинг рассмотрим в другой раз): данный код уже не работает в SketchUp, они плевать хотели на обратную совместимостьНо, если речь идет об объектах серьезных размеров, хотелось бы как-то сократить количество материала. Посмотрите на следующий объект: это мебель, или просто часть стены?..Здесь появляется следующая проблема: как преобразовать 3D объект в каркас из листового материала, части которого стыкуются между собой, желательно без крепежа, паз в паз? Не секрет, что на рынке игрушек есть разнообразные конструкторы, разработчики которых решили эту проблему: наивный байесовский оленьв открытом виде такой код мне обнаружить не удалось, поэтому пришлось писать свой собственный высококачественный лапшекод, за который "coder-nazi" накидают мне минусов в карму, думая что этого достаточно для его автоматического улучшения. Перед тем как вы это увидите, отвлекитесь от детских конструкторов и взгляните, что могут сделать толковые ребята в более серьезных масштабах: И наконец, его величество код! Исполнять в консоли редактора FreeCad. App.ActiveDocument.addObject("Part::Sphere","Sphere")
App.ActiveDocument.ActiveObject.Label = "Sphere" s_offset = 200 App.ActiveDocument.Sphere.Radius = s_offset #App.ActiveDocument.Sphere.Placement = App.Placement(App.Vector(500,500,500),App.Rotation(App.Vector(0,0,1),0)) App.ActiveDocument.recompute() def isEmpty(sh): if sh == None: return True if sh.Shape.BoundBox.ZMin == sys.float_info.max and sh.Shape.BoundBox.ZMax == -sys.float_info.max: return True return False def slice(name): if name == "": name = "Sphere" sx = 1310 sy = 1510 offset = 10000 rHeigth = 1400 rThickness = 4 rLength = 1500 stepx = 80 stepy = 80 dx = 10 dy = 10 mx = {} my = {} n = 0 copy = FreeCAD.ActiveDocument.copyObject(FreeCAD.activeDocument().getObject(name),False) copy.Placement = App.Placement(App.Vector(s_offset,offset+s_offset,s_offset),App.Rotation(App.Vector(0,0,1),0)) while dx < sx: box = App.ActiveDocument.addObject("Part::Box","Box"+str(n)) box.Length=rThickness box.Width=rLength box.Height=rHeigth box.Placement=App.Placement(App.Vector(dx,offset,0),App.Rotation(App.Vector(0,0,1),0)) common = App.activeDocument().addObject("Part::MultiCommon","CommonX"+str(n)) common.Shapes = [copy,box] #common.Placement=App.Placement(App.Vector(0,0,0),App.Rotation(App.Vector(0,0,1),0)) #copy.Visibility=False #box.Visibility=False #common.ShapeColor=copy.ShapeColor #common.DisplayMode=copy.DisplayMode mx[n] = common dx = dx + stepx n = n + 1 colx = n n = 0 while dy < sy: box = App.ActiveDocument.addObject("Part::Box","Box"+str(n)) box.Length=rLength box.Width=rThickness box.Height=rHeigth box.Placement=App.Placement(App.Vector(0,offset+dy,0),App.Rotation(App.Vector(0,0,1),0)) common = App.activeDocument().addObject("Part::MultiCommon","CommonY"+str(n)) common.Shapes = [copy,box] #common.Placement=App.Placement(App.Vector(0,0,0),App.Rotation(App.Vector(0,0,1),0)) #copy.Visibility=False #box.Visibility=False #common.ShapeColor=copy.ShapeColor #common.DisplayMode=copy.DisplayMode my[n] = common dy = dy + stepy n = n + 1 coly = n print("!!!---") App.ActiveDocument.recompute() inter = {} for i in range(0,colx): for j in range(0,coly): if not (isEmpty(mx[i]) or isEmpty(my[j])): common = App.activeDocument().addObject("Part::MultiCommon","ComX"+str(i)+"Y"+str(j)) common.Shapes = [mx[i],my[j]] inter[(i,j)] = common #print(str(i)+" "+ str(j)+" " + str(common.Shape.BoundBox.ZMax)+" "+str(common.Shape.BoundBox.ZMax)) App.ActiveDocument.recompute() for i in range(0,colx): for j in range(0,coly): if not isEmpty(inter.get((i,j))): com = inter.get((i,j)) d = (com.Shape.BoundBox.ZMax - com.Shape.BoundBox.ZMin)/2 box = App.ActiveDocument.addObject("Part::Box","Box"+str(n)) box.Length= com.Shape.BoundBox.XMax - com.Shape.BoundBox.XMin box.Width= com.Shape.BoundBox.YMax - com.Shape.BoundBox.YMin box.Height=d+rThickness/2 box.Placement=App.Placement(App.Vector(com.Shape.BoundBox.XMin,com.Shape.BoundBox.YMin,com.Shape.BoundBox.ZMin),App.Rotation(App.Vector(0,0,1),0)) box1 = App.ActiveDocument.copyObject(box, False) box1.Placement=App.Placement(App.Vector(com.Shape.BoundBox.XMin,com.Shape.BoundBox.YMin,com.Shape.BoundBox.ZMin+d-rThickness/2),App.Rotation(App.Vector(0,0,1),0)) com2 = App.activeDocument().addObject("Part::MultiCommon","com2_") com2.Shapes = [com,box] com3 = App.activeDocument().addObject("Part::MultiCommon","com3_") com3.Shapes = [com,box1] comX = App.activeDocument().addObject("Part::Cut","CutX"+str(i)) comX.Base = mx[i] comX.Tool = com2 mx[i] = comX comY = App.activeDocument().addObject("Part::Cut","CutY"+str(j)) comY.Base = my[j] comY.Tool = com3 my[j] = comY #print(str(i)+" "+ str(j)) App.ActiveDocument.recompute() for i in range(0,colx): if not (isEmpty(mx[i])): mx[i].Placement=App.Placement(App.Vector(stepx*i,20000,0),App.Rotation(App.Vector(0,1,0),90)) for j in range(0,coly): if not (isEmpty(my[j])): my[j].Placement=App.Placement(App.Vector(20000,stepy*j,0),App.Rotation(App.Vector(1,0,0),90)) #App.ActiveDocument.addObject('Part::Feature','Line002').Shape=App.ActiveDocument.Line002.Shape.removeSplitter() #App.ActiveDocument.Common.Shape.BoundBox.ZMax App.ActiveDocument.recompute() x1=rThickness y1=rThickness yMax = 0 #from typing import Dict, List all = list()#List[DocumentObject] for i in range(0,colx): if not (isEmpty(mx[i])): if (x1+(mx[i].Shape.BoundBox.XMax-mx[i].Shape.BoundBox.XMin)) > sx: x1 = 0 y1 = yMax+rThickness*3 x=mx[i].Shape.BoundBox.XMin y=mx[i].Shape.BoundBox.YMin z=mx[i].Shape.BoundBox.ZMin mx[i].Placement.move(FreeCAD.Base.Vector(-x+x1+rThickness*3,-y+y1,-z)) x1=mx[i].Shape.BoundBox.XMax if (mx[i].Shape.BoundBox.YMax>yMax): yMax = mx[i].Shape.BoundBox.YMax all.append(App.activeDocument().getObject(mx[i].Name)) for j in range(0,coly): if not (isEmpty(my[j])): if (x1+(my[j].Shape.BoundBox.XMax-my[j].Shape.BoundBox.XMin)) > sx: x1 = 0 y1 = yMax+rThickness*3 x=my[j].Shape.BoundBox.XMin y=my[j].Shape.BoundBox.YMin z=my[j].Shape.BoundBox.ZMin my[j].Placement.move(FreeCAD.Base.Vector(-x+x1+rThickness*3,-y+y1,-z)) #App.ActiveDocument.recompute() x1=my[j].Shape.BoundBox.XMax #print "--"+str(x1) #y1=my[j].Shape.BoundBox.YMax if (my[j].Shape.BoundBox.YMax>yMax): yMax = my[j].Shape.BoundBox.YMax all.append(App.activeDocument().getObject(my[j].Name)) #print all Gui.activeDocument().getObject(name).Visibility=False App.activeDocument().addObject("Part::Compound","Compound") App.activeDocument().Compound.Links = all App.ActiveDocument.recompute() return "" slice("") Далее, она нарезается горизонтально решеткой рассекающих Box'ов: Особенность ее - в том, что на половине высоты каждого пересечения у продольных и поперечных ребер вырезается паз. Так как у меня фрезер, а не лазерный станок, пазы следует увеличить, иначе за счет радиуса фрезы при вставке деталей будет пазы окажутся недостаточными. Но ребра еще предстоит разложить на листе материала: На основе этого compaund'а из всех деталей можно построить программу для станка. Программно я этого сделать не смог (может, кто-то подскажет как это сделать), поэтому следует вручную добавить Job, выставить параметры фрезы, и добавить тех. операцию profile (к которой было бы неплохо добавить "Перемычки для удержания деталей в заготовке", иначе детали разбросает после отделения от листа): Отсюда уже можно экспортировать G-код для станка: Видео-версия:Извините, данный ресурс не поддреживается. :( =========== Источник: habr.com =========== Похожие новости:
Промышленное программирование ), #_prototipirovanie ( Прототипирование ), #_vizualnoe_programmirovanie ( Визуальное программирование ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 07:14
Часовой пояс: UTC + 5