Python на службе у конструктора. Укрощаем API Kompas 3D

Logo


Работая в конструкторском отделе, я столкнулся с задачей — рассчитать трудоёмкость разработки конструкторской документации. Если брать за основу документ: «Типовые нормативы времени на разработку конструкторской документации. ШИФР 13.01.01" (утв. Минтрудом России 07.03.2014 N 003)», то для расчета трудоёмкости чертежа детали нам необходимы следующие данные:


  • Формат чертежа и количество листов
  • Масштаб
  • Количество размеров на чертеже (включая знаки шероховатости и выносные линии)
  • Количество технических требований

Из имеющихся инструментов на предприятии имеем: Kompas 3D v14 и Python 3.5.


В интернете не так много статей о написании программ с использованием API Kompas 3D, и ещё меньше информации о том, как это сделать на Python. Попробую рассказать по шагам, как решалась поставленная задача и на какие грабли приходилось наступать. Статья рассчитана на людей, владеющих основами программирования и знакомых с языком Python. Итак, приступим.



Подготовительная операция:


Убедитесь, что на вашем компьютере установлена программа Kompas 3D, версии не ниже 14 и Python 3. Вам также необходимо установить pywin3 (Python for Windows extensions).


Подключение к Kompas 3D:


Система Kompas 3D имеет две версии API: API5, которая предоставляет интерфейс KompasObject, и API7, предоставляющая интерфейс IKompasAPIObject. API версии 5 и 7 во многом дублируют свой функционал, но, со слов разработчиков, в 7-ой версии более выражен объектно-ориентированный подход. В данной статье акцент сделан на 7-ю версию.


Функция подключения выглядит следующим образом:


import pythoncom
from win32com.client import Dispatch, gencache

# Подключение к API7 программы Kompas 3D
def get_kompas_api7():
    module = gencache.EnsureModule("{69AC2981-37C0-4379-84FD-5DD2F3C0A520}", 0, 1, 0)
    api = module.IKompasAPIObject(
        Dispatch("Kompas.Application.7")._oleobj_.QueryInterface(module.IKompasAPIObject.CLSID,
                                                                 pythoncom.IID_IDispatch))
    const = gencache.EnsureModule("{75C9F5D0-B5B8-4526-8681-9903C567D2ED}", 0, 1, 0).constants
    return module, api, const

Чуть подробнее о модуле win32com здесь.


Теперь, чтобы подключиться к интерфейсу, нам понадобиться следующий код:


module7, api7, const7 = get_kompas_api7()   # Подключаемся к API7 
app7 = api7.Application                     # Получаем основной интерфейс
app7.Visible = True                         # Показываем окно пользователю (если скрыто)
app7.HideMessage = const7.ksHideMessageNo   # Отвечаем НЕТ на любые вопросы программы
print(app7.ApplicationName(FullName=True))  # Печатаем название программы

Для более глубокого понимания API заглянем в SDK. На моём компьютере она находится по адресу: C:\Program Files\ASCON\KOMPAS-3D V16\SDK\SDK.chm. Здесь можно подробнее узнать, например, о методе HideMessage:


HideMessage


После выполнения нашего кода вернём всё на свои места: если Kompas 3D был запущен нами (в процессе работы скрипта), мы его и закроем. Самый простой способ определить, запущен ли процесс, — использовать стандартный модуль subprocess:


import subprocess

# Функция проверяет, запущена ли программа Kompas 3D
def is_running():
    proc_list = subprocess.Popen('tasklist /NH /FI "IMAGENAME eq KOMPAS*"',
                                 shell=False,
                                 stdout=subprocess.PIPE).communicate()[0]
    return True if proc_list else False

Данная функция проверяет, запущен ли процесс «KOMPAS» стандартными методами Windows. Обратите внимание, что разные версии программы Kompas 3D могут иметь разные наименования процессов!


Считаем количество листов и их формат:


