[Python, CAD/CAM, Промышленное программирование, Прототипирование, Визуальное программирование] Slicer: нарезка твердотельных объектов под раскрой

Автор Сообщение
news_bot ®

Стаж: 6 лет 3 месяца
Сообщений: 27286

Создавать темы news_bot ® написал(а)
12-Июл-2021 05:32
Извините, данный ресурс не поддреживается. :( Всем привет. Красивая фэшн мебель, предметы роскоши и интересный интерьер - это то, что позволяет пустить пыль в глаза вашим гостям и прослыть интересными людьми. Но как все это раздобыть, если у вас ипотека и бюджет ограничен? Этими вопросами я и задался, когда решил построить свой личный 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, #_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 (
Визуальное программирование
)
Профиль  ЛС 
Показать сообщения:     

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

Текущее время: 16-Май 03:11
Часовой пояс: UTC + 5