Код Python для преобразования stp-файла CAD в код openscad не дает желаемых результатовPython

Программы на Python
Ответить Пред. темаСлед. тема
Anonymous
 Код Python для преобразования stp-файла CAD в код openscad не дает желаемых результатов

Сообщение Anonymous »

Я написал код Python для преобразования stp-файла САПР в код openscad, но результат отличается от того, что я ожидал.
Хотя расположение объектов было схожим, выходное значение и форма полностью отличались от оригинала.
Это мои коды для преобразования файла .stp в .scad
Analyzer.py< /em>

Код: Выделить всё

import logging

import OCC.Core.TopAbs as TopAbs
from OCC.Core.Bnd import Bnd_Box
from OCC.Core.BRepAdaptor import BRepAdaptor_Surface
from OCC.Core.BRepBndLib import brepbndlib
from OCC.Core.BRepGProp import brepgprop
from OCC.Core.GeomAbs import (
GeomAbs_BezierSurface,
GeomAbs_BSplineSurface,
GeomAbs_Cone,
GeomAbs_Cylinder,
GeomAbs_OffsetSurface,
GeomAbs_OtherSurface,
GeomAbs_Plane,
GeomAbs_Sphere,
GeomAbs_SurfaceOfExtrusion,
GeomAbs_SurfaceOfRevolution,
GeomAbs_Torus,
)
from OCC.Core.GProp import GProp_GProps
from OCC.Core.TopExp import TopExp_Explorer
from OCC.Core.TopoDS import TopoDS_Shape, topods

import lib.types as DataTypes
from lib import FileReader, GeometryValidator, ShapeRecognizer

class Analyzer:
def __init__(self, file_path: str):
self.shapes: TopoDS_Shape
self.logger = logging.getLogger("Analyzer")

self._read_step_file(file_path)

def _read_step_file(self, file_path: str) -> bool:
"""Read STEP file and store shapes

Returns:
bool: Success
"""
reader = FileReader(file_path)
self.shapes = reader.read()

def identify_surface_type(self, face) -> str:
"""Identify the type of surface.  Extends `BRepAdaptor_Surface -> GetType()`

Returns:
str: The type of surface in strings"""
try:
surf = BRepAdaptor_Surface(face)
surf_type = surf.GetType()
surface_types = {
# Elementary surfaces
GeomAbs_Plane: "Plane",
GeomAbs_Cylinder: "Cylinder",
GeomAbs_Cone: "Cone",
GeomAbs_Sphere: "Sphere",
GeomAbs_Torus: "Torus",
# Bounded surfaces
GeomAbs_BezierSurface: "BezierSurface",
GeomAbs_BSplineSurface: "BSplineSurface",
# Swept surfaces
GeomAbs_SurfaceOfRevolution: "SurfaceOfRevolution",
GeomAbs_SurfaceOfExtrusion: "SurfaceOfExtrusion",
# Misc
GeomAbs_OffsetSurface: "OffsetSurface",
GeomAbs_OtherSurface: "OtherSurface",
}

return surface_types.get(surf_type, f"Unknown({surf_type})")
except Exception as e:
self.logger.warning(f"Error identifying surface type: {str(e)}")
return "Unknown"

def extract_geometric_data(self) -> list[DataTypes.Geometry]:
"""Extract geometric data from shapes"""
if not self.shapes:
self.logger.error("No shapes available for extraction")
return None

geometric_data: list[DataTypes.Geometry] = []

shape_explorer = TopExp_Explorer(self.shapes, TopAbs.TopAbs_SOLID)
while shape_explorer.More():
current_shape = shape_explorer.Current()

payload: DataTypes.Geometry = {}

# Get overall dimensions from bounding box
bbox = Bnd_Box()
brepbndlib.Add(current_shape, bbox)
xmin, ymin, zmin, xmax, ymax, zmax = bbox.Get()

payload["dimensions"] = {
"width": xmax - xmin,
"length": ymax - ymin,
"height": zmax - zmin,
}

# Extract faces
payload["faces"] = self.extract_face_data(current_shape)

# Add analysis results
props = GProp_GProps()
brepgprop.VolumeProperties(self.shapes, props)
center = props.CentreOfMass()