Тут всё просто: у нашего документа doc7 имеется интерфейс коллекции листов оформления LayoutSheets. Каждый лист обладает свойством формата и кратности. Для Компаса, начиная с 15 версии, интерфейс LayoutSheets доступен не только для файлов чертежей, но и для спецификаций и текстовых документов.


# Посчитаем количество листов каждого из формата
def amount_sheet(doc7):
    sheets = {"A0": 0, "A1": 0, "A2": 0, "A3": 0, "A4": 0, "A5": 0}
    for sheet in range(doc7.LayoutSheets.Count):
        format = doc7.LayoutSheets.Item(sheet).Format  # sheet - номер листа, отсчёт начинается от 0
        sheets["A" + str(format.Format)] += 1 * format.FormatMultiplicity
    return sheets

Посмотрим на процесс изучения SDK для поиска интересующих нас функций:


Animated


Читаем основную надпись:


Здесь нам поможет всё тот же LayoutSheets:


# Прочитаем масштаб из штампа, ячейка №6
def stamp_scale(doc7):
    stamp = doc7.LayoutSheets.Item(0).Stamp  # Item(0) указывает на штамп первого листа 
    return stamp.Text(6).Str    

На самом деле ячейка №6 для листа с другим оформлением может содержать не масштаб, а совсем иную информацию. Посмотрим, как в Kompas 3D определяются стили оформления чертежа:


Style


Таким образом, важно проверять, какому файлу и номеру оформления соответствует лист чертежа. Также стоит помнить, что документ может содержать титульный лист! Поэтому придётся усложнить код. Применим регулярные выражения, т.к. текст в ячейке может являться ссылкой:


import os
import re

# Прочитаем основную надпись чертежа
def stamp(doc7):
    for sheet in range(doc7.LayoutSheets.Count):
        style_filename = os.path.basename(doc7.LayoutSheets.Item(sheet).LayoutLibraryFileName)
        style_number = int(doc7.LayoutSheets.Item(sheet).LayoutStyleNumber)

        if style_filename in ['graphic.lyt', 'Graphic.lyt'] and style_number == 1:
            stamp = doc7.LayoutSheets.Item(sheet).Stamp
            return {"Scale": re.search(r"\d+:\d+", stamp.Text(6).Str).group(),
                    "Designer": stamp.Text(110).Str}

    return {"Scale": 'Неопределенный стиль оформления',
            "Designer": 'Неопределенный стиль оформления'}

Остался последний вопрос: как узнать нужный номер ячейки? Для этих целей удобно создать файл чертежа, в котором интересующие нас ячейки будут заполнены, а после — прочитать все возможные варианты с помощью следующей функции:


# Просмотр всех ячеек
def parse_stamp(doc7, number_sheet):
    stamp = doc7.LayoutSheets.Item(number_sheet).Stamp
    for i in range(10000):
        if stamp.Text(i).Str:
            print('Номер ячейки = %-5d Значение = %s' % (i, stamp.Text(i).Str))

Считаем количество пунктов технических требований:


Согласно SDK, нам всего-то нужно получить интерфейс TechnicalDemand от IDrawingDocument, а
IDrawingDocument можно получить от iDocuments с помощью замечательного метода с говорящим названием IUnknown::QueryInterface. И только в SDK 16 версии Kompas 3D появилось разъяснение, как это сделать:


IUnknown


С такими разъяснениями легко написать следующее:


# Подсчет технических требований, в том случае, если включена автоматическая нумерация
def count_TT(doc7, module7):
    doc2D_s = doc7._oleobj_.QueryInterface(module7.NamesToIIDMap['IDrawingDocument'],
                                           pythoncom.IID_IDispatch)
    doc2D = module7.IDrawingDocument(doc2D_s)
    text_TT = doc2D.TechnicalDemand.Text

    count_tt = 0                                 # Количество пунктов технических требований
    for i in range(text_TT.Count):               # Проходим по каждой строчке технических требований
        if text_TT.TextLines[i].Numbering == 1:  # и проверяем, есть ли у строки нумерация
            count_tt += 1                        

    # Если нет нумерации, но есть текст
    if not count_tt and text_TT.TextLines[0]:
        count_tt += 1

    return count_tt

