diff --git a/amworkflow/api.py b/amworkflow/api.py index 6ae72da..bd1fd77 100644 --- a/amworkflow/api.py +++ b/amworkflow/api.py @@ -318,10 +318,10 @@ def create_sym_hexagon1_infill(total_len: float, total_wid:float, height:float, # """ # return cg.create_wall_by_points(pts, th, isclose, height,debug, debug_type, output,interpolate, R) - @staticmethod - class CreateWallByPoints(cg.CreateWallByPoints): - def __init__(self, pts: list, th: float, height: float): - super().__init__(pts,th,height) + # @staticmethod + class CreateWallByPoints(cg.CreateWallByPointsUpdate): + def __init__(self, pts: list, th: float, height: float, is_close:bool = True): + super().__init__(pts,th,height,is_close) @staticmethod def get_face_center_of_mass(face: TopoDS_Face, gp_pnt: bool = False) -> tuple | gp_Pnt: diff --git a/amworkflow/src/geometries/composite_geometry.py b/amworkflow/src/geometries/composite_geometry.py index bb1c092..05383e8 100644 --- a/amworkflow/src/geometries/composite_geometry.py +++ b/amworkflow/src/geometries/composite_geometry.py @@ -1,6 +1,6 @@ from amworkflow.src.geometries.simple_geometry import create_edge, create_wire, create_face, create_prism, random_polygon_constructor, angle_of_two_arrays, laterality_indicator, angular_bisector, p_center_of_mass, linear_interpolate, Pnt, Segments from amworkflow.src.geometries.operator import reverse, geom_copy, translate, rotate_face, fuser, hollow_carver, cutter3D, bender -from amworkflow.src.geometries.property import topo_explorer, p_bounding_box +from amworkflow.src.geometries.property import topo_explorer, p_bounding_box,shortest_distance_point_line, p_get_face_area from amworkflow.src.geometries.builder import solid_maker from OCC.Core.gp import gp_Pnt import numpy as np @@ -13,6 +13,7 @@ import itertools import copy as cp import networkx as nx +from amworkflow.src.utils.meter import timer def polygon_maker(side_num: int, @@ -187,183 +188,6 @@ def create_sym_hexagon1_infill(total_len: float, total_wid:float, height:float, p0 = [0,th * 0.5] p1 = [] -# def create_wall_by_points(pts:list, th: float, isclose:bool, height: float = None, debug: bool = False, debug_type: str = "linear", output: str = "prism", interpolate:float = None, R: float = None) -> np.ndarray or TopoDS_Face or TopoDS_Shell: - """ - @brief Create a prism wall by points. It takes a list of points as a skeleton of a central path and then build a strip or a loop. - @param pts list of 2D points that define the wall. The algorithm can compute points in 3D theoretically but the result may make no sense. - @param th thickness of the wall. - @param isclose True if the wall is closed (loop) - @param height height of the wall if a prism is needed. - @param debug if True output two groups of points for plotting. - @param output selecting result intended to output. can be varied among "face" and "prism". - @return two arrays or a face or a prism. - """ - is_loop = False - pts = [np.array(list(i.Coord())) if isinstance(i, gp_Pnt) else np.array(i) for i in pts] - if R is not None: - pts = polygon_interpolater(pts, interpolate) - bender(pts, R) - pts = [i for i in pts] - th *= 0.5 - opt_pts = [] - vecs = [] - dir_vecs = [] - ths = [] - lft_pts = [] - rgt_pts = [] - segaments = [] - for i,p in enumerate(pts): - if i != len(pts) - 1: - a1 = pts[i+1] - pts[i] - if i == 0: - if isclose: - dr = angular_bisector(pts[-1] - p, a1) - # ang = angle_of_two_arrays(dir_vecs[i-1],dr) - ang2 = angle_of_two_arrays(laterality_indicator(p - pts[-1], True), dr) - ang_th = ang2 - if ang2 > np.pi / 2: - dr *= -1 - ang_th = np.pi - ang2 - nth = np.abs(th / np.cos(ang_th)) - else: - dr = laterality_indicator(a1, True) - nth = th - else: - dr = angular_bisector(-vecs[i-1], a1) - ang2 = angle_of_two_arrays(laterality_indicator(vecs[i-1], True), dr) - ang_th = ang2 - if ang2 > np.pi / 2: - dr *= -1 - ang_th = np.pi - ang2 - nth = np.abs(th / np.cos(ang_th)) - else: - if isclose: - a1 = pts[0] - pts[i] - dr = angular_bisector(-vecs[i-1], a1) - ang2 = angle_of_two_arrays(laterality_indicator(vecs[i-1], True), dr) - ang_th = ang2 - if ang2 > np.pi / 2: - dr *= -1 - ang_th = np.pi - ang2 - nth = np.abs(th / np.cos(ang_th)) - else: - dr = laterality_indicator(a1, True) - nth = th - vecs.append(a1) - ths.append(nth) - dir_vecs.append(dr) - lft_pts.append(dr * nth + p) - opt_pts.append(dr * nth + p) - if isclose: - lft_pts.append(lft_pts[0]) - for i,p in enumerate(pts[::-1]): - dr = -dir_vecs[::-1][i] - nth = ths[::-1][i] - rgt_pts.append(dr * nth + p) - if isclose: - rgt_pts.append(rgt_pts[0]) - pts.append(pts[0]) - #find bounding box if bending needed - if R is not None: - mxpt, mnpt = p_bounding_box(lft_pts+rgt_pts) - # Deal with overlapping sides. - lft_pts = break_overlap(lft_pts) - rgt_pts = break_overlap(rgt_pts) - loops_lft_pt_i, peak_lft_pt_i = find_loop(lft_pts) - loops_rgt_pt_i, peak_rgt_pt_i = find_loop(rgt_pts) - if (len(loops_lft_pt_i+peak_lft_pt_i)>0) or (len(loops_rgt_pt_i+peak_rgt_pt_i)>0): - is_loop = True - loops_lft = index2array(loops_lft_pt_i, lft_pts) - loops_rgt = index2array(loops_rgt_pt_i, rgt_pts) - loops = loops_lft+loops_rgt - # if interpolate is not None: - # for i in range(len(loops)): - # loops[i] = polygon_interpolater(loops[i], interpolate) - # if R is not None: - # bender(loops[i], mxpt, mnpt) - loops_h = find_topology(loops) - - if debug: - if debug_type == "polygon": - fig, ax = plt.subplots() - for polygon in loops: - poly2d = np.array([[i[0], i[1]] for i in polygon]) - polygon_patch = Polygon(poly2d, closed=True, fill=False, edgecolor='black') - ax.add_patch(polygon_patch) - ax.set_xlabel('X-axis') - ax.set_ylabel('Y-axis') - ax.set_xlim(-200, 200) - ax.set_ylim(-200, 200) - ax.set_title('Visualization of Polygons') - plt.show() - elif debug_type == "linear": - plt.figure(figsize=(8, 6)) # Optional: Set the figure size - output1 = np.array(lft_pts) - output2 = np.array(rgt_pts) - talist = np.array(pts).T - toutput1 = output1.T - toutput2 = output2.T - x1 = talist[0] - y1 = talist[1] - x2 = toutput1[0] - y2 = toutput1[1] - x3 = toutput2[0] - y3 = toutput2[1] - plt.plot(x1, y1, 'bo-', label='central path') - # Plot Group 2 points and connect with lines in red - plt.plot(x2, y2, 'ro-', label='outer line') - # Plot Group 3 points and connect with lines in green - plt.plot(x3, y3, 'go-', label='inner line') - # Add labels and a legend - for i in range(x2.shape[0]): - plt.text(x2[i], y2[i], str(i)) - for i in range(x3.shape[0]): - plt.text(x3[i], y3[i], str(i)) - - plt.xlabel('X-axis') - plt.ylabel('Y-axis') - plt.legend() - plt.axis('equal') - plt.grid(True) # Optional: Add grid lines - plt.show() - else: - if not is_loop: - gp_pts_lft = [gp_Pnt(i[0],i[1],i[2]) for i in lft_pts] - gp_pts_rgt = [gp_Pnt(i[0],i[1],i[2]) for i in rgt_pts] - gp_pts = [gp_Pnt(i[0],i[1],i[2]) for i in opt_pts] - poly = random_polygon_constructor(gp_pts) - else: - for i,v in enumerate(loops_h): - for j,vv in enumerate(loops_h[i]): - loops_h[i][j] = list(loops_h[i][j]) - for ind,k in enumerate(loops_h[i][j]): - loops_h[i][j][ind] = gp_Pnt(k[0], k[1], k[2]) - poly0 = random_polygon_constructor(loops_h[0][0]) - poly_r = poly0 - for i, h in enumerate(loops_h): - if i == 0: - continue - for j in h: - poly_c = random_polygon_constructor(j) - poly_r = cutter3D(poly_r, poly_c) - poly = poly_r - match output: - case "face": - if not isclose: - return poly - else: - return poly - case "prism": - pr = create_prism(poly, [0,0,height],True) - # top = geom_copy(poly) - # translate(top,[0,0,height]) - # opt = sewer([top,pr,poly]) - # print(opt) - pr_face = topo_explorer(pr,"face") - pr_remake = sewer(pr_face) - opt = solid_maker(pr_remake) - return opt - def find_intersect(lines: np.ndarray) -> np.ndarray: parallel = False coplanarity = False @@ -408,7 +232,6 @@ def index2array(ind: list, array: np.ndarray): real_array.append(item) return real_array - def polygon_interpolater(plg: np.ndarray, step_len: float = None, num: int = None, isclose: bool = True): def deter_dum(line: np.ndarray): ratio = step_len / np.linalg.norm(line[0]-line[1]) @@ -445,400 +268,7 @@ def deter_dum(line: np.ndarray): pos +=p_num+1 return new_plg -# def create_wall_by_points2(pts:list, th: float, isclose:bool, height: float = None, debug: bool = False, output: str = "prism", interpolate:float = None, R: float = None) -> np.ndarray or TopoDS_Face or TopoDS_Shell: - """ - @brief Create a prism wall by points. It takes a list of points as a skeleton of a central path and then build a strip or a loop. - @param pts list of 2D points that define the wall. The algorithm can compute points in 3D theoretically but the result may make no sense. - @param th thickness of the wall. - @param isclose True if the wall is closed (loop) - @param height height of the wall if a prism is needed. - @param debug if True output two groups of points for plotting. - @param output selecting result intended to output. can be varied among "face" and "prism". - @return two arrays or a face or a prism. - """ - pts = [np.array(list(i.Coord())) if isinstance(i, gp_Pnt) else np.array(i) for i in pts] - if R is not None: - pts = polygon_interpolater(pts, interpolate) - bender(pts, R) - pts = [i for i in pts] - th += 0.1 - th *= 0.5 - vecs = [] - dir_vecs = [] - ths = [] - lft_pts = [] - rgt_pts = [] - for i,p in enumerate(pts): - if i != len(pts) - 1: - a1 = pts[i+1] - pts[i] - if i == 0: - if isclose: - dr = angular_bisector(pts[-1] - p, a1) - # ang = angle_of_two_arrays(dir_vecs[i-1],dr) - ang2 = angle_of_two_arrays(laterality_indicator(p - pts[-1], True), dr) - ang_th = ang2 - if ang2 > np.pi / 2: - dr *= -1 - ang_th = np.pi - ang2 - nth = np.abs(th / np.cos(ang_th)) - else: - dr = laterality_indicator(a1, True) - nth = th - else: - dr = angular_bisector(-vecs[i-1], a1) - ang2 = angle_of_two_arrays(laterality_indicator(vecs[i-1], True), dr) - ang_th = ang2 - if ang2 > np.pi / 2: - dr *= -1 - ang_th = np.pi - ang2 - nth = np.abs(th / np.cos(ang_th)) - else: - if isclose: - a1 = pts[0] - pts[i] - dr = angular_bisector(-vecs[i-1], a1) - ang2 = angle_of_two_arrays(laterality_indicator(vecs[i-1], True), dr) - ang_th = ang2 - if ang2 > np.pi / 2: - dr *= -1 - ang_th = np.pi - ang2 - nth = np.abs(th / np.cos(ang_th)) - else: - dr = laterality_indicator(a1, True) - nth = th - vecs.append(a1) - ths.append(nth) - dir_vecs.append(dr) - lft_pts.append(dr * nth + p) - rgt_pts.append(-dr * nth + p) - if isclose: - lft_pts.append(lft_pts[0]) - if isclose: - rgt_pts.append(rgt_pts[0]) - pts.append(pts[0]) - fc_set = [] - for i in range(len(lft_pts)-1): - opts = lft_pts - ipts = rgt_pts - opt1 = gp_Pnt(opts[i][0], opts[i][1], opts[i][2]) - opt2 = gp_Pnt(opts[i+1][0], opts[i+1][1], opts[i+1][2]) - ipt2 = gp_Pnt(ipts[i][0], ipts[i][1], ipts[i][2]) - ipt1 = gp_Pnt(ipts[i+1][0], ipts[i+1][1], ipts[i+1][2]) - fc = random_polygon_constructor([opt1, opt2, ipt1, ipt2]) - fc_set.append(fc) - face = fc_set[0] - for fce in fc_set[1:]: - face = fuser(face, fce) - return create_prism(face, [0,0,height]) - -class CreateWallByPoints(): - def __init__(self, pts: list, th: float, height: float): - self.coords = [np.array(list(i.Coord())) if isinstance(i, gp_Pnt) else np.array(i) for i in pts] - self.height = height - self.is_loop = False - self.R = None - self.overlap = False - self.interpolate = 6 - self.th = th - self.is_close = False - self.vecs = [] - self.dir_vecs = [] - self.ths = [] - self.lft_coords = [] - self.rgt_coords = [] - self.loops_h = [] - self.loops = [] - self.fc_set = [] - self.poly: TopoDS_Shape - - def create_polygon(self): - if not self.is_loop: - gp_pts_lft = [gp_Pnt(i[0],i[1],i[2]) for i in self.lft_coords] - gp_pts_rgt = [gp_Pnt(i[0],i[1],i[2]) for i in self.rgt_coords] - self.gp_pts = gp_pts_lft + gp_pts_rgt - self.poly = random_polygon_constructor(self.gp_pts) - else: - for i,v in enumerate(self.loops_h): - for j,vv in enumerate(self.loops_h[i]): - self.loops_h[i][j] = list(self.loops_h[i][j]) - for ind,k in enumerate(self.loops_h[i][j]): - self.loops_h[i][j][ind] = gp_Pnt(k[0], k[1], k[2]) - poly0 = random_polygon_constructor(self.loops_h[0][0]) - poly_r = poly0 - for i, h in enumerate(self.loops_h): - if i == 0: - continue - for j in h: - poly_c = random_polygon_constructor(j) - poly_r = cutter3D(poly_r, poly_c) - self.poly = poly_r - - def Shape(self): - if self.overlap: - self.create_sides() - for i in range(len(self.lft_coords)-1): - opts = self.lft_coords - ipts = self.rgt_coords - opt1 = gp_Pnt(opts[i][0], opts[i][1], opts[i][2]) - opt2 = gp_Pnt(opts[i+1][0], opts[i+1][1], opts[i+1][2]) - ipt2 = gp_Pnt(ipts[i][0], ipts[i][1], ipts[i][2]) - ipt1 = gp_Pnt(ipts[i+1][0], ipts[i+1][1], ipts[i+1][2]) - fc = random_polygon_constructor([opt1, opt2, ipt1, ipt2]) - self.fc_set.append(fc) - face = self.fc_set[0] - for fce in self.fc_set[1:]: - face = fuser(face, fce) - pr = create_prism(face, [0,0,self.height], True) - faces = topo_explorer(pr, "face") - pr_remake = sewer(faces) - opt = solid_maker(pr_remake) - return opt - else: - self.create_sides() - self.create_loop() - self.create_polygon() - if np.isclose(self.height, 0): - opt = self.poly - else: - pr = create_prism(self.poly, [0,0,self.height],True) - pr_face = topo_explorer(pr,"face") - pr_remake = sewer(pr_face) - opt = solid_maker(pr_remake) - return opt - - def create_sides(self): - if self.R is not None: - self.coords = polygon_interpolater(self.coords, self.interpolate) - self.coords = bender(self.coords, self.R) - self.coords = [i for i in self.coords] - self.th *= 0.5 - for i,p in enumerate(self.coords): - if i != len(self.coords) - 1: - a1 = self.coords[i+1] - self.coords[i] - if i == 0: - if self.is_close: - dr = angular_bisector(self.coords[-1] - p, a1) - # ang = angle_of_two_arrays(dir_vecs[i-1],dr) - ang2 = angle_of_two_arrays(laterality_indicator(p - self.coords[-1], True), dr) - ang_th = ang2 - if ang2 > np.pi / 2: - dr *= -1 - ang_th = np.pi - ang2 - nth = np.abs(self.th / np.cos(ang_th)) - else: - dr = laterality_indicator(a1, True) - nth = self.th - else: - dr = angular_bisector(-self.vecs[i-1], a1) - ang2 = angle_of_two_arrays(laterality_indicator(self.vecs[i-1], True), dr) - ang_th = ang2 - if ang2 > np.pi / 2: - dr *= -1 - ang_th = np.pi - ang2 - nth = np.abs(self.th / np.cos(ang_th)) - else: - if self.is_close: - a1 = self.coords[0] - self.coords[i] - dr = angular_bisector(-self.vecs[i-1], a1) - ang2 = angle_of_two_arrays(laterality_indicator(self.vecs[i-1], True), dr) - ang_th = ang2 - if ang2 > np.pi / 2: - dr *= -1 - ang_th = np.pi - ang2 - nth = np.abs(self.th / np.cos(ang_th)) - else: - dr = laterality_indicator(a1, True) - nth = self.th - self.vecs.append(a1) - self.ths.append(nth) - self.dir_vecs.append(dr) - self.lft_coords.append(dr * nth + p) - if self.overlap: - self.rgt_coords.append(-dr * nth + p) - if self.is_close: - self.lft_coords.append(self.lft_coords[0]) - if not self.overlap: - for i,p in enumerate(self.coords[::-1]): - dr = -self.dir_vecs[::-1][i] - nth = self.ths[::-1][i] - self.rgt_coords.append(dr * nth + p) - if self.is_close: - self.rgt_coords.append(self.rgt_coords[0]) - self.coords.append(self.coords[0]) - - def create_loop(self): - if self.R is not None: - mxpt, mnpt = p_bounding_box(self.lft_coords+self.rgt_coords) - self.lft_coords = self.break_overlap(self.lft_coords) - self.rgt_coords = self.break_overlap(self.rgt_coords) - loops_lft_pt_i, peak_lft_pt_i = self.find_loop(self.lft_coords) - loops_rgt_pt_i, peak_rgt_pt_i = self.find_loop(self.rgt_coords) - if (len(loops_lft_pt_i+peak_lft_pt_i)>0) or (len(loops_rgt_pt_i+peak_rgt_pt_i)>0): - self.is_loop = True - self.loops_lft = index2array(loops_lft_pt_i, self.lft_coords) - self.loops_rgt = index2array(loops_rgt_pt_i, self.rgt_coords) - self.loops = self.loops_lft+self.loops_rgt - self.loops_h = self.find_topology(self.loops) - - - def is_include(self, point: np.ndarray, polygon: np.ndarray) -> bool: - polygon = np.concatenate((polygon, np.array([polygon[0]]))) - ang = 0 - for i,v in enumerate(polygon): - if i == polygon.shape[0]-1: - break - v1 = np.array(v-point) - v2 = np.array(polygon[i+1]-point) - # if np.isclose(np.linalg.norm(v1),0,1e-8) or np.isclose(np.linalg.norm(v2),0,1e-8): - # continue - crt = angle_of_two_arrays(v1, v2) - ang += crt - if np.isclose(ang, 2*np.pi, 1e-2): - return True - else: return False - - def find_topology(self, loops: list) -> list: - ck_lst = [] - loop_with_hierarchy = [] - topo = np.zeros(len(loops)) - for i,lp in enumerate(loops): - p = lp[0] - for j, llpp in enumerate(loops): - if (i == j) or ((i,j) in ck_lst): - continue - else: - if self.is_include(p, llpp): - topo[i] += 1 - elif self.is_include(llpp[0], lp): - topo[j] += 1 - ck_lst.append((i,j)) - ck_lst.append((j,i)) - lyr_mx = int(np.max(topo)) - for i in range(lyr_mx+1): - loop_h = [loops[j] for j,v in enumerate(topo) if v == i] - loop_with_hierarchy.append(loop_h) - return loop_with_hierarchy - - def break_overlap(self, pts: np.ndarray) -> np.ndarray: - n_pts = np.copy(pts) - inst_p = [] - # otr_vecs = np.array([pts[i+1] - pts[i] if i != len(pts)-1 else pts[0] - pts[i] for i in range(len(pts))]) - ck_lst = [] - m = len(pts) - i = 0 - pos = 0 - while i < m: - for ind,v in enumerate(pts): - if i == m-1: - next_p = pts[0] - else: - next_p = pts[i+1] - if (np.linalg.norm(pts[i] - v, 1) < 1e-8) or (np.linalg.norm(next_p - v, 1) < 1e-8): - continue - else: - comb = (i, ind, i+1) - if comb in ck_lst: - continue - else: - if i == m - 1: - half1 = v - pts[i] - half2 = pts[0] - v - else: - half1 = v - pts[i] - half2 = pts[i+1] - v - coline = np.isclose(np.linalg.norm(np.cross(half1, half2)), 0, 1e-8) - same_dir = np.dot(half1, half2) > 0 - if coline and same_dir: - inst_p.append(v) - comb_f = list(itertools.permutations(cp.copy(comb))) - ck_lst += comb_f - inst_p = np.array(inst_p) - icr_pos = inst_p.shape[0] - if icr_pos != 0: - dist = [[np.linalg.norm(p-pts[i]), p] for p in inst_p] - def sort_ind(lst): - return lst[0] - std_inst_p = np.array([i[1] for i in sorted(dist, key=sort_ind)]) - n_pts = np.concatenate((n_pts[:pos+1], std_inst_p, n_pts[pos+1:])) - pos += icr_pos - i +=1 - pos+=1 - inst_p = [] - return n_pts - - def find_loop(self, pts: np.ndarray) -> tuple: - pts = np.array([np.array(list(i.Coord())) if isinstance(i, gp_Pnt) else np.array(i) for i in pts]) - peak_p = [] - dim = pts.shape[0] - distance = np.ones((dim, dim)) * np.nan - for i, p in enumerate(pts): - for j in range(i+1,dim,1): - dist = np.linalg.norm(p - pts[j]) - distance[i,j] = dist - knots = np.array(np.where(distance < 1e-6)).T - loop_l = [] - for i in range(len(knots)-1): - half1 = np.arange(knots[i, 0], knots[i+1, 0]+1) - half2 = np.arange(knots[i+1, 1]+1, knots[i, 1]) - loop = np.concatenate((half1, half2)) - if loop.shape[0] < 3: - if loop.shape[0] == 2: - if np.isclose(np.linalg.norm(pts[knots[i, 0]] - pts[loop[1]+2]), 0, 1e-8): - print(loop) - peak_p.append(loop[1]) - continue - else: - loop_l.append(loop) - lst_loop = np.arange(knots[-1,0], knots[-1,1]) - if lst_loop.shape[0] >=3: - loop_l.append(lst_loop) - return loop_l, peak_p - - def visualize(self, plot_type: str) -> None: - if len(self.lft_pts) == 0: - self.Shape() - if plot_type == "polygon": - fig, ax = plt.subplots() - for polygon in self.loops: - poly2d = np.array([[i[0], i[1]] for i in polygon]) - polygon_patch = Polygon(poly2d, closed=True, fill=False, edgecolor='black') - ax.add_patch(polygon_patch) - ax.set_xlabel('X-axis') - ax.set_ylabel('Y-axis') - ax.set_xlim(-200, 200) - ax.set_ylim(-200, 200) - ax.set_title('Visualization of Polygons') - plt.show() - elif plot_type == "linear": - plt.figure(figsize=(8, 6)) # Optional: Set the figure size - output1 = np.array(self.lft_coords) - output2 = np.array(self.rgt_coords) - talist = np.array(self.coords).T - toutput1 = output1.T - toutput2 = output2.T - x1 = talist[0] - y1 = talist[1] - x2 = toutput1[0] - y2 = toutput1[1] - x3 = toutput2[0] - y3 = toutput2[1] - plt.plot(x1, y1, 'bo-', label='central path') - # Plot Group 2 points and connect with lines in red - plt.plot(x2, y2, 'ro-', label='outer line') - # Plot Group 3 points and connect with lines in green - plt.plot(x3, y3, 'go-', label='inner line') - # Add labels and a legend - for i in range(x2.shape[0]): - plt.text(x2[i], y2[i], str(i)) - for i in range(x3.shape[0]): - plt.text(x3[i], y3[i], str(i)) - - plt.xlabel('X-axis') - plt.ylabel('Y-axis') - plt.legend() - plt.axis('equal') - plt.grid(True) # Optional: Add grid lines - plt.show() - +# @timer class CreateWallByPointsUpdate(): def __init__(self, coords: list, th: float, height: float): self.coords = Pnt(coords).coords @@ -848,6 +278,7 @@ def __init__(self, coords: list, th: float, height: float): self.th = th self.is_close = True self.vecs = [] + self.central_segments = [] self.dir_vecs = [] self.ths = [] self.lft_coords = [] @@ -856,11 +287,11 @@ def __init__(self, coords: list, th: float, height: float): self.create_sides() self.pnts = Segments(self.side_coords) self.G = nx.from_dict_of_lists(self.pnts.pts_digraph, create_using=nx.DiGraph) - # self.all_loops = list(nx.simple_cycles(self.G)) - self.self_loops = nx.selfloop_edges(self.G) # self.all_loops = list(nx.simple_cycles(self.H)) # Dangerous! Ran out of memory. self.loop_generator = nx.simple_cycles(self.G) - + self.check_pnt_in_wall() + self.postprocessing() + def create_sides(self): if self.R is not None: self.coords = polygon_interpolater(self.coords, self.interpolate) @@ -869,6 +300,7 @@ def create_sides(self): self.th *= 0.5 for i,p in enumerate(self.coords): if i != len(self.coords) - 1: + self.central_segments.append([self.coords[i], self.coords[i+1]]) a1 = self.coords[i+1] - self.coords[i] if i == 0: if self.is_close: @@ -893,6 +325,7 @@ def create_sides(self): nth = np.abs(self.th / np.cos(ang_th)) else: if self.is_close: + self.central_segments.append([self.coords[i], self.coords[0]]) a1 = self.coords[0] - self.coords[i] dr = angular_bisector(-self.vecs[i-1], a1) ang2 = angle_of_two_arrays(laterality_indicator(self.vecs[i-1], True), dr) @@ -916,7 +349,18 @@ def create_sides(self): self.coords.append(self.coords[0]) else: self.rgt_coords = self.rgt_coords[::-1] - self.side_coords = self.lft_coords + self.rgt_coords + self.lft_coords[0] + self.side_coords = self.lft_coords + self.rgt_coords + # + [self.lft_coords[0]] + + def check_pnt_in_wall(self): + for pnt, coord in self.pnts.pts_index.items(): + for vec in self.central_segments: + lmbda, dist = shortest_distance_point_line(vec,coord) + if dist < 0.9 * self.th: + print(f"pnt:{pnt},dist:{dist},lmbda:{lmbda}, vec:{vec}") + self.in_wall_pts_list.update({pnt:True}) + break + def visualize(self, display_polygon: bool = True): # Extract the x and y coordinates and IDs @@ -924,7 +368,6 @@ def visualize(self, display_polygon: bool = True): x = [coord[0] for coord in a.values()] y = [coord[1] for coord in a.values()] ids = list(a.keys()) # Get the point IDs - # Create a scatter plot in 2D plt.subplot(1,2,1) # plt.figure() @@ -935,12 +378,24 @@ def visualize(self, display_polygon: bool = True): plt.annotate(f'{ids[i]}', (xi, yi), fontsize=12, ha='right') if display_polygon: - for lp in self.loop_generator: - if len(lp) > 2: - coords = [self.pnts.pts_index[i] for i in lp] - x = [point[0] for point in coords] - y = [point[1] for point in coords] - plt.plot(x + [x[0]], y + [y[0]], linestyle='-', marker='o') + for lp in self.result_loops: + print(lp) + coords = [self.pnts.pts_index[i] for i in lp] + x = [point[0] for point in coords] + y = [point[1] for point in coords] + plt.plot(x + [x[0]], y + [y[0]], linestyle='-', marker='o') + + # talist = np.array(self.coords).T + # x1 = talist[0] + # y1 = talist[1] + # plt.plot(x1, y1, 'bo-', label='central path') + # Create segments by connecting consecutive points + + # a_subtitute = np.array(self.side_coords) + # toutput1 = a_subtitute.T + # x2 = toutput1[0] + # y2 = toutput1[1] + # plt.plot(x2, y2, 'ro-', label='outer line') # Set labels and title plt.xlabel('X-axis') @@ -966,4 +421,94 @@ def visualize_graph(self): nx.draw(self.G, pos=layout, with_labels=True, node_color='skyblue', font_size=10, node_size=500) plt.title("NetworkX Graph Visualization") plt.show() - \ No newline at end of file + + def Shape(self): + loop_r = self.rank_result_loops() + print(loop_r) + boundary = [self.occ_pnt(self.pnts.pts_index[i]) for i in loop_r[0]] + poly0 = random_polygon_constructor(boundary) + poly_r = poly0 + for i, h in enumerate(loop_r): + if i == 0: + continue + h = [self.occ_pnt(self.pnts.pts_index[i]) for i in h] + poly_c = random_polygon_constructor(h) + poly_r = cutter3D(poly_r, poly_c) + self.poly = poly_r + if not np.isclose(self.height, 0): + wall_compound = create_prism(self.poly, [0,0,self.height]) + faces = topo_explorer(wall_compound, "face") + wall_shell = sewer(faces) + self.wall = solid_maker(wall_shell) + return self.wall + else: + return self.poly + + def postprocessing(self): + correct_loop_count = 0 + for lp in self.loop_generator: + real_loop = True + visible_loop = True + in_wall_pt_count = 0 + virtual_vector_count = 0 + if len(lp) > 2: + for i,pt in enumerate(lp): + if i == 0: + if pt in self.in_wall_pts_list: + in_wall_pt_count += 1 + if (lp[-1],pt) in self.pnts.virtual_vector: + virtual_vector_count += 1 + else: + if pt in self.in_wall_pts_list: + in_wall_pt_count += 1 + if (lp[i-1],pt) in self.pnts.virtual_vector: + virtual_vector_count += 1 + if (in_wall_pt_count > 0) or (virtual_vector_count > 1): + # if (in_wall_pt_count > 0): + visible_loop = False + break + else: + real_loop = False + if real_loop and visible_loop: + self.result_loops.append(lp) + for pt in lp: + if pt not in self.in_loop_pts_list: + self.in_loop_pts_list.update({pt:[correct_loop_count]}) + else: + self.in_loop_pts_list[pt].append(correct_loop_count) + correct_loop_count += 1 + loop_counter = np.zeros(len(self.result_loops)) + visited = [] + counter = 0 + for pt, lp in self.in_loop_pts_list.items(): + if len(lp) > 1: + if counter == 0: + visited.append(lp) + for ind in lp: + loop_counter[ind] += 1 + else: + if any(sorted(lp) == sorted(item) for item in visited): + continue + else: + visited.append(lp) + for ind in lp: + loop_counter[ind] += 1 + counter += 1 + filtered_lp = np.where(loop_counter > 1)[0].tolist() + print(self.result_loops) + print(filtered_lp) + print(loop_counter) + self.result_loops = [v for i,v in enumerate(self.result_loops) if i not in filtered_lp] + + def rank_result_loops(self): + areas = np.zeros(len(self.result_loops)) + for i,lp in enumerate(self.result_loops): + lp_coord = [self.pnts.pts_index[i] for i in lp] + area = p_get_face_area(lp_coord) + areas[i] = area + rank = np.argsort(areas).tolist() + self.result_loops = sorted(self.result_loops, key=lambda x: rank.index(self.result_loops.index(x)),reverse=True) + return self.result_loops + + def occ_pnt(self,coord) -> gp_Pnt: + return gp_Pnt(*coord) \ No newline at end of file diff --git a/amworkflow/src/geometries/mesher.py b/amworkflow/src/geometries/mesher.py index e8ffa84..ce0f0de 100644 --- a/amworkflow/src/geometries/mesher.py +++ b/amworkflow/src/geometries/mesher.py @@ -45,7 +45,6 @@ def mesher(item: TopoDS_Shape, model.add(model_name) v = get_geom_pointer(model, geo) model.occ.synchronize() - gmsh.fltk.run() for layer in v: model.add_physical_group(3,[layer[1]], name=f"layer{layer[1]}") phy_gp = model.getPhysicalGroups() diff --git a/amworkflow/src/geometries/operator.py b/amworkflow/src/geometries/operator.py index 0306ea2..07e3904 100644 --- a/amworkflow/src/geometries/operator.py +++ b/amworkflow/src/geometries/operator.py @@ -81,7 +81,7 @@ def split(item: TopoDS_Shape, plan_len = 1.2 * max(abs(xmin - xmax), abs(ymin - ymax)) z = zmax - zmin if nz != None: - z_list = np.linspace(zmin, z, nz) + z_list = np.linspace(zmin, z, nz+1) if layer_thickness != None: z_list = np.arange(zmin, z, layer_thickness) z_list = np.concatenate((z_list,np.array([z]))) diff --git a/amworkflow/src/geometries/property.py b/amworkflow/src/geometries/property.py index 4962a98..7aa627a 100644 --- a/amworkflow/src/geometries/property.py +++ b/amworkflow/src/geometries/property.py @@ -126,8 +126,8 @@ def shortest_distance_point_line(line, p): pt1, pt2 = line s = pt2 - pt1 lmbda = (p - pt1).dot(s) / s.dot(s) - pt_compute = pt1 + lmbda * s if lmbda < 1 and lmbda > 0: + pt_compute = pt1 + lmbda * s distance = np.linalg.norm(pt_compute - p) return lmbda, distance elif lmbda <= 0: @@ -144,6 +144,20 @@ def shortest_distance_line_line(line1, line2): s2 = pt22 - pt21 s1square = np.dot(s1, s1) s2square = np.dot(s2, s2) + term1 = s1square * s2square - (np.dot(s1, s2)**2) + term2 = s1square * s2square - (np.dot(s1, s2)**2) + if np.isclose(term1,0) or np.isclose(term2, 0): + if np.isclose(s1[0],0): + s_p = np.array([-s1[1],s1[0],0]) + else: + s_p = np.array([s1[1],-s1[0],0]) + l1 = np.random.randint(1,4) * 0.1 + l2 = np.random.randint(6,9) * 0.1 + pt1i = s1 * l1 + pt11 + pt2i = s2 * l2 + pt21 + si = pt2i - pt1i + dist = np.linalg.norm(si * ( si * s_p) / (np.linalg.norm(si) * np.linalg.norm(s_p))) + return dist, np.array([pt1i,pt2i]) lmbda1 = (np.dot(s1,s2) * np.dot(pt11 - pt21,s2) - s2square * np.dot(pt11 - pt21, s1)) / (s1square * s2square - (np.dot(s1, s2)**2)) lmbda2 = -(np.dot(s1,s2) * np.dot(pt11 - pt21,s1) - s1square * np.dot(pt11 - pt21, s2)) / (s1square * s2square - (np.dot(s1, s2)**2)) condition1 = lmbda1 >= 1 @@ -234,3 +248,15 @@ def check_overlap(line1: np.ndarray, line2: np.ndarray) -> np.ndarray: indicator[1] = 1 return np.where(indicator == 1)[0], np.unique(pnt_list[np.where(indicator == 1)[0]], axis=0) +def p_get_face_area(points: list): + pts = np.array(points).T + x = pts[0] + y = pts[1] + result = 0 + for i in range(len(x)): + if i < len(x) - 1: + t = x[i]*y[i+1] - x[i+1]*y[i] + else: + t = x[i]*y[0] - x[0]*y[i] + result += t + return np.abs(result) * 0.5 \ No newline at end of file diff --git a/amworkflow/src/geometries/simple_geometry.py b/amworkflow/src/geometries/simple_geometry.py index 1aaad73..76db92e 100644 --- a/amworkflow/src/geometries/simple_geometry.py +++ b/amworkflow/src/geometries/simple_geometry.py @@ -8,13 +8,15 @@ from OCCUtils.Construct import make_face from amworkflow.src.geometries.builder import geometry_builder, sewer from amworkflow.src.geometries.property import check_overlap, check_parallel_line_line, shortest_distance_line_line - +from amworkflow.src.utils.system import threads_count from OCC.Core.GC import GC_MakeArcOfCircle import math as m from OCC.Core.BRepOffsetAPI import BRepOffsetAPI_MakeOffsetShape from OCCUtils.Topology import Topo import numpy as np - +import multiprocessing +from itertools import repeat +from amworkflow.src.utils.meter import timer def create_box(length: float, width: float, @@ -373,6 +375,7 @@ def pnt(self, pt_coord) -> np.ndarray: def new_pnt(self, pt_coords: list): pt_coords = self.pnt(pt_coords) + for i, v in self.pts_index.items(): if self.pnt_overlap(v, pt_coords): return False, i @@ -423,12 +426,15 @@ def update_digraph(self, start_node: int, end_node: int, insert_node: int = None self.pts_digraph.update({start_node: [end_node]}) else: raise Exception("No edge found for insertion option.") - + + class Segments(Pnt): def __init__(self, *coords: list): super().__init__(*coords) self.segments_index = {} self.modify_edge_list = {} + self.virtual_vector = {} + self.virtual_pnt = {} self.find_overlap_node_on_edge() self.modify_edge() @@ -467,13 +473,65 @@ def modify_edge(self): if i == 0: continue self.update_digraph(pts_list[i-1],nd,build_new_edge=False) + if (i != 1) and (i != len(pts_list) - 1): + if (pts_list[i-1] in self.virtual_pnt) and nd in (self.virtual_pnt): + self.virtual_vector.update({(pts_list[i-1],nd): True}) def check_self_edge(self, line: np.ndarray) -> bool: if self.pnt_overlap(line[0],line[1]): return True else: return False - + + def overlap_node_on_edge_finder(self,i,j): + v = self.init_pts_sequence[i] + vv = self.init_pts_sequence[j] + print(i,j) + lin1 = self.get_segment(v[0], v[1]) + lin2 = self.get_segment(vv[0], vv[1]) + self_edge = (self.check_self_edge(lin1) or self.check_self_edge(lin2)) + if not self_edge: + parallel, colinear = check_parallel_line_line(lin1, lin2) + # if v == [13,14]: + # print("line:",(v,vv), parallel, colinear) + if parallel: + if colinear: + index, coords = check_overlap(lin1, lin2) + if len(index) < 4: + for ind in index: + if ind in [0,1]: + self.add_pending_change(tuple(vv),v[ind]) + else: + self.add_pending_change(tuple(v),vv[ind]) + else: + distance = shortest_distance_line_line(lin1, lin2) + intersect = np.isclose(distance[0],0) + new,pt = self.new_pnt(distance[1][0]) + if intersect and new: + pnt_id = self.register_pnt(distance[1][0]) + self.add_pending_change(tuple(v),pnt_id) + self.add_pending_change(tuple(vv), pnt_id) + + + def arg_generator(self): + iter_range = range(len(self.init_pts_sequence)) + visited = {} + for i in iter_range: + for j in iter_range: + if i == j: + continue + if i == j + 1: + continue + if j == i - 1: + continue + if (i,j) in visited or (j,i) in visited: + continue + args = (self,i,j) + print(args) + yield args + visited.update({(i,j): True, (j,i): True}) + + def find_overlap_node_on_edge(self): visited = {} for i,v in enumerate(self.init_pts_sequence): @@ -482,7 +540,9 @@ def find_overlap_node_on_edge(self): continue if i == j + 1: continue - if j == i - 1: + if j == i + 1: + continue + if i == len(self.init_pts_sequence) * 2 -1 - i: continue if (i,j) in visited or (j,i) in visited: continue @@ -502,13 +562,22 @@ def find_overlap_node_on_edge(self): if ind in [0,1]: self.add_pending_change(tuple(vv),v[ind]) else: - self.add_pending_change(tuple(v),vv[ind]) + self.add_pending_change(tuple(v),vv[ind-2]) else: distance = shortest_distance_line_line(lin1, lin2) intersect = np.isclose(distance[0],0) new,pt = self.new_pnt(distance[1][0]) if intersect and new: pnt_id = self.register_pnt(distance[1][0]) + self.virtual_pnt.update({pnt_id: True}) self.add_pending_change(tuple(v),pnt_id) self.add_pending_change(tuple(vv), pnt_id) visited.update({(i,j): True, (j,i): True}) + + # def find_overlap_node_on_edge(self): + # with multiprocessing.Pool(processes=threads_count) as pool: + # args = self.arg_generator() + # # b = zip(repeat(self),args) + # # print(tuple(b)) + # # pool.map(Segments.overlap_node_on_edge_finder,zip(repeat(self),args)) + # pool.map(Segments.overlap_node_on_edge_finder,args) \ No newline at end of file diff --git a/amworkflow/src/utils/meter.py b/amworkflow/src/utils/meter.py new file mode 100644 index 0000000..a2415f5 --- /dev/null +++ b/amworkflow/src/utils/meter.py @@ -0,0 +1,11 @@ +import time + +def timer(func): + def wrapper(*args, **kwargs): + start_time = time.time() + result = func(*args, **kwargs) + end_time = time.time() + elapsed_time = end_time - start_time + print(f"{func.__name__} took {elapsed_time:.6f} seconds to run") + return result + return wrapper \ No newline at end of file diff --git a/amworkflow/src/utils/system.py b/amworkflow/src/utils/system.py new file mode 100644 index 0000000..9431c22 --- /dev/null +++ b/amworkflow/src/utils/system.py @@ -0,0 +1,2 @@ +import psutil +threads_count = psutil.cpu_count() \ No newline at end of file diff --git a/amworkflow/src/utils/visualizer.py b/amworkflow/src/utils/visualizer.py index e579a56..3b765fa 100644 --- a/amworkflow/src/utils/visualizer.py +++ b/amworkflow/src/utils/visualizer.py @@ -3,6 +3,8 @@ from amworkflow.src.constants.exceptions import GmshUseBeforeInitializedException import networkx as nx import matplotlib.pyplot as plt +from amworkflow.src.geometries.property import shortest_distance_line_line +import numpy as np def mesh_visualizer(): try: @@ -25,4 +27,63 @@ def plot_digraph(dataset: dict) -> None: # Draw the nodes and edges nx.draw(G, pos=layout, with_labels=True, node_color='skyblue', font_size=10, node_size=500) plt.title("NetworkX Graph Visualization") + plt.show() + +def plot_intersect(x11 = 0, x12 = 0, y11 = 0, y12 = 0, x21 = 0, x22 = 0, y21 = 0, y22 = 0,segment1 = None, segment2 = None): + if (segment1 is None) and (segment2 is None): + # Coordinates for the two segments + segment1_x = [x11, x12] + segment1_y = [y11, y12] + + segment2_x = [x21, x22] + segment2_y = [y21, y22] + intersect = shortest_distance_line_line(np.array([[x11, y11,0], [x12, y12,0]]), np.array([[x21, y21,0], [x22, y22,0]]))[1] + print(shortest_distance_line_line(np.array([[x11, y11,0], [x12, y12,0]]), np.array([[x21, y21,0], [x22, y22,0]]))[0]) + else: + segment1_x = segment1.T[0] + segment1_y = segment1.T[1] + segment2_x = segment2.T[0] + segment2_y = segment2.T[1] + intersect = shortest_distance_line_line(segment1, segment2)[1] + + + + # Coordinates for the single point + + point_x_1 = [intersect[0].T[0]] + point_y_1 = [intersect[0].T[1]] + point_x_2 = [intersect[1].T[0]] + point_y_2 = [intersect[1].T[1]] + + # Create a figure and axis + fig, ax = plt.subplots() + + # Plot the two segments + ax.plot(segment1_x, segment1_y, color='blue', linestyle='-', linewidth=2, label='Segment 1') + ax.plot(segment2_x, segment2_y, color='green', linestyle='-', linewidth=2, label='Segment 2') + + # Plot the single point + ax.plot(point_x_1, point_y_1, marker='o', markersize=8, color='red', label='Point1') + ax.plot(point_x_2, point_y_2, marker='o', markersize=8, color='red', label='Point2') + + # Add labels for the point and segments + ax.text(2, 3, f'Point ({intersect[0]}, {intersect[1]})', fontsize=12, ha='right') + ax.text(1, 2, 'Segment 1', fontsize=12, ha='right') + ax.text(6, 3, 'Segment 2', fontsize=12, ha='right') + + # Add a legend + ax.legend() + + # Set axis limits for better visualization + ax.set_xlim(0, 7) + ax.set_ylim(0, 6) + + # Set axis labels + ax.set_xlabel('X-axis') + ax.set_ylabel('Y-axis') + + # Set plot title + ax.set_title('Two Segments and One Point') + plt.tight_layout() + # Display the plot plt.show() \ No newline at end of file diff --git a/environment.yml b/environment.yml index e0900e5..1785f8f 100644 --- a/environment.yml +++ b/environment.yml @@ -399,6 +399,7 @@ dependencies: - mdit-py-plugins==0.4.0 - mistune==3.0.1 - nbclassic==1.0.0 + - networkx - nbclient==0.8.0 - nbconvert==7.6.0 - nbformat==5.9.0 diff --git a/environment_clean.yml b/environment_clean.yml new file mode 100644 index 0000000..ffbe170 --- /dev/null +++ b/environment_clean.yml @@ -0,0 +1,22 @@ +name: amworkflow_clean +channels: + - conda-forge + - defaults +dependencies: + - pythonocc-core=7.7.0 + - python=3.10 + - pandas + - sqlite + - numpy + - fenics-dolfinx + - mpich + - pyvista + - pip + - pip: + - gmsh==4.11.1 + - networkx + - pyqt5 + - sphinx + - sqlalchemy + - ruamel-yaml + - doit diff --git a/examples/TrussArc/print110823.csv b/examples/TrussArc/print110823.csv new file mode 100644 index 0000000..2954d10 --- /dev/null +++ b/examples/TrussArc/print110823.csv @@ -0,0 +1,123 @@ +ID,x,y +1,0.00,250.00 +2,0.00,0.00 +3,150.00,0.00 +4,192.50,39.00 +5,235.00,76.00 +6,277.50,111.00 +7,320.00,144.00 +8,362.50,175.00 +9,405.00,204.00 +10,447.50,231.00 +11,490.00,256.00 +12,532.50,279.00 +13,575.00,300.00 +14,617.50,319.00 +15,660.00,336.00 +16,702.50,351.00 +17,745.00,364.00 +18,787.50,375.00 +19,830.00,384.00 +20,872.50,391.00 +21,915.00,396.00 +22,957.50,399.00 +23,1000.00,400.00 +24,1042.50,399.00 +25,1085.00,396.00 +26,1127.50,391.00 +27,1170.00,384.00 +28,1212.50,375.00 +29,1255.00,364.00 +30,1297.50,351.00 +31,1340.00,336.00 +32,1382.50,319.00 +33,1425.00,300.00 +34,1467.50,279.00 +35,1510.00,256.00 +36,1552.50,231.00 +37,1595.00,204.00 +38,1637.50,175.00 +39,1680.00,144.00 +40,1722.50,111.00 +41,1765.00,76.00 +42,1807.50,39.00 +43,1850.00,0.00 +44,2000.00,0.00 +45,2000.00,250.00 +46,1925.00,300.53 +47,1850.00,347.13 +48,1807.50,371.78 +49,1765.00,395.17 +50,1722.50,417.30 +51,1680.00,438.16 +52,1637.50,457.76 +53,1595.00,476.09 +54,1552.50,493.16 +55,1510.00,508.97 +56,1467.50,523.51 +57,1425.00,536.78 +58,1382.50,548.79 +59,1340.00,559.54 +60,1297.50,569.02 +61,1255.00,577.24 +62,1212.50,584.20 +63,1170.00,589.89 +64,1127.50,594.31 +65,1085.00,597.47 +66,1042.50,599.37 +67,1021.25,599.84 +68,1000.00,600.00 +69,978.75,599.84 +70,957.50,599.37 +71,915.00,597.47 +72,872.50,594.31 +73,830.00,589.89 +74,787.50,584.20 +75,745.00,577.24 +76,702.50,569.02 +77,660.00,559.54 +78,617.50,548.79 +79,575.00,536.78 +80,532.50,523.51 +81,490.00,508.97 +82,447.50,493.16 +83,405.00,476.09 +84,362.50,457.76 +85,320.00,438.16 +86,277.50,417.30 +87,235.00,395.17 +88,192.50,371.78 +89,150.00,347.13 +90,75.00,300.53 +91,0.00,250.00 +92,121.57,31.16 +93,164.07,70.16 +94,253.78,357.26 +95,296.28,379.38 +96,382.87,239.98 +97,425.37,266.98 +98,502.57,468.39 +99,545.07,482.93 +100,647.02,376.43 +101,689.52,391.43 +102,750.27,534.83 +103,792.77,541.79 +104,869.24,433.69 +105,911.74,438.69 +106,978.75,552.84 +107,1021.25,552.84 +108,1088.26,442.69 +109,1130.76,437.69 +110,1207.23,537.79 +111,1249.73,530.83 +112,1310.48,395.43 +113,1352.98,380.43 +114,1454.93,478.93 +115,1497.43,464.39 +116,1574.63,270.98 +117,1617.13,243.98 +118,1703.72,375.38 +119,1746.22,353.26 +120,1835.93,74.16 +121,1878.43,35.16 +122,2000.00,250.00 \ No newline at end of file diff --git a/examples/TrussArc/trussarc.py b/examples/TrussArc/trussarc.py new file mode 100644 index 0000000..9aadf63 --- /dev/null +++ b/examples/TrussArc/trussarc.py @@ -0,0 +1,35 @@ +import pathlib +import os +import pandas as pd +import numpy as np +from amworkflow.api import amWorkflow as aw + +# python trussarc.py -n trussarc -gp thickness height -gpv 50 100 -mbt 10 -msf 5 -vtk + +@aw.engine.amworkflow() #("draft") # for visulaization +def geometry_spawn(pm): + #Define model by given file with points + # float parameters: + # pm.thickness: float - thickness of layers + # pm.height: float - global height of model + + # from points list + name = 'print110823' + root = pathlib.Path(__file__).parent + data = pd.read_csv(root / f"{name}.csv", sep=',') + data['z'] = np.zeros(len(data)) # add z coordinate + # print(data) + pmfo = np.array(data[['x','y','z']]) + # print(len(pmfo)) + # # only for outer line + # print(pmfo[0:90]) + g = aw.geom + # pmfo = pmfo[0:90] # outline + wall_maker = g.CreateWallByPoints(pmfo, pm.thickness, pm.height,is_close=False) + design = wall_maker.Shape() + # wall_maker.visualize # Uncomment this line if you would like to visualize it in plot. + + return design #TopoDS_Shape + + + diff --git a/pyproject.toml b/pyproject.toml index 1a8b2ff..53e07b4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,9 +17,6 @@ classifiers = [ license = {file = "LICENSE"} keywords = ["AM concrete", "workflow", "CAD"] dependencies = [ - "fenics-dolfinx", - "gmsh", - "sqlalchemy" ] [project.urls] diff --git a/some_thoughts_20230822_new/guii/1.py b/some_thoughts_20230822_new/guii/1.py new file mode 100644 index 0000000..2ed9473 --- /dev/null +++ b/some_thoughts_20230822_new/guii/1.py @@ -0,0 +1,75 @@ +##Author github user @Tanneguydv, 2021 + +import os +import sys +from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeBox + +from PyQt5.QtWidgets import ( + QApplication, + QWidget, + QPushButton, + QHBoxLayout, + QGroupBox, + QDialog, + QVBoxLayout, +) + +from OCC.Display.backend import load_backend + +load_backend("qt-pyqt5") +import OCC.Display.qtDisplay as qtDisplay + + +class App(QDialog): + def __init__(self): + super().__init__() + self.title = "PyQt5 / pythonOCC" + self.left = 300 + self.top = 300 + self.width = 800 + self.height = 300 + self.initUI() + + def initUI(self): + self.setWindowTitle(self.title) + self.setGeometry(self.left, self.top, self.width, self.height) + self.createHorizontalLayout() + + windowLayout = QVBoxLayout() + windowLayout.addWidget(self.horizontalGroupBox) + self.setLayout(windowLayout) + self.show() + + def createHorizontalLayout(self): + self.horizontalGroupBox = QGroupBox("Display PythonOCC") + layout = QHBoxLayout() + + disp = QPushButton("Display Box", self) + disp.clicked.connect(self.displayBOX) + layout.addWidget(disp) + + eras = QPushButton("Erase Box", self) + eras.clicked.connect(self.eraseBOX) + layout.addWidget(eras) + + self.canvas = qtDisplay.qtViewer3d(self) + layout.addWidget(self.canvas) + self.canvas.resize(200, 200) + self.canvas.InitDriver() + self.display = self.canvas._display + self.horizontalGroupBox.setLayout(layout) + + def displayBOX(self): + a_box = BRepPrimAPI_MakeBox(10.0, 20.0, 30.0).Shape() + self.ais_box = self.display.DisplayShape(a_box)[0] + self.display.FitAll() + + def eraseBOX(self): + self.display.Context.Erase(self.ais_box, True) + + +if __name__ == "__main__": + app = QApplication(sys.argv) + ex = App() + if os.getenv("APPVEYOR") is None: + sys.exit(app.exec_()) \ No newline at end of file diff --git a/some_thoughts_20230822_new/guii/try_qt_thread.py b/some_thoughts_20230822_new/guii/try_qt_thread.py new file mode 100644 index 0000000..df1c31b --- /dev/null +++ b/some_thoughts_20230822_new/guii/try_qt_thread.py @@ -0,0 +1,96 @@ +import sys +from time import sleep +from PyQt5.QtCore import QObject, QThread, pyqtSignal +from PyQt5.QtCore import Qt +from PyQt5.QtWidgets import ( + QApplication, + QLabel, + QMainWindow, + QPushButton, + QVBoxLayout, + QWidget, +) + +class Worker(QObject): + finished = pyqtSignal() + progress = pyqtSignal(int) + + def run(self): + """Long-running task.""" + for i in range(5): + sleep(1) + self.progress.emit(i + 1) + self.finished.emit() + + +class Window(QMainWindow): + def __init__(self, parent=None): + super().__init__(parent) + self.clicksCount = 0 + self.setupUi() + + def setupUi(self): + self.setWindowTitle("Freezing GUI") + self.resize(300, 150) + self.centralWidget = QWidget() + self.setCentralWidget(self.centralWidget) + # Create and connect widgets + self.clicksLabel = QLabel("Counting: 0 clicks", self) + self.clicksLabel.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) + self.stepLabel = QLabel("Long-Running Step: 0") + self.stepLabel.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) + self.countBtn = QPushButton("Click me!", self) + self.countBtn.clicked.connect(self.countClicks) + self.longRunningBtn = QPushButton("Long-Running Task!", self) + self.longRunningBtn.clicked.connect(self.runLongTask) + # Set the layout + layout = QVBoxLayout() + layout.addWidget(self.clicksLabel) + layout.addWidget(self.countBtn) + layout.addStretch() + layout.addWidget(self.stepLabel) + layout.addWidget(self.longRunningBtn) + self.centralWidget.setLayout(layout) + + def countClicks(self): + self.clicksCount += 1 + self.clicksLabel.setText(f"Counting: {self.clicksCount} clicks") + + def reportProgress(self, n): + self.stepLabel.setText(f"Long-Running Step: {n}") + + # def runLongTask(self): + # """Long-running task in 5 steps.""" + # for i in range(5): + # sleep(1) + # self.reportProgress(i + 1) + + def runLongTask(self): + # Step 2: Create a QThread object + self.thread = QThread() + # Step 3: Create a worker object + self.worker = Worker() + # Step 4: Move worker to the thread + self.worker.moveToThread(self.thread) + # Step 5: Connect signals and slots + self.thread.started.connect(self.worker.run) + self.worker.finished.connect(self.thread.quit) + self.worker.finished.connect(self.worker.deleteLater) + self.thread.finished.connect(self.thread.deleteLater) + self.worker.progress.connect(self.reportProgress) + # Step 6: Start the thread + self.thread.start() + + # Final resets + self.longRunningBtn.setEnabled(False) + self.thread.finished.connect( + lambda: self.longRunningBtn.setEnabled(True) + ) + self.thread.finished.connect( + lambda: self.stepLabel.setText("Long-Running Step: 0") + ) + +app = QApplication(sys.argv) +win = Window() +win.show() +sys.exit(app.exec()) \ No newline at end of file diff --git a/some_thoughts_20230822_new/test_largest_poly/1.py b/some_thoughts_20230822_new/test_largest_poly/1.py new file mode 100644 index 0000000..5fd0842 --- /dev/null +++ b/some_thoughts_20230822_new/test_largest_poly/1.py @@ -0,0 +1,4 @@ +from amworkflow.api import amWorkflow as aw + +imp = aw.tool.read_stl("/home/yhe/Documents/new_am2/amworkflow/examples/param_prism/terrain.stl") + diff --git a/some_thoughts_20230822_new/test_largest_poly/test_split.stl b/some_thoughts_20230822_new/test_largest_poly/test_split.stl new file mode 100644 index 0000000..e2fcaa6 Binary files /dev/null and b/some_thoughts_20230822_new/test_largest_poly/test_split.stl differ diff --git a/some_thoughts_20230822_new/test_new_idea/try1.py b/some_thoughts_20230822_new/test_new_idea/try1.py new file mode 100644 index 0000000..6ae06a7 --- /dev/null +++ b/some_thoughts_20230822_new/test_new_idea/try1.py @@ -0,0 +1,10 @@ +import numpy as np +def convert_central_line_to_wall(pts: np.ndarray): + # create two sides. + pts_lft = [] + pts_rgt = [] + loop_whole = np.array(pts_lft+pts_rgt) + vectors = np.hstack((loop_whole, np.zeros((loop_whole.shape[0], 1)))) + + for i,pt in loop_whole: + \ No newline at end of file diff --git a/some_thoughts_20230822_new/try_new_thought/sucess_new_scheme.stl b/some_thoughts_20230822_new/try_new_thought/sucess_new_scheme.stl new file mode 100644 index 0000000..ad5ffc0 Binary files /dev/null and b/some_thoughts_20230822_new/try_new_thought/sucess_new_scheme.stl differ diff --git a/some_thoughts_20230822_new/try_new_thought/sucess_new_scheme2.stl b/some_thoughts_20230822_new/try_new_thought/sucess_new_scheme2.stl new file mode 100644 index 0000000..7215a07 Binary files /dev/null and b/some_thoughts_20230822_new/try_new_thought/sucess_new_scheme2.stl differ diff --git a/some_thoughts_20230822_new/try_new_thought/sucess_new_scheme3.stl b/some_thoughts_20230822_new/try_new_thought/sucess_new_scheme3.stl new file mode 100644 index 0000000..d27956f Binary files /dev/null and b/some_thoughts_20230822_new/try_new_thought/sucess_new_scheme3.stl differ diff --git a/some_thoughts_20230822_new/try_new_thought/trail_3.py b/some_thoughts_20230822_new/try_new_thought/trail_3.py index 2c10c21..1e2fb48 100644 --- a/some_thoughts_20230822_new/try_new_thought/trail_3.py +++ b/some_thoughts_20230822_new/try_new_thought/trail_3.py @@ -44,21 +44,6 @@ pmfo = np.vstack((pmf, pout_nd)) wall = CreateWallByPointsUpdate(pmfo, th, height) -# print(wall.pnts.init_pts_sequence) -# print(wall.pnts.modify_edge_list) -# print(wall.side_coords) -# print(wall.pnts.pts_index) -# print(wall.pnts.pts_digraph) -# G = nx.from_dict_of_lists(wall.pnts.pts_digraph, create_using=nx.DiGraph) -# loops = list(nx.simple_cycles(G)) - -# print("Loops in the MultiDiGraph:") -# for loop in loops: -# print(loop) - - -# plot_digraph(wall.pnts.pts_digraph) -# wall.visualize() -# print(wall.loops) -# wall.visualize_graph() -wall.visualize() \ No newline at end of file +poly = wall.Shape() +wall.visualize() +aw.tool.write_stl(poly, "sucess_new_scheme",store_dir="/home/yhe/Documents/new_am2/amworkflow/some_thoughts_20230822_new/try_new_thought") diff --git a/some_thoughts_20230822_new/try_new_thought/trail_4.py b/some_thoughts_20230822_new/try_new_thought/trail_4.py index b0df52c..ac7b5d1 100644 --- a/some_thoughts_20230822_new/try_new_thought/trail_4.py +++ b/some_thoughts_20230822_new/try_new_thought/trail_4.py @@ -5,6 +5,8 @@ import os import pandas as pd import numpy as np +import time +from amworkflow.src.utils.meter import timer name = 'print110823' root = pathlib.Path(__file__).parent @@ -12,12 +14,16 @@ data['z'] = np.zeros(len(data)) # add z coordinate # print(data) pmfo = np.array(data[['x','y','z']]) -print(pmfo) +print(pmfo.shape) # print(len(pmfo)) # # only for outer line # print(pmfo[0:90]) g = aw.geom -wall = CreateWallByPointsUpdate(pmfo, 8, 12) +wall = CreateWallByPointsUpdate(pmfo, 50, 12, is_close=False) # print(wall.loops) # wall.visualize_graph() -wall.visualize(display_polygon=False) +wall.visualize(display_polygon=True) +poly = wall.Shape() +wall.visualize() +aw.tool.write_stl(poly, "sucess_new_scheme2",store_dir="/home/yhe/Documents/new_am2/amworkflow/some_thoughts_20230822_new/try_new_thought") + diff --git a/some_thoughts_20230822_new/try_new_thought/trail_5.py b/some_thoughts_20230822_new/try_new_thought/trail_5.py index 6031d97..13f916f 100644 --- a/some_thoughts_20230822_new/try_new_thought/trail_5.py +++ b/some_thoughts_20230822_new/try_new_thought/trail_5.py @@ -4,6 +4,8 @@ points = [[],[0,2],[2,4],[5,4],[8,4],[8,6],[3,6],[3,1]] wall = CreateWallByPointsUpdate(points,1,2) -print(wall.loops) # wall.visualize_graph() +poly = wall.Shape() + +aw.tool.write_stl(poly, "sucess_new_scheme3",store_dir="/home/yhe/Documents/new_am2/amworkflow/some_thoughts_20230822_new/try_new_thought") wall.visualize() \ No newline at end of file diff --git a/some_thoughts_20230822_new/try_new_thought/visulize_intersect.py b/some_thoughts_20230822_new/try_new_thought/visulize_intersect.py new file mode 100644 index 0000000..d40cc3e --- /dev/null +++ b/some_thoughts_20230822_new/try_new_thought/visulize_intersect.py @@ -0,0 +1,5 @@ +from amworkflow.src.utils.visualizer import plot_intersect +from amworkflow.src.geometries.simple_geometry import random_line_gen +lin1 = random_line_gen(0,10,0,10) +lin2 = random_line_gen(0,10,0,10) +plot_intersect(0,6,5,5,0,6,1900,1900) \ No newline at end of file