payload["analysis"] = {
"volume": props.Mass(),
"center": (center.X(), center.Y(), center.Z()),
}

# Go next geometry
geometric_data.append(payload)
shape_explorer.Next()
return geometric_data

def extract_face_data(self, geometric_data: TopoDS_Shape) ->  list[DataTypes.Face]:
"""Extracts face data from geometric data"""

face_data: list[DataTypes.Face] = []

face_explorer = TopExp_Explorer(geometric_data, TopAbs.TopAbs_FACE)
while face_explorer.More():
face = topods.Face(face_explorer.Current())
_face_data = self._extract_face_data(face)
# face_data["boundaries"] = self._extract_face_boundaries(face)
face_data.append(_face_data)
# geometric_data["topology"]["faces_n"] += 1
face_explorer.Next()
self.logger.info(f"Extracted {len(face_data)} faces")

return face_data

# def _extract_face_boundaries(self, face):
#     """Extract boundary information for a face"""
#     boundaries = {
#         "outer_wire": None,
#         "inner_wires": [],
#         "edges": []
#     }

#     # Get the wires (loops) of the face
#     wire_explorer = TopExp_Explorer(face, TopAbs.TopAbs_WIRE)
#     is_first = True

#     while wire_explorer.More():
#         wire = topods.Wire(wire_explorer.Current())
#         wire_data = WireDataExtractor().extract(wire)

#         if is_first:
#             boundaries["outer_wire"] = wire_data
#             is_first = False
#         else:
#             boundaries["inner_wires"].append(wire_data)

#         wire_explorer.Next()

#     return boundaries

def _extract_face_data(self, face):
"""Extract properties from a face"""
surface_type = self.identify_surface_type(face)

face_data = {
"surfaceType": surface_type,
"parameters": self._get_surface_parameters(face, surface_type),
}
return face_data

def _get_surface_parameters(self, face, surface_type):
"""Extract specific parameters based on surface type"""
try:
surf = BRepAdaptor_Surface(face)
params = {}
if surface_type == "Cylinder":
cylinder = surf.Cylinder()
params["radius"] = cylinder.Radius()
location = cylinder.Location()
params["location"] = (location.X(), location.Y(), location.Z())

elif surface_type == "Plane":
plane = surf.Plane()
location = plane.Location()
params["location"] = (location.X(), location.Y(), location.Z())

elif surface_type == "Cone":
cone = surf.Cone()
location = cone.Location()
params["radius"] = cone.RefRadius()
params["angle"] = cone.SemiAngle()
params["location"] = (location.X(), location.Y(), location.Z())

elif surface_type == "Sphere":
sphere = surf.Sphere()
location = sphere.Location()
params["radius"] = sphere.Radius()
params["location"] = (location.X(), location.Y(), location.Z())

elif surface_type == "Torus":
torus = surf.Torus()
location = torus.Location()
params["MajorRadius"] = torus.MajorRadius()
params["MinorRadius"] = torus.MinorRadius()
params["location"] = (location.X(), location.Y(), location.Z())
params["Volume"] = torus.Volume()

elif surface_type == "BSplineSurface":
b_spline_surface = surf.BSpline()
params["D0"] = b_spline_surface.D0()

else:
self.logger.warning(
f"Unknown surface type {surface_type} when extracting surface parameters"
)
return params

except Exception as e:
self.logger.warning(
f"Error extracting parameters for {surface_type}:  {str(e)}"
)
return {}

def analyze_and_validate(self):
"""Analyze and validate the loaded shapes"""
results = []

shape_info = ShapeRecognizer.analyze(self.shapes)
validation = GeometryValidator.validate(self.shapes)

results.append(
{
"shape_type": shape_info["type"],
"properties": shape_info,
"validation": validation,
}
)

# Log results
self.logger.info(f"Shape Type: {shape_info['type']}")
self.logger.info(f"Volume: {shape_info['volume']:.2f}")
self.logger.info(f"Center: {shape_info['center']}")

if not validation["is_valid"]:
self.logger.warning("Validation issues found:")
for issue in validation["issues"]:
self.logger.warning("- %s", issue)

return results

Converter.py

Код: Выделить всё

import logging

from OCC.Core.TopoDS import TopoDS_Shape

from converter import Analyzer

DEFAULT_SMOOTHNESS = 50

class Converter:
def __init__(self, file_path: str):
self.file_path = file_path
self.shapes: TopoDS_Shape
self.geometric_data = []
self.logger = logging.getLogger("Converter")

self._analyze()

def _analyze(self):
"""Validates and stores the geometric data in a variable"""
analyzer = Analyzer(self.file_path)
analyzer.analyze_and_validate()
self.geometric_data = analyzer.extract_geometric_data()

# ! Currently very limited (hardcoded values).
# TODO: Allow complex models procedurally
def generate_openscad_code(self):
"""Generate OpenSCAD code based on analyzed geometry"""
code = [
"// OpenSCAD code generated from STEP file",
"// Generated by StepToCADConverter\n",
"$fn = 50;  // Set smoothness for curved surfaces\n",
]
# Extract dimensions from the analysis
dims = self.geometric_data[0].get("dimensions", {})
width = float(dims.get("width"))
height = float(dims.get("height"))
cylinder_radius = float(dims.get("cylinderRadius", 5))

# Generate the actual geometry code
# TODO: remove comment
# for i in geometric_data["faces"]:
#     print(i["surface-type"])
#     print(i["parameters"])
code.extend([
"difference() {  // Main shape",
"    union() {  // Combine positive shapes",
""
])
for i in self.geometric_data:
for a in i['faces']:
try:
surf_type = a['surfaceType']
location = a['parameters']['location']
dimensions = a['parameters'].get('dimensions', [1, 1, 1])  # Default dimensions if not specified
radius = a['parameters'].get('radius', 1)  # Default radius if not specified

if surf_type == 'Plane':
code.extend([
"        // Plane/Rectangle",
f"        translate([{location[0]:.2f}, {location[1]:.2f}, {location[2]:.2f}])",
f"          cube([{dimensions[0]:.2f}, {dimensions[1]:.2f}, 0.01]);"  # Very thin cube to represent a plane
])

elif surf_type == 'Sphere':
code.extend([
"        // Sphere",
f"        translate([{location[0]:.2f}, {location[1]:.2f}, {location[2]:.2f}])",
f"          sphere(r = {radius:.2f});"
])

elif surf_type == 'Cylinder':
height = a['parameters'].get('height', 1)
code.extend([
"        // Cylinder",
f"         translate([{location[0]:.2f}, {location[1]:.2f}, {location[2]:.2f}])",
f"          cylinder(h = {height:.2f}, r = {radius:.2f});"
])

elif surf_type == 'Cone':
height = a['parameters'].get('height', 1)
radius2 = a['parameters'].get('radius2', 0)  # Top radius
code.extend([
"        // Cone",
f"        translate([{location[0]:.2f}, {location[1]:.2f}, {location[2]:.2f}])",
f"          cylinder(h = {height:.2f}, r1 = {radius:.2f}, r2 = {radius2:.2f});"
])

elif surf_type == 'Torus':
outer_radius = a['parameters'].get('outerRadius', 2)
code.extend([
"        // Torus",
f"        translate([{location[0]:.2f}, {location[1]:.2f}, {location[2]:.2f}])",
f"          rotate_extrude()",
f"            translate([{outer_radius:.2f}, 0, 0])",
f"              circle(r = {radius:.2f});"
])

except Exception as e:
print(a)
print(e)
code.extend(
[
"    }  // End union",
"}  // End difference",
]
)
# Add analysis info as comments
analysis = self.geometric_data[0].get("analysis", {})
code.extend(
[
"\n// Shape Information:",
f"// - Total Width: {width:.2f}",
f"// - Total Height: {height:.2f}",
f"// - Cylinder Radius: {cylinder_radius:.2f}",
f"// - Volume: {analysis.get('volume', 0):.2f}",
f"// - Center: {analysis.get('center', (0,0,0))}",
f"// - Number of Faces: {len(self.geometric_data[0]['faces'])}",
]
)

self.logger.info("Convert complete")

return "\n".join(code)

stp-модель(ИСХОДНЫЕ ДАННЫЕ) и .scad(РЕЗУЛЬТАТ)
Я думаю, что размер и наклон не применялись. А может это другая проблема.
Или есть более простой способ?

Подробнее здесь: https://stackoverflow.com/questions/791 ... ired-resul
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Python»