Стоит отметить, что данный код полагается на автоматическую нумерацию технических требований. Так что, если автоматическая нумерация не применялась или технические требования набраны с использованием простого инструмента «Текст», код будет сложнее. Оставляю решение данной задачи на читателя.


Считаем количество размеров на чертеже:


При подсчёте размеров, надо иметь в виду, что необходимо посчитать их на каждом из видов чертежа:


# Подсчёт размеров на чертеже, для каждого вида по отдельности
def count_dimension(doc7, module7):
    IKompasDocument2D = doc7._oleobj_.QueryInterface(module7.NamesToIIDMap['IKompasDocument2D'],
                                                     pythoncom.IID_IDispatch)
    doc2D = module7.IKompasDocument2D(IKompasDocument2D)
    views = doc2D.ViewsAndLayersManager.Views

    count_dim = 0
    for i in range(views.Count):
        ISymbols2DContainer = views.View(i)._oleobj_.QueryInterface(module7.NamesToIIDMap['ISymbols2DContainer'],
                                                                    pythoncom.IID_IDispatch)
        dimensions = module7.ISymbols2DContainer(ISymbols2DContainer)

        # Складываем все необходимые размеры
        count_dim += dimensions.AngleDimensions.Count + \
                     dimensions.ArcDimensions.Count + \
                     dimensions.Bases.Count + \
                     dimensions.BreakLineDimensions.Count + \
                     dimensions.BreakRadialDimensions.Count + \
                     dimensions.DiametralDimensions.Count + \
                     dimensions.Leaders.Count + \
                     dimensions.LineDimensions.Count + \
                     dimensions.RadialDimensions.Count + \
                     dimensions.RemoteElements.Count + \
                     dimensions.Roughs.Count + \
                     dimensions.Tolerances.Count

    return count_dim

Основная функция скрипта


В результате проделанной работы мы получили следующее:


def parse_design_documents(paths):
    is_run = is_running()                           # Установим флаг, который нам говорит, 
                                                    # запущена ли программа до запуска нашего скрипта

    module7, api7, const7 = get_kompas_api7()       # Подключаемся к программе
    app7 = api7.Application                         # Получаем основной интерфейс программы
    app7.Visible = True                             # Показываем окно пользователю (если скрыто)
    app7.HideMessage = const7.ksHideMessageNo       # Отвечаем НЕТ на любые вопросы программы

    table = []                                      # Создаём таблицу параметров
    for path in paths:
        doc7 = app7.Documents.Open(PathName=path,
                                   Visible=True,
                                   ReadOnly=True)       # Откроем файл в видимом режиме без права его изменять

        row = amount_sheet(doc7)                        # Посчитаем кол-во листов каждого формат
        row.update(stamp(doc7))                         # Читаем основную надпись
        row.update({
            "Filename": doc7.Name,                      # Имя файла
            "CountTD": count_demand(doc7, module7),     # Количество пунктов технических требований
            "CountDim": count_dimension(doc7, module7), # Количество размеров на чертеже
        })
        table.append(row)                               # Добавляем строку параметров в таблицу

        doc7.Close(const7.kdDoNotSaveChanges)           # Закроем файл без изменения

    if not is_run: app7.Quit()                          # Выходим из программы
    return table

Диалоговое окно выбора файлов


Для удобного использования нашего скрипта воспользуемся возможностями стандартного модуля tkinter и выведем диалоговое окно выбора файлов:


from tkinter import Tk
from tkinter.filedialog import askopenfilenames

if __name__ == "__main__":
    root = Tk()
    root.withdraw()  # Скрываем основное окно и сразу окно выбора файлов

    filenames = askopenfilenames(title="Выберете чертежи деталей",
                                 filetypes=[('Kompas 3D', '*.cdw'),])

    print_to_excel(parse_design_documents(filenames))

    root.destroy()  # Уничтожаем основное окно
    root.mainloop()

Отчётность


Чтобы не рисовать в tkintere интерфейс пользователя, предлагаю воспользоваться хорошей программой Excel, куда и выведем результат нашего труда:


