Working in the design department, I was faced with the task - to calculate the complexity of the development of design documentation. If we take the document as a basis: “Typical time standards for the development of design documentation. Cipher 13.01.01 "(approved by the Ministry of Labor of Russia 07.03.2014 N 003)" , then to calculate the complexity of the drawing details, we need the following data:
From the available tools in the enterprise we have: Kompas 3D v14 and Python 3.5.
There are not so many articles on writing programs using the Kompas 3D API, and even less information on how to do this in Python. I will try to tell you in steps how the task was solved and what rakes you had to step on. The article is intended for people who know the basics of programming and are familiar with the Python language. So let's get started.
Make sure you have Kompas 3D, version 14, and Python 3 installed on your computer. You also need to install pywin3 (Python for Windows extensions).
The Kompas 3D system has two API versions: API5, which provides the KompasObject interface, and API7, which provides the IKompasAPIObject interface. API versions 5 and 7 largely duplicate their functionality, but according to the developers, in the 7th version, the object-oriented approach is more pronounced. This article focuses on the 7th version.
The connection function is as follows:
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
A little more about the win32com module here .
Now, to connect to the interface, we need the following code:
module7, api7, const7 = get_kompas_api7() # API7 app7 = api7.Application # app7.Visible = True # ( ) app7.HideMessage = const7.ksHideMessageNo # print(app7.ApplicationName(FullName=True)) #
For a deeper understanding of the API, let's take a look at the SDK. On my computer, it is located at: C: \ Program Files \ ASCON \ KOMPAS-3D V16 \ SDK \ SDK.chm . Here you can learn more about, for example, the HideMessage method:
After executing our code, we will return everything to its place: if Kompas 3D was launched by us (in the process of the script), we will close it. The easiest way to determine if a process is running is to use the standard subprocess module:
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
This function checks if the KOMPAS process is running using standard Windows methods . Please note that different versions of the Kompas 3D program may have different process names!
Everything is simple: our doc7 document has an interface for the collection of layout sheets, LayoutSheets. Each sheet has the property of format and multiplicity. For Compass, starting with version 15, the LayoutSheets interface is available not only for drawing files, but also for specifications and text documents.
# 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
Let's look at the process of studying the SDK to find the functions of interest to us:
Here all the same LayoutSheets will help us:
# , â„–6 def stamp_scale(doc7): stamp = doc7.LayoutSheets.Item(0).Stamp # Item(0) return stamp.Text(6).Str
In fact, cell number 6 for a sheet with a different design may contain not a scale, but completely different information. Let's see how drawing styles are defined in Kompas 3D:
Thus, it is important to check which file and design number correspond to the drawing sheet. It is also worth remembering that the document may contain a title page! Therefore it is necessary to complicate the code. Let's use regular expressions , since the text in the cell can be a link:
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": ' '}
The last question remains: how to find out the desired cell number? For these purposes, it is convenient to create a drawing file in which the cells of interest will be filled, and then read all possible options using the following function:
# 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))
According to the SDK, we just need to get the TechnicalDemand interface from IDrawingDocument, and
IDrawingDocument can be obtained from iDocuments using a wonderful method with the speaker name IUnknown :: QueryInterface. And only in the SDK 16 version of Kompas 3D, an explanation appeared how to do it:
With such clarifications, it is easy to write the following:
# , , 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
It should be noted that this code relies on the automatic numbering of technical requirements. So, if automatic numbering was not applied or technical requirements are typed using a simple “Text” tool, the code will be more complicated. I leave the solution of this problem to the reader.
When calculating the dimensions, one must bear in mind that it is necessary to count them on each type of drawing:
# , 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
As a result of the work done, we received the following:
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
For convenient use of our script, we will use the capabilities of the standard tkinter module and display the file selection dialog box:
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()
In order not to draw a user interface in tkintere, I suggest using a good Excel program, where we will output the result of our work:
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'], '"'))]
If you don’t be lazy and prepare the Excel file correctly, then the result of the work of our script can be immediately presented in a visual form:
The graph shows the participation of each employee of the department in the release of product documentation.
Using the script for the drawing, created specifically for this article, we get the following results:
Labor costs, according to the document mentioned at the beginning of the article, were: 1 hour 20 minutes. Oddly enough, about as much time was spent on the development of the drawing.
Of course, for the introduction of such standards in the enterprise, more serious research and completely different volumes of design documentation are needed. This article will help to simplify the work with the Kompas 3D API when solving similar problems.
I will be glad to any of your comments and suggestions to the article.
Source: https://habr.com/ru/post/323078/
All Articles