[CDR 2025] ZigZag удачи (макрос сетки раскроя для CorelDraw)

  • Автор темы Автор темы MrDesigner
  • Дата начала Дата начала

MrDesigner

Топикстартер
15 лет на форуме
Сообщения
2 299
Реакции
853
Всем привет!

Есть такая задача: создать контуры прямоугольников для последующего раскроя плёнки на каттере.

В начале работы макроса пользователем задаётся размер ячейки (ширина, высота), размер оверката (overcut - внешние вылеты за границы ячеек), количество ячеек по горизонтали и вертикали.

Макрос "рисует" сетку раскроя с максимальной оптимизацией. Первая (верхняя) горизонтальная линия должна начинаться с левого верхнего края документа и иметь направление слева направо.

Остальные линии рисуются "ёлочкой" (зигзагом), чтобы не было "холостого" хода ножа при крое (на схеме показан стрелками направление кроя, числами - порядок следования.):

1755778295342.jpeg


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

"Пообщавшись" с ChatGPT, родился следующий макрос, который работает с некоторыми ошибками:

Код:
Sub CreateZigzagGrid_FixedVerticalOrder_Centered()
    Dim doc As Document
    Dim pg As Page
    Dim layer As Layer
    Dim cellWidthMM As Double, cellHeightMM As Double, overcutMM As Double
    Dim rows As Long, cols As Long
    Dim cellWidthDU As Double, cellHeightDU As Double, overcutDU As Double
    Dim i As Long, yPos As Double
    Dim lastX As Double, lastY As Double
    Dim vertTopToBottom As Boolean
    Dim xStart As Double, xEnd As Double
    Dim firstColIndex As Long
    Dim colOffset As Long, jIndex As Long
    Dim xPos As Double, yBottom As Double, yTop As Double
    Dim s As Shape, gridGroup As Shape, rect As Rect
    Dim offsetX As Double, offsetY As Double
    Dim allLines As New Collection
    
    Set doc = ActiveDocument
    Set pg = doc.ActivePage
    Set layer = ActiveLayer
    
    ' Ввод параметров
    cellWidthMM = Val(InputBox("Введите ширину ячейки (мм):", "Сетка", "30"))
    cellHeightMM = Val(InputBox("Введите высоту ячеек (мм):", "Сетка", "20"))
    overcutMM = Val(InputBox("Введите overcut (мм):", "Сетка", "2"))
    rows = Val(InputBox("Введите количество рядов:", "Сетка", "10"))
    cols = Val(InputBox("Введите количество столбцов:", "Сетка", "5"))
    
    If cellWidthMM <= 0 Or cellHeightMM <= 0 Or rows <= 0 Or cols <= 0 Or overcutMM < 0 Then
        MsgBox "Все значения должны быть корректными!", vbExclamation
        Exit Sub
    End If
    
    ' Конвертация в единицы документа
    cellWidthDU = doc.ToUnits(cellWidthMM, cdrMillimeter)
    cellHeightDU = doc.ToUnits(cellHeightMM, cdrMillimeter)
    overcutDU = doc.ToUnits(overcutMM, cdrMillimeter)
    
    ' --- Горизонтальные линии (змейка) ---
    For i = 0 To rows
        yPos = i * cellHeightDU   ' Считаем от низа страницы вверх
        
        If i Mod 2 = 0 Then
            xStart = -overcutDU
            xEnd = cols * cellWidthDU + overcutDU
        Else
            xStart = cols * cellWidthDU + overcutDU
            xEnd = -overcutDU
        End If
        
        Set s = layer.CreateLineSegment(xStart, yPos, xEnd, yPos)
        allLines.Add s
        
        If i = rows Then
            lastX = IIf(i Mod 2 = 0, cols * cellWidthDU, 0)
            lastY = yPos
        End If
    Next i
    
    ' Определяем индекс первой вертикали
    If lastX = 0 Then
        firstColIndex = 0
    Else
        firstColIndex = cols
    End If
    
    ' --- Вертикальные линии (змейка) ---
    vertTopToBottom = True
    yBottom = -overcutDU
    yTop = rows * cellHeightDU + overcutDU
    
    For colOffset = 0 To cols
        If lastX = 0 Then
            jIndex = firstColIndex + colOffset
        Else
            jIndex = firstColIndex - colOffset
        End If
        
        If jIndex < 0 Or jIndex > cols Then Exit For
        
        xPos = jIndex * cellWidthDU
        
        If vertTopToBottom Then
            Set s = layer.CreateLineSegment(xPos, yBottom, xPos, yTop)
        Else
            Set s = layer.CreateLineSegment(xPos, yTop, xPos, yBottom)
        End If
        
        allLines.Add s
        vertTopToBottom = Not vertTopToBottom
    Next colOffset
    
    ' --- Группируем все линии ---
    Dim arr() As Shape
    ReDim arr(1 To allLines.Count)
    For i = 1 To allLines.Count
        Set arr(i) = allLines(i)
    Next i
    
    Set gridGroup = layer.Group(arr)
    
    ' --- Центрирование относительно страницы ---
    Set rect = gridGroup.BoundingBox
    offsetX = (pg.SizeWidth / 2) - (rect.Left + rect.Width / 2)
    offsetY = (pg.SizeHeight / 2) - (rect.Bottom + rect.Height / 2)
    gridGroup.Move offsetX, offsetY
    
    ' --- Снять выделение ---
    doc.ClearSelection
    
    MsgBox "Сетка готова и отцентрирована по центру страницы!"