def print_to_excel(result):
    excel = Dispatch("Excel.Application")  # Подключаемся к Excel
    excel.Visible = True                   # Делаем окно видимым
    wb = excel.Workbooks.Add()             # Добавляем новую книгу
    sheet = wb.ActiveSheet                 # Получаем ссылку на активный лист

    # Создаём заголовок таблицы
    sheet.Range("A1:J1").value = ["Имя файла", "Разработчик",
                                  "Кол-во размеров", "Кол-во пунктов ТТ",
                                  "А0", "А1", "А2", "А3", "А4", "Масштаб"]

    # Заполняем таблицу
    for i, row in enumerate(result):
        sheet.Range("A%d:J%d" % i+2).value = [row['Filename'],
                                              row['Designer'],
                                              row['CountDim'],
                                              row['CountTD'],
                                              row['A0'],
                                              row['A1'],
                                              row['A2'],
                                              row['A3'],
                                              row['A4'],
                                              "".join(('="', row['Scale'], '"'))]

Если не полениться и правильно подготовить Excel файл, то результат работы нашего скрипта можно сразу представить в наглядном виде:


Здесь красивая цветная картинка из Excel


На графике изображено участие каждого сотрудника отдела в выпуске документации на изделие.


Заключение


Используя скрипт для чертежа, созданного специально для данной статьи, мы получим следующие результаты:


  • Количество размеров: 25 штук
  • Количество пунктов технических требований: 3 штуки
  • Масштаб: 1:1
  • Количество листов: 1, формата А3

Трудозатраты, согласно упомянутому в начале статьи документу, составили: 1 час 20 минут. Как ни странно, примерно столько и было потрачено времени на разработку чертежа.
Конечно, для внедрения подобных норм на предприятии нужны более серьёзные исследования и совершенно другие объёмы конструкторской документации. Данная же статья поможет упростить работу с API Kompas 3D при решении аналогичных задач.
Буду рад любым вашим замечаниями и предложениями к статье.


Исходный код



Ресурсы в помощь:


  1. SDK (C:\Program Files\ASCON\KOMPAS-3D V16\SDK\SDK.chm)
  2. forum.ascon.ru
