Files
OpenECAD_Project/Bethany/py2step.py
2024-08-16 17:50:51 +08:00

214 lines
8.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import os
import glob
import numpy as np
import argparse
import sys
sys.path.append(".")
from lib.DataExchange import write_step_file
from lib.visualize import create_CAD
from lib.curves import Line, Arc, Circle
from lib.sketch import Loop, Profile
from lib.math_utils import *
from lib.extrude import CoordSystem, Extrude, CADSequence
# Curves
def add_line(start, end):
start = np.array(start)
end = np.array(end)
return Line(start, end)
def add_arc(start, end, mid):
# get radius and center point
start = np.array(start)
end = np.array(end)
mid = np.array(mid)
center, radius = find_circle_center_and_radius(start, end, mid)
def get_angles_counterclockwise(eps=1e-8):
c2s_vec = (start - center) / (np.linalg.norm(start - center) + eps)
c2m_vec = (mid - center) / (np.linalg.norm(mid - center) + eps)
c2e_vec = (end - center) / (np.linalg.norm(end - center) + eps)
angle_s, angle_m, angle_e = angle_from_vector_to_x(c2s_vec), angle_from_vector_to_x(c2m_vec), \
angle_from_vector_to_x(c2e_vec)
angle_s, angle_e = min(angle_s, angle_e), max(angle_s, angle_e)
if not angle_s < angle_m < angle_e:
angle_s, angle_e = angle_e - np.pi * 2, angle_s
return angle_s, angle_e
angle_s, angle_e = get_angles_counterclockwise()
return Arc(start, end, center, radius, start_angle=angle_s, end_angle=angle_e, mid_point=mid)
def add_circle(center, radius):
center = np.array(center)
return Circle(center, radius)
# Loops
def add_loop(curves):
res = Loop(curves)
res.reorder()
def autofix(loop):
if len(loop.children) <= 1:
return
if isinstance(loop.children[0], Circle):
return
for i in range(0, len(loop.children) - 1):
if not np.allclose(loop.children[i].end_point, loop.children[i+1].start_point):
loop.children[i+1].start_point = loop.children[i].end_point
print("warning: fixing loop")
if not np.allclose(loop.children[len(loop.children) - 1].end_point, loop.children[0].start_point):
loop.children[len(loop.children) - 1].start_point = loop.children[0].end_point
print("warning: fixing loop")
autofix(res)
return res
# Sketch-Profile
def add_profile(loops):
return Profile(loops)
def add_sketchplane(origin, normal, x_axis):#, y_axis):
#print(origin, normal, x_axis)
origin = np.array(origin)
normal = np.array(normal)
x_axis = np.array(x_axis)
y_axis = find_n_from_x_and_y(normal, x_axis)
# get theta and phi
theta, phi, gamma = polar_parameterization(normal, x_axis)
#print(normal_axis, x_axis)
#print(theta, phi, gamma)
return CoordSystem(origin, theta, phi, gamma, y_axis=cartesian2polar(y_axis))
def add_sketchplane_ref(extrude: Extrude, origin, type: str, line: Line = None, reverse = False, angle=0):
origin = np.array(origin)
types_dict = ["sameplane", "extent_one", "extent_two", "line"]
"""
sameplane: 参考Extrude的SketchPlaneangle是以normal为轴向下看逆时针角度原点是在SketchPlane内的2D相对坐标。reverse只在最后反转normal其他参考并不反转。
line默认normal为y轴line start to end 为x轴它们的叉积为方向向量normal'原点是在该默认平面的2D相对坐标。angle是以normal'为轴向下看逆时针角度。reverse只在最后反转normal',其他参考并不反转。
"""
if type not in types_dict:
raise ValueError
ref_plane = extrude.sketch_plane
ref_x_axis = unit_vector(ref_plane.x_axis)
ref_y_axis = unit_vector(ref_plane.y_axis)
ref_n_axis = unit_vector(ref_plane.normal)
ref_origin = ref_plane.origin
if type == "sameplane":
real_origin = map_2d_to_3d(ref_origin, ref_x_axis, ref_y_axis, origin)
elif type == "extent_one":
ref_origin_ = ref_origin + extrude.extent_one * ref_n_axis
real_origin = map_2d_to_3d(ref_origin_, ref_x_axis, ref_y_axis, origin)
elif type == "extent_two":
ref_origin_ = ref_origin - extrude.extent_two * ref_n_axis
real_origin = map_2d_to_3d(ref_origin_, ref_x_axis, ref_y_axis, origin)
if type in types_dict[:3]:
real_x_axis = rotate_vector(ref_x_axis, ref_n_axis, angle)
return add_sketchplane(real_origin, ref_n_axis if not reverse else -ref_n_axis, real_x_axis)
if type == "line":
if line is None:
raise TypeError
start_point = map_2d_to_3d(ref_origin, ref_x_axis, ref_y_axis, line.start_point)
end_point = map_2d_to_3d(ref_origin, ref_x_axis, ref_y_axis, line.end_point)
default_x_axis = unit_vector(end_point - start_point)
real_origin = map_2d_to_3d(start_point, default_x_axis, ref_n_axis, origin) # ref_n_axis is y axis of default plane
default_normal = find_n_from_x_and_y(default_x_axis, ref_n_axis)
real_x_axis = rotate_vector(default_x_axis, default_normal, angle)
return add_sketchplane(real_origin, default_normal if not reverse else -default_normal, real_x_axis)
raise ValueError
class Sketch(object):
def __init__(self, sketch_plane, profile, sketch_position, sketch_size):
self.sketch_plane = sketch_plane
self.profile = profile
self.sketch_position = sketch_position
self.sketch_size = sketch_size
def add_sketch(sketch_plane, profile, sketch_position=[0.0,0.0,0.0], sketch_size=0):
return Sketch(sketch_plane, profile, np.array(sketch_position), sketch_size)
cad_seq = []
def add_extrude(sketch: Sketch, operation, type, extent_one, extent_two):
res = Extrude(
sketch.profile,
sketch.sketch_plane,
np.intc(operation), np.intc(type), np.double(extent_one), np.double(extent_two),
np.double(sketch.sketch_position),
np.double(sketch.sketch_size)
)
cad_seq.append(res)
return res
from OCC.Core.TDocStd import TDocStd_Document
from OCC.Core.TCollection import TCollection_ExtendedString
def _process(path, path_o):
global cad_seq
cad_seq.clear()
with open(path, 'r') as file:
codes = file.read()
# 执行读取到的代码
codes = codes.split("\n")
i = 0
last_curves_list, last_loops_list = None, None
while i < len(codes):
code = codes[i]
last_curve_name, last_loop_name = None, None
if codes[i].startswith('Curves'):
last_curves_list = codes[i].split('=', 1)[0].split()[0]
elif codes[i].startswith('Loops'):
last_loops_list = codes[i].split('=', 1)[0].split()[0]
elif codes[i].startswith('Arc') or codes[i].startswith('Line') or codes[i].startswith('Circle'):
last_curve_name = codes[i].split('=', 1)[0].split()[0]
elif codes[i].startswith('Loop'):
last_loop_name = codes[i].split('=', 1)[0].split()[0]
for j in range(i + 1, len(codes)):
if codes[j].startswith('\t') or codes[j].startswith(' '):
code += '\n' + codes[j]
i += 1
else:
break
exec(code)
if last_curve_name is not None:
exec(f"{last_curves_list}.append({last_curve_name})")
elif last_loop_name is not None:
exec(f"{last_loops_list}.append({last_loop_name})")
i += 1
doc_name = TCollection_ExtendedString("pythonocc-doc")
doc = TDocStd_Document(doc_name)
cad = CADSequence(cad_seq)
#print(cad)
out_shape = create_CAD(doc, cad)
write_step_file(doc, path_o)
error_list = []
from lib.file_utils import ensure_dir
parser = argparse.ArgumentParser()
parser.add_argument('--src', type=str, required=True, help="source folder")
parser.add_argument('-o', '--outputs', type=str, default=None, help="save folder")
args = parser.parse_args()
src_dir = args.src
print(src_dir)
out_paths = sorted(glob.glob(os.path.join(src_dir, "*.{}".format("py"))))
save_dir = args.src + "_step" if args.outputs is None else args.outputs
ensure_dir(save_dir)
import traceback
for path in out_paths:
name = path.split("/")[-1].split(".")[0]
try:
save_path = os.path.join(save_dir, name + ".step")
_process(path, save_path)
except Exception as e:
print("load and create failed.")
traceback.print_exc()
print(name)
error_list.append(name)
for error in error_list:
print(error)