Last active
February 12, 2026 09:10
-
-
Save AlexandrDragunkin/0e6c471e977553063068d342723fff8d to your computer and use it in GitHub Desktop.
Construction of a smooth ellipse in k3mebel https://k3-mebel.ru/
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # -*- coding: utf-8 -*- | |
| from __future__ import annotations | |
| import traceback | |
| import logging | |
| __author__ = 'Aleksandr Dragunkin ' | |
| __created__ = '11.02.2026' | |
| # ------------------------------------------------------------------------------- | |
| # Name: Build_ElipseStPortable.py | |
| # Purpose: macro protopath+"Build_ElipseStPortable.py" 800 300 0; | |
| # Copyright: (c) GEOS 2012-2026 http://k3info.ru/ | |
| # Licence: FREE | |
| # ------------------------------------------------------------------------------ | |
| import k3 | |
| from typing import Iterable | |
| # import math | |
| # Глобальные переменные для хранения размеров | |
| L_E = k3.GlobalVar('L_E') # Длина | |
| L_D = k3.GlobalVar('L_D') # Ширина | |
| L_E.value = 0 # Длина | |
| L_D.value = 0 # Ширина | |
| #------------------------------------------- | |
| f_round = lambda x: round(x,3) | |
| #----------------------------- | |
| def PointOutListPoint(args): | |
| ''' | |
| Возвращает список из трех превых элементов списка args и изменяет список args укорачивачивая его. | |
| :: | |
| ...point,args = PointOutListPoint(args) | |
| ,где | |
| На входе | |
| args - список вида [Real,Real,Real,Real,Real,Real,....,Real,Real,Real,] | |
| На выходе | |
| point - список вида [Real,Real,Real] | |
| args - список вида [Real,Real,Real,....,Real,Real,Real,] | |
| ''' | |
| return list(map(f_round,args[:3])),args[3:] | |
| #----------------------------- | |
| def ptransGcsToPsc(args=[]): | |
| ''' | |
| Принимает на вход список кратный 3 и преобразует точки из ГСК системы в ПСК. | |
| :: | |
| ...point = ptransGcsToPsc(args) | |
| ,где | |
| На входе | |
| args - список вида [Real,Real,Real,Real,Real,Real,....,Real,Real,Real,] | |
| На выходе | |
| args - список вида [Real,Real,Real,Real,Real,Real,....,Real,Real,Real,] | |
| ''' | |
| result=[] | |
| Xc,Yc,Zc=k3.Var(),k3.Var(),k3.Var() | |
| if isinstance(args, (map, tuple)): | |
| args = list(args) | |
| while len(args)>0: | |
| point,args = PointOutListPoint(args) | |
| k3.ptranscs(3,0,point,Xc,Yc,Zc) | |
| result.append(Xc.value) | |
| result.append(Yc.value) | |
| result.append(Zc.value) | |
| return list(map(f_round,result)) | |
| def vtransGcsToPsc(args=[]): | |
| ''' | |
| Принимает на вход список кратный 3 и преобразует вектор из ГСК системы в ПСК. | |
| :: | |
| ...vector = vtransGcsToPsc(args) | |
| ,где | |
| На входе | |
| args - список вида [Real,Real,Real,Real,Real,Real,....,Real,Real,Real,] | |
| На выходе | |
| args - список вида [Real,Real,Real,Real,Real,Real,....,Real,Real,Real,] | |
| ''' | |
| result=[] | |
| Xc,Yc,Zc=k3.Var(),k3.Var(),k3.Var() | |
| if isinstance(args, (map, tuple)): | |
| args = list(args) | |
| while len(args)>0: | |
| point,args = PointOutListPoint(args) | |
| k3.vtranscs(3,0,point,Xc,Yc,Zc) | |
| result.append(Xc.value) | |
| result.append(Yc.value) | |
| result.append(Zc.value) | |
| return list(map(f_round,result)) | |
| def list_or_vararray(function_to_decorate): | |
| """Декоратор для функции. который обрабатывает аргумент и если этот аргумент | |
| массив к3, то превратит его в список и передаст в декорируемую функцию. | |
| И на выходе вернет так же массив к3""" | |
| def a_wrapper_accepting_arguments(args=[]): | |
| k3_variant = isinstance(args, k3.VarArray) | |
| if k3_variant: | |
| arg2 = [a.value for a in args] | |
| else: | |
| arg2 = args | |
| return_result = function_to_decorate(arg2) | |
| if k3_variant: | |
| args = k3.VarArray(len(return_result)) | |
| for i, e in enumerate(return_result): | |
| args[i].value = e | |
| return_result = args | |
| return return_result | |
| return a_wrapper_accepting_arguments | |
| def array_to_iter(vararray: k3.VarArray, nametype=tuple) -> Iterable: | |
| '''Преобразует массив к3 (vararray) в список, кортеж или множество | |
| в зависимости от (nametype) | |
| Параметры: | |
| - vararray - <k3.VarArray> массив к3 | |
| - nametype - <list,tuple,set> тип который требуется получить на выходе | |
| Результат: | |
| список, кортеж или множество в зависимости от (nametype) | |
| ''' | |
| n = len(vararray) | |
| if n: | |
| return nametype([a.value for a in vararray]) | |
| return nametype() | |
| class Point3D: | |
| def __init__(self): | |
| self.x = None | |
| self.y = None | |
| self.z = None | |
| def getValue(self): | |
| return self.x, self.y, self.z | |
| def getValuePSC(self): | |
| return ptransGcsToPsc(args=self.getValue()) | |
| def setValue(self, *wards, **kwards): | |
| keys = list(self.__dict__.keys()) | |
| if wards: | |
| for i, v in enumerate(wards): | |
| setattr(self, keys[i], wards[i]) | |
| if kwards: | |
| for key in keys: | |
| setattr(self, key, kwards.get( | |
| key, default = getattr(self, key, None))) | |
| class LinearObjectGeoInfo: | |
| """Базовый класс для классов описывающих геометрическую информацию плоских линейных объектов (точка, отрезок, окружность, дуга)""" | |
| def type_nm(self): | |
| raise NotImplementedError() | |
| def setValue(self): | |
| raise NotImplementedError() | |
| def valid_type(self): | |
| raise NotImplementedError() | |
| def validate_type_nm(self): | |
| if not self.type_nm is self.valid_type: | |
| raise TypeError() | |
| class LineGeoInfo(LinearObjectGeoInfo): | |
| """Класс описывающий геометрическую информацию плоского линейного объекта (отрезок)""" | |
| valid_type = 2 # TypeNm.Line | |
| def __init__(self, type_nm, *wards): | |
| self.type_nm = type_nm | |
| # Убираем проверку типа, чтобы избежать ошибки | |
| # self.validate_type_nm() | |
| self.point_start = Point3D() | |
| self.point_end = Point3D() | |
| self.setValue(*wards) | |
| def __repr__(self): | |
| return '{} type_nm:{}, start:{}, end:{} '.format(self.__class__.__name__, self.type_nm, self.point_start, self.point_end) | |
| def setValue(self, *wards): | |
| self.point_start.setValue(*wards[:3]) | |
| self.point_end.setValue(*wards[3:6]) | |
| def getObjGeo(obj): | |
| """Работа с геометрией объекта | |
| Вернуть экземпляр класса, описывающий геометрическую информацию о линейном объекте (точка, отрезок, окружность, дуга) <Obj>.""" | |
| # Имитация функции getObjType для получения типа объекта | |
| obj_type_nm = k3.getobjtype(obj) | |
| # Проверяем, что объект является отрезком (тип 2) | |
| if obj_type_nm == 2: # TypeNm.Line | |
| arr = k3.VarArray(15) | |
| n = k3.getobjgeo(obj, arr) | |
| if n: | |
| # Преобразуем массив в список числовых значений | |
| geo_info_arr = array_to_iter(arr) | |
| geo_info = LineGeoInfo(obj_type_nm, *geo_info_arr[:6]) | |
| return geo_info | |
| return None | |
| def filter_first_quadrant_lines(objs): | |
| """ | |
| Фильтрует список трехмерных отрезков, оставляя только те, которые | |
| полностью принадлежат первому квадранту плоскости xOy. | |
| Аргументы: | |
| objs: список объектов типа core_k.fetch_sceneobj.LineGeoInfo | |
| Возвращает: | |
| list: упорядоченный список отрезков первого квадранта | |
| """ | |
| first_quadrant_lines = [] | |
| for e in objs: | |
| esv = getObjGeo(e) | |
| # Проверяем, что объект является отрезком | |
| if isinstance(esv, LineGeoInfo): | |
| # Получаем координаты начальной и конечной точек в плоскости xOy | |
| start_x, start_y = esv.point_start.getValuePSC()[0], esv.point_start.getValuePSC()[1] | |
| end_x, end_y = esv.point_end.getValuePSC()[0], esv.point_end.getValuePSC()[1] | |
| # Проверяем, что все координаты положительные (принадлежат первому квадранту) | |
| if round(float(start_x), 1) >= 0 and round(float(start_y),1) >= 0 and round(float(end_x),1) >= 0 and round(float(end_y),1) >= 0: | |
| first_quadrant_lines.append(esv) | |
| return first_quadrant_lines | |
| def build_ellipse_top(x, y, Hc): | |
| """ | |
| Построение эллиптической столешницы | |
| Параметры: | |
| x - ширина столешницы | |
| y - глубина столешницы | |
| Hc - высота установки конструкции | |
| """ | |
| # Сохраняем текущие настройки | |
| cash_meridians = k3.sysvar(73) | |
| global L_E, L_D | |
| try: | |
| # Установка параметров аппроксимации | |
| k3.approximation(k3.k_meridians, 200) | |
| # Создание эллипсоида | |
| el = k3.elipsoid(0, 0, Hc, 0.5 * x, 0, Hc, 0, 0.5 * y, Hc, 0, 0, Hc + 10) | |
| # Создание эллипса сечения | |
| elipse = k3.cut(el, k3.k_done, k3.k_3points, 0, 0, Hc, 10, 0, Hc, 0, 10, Hc) | |
| # Удаление вспомогательных элементов | |
| k3.delete(el) | |
| if k3.getobjtype(elipse) == 5: | |
| n = int(k3.getcntobjga(elipse)) | |
| objs = k3.VarArray(n) | |
| k3.scang(elipse, objs) | |
| lines = filter_first_quadrant_lines(objs) | |
| k3.delete(elipse) | |
| for e in lines: | |
| k3.line((e.point_start.getValuePSC(), e.point_end.getValuePSC())) | |
| elipse = k3.path(k3.k_last, len(lines)) | |
| elipse = k3.arcs_path(k3.k_tolarc, 0.5, elipse) | |
| k3.mirror(k3.k_copy, elipse, k3.k_done, k3.k_3points, 0,0,0, 100,0,0, 0,0,100) | |
| k3.mirror(k3.k_copy, k3.k_last,2, k3.k_done, k3.k_3points, 0,0,0, 0,100,0, 0,0,100) | |
| elipse = k3.path(k3.k_last, 4) | |
| # Вычисление длины контура эллипса | |
| # В упрощенной реализации используем формулу приближения | |
| # semi_major = x / 2 # Большая полуось | |
| # semi_minor = y / 2 # Малая полуось | |
| # # Приближенная формула для периметра эллипса | |
| # perimeter = math.pi * ( | |
| # 3 * (semi_major + semi_minor) | |
| # - math.sqrt((3 * semi_major + semi_minor) * (semi_major + 3 * semi_minor)) | |
| # ) | |
| perimeter = k3.clength( elipse)[0] | |
| # Сохраняем половины периметра как длины сторон | |
| L_E.value = perimeter / 2 | |
| L_D.value = perimeter / 2 | |
| # Установка допусков для дуг | |
| except: | |
| traceback.print_exc() | |
| finally: | |
| k3.approximation(k3.k_meridians, cash_meridians) | |
| return L_E.value, L_D.value | |
| # Пример использования функции | |
| if __name__ == "__main__": | |
| params = k3.getpar() | |
| if len(params)!=3: | |
| raise ValueError("Неверное количество параметров. Требуется 3") | |
| # Параметры столешницы | |
| width = params[0] # ширина | |
| depth = params[1] # глубина | |
| height = params[2] # высота установки | |
| # Построение столешницы | |
| length_E, length_D = build_ellipse_top(width, depth, height) | |
| logging.debug(f"Построена эллиптическая столешница:") | |
| logging.debug(f"Ширина: {width} мм") | |
| logging.debug(f"Глубина: {depth} мм") | |
| logging.debug(f"Высота установки: {height} мм") | |
| logging.debug(f"Длина стороны E: {length_E:.2f} мм") | |
| logging.debug(f"Длина стороны D: {length_D:.2f} мм") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment