Skip to content

Instantly share code, notes, and snippets.

@AlexandrDragunkin
Last active February 12, 2026 09:10
Show Gist options
  • Select an option

  • Save AlexandrDragunkin/0e6c471e977553063068d342723fff8d to your computer and use it in GitHub Desktop.

Select an option

Save AlexandrDragunkin/0e6c471e977553063068d342723fff8d to your computer and use it in GitHub Desktop.
Construction of a smooth ellipse in k3mebel https://k3-mebel.ru/
# -*- 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