Share post
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 27

    0
    А в питоне, конечно, трудоемкость следует считать интегрированием отступов начальных. Какая там трудоемкость вашего питоньего решения выходит?
      +1
      Cчитать чужой труд дело не благородное, но иногда нужное. В нашем случае, что бы отчитываться перед заказчиком.
      На написание кода ушло около 2-х недель в свободное от работы время, плюс две недели на написание статьи и рефакторинг. Намного больше времени понадобилась, что бы разобраться с API и именно по этой причине и была написана данная статья.
        0
        API дело полезное, но область его конкретного применения здесь удручает, еще и в свободное от работы время :)
      0
      Не сколь замечание, а любопытство. Я далек о чертежей на производстве, но вот вопрос: ведь перерисовка чертежа (предположим), создание чертежа непосредственно с модели, или реактивное моделирование (когда «рожаешь» чертеж в уме и стараешься непосредственно его привести к размерам на чертеже) — это ведь не одни и те же временные операции. Как бы в таком случае с расчетом времени, ведь исходя из моего списка по времени:
      1 пункт < 2 пункт < 3 пункт.
        0

        Если вы имеет НИОКР (научно-исследовательские и опытно-конструкторские работы) то трудозатратность считается по другому.

          0
          То есть данный подсчет верен только для какого то одного из типов работ?
            0
            Скажите как, актуально. Спасибо
              0

              Есть статья на тему: "ОЦЕНКА ТРУДОЕМКОСТИ НИОКР: ПРИМЕРЫ ПРИМЕНЕНИЯ МЕТОДИКИ", авторы Дурнев Р.А., Жданенко И.В. И ещё одна статья, этих же авторов, на тему: "ПРОЕКТ МЕТОДИКИ ОЦЕНКИ ТРУДОЕМКОСТИ И СТОИМОСТИ НАУЧНО-ИССЛЕДОВАТЕЛЬСКИХ И ОПЫТНО-КОНСТРУКТОРСКИХ РАБОТ."

                0
                Спасибо! будем искать.
            0
            Согласно ГОСТ 2.103-2013 существует несколько стадий разработки конструкторской документации (Эскизный проект -> Технический проект -> Рабочая документация), на каждой стадии, согласно упомянутому в статье документу, расчёт норм производиться по разному.
            Если говорить от чистого сердца, то документ не является эталоном, а служит отправной точкой для каждого предприятие, при разработке своих собственных норм, основываясь на личном опыте и на те задачи, ради которых эти нормы и разрабатываются.
              0
              Спасибо за подробное пояснение
            0
            было бы неплохо, посмотреть как это работает, чуть более подробнее. Никак не могу подружить компас с кодом:(
              +1
              Напиши в личную почту или e-mail поподробнее, что делаешь, вместе разберемся, что не так.
                0
                В папке SDK в папке Компаса есть примеры для Delphi, C#, C++. В своё время по этим примерам я очень много Компас автоматизировал. Советую заглянуть туда.
                +2
                def print_to_excel(result)

                А вот за это отдельное спасибо.
                  +4
                  Особенно бесят тупые работодатели, которые заставляют конструкторов считать трудоёмкость своей работы, писать какие-то планы, отчёты и т.п… Это просто выбешивает. Конструктор должен заниматься конструированием. Программист — программированием. Электронщик — электроникой. А планы с отчётами должны писать технические писатели. Максимум план разработки может писать руководитель разработки, а план работы сотрудников отдела — начальник отдела. Трудоёмкость может посчитать нормоконтроллёр. Поэтому мы и делаем барахло. Зато отчёт прикреплён…
                    0
                    Мне кажется, Вы описываете Утопию.
                      +3
                      Неа. Трудоёмкость в коммерческих компаниях вообще никто не считает. Для технической документации у них действительно есть технические писатели. И отчёты в хороших коммерческих компаниях тоже не пишут. В них есть компетентные лидеры, которые без всякой ерунды могут отличить хорошего сотрудника от балбеса.
                      Трудоёмкость очень любит проверять госзаказчик. Государство ни хрена не умеет эффективно управлять ни разработкой, ни производством, но при этом очень любит всё измерять и взвешивать. Но их можно понять. А вот для начальника вешать эту работу на разрабов — непродуктивно.
                      0
                      Никто не мешает стать нормальным работодателем. И они вовсе не тупые. Просто любому работодателю по-любому придется отчитываться перед проверяющими, контролирующими, в налоговую, банк, санстанцию, пожарную инспекцию и т.д. — а там, угадайте, что будет? Не тайна же ни разу.

                      Отвязаться от них можно «решая вопросы» или финансами или дебильными отчетами. А теперь представьте себе, что это вы работодатель. Что вы сделаете, заплатите(и не раз) или скажете работникам добавить отчетиков побольше?

                      Эта коррумпированная и размазанная по «ответственным лицам» система строилась много-много лет. Она удивительно живучая. Ее можно сломать, но где взять другую? Она просто и быстро воскреснет из любого положения.Сломать сие можно только тоталитаризмом. Но опять же ненадолго. Миллионы подписей под каждой бумажкой — это прямое следствие сталинских «экспериментов».

                      Сломать можно революцией. Но достаточно посмотреть в учебник истории и будет кристально ясно что это еще бОльший идиотизм.

                      Так что проще сесть на трактор и поменять страну, чем менять систему. Благо сейчас это не так трудно как 30 лет назад.
                        +3
                        Ничего тут коррумпированного нет. Работодатель отчитывается только перед заказчиком, в основном. Налоговой абсолютно до фени нормы времени и труда. Это всё госзаказчик требует обычно. И да, возможно, оно ему надо. Но эту работу вешать на технарей — неправильно. Для этого можно завести бумажечный отдел.
                        С подписями, в принципе, всё нормально. Если говорить про документацию по ГОСТ. А вот с отчётами и планами — это труба просто. Разраб, по идее, должен выпустить своё КД и пояснилово к нему. Потом отладить опытный образец. Всё. Когда разраб начинает писать планы, отчёты, он перестаёт делать свою работу. А план с отчётом любой школьник может написать, неправильно бросать на такую плёвую задачу специалиста с хорошей зарплатой.
                          0
                          План должен писать Руководитель. Беда в том что нормальных Руководителей почти нет. Все руководители очень любят потешить свое Чувство Собственного Величия, что они могут раздавать любые задания, но не понимают что кроме власти на них положена и ответственность слаженно управлять вверенными людьми. Все руководители, которых я встречал ленивы/«вечно заняты нечем»/«совещаются» (совещание — отличная альтернатива работе!©) — занимаются чем угодно, кроме собственно руководства. Все их руководство заключается в обращении к своим подчиненным «Нам спустили задачу — решите ее как нибудь сами, там все просто». Эти «руководители» поставлены на свои места такими же «руководителями» — у них свой клуб по интересам безделья.

                          Между тем, грамотно составленный Руководителем план работ — автоматически рождает отчет по проделанной работе, т.к. если KPI плана выполнен — значит работы входящие в данный этап выполнены — они входят в отчет сотрудника/подразделения. Сотрудник не должен думать про отчет — он просто поэтапно выполнят план и ставит галочки в выполненной работе по плану (для этого нужны простейшие CRM/PLM и прочие). Работник не должен и НЕ МОЖЕТ составлять себе план работ! Как минимум потому что на это есть Руководитель который получает много денег за ответственность и составление плана организации/подразделения. Только Руководитель может видеть всю картину в целом.

                          План нужен. Точно так же как и ГОСТы/стандарты. Проблема в конечной реализации и людях. В непонимании. Прошу прощения, накипело.
                            +1
                            Под каждым словом готов подписаться. В начальники идут за большой зарплатой, а не большие дела вершить. За свои скромные 10 лет инженерии в ИТ встретил одного(1) толкового ит-директора, увлеченного своим делом. Но как-то он уволился после того, как «маленькой, но гордой» конторой был поставлен управлять человек «у меня до этого 12тыс. в подчинении было, акционеры попросили, Саш, наладь административный процесс». Он и наладил, взял в руководить ит отделом человека, предлагавшего тесты поводить на продакшене, понабравшего знакомых бездарей-менеджеров по обучению(!) на должность начальника ОТК… собственно в этой профанации долго и я не задержался, обидно, планов было громадье и проект социально-значимый… может и к лучшему :)
                            sad but true
                        0
                        А вы не пробовали что-то почертить из питона в компасе? Например, скрипт рассчитывает какой-нибудь вал, и сам же его чертит в компасе. Насколько это вообще возможно, трудоемко, бредово?
                          0
                          Возможно и относительно просто, но надо понимать, что написать код для черчения всегда сложнее, чем просто взять и начертить. Но если требуется часто считать и рисовать однотипные валики, это уже повод для написании отдельной программы или библиотеки.
                          0
                          Круто, спасибо за примеры по сдк компаса, которых явный дефицит в сети, тем более на питоне.
                          Не знаете, а реально подобное не под виндой как-то поднять? Хотя бы через костыли как-то, wine итд. Задача сейчас подобная есть как раз, и насколько я знаю планируется под вин писать отдельное приложение для отдельного хоста, чисто с sdk работать. Вряд ли, да…
                            0
                            Я честно пытался запустить Компас под wine, но навыков не хватило. Обошёлся виртуальной машиной. В сети есть примеры удачных попыток запуска старых версий программы. Вот почитай: https://appdb.winehq.org/objectManager.php?sClass=application&iId=4606
                            https://debianforum.ru/index.php?topic=151.0
                              0
                              Ну запустить это полдела, а sdk работать будет? Ну там же ole, лицензия как-то используется ну и вот это всё.

                          Only users with full accounts can post comments. Log in, please.