Так уж сложилось, что все незанятое программированием свободное время я "интересуюсь" 3D-моделированием. До появления в относительно свободной доступности 3D-принтеров это было не более чем абстрактным увлечением. Теперь же, мои корявые модельки приобретают физическую форму.

Проектирую, в основном, в Компас3D (дешево и сердито), и особо крокодильский там, как раз, экспорт в STL. Нужно нажать "Сохранить как", выбрать, куда сохранять и формат stl, кликнуть по расширенным настройкам сохранения, поправить эти настройки, чтобы модель была более "гладкой" и лишь потом произойдет чудо. Казалось бы, делать это приходится не так уж часто, но каждый раз неимоверно бесит. Штош, будем автоматизировать! Быстрый гуглёж дал интересную статейку про это НЕ на хабре, но там решение не очень удобное, и вообще C++. А мне выше python не прыгнуть. К счастью, в Компас3D есть возможность "скриптинга" на этом языке программирования - так что пробуем.

На python-е в STL

Автоматизировать действия в Компас3D можно, записав их в макрос через систему КОМПАС-макро, которую нужно не забыть выбрать при установке приложения. Жмем запись макроса, делаем вышеописанную болезненную процедуру экспорта в stl, останавливаем запись и сохраняем код макроса, который на поверку ничего не делает. Ну да, если бы это так сработало, то было бы слишком просто для статьи на хабре. Зато есть хорошая заготовка, которую можно дополнить и отладить в прилагающемся редакторе PyScripter. Да, дорогой гугл, при запросе как отлаживать python-скрипты в Компас3D приводи, пожалуйста, в эту статью, а не куда ты там обычно водишь. Требуется выбрать нужный файл в списке Компас-МАКРО->Макросы, нажать "Изменить", и откроется наш свежезаписанный макрос.

примерно такого содержания
# -*- coding: utf-8 -*-

import pythoncom
from win32com.client import Dispatch, gencache

import LDefin2D
import MiscellaneousHelpers as MH

#  Подключим константы API Компас
kompas6_constants = gencache.EnsureModule("{75C9F5D0-B5B8-4526-8681-9903C567D2ED}", 0, 1, 0).constants
kompas6_constants_3d = gencache.EnsureModule("{2CAF168C-7961-4B90-9DA2-701419BEEFE3}", 0, 1, 0).constants

#  Подключим описание интерфейсов API5
kompas6_api5_module = gencache.EnsureModule("{0422828C-F174-495E-AC5D-D31014DBBE87}", 0, 1, 0)
kompas_object = kompas6_api5_module.KompasObject(Dispatch("Kompas.Application.5")._oleobj_.QueryInterface(kompas6_api5_module.KompasObject.CLSID, pythoncom.IID_IDispatch))
MH.iKompasObject  = kompas_object

#  Подключим описание интерфейсов API7
kompas_api7_module = gencache.EnsureModule("{69AC2981-37C0-4379-84FD-5DD2F3C0A520}", 0, 1, 0)
application = kompas_api7_module.IApplication(Dispatch("Kompas.Application.7")._oleobj_.QueryInterface(kompas_api7_module.IApplication.CLSID, pythoncom.IID_IDispatch))
MH.iApplication  = application


Documents = application.Documents
#  Получим активный документ
kompas_document = application.ActiveDocument
kompas_document_3d = kompas_api7_module.IKompasDocument3D(kompas_document)
iDocument3D = kompas_object.ActiveDocument3D()

В нём пишем/правим код и жмем Run для отладки. Какой именно код, можно накопать в документации по SDK. Вы же не забыли выбрать SDK при установке Компас3D? :-) Он устанавливается в ту же директорию, куда и остальные файлы программы. Документация запутанная, но все что нужно уже скорее всего искали и обсуждали на форуме разработчика. Плюс, есть много примеров в архивах внутри директории SDK/Samples, правда, пока не на python. После недолгих блужданий находим нужный метод SaveAsToAdditionFormat и получаем итоговый макрос с примерно таким кодом. Он должен более менее хорошо читаться сверху вниз - там даже есть комментарии!

import pythoncom
from win32com.client import Dispatch, gencache
import traceback


class StlExport:
    def __init__(self):
        #  Подключим константы API Компас
        self.kompas6_constants = gencache.EnsureModule("{75C9F5D0-B5B8-4526-8681-9903C567D2ED}", 0, 1, 0).constants
        self.kompas6_constants_3d = gencache.EnsureModule("{2CAF168C-7961-4B90-9DA2-701419BEEFE3}", 0, 1, 0).constants

        #  Подключим описание интерфейсов API5
        self.kompas6_api5_module = gencache.EnsureModule("{0422828C-F174-495E-AC5D-D31014DBBE87}", 0, 1, 0)

        self.kompas_object = self.kompas6_api5_module.KompasObject(
            Dispatch("Kompas.Application.5")._oleobj_.QueryInterface(
                self.kompas6_api5_module.KompasObject.CLSID,
                pythoncom.IID_IDispatch
            )
        )

        #  Подключим описание интерфейсов API7
        kompas_api7_module = gencache.EnsureModule("{69AC2981-37C0-4379-84FD-5DD2F3C0A520}", 0, 1, 0)
        kompas_api_object = kompas_api7_module.IKompasAPIObject(
            Dispatch("Kompas.Application.7")._oleobj_.QueryInterface(
                    kompas_api7_module.IKompasAPIObject.CLSID,
                    pythoncom.IID_IDispatch
                )
            )

        # Получим основной объект API и текущий документ
        self.application = kompas_api_object.Application
        self.doc = self.application.ActiveDocument

        # Если открыт документ с 3D моделью пробуем экспортировать ее в stl
        self.iDocument3D = self.kompas_object.ActiveDocument3D()

        if self.iDocument3D:
            self.export_to_stl()
            return

        # Иначе напишем пользователю, что не шмогла
        self.application.MessageBoxEx("Невозможно сохранить этот документ в STL", "", 64)

    def export_to_stl(self):
        # Будем ловить все ошибки и вываливать их модальным окном пользователю
        try:
            # Если документ не сохранен - пути к нему нет
            if not self.doc.Path:
                self.kompas_object.ksMessage('Невозможно экспортировать несохраненный документ')
                return

            # А если сохранен, то запишем рядом с ним документ .stl с таким же именем
            stl_path = "{}{}.stl".format(self.doc.Path, self.doc.Name[:-4])
            self.save_as_stl(self.iDocument3D, stl_path)
        except Exception:
            msg = "При сохранении в STL произошла ошибка:\n\n{}".format(traceback.format_exc())
            self.kompas_object.ksMessage(msg)

    def save_as_stl(self, doc, resultPath):
        # Собственно, воспользуемся API для экспорта в STL с нужными нам параметрами
        additionFormat = doc.AdditionFormatParam()
        additionFormat.Init()  # старт инициализации параметров
        additionFormat.format = self.kompas6_constants_3d.format_STL  # формат STL
        additionFormat.formatBinary = True  # true - бинарный формат, false - текстовый формат
        additionFormat.lengthUnits = self.kompas6_constants.ksLUnMM  # единицы измерения длины, мм (см. ksLengthUnitsEnum)

        # Почему именно такие параметры экспорта - можно на YouTube у Соркина найти
        additionFormat.step = 0.05  # максимальное линейное отклонение
        additionFormat.angle = 3.6  # максимальное угловое отклонение
        # additionFormat.length = 15.792824  # максимальная длина ребра


        additionFormat.GetObjectsOptions(
            self.kompas6_constants_3d.ksD3COSurfaces  # ksD3ConverterOptionsEnum - Константы управляющие разрешением на чтение или запись объектов в дополнительные форматы
        )

        # Далее, осуществляем сам экспорт
        result = doc.SaveAsToAdditionFormat(resultPath, additionFormat)
        if result:
            self.application.MessageBoxEx("Успешно сохранено!\n\n{}".format(resultPath), "", 64)
        else:
            raise Exception('SaveAsToAdditionFormat returned false')

if __name__ == "__main__":
    StlExport()

И как это запускать?

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

Основная идея - добавить выполнение нашего скрипта в качестве сторонней утилиты для Компас3D. Идем через основное меню в Приложения->Конфигуратор, внутри него есть еще одно меню и там нужно выбрать Состав->Добавить утилиты... и указать путь к интерпретатору python из дистрибутива Компас3D. Он у вас по пути типа: "C:\ProgramData\ASCON\KOMPAS-3D\21\Python 3\App\pythonw.exe".

Теперь чуть ниже, в выпадайке "Утилиты", укажите любое название нового инструмента, например "STL", чтобы потом было проще его искать, при добавлении на панель инструментов. А в поле "Параметры" укажите полный путь к файлу макроса, написанного нами выше. Далее, просто закройте этот диалог - он сохраняется автомагически. Уже сейчас можно пользоваться этим инструментом через основное меню Приложения->Утилиты->STL

А как же кнопка на панели инструментов?

Скорее всего, вы и сами знаете как ее добавить, но все-таки. Требуется пойти в Настройка интерфейса->Панели->Настроить, выбрать там во вкладке "Команды" раздел "Утилиты" и перетащить оттуда кнопку с названием вашего макроса на нужную вам панель инструментов. Пользуйтесь на здоровье!

Комментарии (2)


  1. TheKetchup
    25.07.2023 08:20
    +2

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


    1. alrusdi Автор
      25.07.2023 08:20
      -1

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