End Sub

Был бы признателен, если кто-нибудь поделится рабочим решением.

Спасибо.
 
Правишь циферки в начале файла и бросаешь его куда надо. Без никакого корела и прочей проприетарщины.
1755778955910.png

1755779091747.png
 

Вложения

  • Спасибо
Реакции: MrDesigner и zollinger
Правый нижний угол:

1755779437126.png

Направление вертикальной линии должно быть в другую сторону (вверх).
 
Раз уж оптимизиовать холостые проходы, то для чётного и нечётного количества строк вертикальные линии нужно рисовать в разных направлениях: для чётного слева направо, а для нечётного права налево. Верно?
 
Наверное, да. Собственно, в этом и состоит задача - максимально оптимизировать крой, чтобы не было холостых проходов. Ну и задать нулевую точку в левом верхнем углу.
 
какой-то мега сложный код. там весь алгоритм это два цикла по три строчки.



Код:
For i = strt To col_cnt
    If i Mod 2 = 0 Then
        sr.Add ActiveLayer.CreateLineSegment(s.LeftX + xdist * i, s.BottomY, s.LeftX + xdist * i, s.TopY)
    Else
        sr.Add ActiveLayer.CreateLineSegment(s.LeftX + xdist * i, s.TopY, s.LeftX + xdist * i, s.BottomY)
    End If
Next i

For i = row_cnt To strt Step -1
    If i Mod 2 = 0 Then
        sr.Add ActiveLayer.CreateLineSegment(s.LeftX, s.BottomY + ydist * i, s.RightX, s.BottomY + ydist * i)
    Else
        sr.Add ActiveLayer.CreateLineSegment(s.RightX, s.BottomY + ydist * i, s.LeftX, s.BottomY + ydist * i)
    End If
Next i
 
  • Спасибо
Реакции: MrDesigner
Это не ко мне. Там чатжпт наворотил...
уже много на форуме обсуждалось. чатЖПТ с корелом оч плохо дружит. очень уж он любит всё усложнять и выдумывать несуществующие методы для выдуманых объектов.
 
Да-да, мы и это знаем...
 
вот что мне QWEN выдал после трёх пинков чтоыб он код сократил..


Код:
Sub CreateCuttingGrid()
    Dim w As Double, h As Double, oc As Double
    Dim cols As Integer, rows As Integer
    Dim i As Integer, j As Integer
    Dim x As Double, y As Double
    
    w = CDbl(InputBox("Ширина ячейки (мм):", , "100"))
    h = CDbl(InputBox("Высота ячейки (мм):", , "100"))
    oc = CDbl(InputBox("Оверкат (мм):", , "5"))
    cols = CInt(InputBox("Ячеек по горизонтали:", , "3"))
    rows = CInt(InputBox("Ячеек по вертикали:", , "3"))
    
    ' Верхняя линия
    ActiveLayer.CreateLineSegment -oc, 0, cols * w + oc, 0
    
    ' Сетка зигзагом
    For i = 1 To rows
        y = i * h
        ' Вертикальные линии
        For j = 0 To cols
            x = j * w
            ActiveLayer.CreateLineSegment x, (i - 1) * h, x, y
        Next j
        ' Горизонтальные линии (зигзаг)
        If i Mod 2 = 1 Then
            ActiveLayer.CreateLineSegment -oc, y, cols * w + oc, y
        Else
            ActiveLayer.CreateLineSegment cols * w + oc, y, -oc, y
        End If
    Next i
    
    ' Нижние вертикальные линии с оверкатом
    For j = 0 To cols
        x = j * w
        ActiveLayer.CreateLineSegment x, rows * h, x, rows * h + oc
    Next j
End Sub
 
  • Спасибо
Реакции: MrDesigner
Спасибо, на досуге глянем!
 
вот что мне QWEN выдал после трёх пинков чтоыб он код сократил..
Нормально не работает. На единицы измерения внимания не обращаем, но сетка не генерируется. Точнее, там отдельные куски какие-то...
 
во! домучал я его.
самый лаконичный алгоритм получился. (правда без ручных правок и тыканья ЖПТ носом в ошибки не обошлось)
останется только доработать согласно уже личным нуждам )))


Код:
Sub CreateCuttingGrid()
    Dim w As Double, h As Double, oc As Double
    Dim cols As Integer, rows As Integer
    Dim i As Integer
    
    w = CDbl(InputBox("Ширина ячейки (мм):", , "100"))
    h = CDbl(InputBox("Высота ячейки (мм):", , "100"))
    oc = CDbl(InputBox("Оверкат (мм):", , "5"))
    cols = CInt(InputBox("Ячеек по горизонтали:", , "3"))
    rows = CInt(InputBox("Ячеек по вертикали:", , "3"))
    
    ' Горизонтальные линии зигзагом, начинаем с верхнего левого угла
    For i = 0 To rows
        If i Mod 2 = 0 Then
            ActiveLayer.CreateLineSegment -oc, -i * h, cols * w + oc, -i * h  ' слева направо
        Else
            ActiveLayer.CreateLineSegment cols * w + oc, -i * h, -oc, -i * h  ' справа налево
        End If
    Next i
    
    ' Вертикальные линии зигзагом, начинаем с угла где закончилась последняя горизонтальная линия
        ' Последняя горизонтальная линия заканчивается справа, начинаем вертикальные с правого края зигзагом
    For i = 0 To cols
        If i Mod 2 = 0 Then
            If rows Mod 2 = 0 Then
                ActiveLayer.CreateLineSegment (cols - i) * w, -(rows * h + oc), (cols - i) * w, oc
            Else
                ActiveLayer.CreateLineSegment i * w, -(rows * h + oc), i * w, oc
            End If
        Else
            If rows Mod 2 = 0 Then
                ActiveLayer.CreateLineSegment (cols - i) * w, oc, (cols - i) * w, -(rows * h + oc)
            Else
                ActiveLayer.CreateLineSegment i * w, oc, i * w, -(rows * h + oc)
            End If
        End If
    Next i
End Sub
 
  • Спасибо
Реакции: MrDesigner
Нормально не работает. На единицы измерения внимания не обращаем, но сетка не генерируется. Точнее, там отдельные куски какие-то...
так да. это первое что он выдал. об этом и речь, что толковый код ЖПТ не пишет для корела. пока ему конкретные ошибки не укажешь.
 
Единицы измерения врут...
 
  • Спасибо
Реакции: MrDesigner
вот примерно так.
еще по хорошему сделать мини форму с полями ввода вместо кучи всплывающих окошек. Я бы еще сделал чтобы он из текущего выбранного прямоугольника (или нескольких сразу) делал линии на их месте. в общем куча простора для модификаций.
Опять же копируем код - пихаем в ЖПТ и он уже будет выдавать мелкие правки по необходимости

Код:
Public Sub CreateCuttingGrid()
    Dim w As Double, h As Double, oc As Double
    Dim cols As Integer, rows As Integer
    Dim i As Integer, koef As Integer, ud As Integer
   
    ud = ActiveDocument.Unit
    ActiveDocument.Unit = cdrMillimeter
    ActiveDocument.BeginCommandGroup
   
    w = CDbl(InputBox("Ширина ячейки (мм):", , "100"))
    h = CDbl(InputBox("Высота ячейки (мм):", , "100"))
    oc = CDbl(InputBox("Оверкат (мм):", , "5"))
    cols = CInt(InputBox("Ячеек по горизонтали:", , "3"))
    rows = CInt(InputBox("Ячеек по вертикали:", , "3"))
   
    ' Горизонтальные линии зигзагом, начинаем с верхнего левого угла
    For i = 0 To rows
        If i Mod 2 = 0 Then
            ActiveLayer.CreateLineSegment -oc, -i * h, cols * w + oc, -i * h  ' слева направо
        Else
            ActiveLayer.CreateLineSegment cols * w + oc, -i * h, -oc, -i * h  ' справа налево
        End If
    Next i
   
    ' Вертикальные линии зигзагом, начинаем с угла где закончилась последняя горизонтальная линия
        ' Последняя горизонтальная линия заканчивается справа, начинаем вертикальные с правого края зигзагом
    For i = 0 To cols
        koef = IIf(rows Mod 2 = 0, (cols - i), i)
        If i Mod 2 = 0 Then
            ActiveLayer.CreateLineSegment koef * w, -(rows * h + oc), koef * w, oc
        Else
            ActiveLayer.CreateLineSegment koef * w, oc, koef * w, -(rows * h + oc)
        End If
    Next i
   
    ActiveDocument.EndCommandGroup
    ActiveDocument.Unit = ud
End Sub


PS. я не удержался и еще немного сократил логику )))
 
Последнее редактирование:
Это-то всё хорошо. Только, к сожалению, одной копипастой не отделаешься.
Нужно создавать мини-форму (Insert UserForm)... А там - засада... Стар я стал так далеко копать... ))
 
  • Смешно
Реакции: DukereD