Last active
December 28, 2025 15:55
-
-
Save stephensmitchell/bcdb0f8528b6ea0c61cfb134b8b7dc14 to your computer and use it in GitHub Desktop.
Area Moments 2D Sketch - https://www.alibre.com/forum/index.php?threads/area-moments-2d-sketch.26377/page-2#post-182152
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
| # created with Alibre Script Genie by Stephen S. Mitchell, https://github.com/stephensmitchell | |
| from __future__ import division | |
| import sys | |
| import math | |
| from AlibreScript import * | |
| ScriptName = "Batch Area Moments" | |
| ScriptVersion = "1.0" | |
| DIALOG_WIDTH = 400 | |
| CURVE_SEGMENTS = 144 | |
| VERTEX_TOLERANCE = 1e-6 | |
| CIRCUMFERENCE_TOLERANCE = 0.02 | |
| ARC_LENGTH_TOLERANCE = 0.05 | |
| CURVATURE_THRESHOLD = 1.05 | |
| def vec_subtract(a, b): | |
| return [a[0]-b[0], a[1]-b[1], a[2]-b[2]] | |
| def vec_add(a, b): | |
| return [a[0]+b[0], a[1]+b[1], a[2]+b[2]] | |
| def vec_scale(v, s): | |
| return [v[0]*s, v[1]*s, v[2]*s] | |
| def vec_cross(a, b): | |
| return [a[1]*b[2]-a[2]*b[1], a[2]*b[0]-a[0]*b[2], a[0]*b[1]-a[1]*b[0]] | |
| def vec_dot(a, b): | |
| return a[0]*b[0] + a[1]*b[1] + a[2]*b[2] | |
| def vec_length(v): | |
| return math.sqrt(v[0]**2 + v[1]**2 + v[2]**2) | |
| def vec_normalize(v): | |
| L = vec_length(v) | |
| if L < 1e-12: | |
| return [0.0, 0.0, 0.0] | |
| return [v[0]/L, v[1]/L, v[2]/L] | |
| def vec_distance(a, b): | |
| return math.sqrt((b[0]-a[0])**2 + (b[1]-a[1])**2 + (b[2]-a[2])**2) | |
| def vec_midpoint(a, b): | |
| return [(a[0]+b[0])/2.0, (a[1]+b[1])/2.0, (a[2]+b[2])/2.0] | |
| def vec_lerp(a, b, t): | |
| return [a[0] + t*(b[0]-a[0]), a[1] + t*(b[1]-a[1]), a[2] + t*(b[2]-a[2])] | |
| def safe_sqrt(val): | |
| if val < 0: | |
| return 0.0 | |
| return math.sqrt(val) | |
| def safe_div(num, denom, default=float('inf')): | |
| if abs(denom) < 1e-12: | |
| return default | |
| return num / denom | |
| class CircleProperties: | |
| def __init__(self, radius, center_x=0.0, center_y=0.0): | |
| self.shape_type = "Circle" | |
| self.radius = abs(radius) | |
| self.n = 0 | |
| r = self.radius | |
| A = math.pi * r * r | |
| I = math.pi * r**4 / 4.0 | |
| self.area = A | |
| self.centroid_x = center_x | |
| self.centroid_y = center_y | |
| self.Ix_centroid = I | |
| self.Iy_centroid = I | |
| self.Ixy_centroid = 0.0 | |
| self.J_centroid = 2.0 * I | |
| self.Ix_origin = I + A * center_y**2 | |
| self.Iy_origin = I + A * center_x**2 | |
| self.Ixy_origin = A * center_x * center_y | |
| self.I_max = I | |
| self.I_min = I | |
| self.theta_principal = 0.0 | |
| self.theta_principal_deg = 0.0 | |
| self.rx = r / 2.0 | |
| self.ry = r / 2.0 | |
| self.rp = r / math.sqrt(2.0) | |
| self.c_top = r | |
| self.c_bottom = r | |
| self.c_right = r | |
| self.c_left = r | |
| S = safe_div(I, r, 0.0) | |
| self.Sx_top = S | |
| self.Sx_bottom = S | |
| self.Sy_right = S | |
| self.Sy_left = S | |
| self.Sx_min = S | |
| self.Sy_min = S | |
| class AnnulusProperties: | |
| def __init__(self, outer_radius, inner_radius, center_x=0.0, center_y=0.0): | |
| self.shape_type = "Annulus" | |
| R = abs(outer_radius) | |
| r = abs(inner_radius) | |
| if R < r: | |
| R, r = r, R | |
| self.outer_radius = R | |
| self.inner_radius = r | |
| self.n = 0 | |
| A = math.pi * (R**2 - r**2) | |
| I = math.pi * (R**4 - r**4) / 4.0 | |
| self.area = A | |
| self.centroid_x = center_x | |
| self.centroid_y = center_y | |
| self.Ix_centroid = I | |
| self.Iy_centroid = I | |
| self.Ixy_centroid = 0.0 | |
| self.J_centroid = 2.0 * I | |
| self.Ix_origin = I + A * center_y**2 | |
| self.Iy_origin = I + A * center_x**2 | |
| self.Ixy_origin = A * center_x * center_y | |
| self.I_max = I | |
| self.I_min = I | |
| self.theta_principal = 0.0 | |
| self.theta_principal_deg = 0.0 | |
| self.rx = safe_sqrt(safe_div(I, A, 0.0)) | |
| self.ry = safe_sqrt(safe_div(I, A, 0.0)) | |
| self.rp = safe_sqrt(safe_div(2.0 * I, A, 0.0)) | |
| self.c_top = R | |
| self.c_bottom = R | |
| self.c_right = R | |
| self.c_left = R | |
| S = safe_div(I, R, 0.0) | |
| self.Sx_top = S | |
| self.Sx_bottom = S | |
| self.Sy_right = S | |
| self.Sy_left = S | |
| self.Sx_min = S | |
| self.Sy_min = S | |
| class RectangleProperties: | |
| def __init__(self, width, height, center_x=0.0, center_y=0.0, rotation=0.0): | |
| self.shape_type = "Rectangle" | |
| self.width = abs(width) | |
| self.height = abs(height) | |
| self.rotation = rotation | |
| self.n = 4 | |
| b = self.width | |
| h = self.height | |
| A = b * h | |
| Ix_local = b * h**3 / 12.0 | |
| Iy_local = b**3 * h / 12.0 | |
| self.area = A | |
| self.centroid_x = center_x | |
| self.centroid_y = center_y | |
| cos2 = math.cos(2.0 * rotation) | |
| sin2 = math.sin(2.0 * rotation) | |
| I_avg = (Ix_local + Iy_local) / 2.0 | |
| I_diff = (Ix_local - Iy_local) / 2.0 | |
| self.Ix_centroid = I_avg + I_diff * cos2 | |
| self.Iy_centroid = I_avg - I_diff * cos2 | |
| self.Ixy_centroid = -I_diff * sin2 | |
| self.J_centroid = Ix_local + Iy_local | |
| self.Ix_origin = self.Ix_centroid + A * center_y**2 | |
| self.Iy_origin = self.Iy_centroid + A * center_x**2 | |
| self.Ixy_origin = self.Ixy_centroid + A * center_x * center_y | |
| self.I_max = max(Ix_local, Iy_local) | |
| self.I_min = min(Ix_local, Iy_local) | |
| self.theta_principal = rotation if Ix_local >= Iy_local else rotation + math.pi/2.0 | |
| self.theta_principal_deg = math.degrees(self.theta_principal) | |
| self.rx = safe_sqrt(safe_div(self.Ix_centroid, A, 0.0)) | |
| self.ry = safe_sqrt(safe_div(self.Iy_centroid, A, 0.0)) | |
| self.rp = safe_sqrt(safe_div(self.J_centroid, A, 0.0)) | |
| cos_r = abs(math.cos(rotation)) | |
| sin_r = abs(math.sin(rotation)) | |
| self.c_top = (h * cos_r + b * sin_r) / 2.0 | |
| self.c_bottom = self.c_top | |
| self.c_right = (b * cos_r + h * sin_r) / 2.0 | |
| self.c_left = self.c_right | |
| self.Sx_top = safe_div(self.Ix_centroid, self.c_top) | |
| self.Sx_bottom = self.Sx_top | |
| self.Sy_right = safe_div(self.Iy_centroid, self.c_right) | |
| self.Sy_left = self.Sy_right | |
| self.Sx_min = self.Sx_top | |
| self.Sy_min = self.Sy_right | |
| class SemicircleProperties: | |
| def __init__(self, radius, center_x=0.0, center_y=0.0, rotation=0.0): | |
| self.shape_type = "Semicircle" | |
| self.radius = abs(radius) | |
| self.rotation = rotation | |
| self.n = 0 | |
| r = self.radius | |
| A = math.pi * r**2 / 2.0 | |
| y_bar = 4.0 * r / (3.0 * math.pi) | |
| Ix_local = (math.pi/8.0 - 8.0/(9.0*math.pi)) * r**4 | |
| Iy_local = math.pi * r**4 / 8.0 | |
| self.area = A | |
| cos_r = math.cos(rotation) | |
| sin_r = math.sin(rotation) | |
| self.centroid_x = center_x + y_bar * sin_r | |
| self.centroid_y = center_y + y_bar * cos_r | |
| cos2 = math.cos(2.0 * rotation) | |
| sin2 = math.sin(2.0 * rotation) | |
| I_avg = (Ix_local + Iy_local) / 2.0 | |
| I_diff = (Ix_local - Iy_local) / 2.0 | |
| self.Ix_centroid = I_avg + I_diff * cos2 | |
| self.Iy_centroid = I_avg - I_diff * cos2 | |
| self.Ixy_centroid = -I_diff * sin2 | |
| self.J_centroid = Ix_local + Iy_local | |
| self.Ix_origin = self.Ix_centroid + A * self.centroid_y**2 | |
| self.Iy_origin = self.Iy_centroid + A * self.centroid_x**2 | |
| self.Ixy_origin = self.Ixy_centroid + A * self.centroid_x * self.centroid_y | |
| self.I_max = max(Ix_local, Iy_local) | |
| self.I_min = min(Ix_local, Iy_local) | |
| self.theta_principal = rotation | |
| self.theta_principal_deg = math.degrees(rotation) | |
| self.rx = safe_sqrt(safe_div(self.Ix_centroid, A, 0.0)) | |
| self.ry = safe_sqrt(safe_div(self.Iy_centroid, A, 0.0)) | |
| self.rp = safe_sqrt(safe_div(self.J_centroid, A, 0.0)) | |
| self.c_top = r - y_bar | |
| self.c_bottom = y_bar | |
| self.c_right = r | |
| self.c_left = r | |
| self.Sx_top = safe_div(self.Ix_centroid, self.c_top) | |
| self.Sx_bottom = safe_div(self.Ix_centroid, self.c_bottom) | |
| self.Sy_right = safe_div(self.Iy_centroid, self.c_right) | |
| self.Sy_left = safe_div(self.Iy_centroid, self.c_left) | |
| self.Sx_min = min(self.Sx_top, self.Sx_bottom) | |
| self.Sy_min = min(self.Sy_right, self.Sy_left) | |
| class PolygonProperties: | |
| def __init__(self, vertices_2d, shape_name="Polygon"): | |
| self.shape_type = shape_name | |
| self.vertices = vertices_2d | |
| self.n = len(vertices_2d) | |
| if self.n < 3: | |
| raise ValueError("Polygon must have at least 3 vertices") | |
| self._compute_all() | |
| def _compute_all(self): | |
| verts = self.vertices | |
| n = self.n | |
| signed_area = 0.0 | |
| for i in range(n): | |
| j = (i + 1) % n | |
| signed_area += verts[i][0] * verts[j][1] | |
| signed_area -= verts[j][0] * verts[i][1] | |
| signed_area *= 0.5 | |
| self.area = abs(signed_area) | |
| if self.area < 1e-12: | |
| raise ValueError("Polygon has zero or negligible area") | |
| cx, cy = 0.0, 0.0 | |
| for i in range(n): | |
| j = (i + 1) % n | |
| cross = verts[i][0] * verts[j][1] - verts[j][0] * verts[i][1] | |
| cx += (verts[i][0] + verts[j][0]) * cross | |
| cy += (verts[i][1] + verts[j][1]) * cross | |
| factor = 1.0 / (6.0 * signed_area) if abs(signed_area) > 1e-12 else 0.0 | |
| self.centroid_x = cx * factor | |
| self.centroid_y = cy * factor | |
| Ix, Iy, Ixy = 0.0, 0.0, 0.0 | |
| for i in range(n): | |
| j = (i + 1) % n | |
| x0, y0 = verts[i] | |
| x1, y1 = verts[j] | |
| cross = x0 * y1 - x1 * y0 | |
| Ix += (y0*y0 + y0*y1 + y1*y1) * cross | |
| Iy += (x0*x0 + x0*x1 + x1*x1) * cross | |
| Ixy += (x0*y1 + 2.0*x0*y0 + 2.0*x1*y1 + x1*y0) * cross | |
| self.Ix_origin = abs(Ix / 12.0) | |
| self.Iy_origin = abs(Iy / 12.0) | |
| self.Ixy_origin = Ixy / 24.0 if signed_area > 0 else -Ixy / 24.0 | |
| A = self.area | |
| self.Ix_centroid = abs(self.Ix_origin - A * self.centroid_y**2) | |
| self.Iy_centroid = abs(self.Iy_origin - A * self.centroid_x**2) | |
| self.Ixy_centroid = self.Ixy_origin - A * self.centroid_x * self.centroid_y | |
| self.J_centroid = self.Ix_centroid + self.Iy_centroid | |
| Ix_c, Iy_c, Ixy_c = self.Ix_centroid, self.Iy_centroid, self.Ixy_centroid | |
| I_avg = (Ix_c + Iy_c) / 2.0 | |
| I_diff = (Ix_c - Iy_c) / 2.0 | |
| R = safe_sqrt(I_diff**2 + Ixy_c**2) | |
| self.I_max = I_avg + R | |
| self.I_min = max(0.0, I_avg - R) | |
| if abs(Ixy_c) < 1e-12 and abs(I_diff) < 1e-12: | |
| self.theta_principal = 0.0 | |
| else: | |
| self.theta_principal = 0.5 * math.atan2(-2.0 * Ixy_c, Ix_c - Iy_c) | |
| self.theta_principal_deg = math.degrees(self.theta_principal) | |
| self.rx = safe_sqrt(safe_div(self.Ix_centroid, A, 0.0)) | |
| self.ry = safe_sqrt(safe_div(self.Iy_centroid, A, 0.0)) | |
| self.rp = safe_sqrt(safe_div(self.J_centroid, A, 0.0)) | |
| x_rel = [v[0] - self.centroid_x for v in verts] | |
| y_rel = [v[1] - self.centroid_y for v in verts] | |
| self.c_top = max(y_rel) if y_rel else 0.0 | |
| self.c_bottom = abs(min(y_rel)) if y_rel else 0.0 | |
| self.c_right = max(x_rel) if x_rel else 0.0 | |
| self.c_left = abs(min(x_rel)) if x_rel else 0.0 | |
| self.Sx_top = safe_div(self.Ix_centroid, self.c_top) | |
| self.Sx_bottom = safe_div(self.Ix_centroid, self.c_bottom) | |
| self.Sy_right = safe_div(self.Iy_centroid, self.c_right) | |
| self.Sy_left = safe_div(self.Iy_centroid, self.c_left) | |
| self.Sx_min = min(self.Sx_top, self.Sx_bottom) | |
| self.Sy_min = min(self.Sy_right, self.Sy_left) | |
| class PolygonWithCircularHoleProperties: | |
| def __init__(self, outer_vertices_2d, hole_radius, hole_center_x=None, hole_center_y=None, shape_name="Polygon with Hole"): | |
| self.shape_type = shape_name | |
| outer = PolygonProperties(outer_vertices_2d, "outer") | |
| if hole_center_x is None: | |
| hole_center_x = outer.centroid_x | |
| if hole_center_y is None: | |
| hole_center_y = outer.centroid_y | |
| r = abs(hole_radius) | |
| hole_area = math.pi * r * r | |
| hole_Ic = math.pi * r**4 / 4.0 | |
| dx = hole_center_x - outer.centroid_x | |
| dy = hole_center_y - outer.centroid_y | |
| hole_Ix_at_centroid = hole_Ic + hole_area * dy**2 | |
| hole_Iy_at_centroid = hole_Ic + hole_area * dx**2 | |
| hole_Ixy_at_centroid = hole_area * dx * dy | |
| self.n = outer.n | |
| self.area = outer.area - hole_area | |
| if self.area < 1e-12: | |
| raise ValueError("Hole area exceeds outer polygon area") | |
| self.centroid_x = outer.centroid_x | |
| self.centroid_y = outer.centroid_y | |
| self.Ix_centroid = outer.Ix_centroid - hole_Ix_at_centroid | |
| self.Iy_centroid = outer.Iy_centroid - hole_Iy_at_centroid | |
| self.Ixy_centroid = outer.Ixy_centroid - hole_Ixy_at_centroid | |
| self.J_centroid = self.Ix_centroid + self.Iy_centroid | |
| self.Ix_origin = outer.Ix_origin - (hole_Ic + hole_area * hole_center_y**2) | |
| self.Iy_origin = outer.Iy_origin - (hole_Ic + hole_area * hole_center_x**2) | |
| self.Ixy_origin = outer.Ixy_origin - hole_area * hole_center_x * hole_center_y | |
| Ix_c, Iy_c, Ixy_c = self.Ix_centroid, self.Iy_centroid, self.Ixy_centroid | |
| I_avg = (Ix_c + Iy_c) / 2.0 | |
| I_diff = (Ix_c - Iy_c) / 2.0 | |
| R = safe_sqrt(I_diff**2 + Ixy_c**2) | |
| self.I_max = I_avg + R | |
| self.I_min = max(0.0, I_avg - R) | |
| if abs(Ixy_c) < 1e-12 and abs(I_diff) < 1e-12: | |
| self.theta_principal = 0.0 | |
| else: | |
| self.theta_principal = 0.5 * math.atan2(-2.0 * Ixy_c, Ix_c - Iy_c) | |
| self.theta_principal_deg = math.degrees(self.theta_principal) | |
| self.rx = safe_sqrt(safe_div(self.Ix_centroid, self.area, 0.0)) | |
| self.ry = safe_sqrt(safe_div(self.Iy_centroid, self.area, 0.0)) | |
| self.rp = safe_sqrt(safe_div(self.J_centroid, self.area, 0.0)) | |
| self.c_top = outer.c_top | |
| self.c_bottom = outer.c_bottom | |
| self.c_right = outer.c_right | |
| self.c_left = outer.c_left | |
| self.Sx_top = safe_div(self.Ix_centroid, self.c_top) | |
| self.Sx_bottom = safe_div(self.Ix_centroid, self.c_bottom) | |
| self.Sy_right = safe_div(self.Iy_centroid, self.c_right) | |
| self.Sy_left = safe_div(self.Iy_centroid, self.c_left) | |
| self.Sx_min = min(self.Sx_top, self.Sx_bottom) | |
| self.Sy_min = min(self.Sy_right, self.Sy_left) | |
| self.outer_area = outer.area | |
| self.hole_radius = r | |
| self.hole_area = hole_area | |
| x_coords = [v[0] for v in outer_vertices_2d] | |
| y_coords = [v[1] for v in outer_vertices_2d] | |
| self.outer_width = max(x_coords) - min(x_coords) | |
| self.outer_height = max(y_coords) - min(y_coords) | |
| class EdgeInfo: | |
| def __init__(self, edge, index): | |
| self.edge = edge | |
| self.index = index | |
| self.diameter = None | |
| self.length = None | |
| self.vertices = [] | |
| self.vertex_count = 0 | |
| self.is_circular = False | |
| self.is_closed = False | |
| self.is_full_circle = False | |
| self.is_curved = False | |
| self.chord_length = 0.0 | |
| self._analyze() | |
| def _analyze(self): | |
| try: | |
| d = self.edge.Diameter | |
| if d is not None and d > 0: | |
| self.diameter = d | |
| self.is_circular = True | |
| except Exception: | |
| pass | |
| try: | |
| self.length = self.edge.Length | |
| except Exception: | |
| pass | |
| try: | |
| verts = self.edge.GetVertices() | |
| if verts: | |
| self.vertex_count = len(verts) | |
| for v in verts: | |
| self.vertices.append([v.X, v.Y, v.Z]) | |
| except Exception: | |
| pass | |
| self.is_closed = (self.vertex_count == 0) | |
| if self.is_circular and self.diameter: | |
| if self.is_closed: | |
| self.is_full_circle = True | |
| elif not self.length or self.length < 1e-9: | |
| self.is_full_circle = True | |
| elif self.length > 0: | |
| expected_circumference = math.pi * self.diameter | |
| if abs(self.length - expected_circumference) < expected_circumference * CIRCUMFERENCE_TOLERANCE: | |
| self.is_full_circle = True | |
| if self.vertex_count >= 2: | |
| self.chord_length = vec_distance(self.vertices[0], self.vertices[1]) | |
| if self.length and self.chord_length > 1e-12: | |
| ratio = self.length / self.chord_length | |
| if ratio > CURVATURE_THRESHOLD: | |
| self.is_curved = True | |
| def is_complete_circle(edge_info): | |
| return edge_info.is_closed or edge_info.is_full_circle | |
| def collect_unique_vertices(edges, tolerance=VERTEX_TOLERANCE): | |
| all_verts = [] | |
| for e in edges: | |
| for v in e.vertices: | |
| is_dup = False | |
| for existing in all_verts: | |
| if vec_distance(v, existing) < tolerance: | |
| is_dup = True | |
| break | |
| if not is_dup: | |
| all_verts.append(v) | |
| return all_verts | |
| def analyze_face_geometry(face, num_segments=CURVE_SEGMENTS): | |
| alibre_area = None | |
| try: | |
| alibre_area = face.GetArea() | |
| if alibre_area == 0: | |
| alibre_area = None | |
| except Exception: | |
| pass | |
| edges = [] | |
| try: | |
| edges = face.GetEdges() or [] | |
| except Exception: | |
| pass | |
| face_vertices = [] | |
| try: | |
| face_vertices = face.GetVertices() or [] | |
| except Exception: | |
| pass | |
| is_rect = False | |
| try: | |
| is_rect = face.IsRectangle() | |
| except Exception: | |
| pass | |
| edge_infos = [EdgeInfo(e, i) for i, e in enumerate(edges)] | |
| circular_edges = [e for e in edge_infos if e.is_circular] | |
| curved_edges = [e for e in edge_infos if e.is_curved and not e.is_circular] | |
| linear_edges = [e for e in edge_infos if not e.is_curved and not e.is_circular and e.vertex_count >= 2] | |
| diameters = [e.diameter for e in circular_edges if e.diameter] | |
| unique_diameters = list(set([round(d, 6) for d in diameters])) | |
| if is_rect and len(linear_edges) == 4: | |
| lengths = sorted([e.length for e in linear_edges if e.length]) | |
| if len(lengths) == 4: | |
| width = (lengths[0] + lengths[1]) / 2.0 | |
| height = (lengths[2] + lengths[3]) / 2.0 | |
| return ("rectangle", RectangleProperties(width, height), alibre_area) | |
| if len(circular_edges) == 1 and is_complete_circle(circular_edges[0]) and len(linear_edges) == 0: | |
| radius = circular_edges[0].diameter / 2.0 | |
| return ("circle", CircleProperties(radius), alibre_area) | |
| if len(circular_edges) == 2 and all(is_complete_circle(e) for e in circular_edges): | |
| r1 = circular_edges[0].diameter / 2.0 | |
| r2 = circular_edges[1].diameter / 2.0 | |
| outer_r, inner_r = max(r1, r2), min(r1, r2) | |
| if outer_r - inner_r < 0.001: | |
| return ("circle", CircleProperties(outer_r), alibre_area) | |
| return ("annulus", AnnulusProperties(outer_r, inner_r), alibre_area) | |
| if len(unique_diameters) == 1 and len(circular_edges) >= 1 and len(linear_edges) == 0: | |
| radius = unique_diameters[0] / 2.0 | |
| total_arc = sum(e.length for e in circular_edges if e.length) | |
| expected_circumference = math.pi * unique_diameters[0] | |
| if abs(total_arc - expected_circumference) < expected_circumference * 0.02: | |
| return ("circle", CircleProperties(radius), alibre_area) | |
| if len(unique_diameters) == 2: | |
| r1, r2 = max(unique_diameters) / 2.0, min(unique_diameters) / 2.0 | |
| if r1 - r2 < 0.001: | |
| return ("circle", CircleProperties(r1), alibre_area) | |
| return ("annulus", AnnulusProperties(r1, r2), alibre_area) | |
| if len(circular_edges) == 1 and len(linear_edges) == 1: | |
| arc_edge = circular_edges[0] | |
| if arc_edge.diameter and arc_edge.length: | |
| expected_semicircle = math.pi * arc_edge.diameter / 2.0 | |
| if abs(arc_edge.length - expected_semicircle) < expected_semicircle * ARC_LENGTH_TOLERANCE: | |
| radius = arc_edge.diameter / 2.0 | |
| return ("semicircle", SemicircleProperties(radius), alibre_area) | |
| if len(linear_edges) >= 3 and len(circular_edges) == 1 and is_complete_circle(circular_edges[0]): | |
| hole_edge = circular_edges[0] | |
| if hole_edge.diameter: | |
| hole_radius = hole_edge.diameter / 2.0 | |
| outer_verts = collect_unique_vertices(linear_edges) | |
| if len(outer_verts) >= 3: | |
| outer_2d = project_to_2d(outer_verts) | |
| shape_name = "Polygon (%d sides) with Hole" % len(linear_edges) | |
| return ("polygon_with_hole", PolygonWithCircularHoleProperties(outer_2d, hole_radius, shape_name=shape_name), alibre_area) | |
| if len(linear_edges) == 3 and len(circular_edges) == 0: | |
| all_verts = collect_unique_vertices(linear_edges) | |
| if len(all_verts) == 3: | |
| points_2d = project_to_2d(all_verts) | |
| return ("triangle", PolygonProperties(points_2d, "Triangle"), alibre_area) | |
| if len(linear_edges) >= 3 and len(circular_edges) == 0 and len(curved_edges) == 0: | |
| all_verts = collect_unique_vertices(linear_edges) | |
| if len(all_verts) >= 3: | |
| points_2d = project_to_2d(all_verts) | |
| return ("polygon", PolygonProperties(points_2d, "Polygon (%d sides)" % len(linear_edges)), alibre_area) | |
| if len(curved_edges) > 0 or (len(circular_edges) > 0 and not all(is_complete_circle(e) for e in circular_edges)): | |
| boundary_points = discretize_face_boundary(edge_infos, num_segments) | |
| if len(boundary_points) >= 3: | |
| points_2d = project_to_2d(boundary_points) | |
| return ("freeform", PolygonProperties(points_2d, "Freeform (%d pts)" % len(points_2d)), alibre_area) | |
| boundary_points = [] | |
| for v in face_vertices: | |
| try: | |
| pt = [v.X, v.Y, v.Z] | |
| is_dup = any(vec_distance(pt, ex) < VERTEX_TOLERANCE for ex in boundary_points) | |
| if not is_dup: | |
| boundary_points.append(pt) | |
| except Exception: | |
| pass | |
| if len(boundary_points) >= 3: | |
| points_2d = project_to_2d(boundary_points) | |
| return ("polygon", PolygonProperties(points_2d, "Polygon (from vertices)"), alibre_area) | |
| if alibre_area and alibre_area > 0: | |
| radius = math.sqrt(alibre_area / math.pi) | |
| props = CircleProperties(radius) | |
| props.shape_type = "Equivalent Circle (from area)" | |
| return ("equivalent_circle", props, alibre_area) | |
| return ("unknown", None, alibre_area) | |
| def discretize_face_boundary(edge_infos, num_segments): | |
| boundary_points = [] | |
| ordered_edges = order_edges_by_connectivity(edge_infos) | |
| for edge_info in ordered_edges: | |
| if is_complete_circle(edge_info) and edge_info.diameter: | |
| radius = edge_info.diameter / 2.0 | |
| center = estimate_circle_center(edge_info) | |
| for i in range(num_segments): | |
| angle = 2.0 * math.pi * i / num_segments | |
| pt = [center[0] + radius * math.cos(angle), center[1] + radius * math.sin(angle), center[2]] | |
| boundary_points.append(pt) | |
| elif edge_info.is_curved or edge_info.is_circular: | |
| pts = discretize_curved_edge(edge_info, max(8, num_segments // 4)) | |
| for pt in pts: | |
| is_dup = any(vec_distance(pt, ex) < VERTEX_TOLERANCE for ex in boundary_points) | |
| if not is_dup: | |
| boundary_points.append(pt) | |
| else: | |
| for v in edge_info.vertices: | |
| is_dup = any(vec_distance(v, ex) < VERTEX_TOLERANCE for ex in boundary_points) | |
| if not is_dup: | |
| boundary_points.append(v) | |
| return boundary_points | |
| def order_edges_by_connectivity(edge_infos): | |
| if not edge_infos: | |
| return [] | |
| ordered = [] | |
| remaining = list(edge_infos) | |
| ordered.append(remaining.pop(0)) | |
| while remaining: | |
| last_edge = ordered[-1] | |
| found_idx = -1 | |
| for i, edge in enumerate(remaining): | |
| if edges_share_vertex(last_edge, edge): | |
| found_idx = i | |
| break | |
| if found_idx >= 0: | |
| ordered.append(remaining.pop(found_idx)) | |
| else: | |
| ordered.append(remaining.pop(0)) | |
| return ordered | |
| def edges_share_vertex(edge1, edge2): | |
| for v1 in edge1.vertices: | |
| for v2 in edge2.vertices: | |
| if vec_distance(v1, v2) < VERTEX_TOLERANCE: | |
| return True | |
| return False | |
| def estimate_circle_center(edge_info): | |
| if edge_info.vertices: | |
| n = len(edge_info.vertices) | |
| cx = sum(v[0] for v in edge_info.vertices) / n | |
| cy = sum(v[1] for v in edge_info.vertices) / n | |
| cz = sum(v[2] for v in edge_info.vertices) / n | |
| return [cx, cy, cz] | |
| return [0.0, 0.0, 0.0] | |
| def discretize_curved_edge(edge_info, num_points): | |
| points = [] | |
| num_points = max(4, num_points) | |
| if len(edge_info.vertices) >= 2: | |
| v1, v2 = edge_info.vertices[0], edge_info.vertices[1] | |
| for i in range(num_points + 1): | |
| t = i / float(num_points) | |
| points.append(vec_lerp(v1, v2, t)) | |
| return points | |
| def project_to_2d(points_3d): | |
| n = len(points_3d) | |
| if n < 3: | |
| raise ValueError("Need at least 3 points for 2D projection") | |
| cx = sum(p[0] for p in points_3d) / n | |
| cy = sum(p[1] for p in points_3d) / n | |
| cz = sum(p[2] for p in points_3d) / n | |
| origin = [cx, cy, cz] | |
| p0 = points_3d[0] | |
| v1 = None | |
| for i in range(1, n): | |
| vec = vec_subtract(points_3d[i], p0) | |
| if vec_length(vec) > VERTEX_TOLERANCE: | |
| v1 = vec | |
| break | |
| if v1 is None: | |
| raise ValueError("All points are coincident") | |
| v2 = None | |
| for i in range(2, n): | |
| vec = vec_subtract(points_3d[i], p0) | |
| cross = vec_cross(v1, vec) | |
| if vec_length(cross) > VERTEX_TOLERANCE: | |
| v2 = vec | |
| break | |
| if v2 is None: | |
| if abs(v1[2]) < 0.9: | |
| v2 = vec_cross(v1, [0.0, 0.0, 1.0]) | |
| else: | |
| v2 = vec_cross(v1, [1.0, 0.0, 0.0]) | |
| normal = vec_normalize(vec_cross(v1, v2)) | |
| u_axis = vec_normalize(v1) | |
| v_axis = vec_cross(normal, u_axis) | |
| points_2d = [] | |
| for p3d in points_3d: | |
| rel = vec_subtract(p3d, origin) | |
| u = vec_dot(rel, u_axis) | |
| v = vec_dot(rel, v_axis) | |
| points_2d.append([u, v]) | |
| cx2 = sum(p[0] for p in points_2d) / n | |
| cy2 = sum(p[1] for p in points_2d) / n | |
| def angle_key(p): | |
| return math.atan2(p[1] - cy2, p[0] - cx2) | |
| points_2d.sort(key=angle_key) | |
| return points_2d | |
| def fmt(value, decimals=6): | |
| if value is None: | |
| return "N/A" | |
| if isinstance(value, float) and (math.isinf(value) or math.isnan(value)): | |
| return "N/A" | |
| if abs(value) < 1e-10: | |
| return "0.0" | |
| elif abs(value) >= 1e6 or (abs(value) < 0.001 and abs(value) > 1e-10): | |
| return "%.4e" % value | |
| else: | |
| return ("%%.%df" % decimals) % value | |
| UNIT_CONVERSIONS = { | |
| 'mm': 1.0, | |
| 'cm': 0.1, | |
| 'm': 0.001, | |
| 'in': 1.0 / 25.4, | |
| 'ft': 1.0 / 304.8 | |
| } | |
| def convert_value(value, power, unit): | |
| if value is None or (isinstance(value, float) and (math.isinf(value) or math.isnan(value))): | |
| return value | |
| factor = UNIT_CONVERSIONS[unit] ** power | |
| return value * factor | |
| def generate_face_section(face_name, props, alibre_area, unit): | |
| u1 = unit | |
| u2 = unit + "^2" | |
| u3 = unit + "^3" | |
| u4 = unit + "^4" | |
| p = props | |
| lines = [] | |
| lines.append(" %s (%s)" % (face_name, props.shape_type)) | |
| lines.append(" " + "-" * 40) | |
| if hasattr(props, 'radius') and not hasattr(props, 'outer_radius'): | |
| lines.append(" Radius: %s %s" % (fmt(convert_value(props.radius, 1, unit)), u1)) | |
| if hasattr(props, 'outer_radius'): | |
| lines.append(" Outer R: %s %s" % (fmt(convert_value(props.outer_radius, 1, unit)), u1)) | |
| lines.append(" Inner R: %s %s" % (fmt(convert_value(props.inner_radius, 1, unit)), u1)) | |
| if hasattr(props, 'width') and hasattr(props, 'height'): | |
| lines.append(" Width: %s %s" % (fmt(convert_value(props.width, 1, unit)), u1)) | |
| lines.append(" Height: %s %s" % (fmt(convert_value(props.height, 1, unit)), u1)) | |
| if hasattr(props, 'outer_width') and hasattr(props, 'outer_height'): | |
| lines.append(" Outer W: %s %s" % (fmt(convert_value(props.outer_width, 1, unit)), u1)) | |
| lines.append(" Outer H: %s %s" % (fmt(convert_value(props.outer_height, 1, unit)), u1)) | |
| if hasattr(props, 'hole_radius'): | |
| lines.append(" Hole R: %s %s" % (fmt(convert_value(props.hole_radius, 1, unit)), u1)) | |
| lines.append(" Area: %s %s" % (fmt(convert_value(p.area, 2, unit)), u2)) | |
| lines.append(" Ix-x: %s %s" % (fmt(convert_value(p.Ix_centroid, 4, unit)), u4)) | |
| lines.append(" Iy-y: %s %s" % (fmt(convert_value(p.Iy_centroid, 4, unit)), u4)) | |
| lines.append(" J: %s %s" % (fmt(convert_value(p.J_centroid, 4, unit)), u4)) | |
| lines.append(" rx-x: %s %s" % (fmt(convert_value(p.rx, 1, unit)), u1)) | |
| lines.append(" ry-y: %s %s" % (fmt(convert_value(p.ry, 1, unit)), u1)) | |
| lines.append(" Sx-x (min): %s %s" % (fmt(convert_value(p.Sx_min, 3, unit)), u3)) | |
| lines.append(" Sy-y (min): %s %s" % (fmt(convert_value(p.Sy_min, 3, unit)), u3)) | |
| lines.append("") | |
| return "\n".join(lines) | |
| def generate_batch_report(face_results): | |
| lines = [] | |
| lines.append("") | |
| lines.append("=" * 70) | |
| lines.append(" BATCH AREA MOMENTS REPORT") | |
| lines.append(" %s v%s" % (ScriptName, ScriptVersion)) | |
| lines.append("=" * 70) | |
| lines.append("") | |
| lines.append("Faces Analyzed: %d" % len(face_results)) | |
| lines.append("") | |
| for unit in ['mm', 'cm', 'm', 'in', 'ft']: | |
| lines.append("=" * 70) | |
| lines.append("RESULTS IN %s" % unit.upper()) | |
| lines.append("=" * 70) | |
| lines.append("") | |
| for face_name, props, alibre_area in face_results: | |
| if props is not None: | |
| lines.append(generate_face_section(face_name, props, alibre_area, unit)) | |
| lines.append("=" * 70) | |
| lines.append("END OF REPORT") | |
| lines.append("=" * 70) | |
| return "\n".join(lines) | |
| def get_all_faces(part): | |
| faces = [] | |
| try: | |
| all_faces = part.GetFaces() | |
| if all_faces: | |
| for face in all_faces: | |
| try: | |
| name = face.Name if hasattr(face, 'Name') and face.Name else None | |
| if name: | |
| faces.append((name, face)) | |
| except Exception: | |
| pass | |
| except Exception: | |
| pass | |
| faces.sort(key=lambda x: x[0]) | |
| return faces | |
| def run(): | |
| Win = Windows() | |
| try: | |
| part = CurrentPart() | |
| if part is None: | |
| Win.ErrorDialog("Please open a part before running this script.", ScriptName) | |
| return | |
| except Exception: | |
| Win.ErrorDialog("Please open a part before running this script.", ScriptName) | |
| return | |
| all_faces = get_all_faces(part) | |
| if not all_faces: | |
| Win.ErrorDialog("No named faces found in the part.\n\nFaces should be named like Face<1>, Face<2>, etc.", ScriptName) | |
| return | |
| print "=" * 70 | |
| print "BATCH AREA MOMENTS - Scanning %d faces..." % len(all_faces) | |
| print "=" * 70 | |
| face_results = [] | |
| for face_name, face in all_faces: | |
| print "Analyzing: %s" % face_name | |
| try: | |
| shape_type, props, alibre_area = analyze_face_geometry(face, CURVE_SEGMENTS) | |
| if props is not None: | |
| if shape_type not in ("polygon_with_hole", "circle", "annulus", "rectangle"): | |
| if alibre_area and alibre_area > 0 and props.area > 0: | |
| area_ratio = alibre_area / props.area | |
| if area_ratio > 1.10 or area_ratio < 0.90: | |
| print " -> Skipping (non-planar, area mismatch: %.1f%%)" % ((area_ratio - 1.0) * 100) | |
| continue | |
| face_results.append((face_name, props, alibre_area)) | |
| print " -> %s (Area: %.2f mm^2)" % (props.shape_type, props.area) | |
| else: | |
| print " -> Could not determine geometry" | |
| except Exception as ex: | |
| print " -> Error: %s" % str(ex) | |
| print "" | |
| if not face_results: | |
| Win.ErrorDialog("No faces could be analyzed.\n\nMake sure faces are planar.", ScriptName) | |
| return | |
| report = generate_batch_report(face_results) | |
| print report | |
| sys.stdout.flush() | |
| Win.InfoDialog("Batch analysis complete!\n\n%d faces analyzed.\nSee console for full report." % len(face_results), ScriptName) | |
| run() |
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
| Topology Summary: | |
| Type Total Failed | |
| ------------ ----- ------ | |
| Bodies 1 0 | |
| Faces 10 0 | |
| Edges 16 0 | |
| Vertices 12 0 | |
| Lumps 1 - | |
| Shells 1 - | |
| Loops 14 - | |
| Coedges 32 - | |
| TEdges 0 - | |
| TVertices 0 - | |
| TCoedges 0 - | |
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
| ====================================================================== | |
| BATCH AREA MOMENTS - Scanning 10 faces... | |
| ====================================================================== | |
| Analyzing: Face<10> | |
| -> Polygon (4 sides) (Area: 13664.78 mm^2) | |
| Analyzing: Face<1> | |
| -> Annulus (Area: 335.64 mm^2) | |
| Analyzing: Face<2> | |
| -> Circle (Area: 1140.09 mm^2) | |
| Analyzing: Face<3> | |
| -> Circle (Area: 804.45 mm^2) | |
| Analyzing: Face<4> | |
| -> Annulus (Area: 2026.83 mm^2) | |
| Analyzing: Face<5> | |
| -> Polygon (4 sides) with Hole (Area: 2639.52 mm^2) | |
| Analyzing: Face<6> | |
| -> Rectangle (Area: 47096.73 mm^2) | |
| Analyzing: Face<7> | |
| -> Polygon (4 sides) (Area: 13643.50 mm^2) | |
| Analyzing: Face<8> | |
| -> Polygon (4 sides) (Area: 13664.78 mm^2) | |
| Analyzing: Face<9> | |
| -> Polygon (4 sides) (Area: 13643.50 mm^2) | |
| ====================================================================== | |
| BATCH AREA MOMENTS REPORT | |
| Batch Area Moments v1.0 | |
| ====================================================================== | |
| Faces Analyzed: 10 | |
| ====================================================================== | |
| RESULTS IN MM | |
| ====================================================================== | |
| Face<10> (Polygon (4 sides)) | |
| ---------------------------------------- | |
| Area: 13664.781537 mm^2 | |
| Ix-x: 9.2139e+06 mm^4 | |
| Iy-y: 2.9826e+07 mm^4 | |
| J: 3.9040e+07 mm^4 | |
| rx-x: 25.966873 mm | |
| ry-y: 46.719223 mm | |
| Sx-x (min): 169835.357191 mm^3 | |
| Sy-y (min): 276397.051143 mm^3 | |
| Face<1> (Annulus) | |
| ---------------------------------------- | |
| Outer R: 19.050000 mm | |
| Inner R: 16.002000 mm | |
| Area: 335.643034 mm^2 | |
| Ix-x: 51937.948861 mm^4 | |
| Iy-y: 51937.948861 mm^4 | |
| J: 103875.897721 mm^4 | |
| rx-x: 12.439519 mm | |
| ry-y: 12.439519 mm | |
| Sx-x (min): 2726.401515 mm^3 | |
| Sy-y (min): 2726.401515 mm^3 | |
| Face<2> (Circle) | |
| ---------------------------------------- | |
| Radius: 19.050000 mm | |
| Area: 1140.091828 mm^2 | |
| Ix-x: 103435.543650 mm^4 | |
| Iy-y: 103435.543650 mm^4 | |
| J: 206871.087300 mm^4 | |
| rx-x: 9.525000 mm | |
| ry-y: 9.525000 mm | |
| Sx-x (min): 5429.687331 mm^3 | |
| Sy-y (min): 5429.687331 mm^3 | |
| Face<3> (Circle) | |
| ---------------------------------------- | |
| Radius: 16.002000 mm | |
| Area: 804.448794 mm^2 | |
| Ix-x: 51497.594789 mm^4 | |
| Iy-y: 51497.594789 mm^4 | |
| J: 102995.189579 mm^4 | |
| rx-x: 8.001000 mm | |
| ry-y: 8.001000 mm | |
| Sx-x (min): 3218.197400 mm^3 | |
| Sy-y (min): 3218.197400 mm^3 | |
| Face<4> (Annulus) | |
| ---------------------------------------- | |
| Outer R: 31.750000 mm | |
| Inner R: 19.050000 mm | |
| Area: 2026.829916 mm^2 | |
| Ix-x: 694678.219081 mm^4 | |
| Iy-y: 694678.219081 mm^4 | |
| J: 1.3894e+06 mm^4 | |
| rx-x: 18.513272 mm | |
| ry-y: 18.513272 mm | |
| Sx-x (min): 21879.628947 mm^3 | |
| Sy-y (min): 21879.628947 mm^3 | |
| Face<5> (Polygon (4 sides) with Hole) | |
| ---------------------------------------- | |
| Outer W: 76.200000 mm | |
| Outer H: 76.200000 mm | |
| Hole R: 31.750000 mm | |
| Area: 2639.518256 mm^2 | |
| Ix-x: 2.0114e+06 mm^4 | |
| Iy-y: 2.0114e+06 mm^4 | |
| J: 4.0229e+06 mm^4 | |
| rx-x: 27.605277 mm | |
| ry-y: 27.605277 mm | |
| Sx-x (min): 52793.920212 mm^3 | |
| Sy-y (min): 52793.920212 mm^3 | |
| Face<6> (Rectangle) | |
| ---------------------------------------- | |
| Width: 215.819414 mm | |
| Height: 218.222875 mm | |
| Area: 47096.733130 mm^2 | |
| Ix-x: 1.8690e+08 mm^4 | |
| Iy-y: 1.8281e+08 mm^4 | |
| J: 3.6971e+08 mm^4 | |
| rx-x: 62.995518 mm | |
| ry-y: 62.301698 mm | |
| Sx-x (min): 1.7129e+06 mm^3 | |
| Sy-y (min): 1.6941e+06 mm^3 | |
| Face<7> (Polygon (4 sides)) | |
| ---------------------------------------- | |
| Area: 13643.503951 mm^2 | |
| Ix-x: 9.0085e+06 mm^4 | |
| Iy-y: 3.0373e+07 mm^4 | |
| J: 3.9381e+07 mm^4 | |
| rx-x: 25.695803 mm | |
| ry-y: 47.182122 mm | |
| Sx-x (min): 167471.687718 mm^3 | |
| Sy-y (min): 278362.405971 mm^3 | |
| Face<8> (Polygon (4 sides)) | |
| ---------------------------------------- | |
| Area: 13664.781537 mm^2 | |
| Ix-x: 9.2139e+06 mm^4 | |
| Iy-y: 2.9826e+07 mm^4 | |
| J: 3.9040e+07 mm^4 | |
| rx-x: 25.966873 mm | |
| ry-y: 46.719223 mm | |
| Sx-x (min): 169835.357191 mm^3 | |
| Sy-y (min): 276397.051143 mm^3 | |
| Face<9> (Polygon (4 sides)) | |
| ---------------------------------------- | |
| Area: 13643.503951 mm^2 | |
| Ix-x: 9.0085e+06 mm^4 | |
| Iy-y: 3.0373e+07 mm^4 | |
| J: 3.9381e+07 mm^4 | |
| rx-x: 25.695803 mm | |
| ry-y: 47.182122 mm | |
| Sx-x (min): 167471.687718 mm^3 | |
| Sy-y (min): 278362.405971 mm^3 | |
| ====================================================================== | |
| RESULTS IN CM | |
| ====================================================================== | |
| Face<10> (Polygon (4 sides)) | |
| ---------------------------------------- | |
| Area: 136.647815 cm^2 | |
| Ix-x: 921.386819 cm^4 | |
| Iy-y: 2982.592485 cm^4 | |
| J: 3903.979304 cm^4 | |
| rx-x: 2.596687 cm | |
| ry-y: 4.671922 cm | |
| Sx-x (min): 169.835357 cm^3 | |
| Sy-y (min): 276.397051 cm^3 | |
| Face<1> (Annulus) | |
| ---------------------------------------- | |
| Outer R: 1.905000 cm | |
| Inner R: 1.600200 cm | |
| Area: 3.356430 cm^2 | |
| Ix-x: 5.193795 cm^4 | |
| Iy-y: 5.193795 cm^4 | |
| J: 10.387590 cm^4 | |
| rx-x: 1.243952 cm | |
| ry-y: 1.243952 cm | |
| Sx-x (min): 2.726402 cm^3 | |
| Sy-y (min): 2.726402 cm^3 | |
| Face<2> (Circle) | |
| ---------------------------------------- | |
| Radius: 1.905000 cm | |
| Area: 11.400918 cm^2 | |
| Ix-x: 10.343554 cm^4 | |
| Iy-y: 10.343554 cm^4 | |
| J: 20.687109 cm^4 | |
| rx-x: 0.952500 cm | |
| ry-y: 0.952500 cm | |
| Sx-x (min): 5.429687 cm^3 | |
| Sy-y (min): 5.429687 cm^3 | |
| Face<3> (Circle) | |
| ---------------------------------------- | |
| Radius: 1.600200 cm | |
| Area: 8.044488 cm^2 | |
| Ix-x: 5.149759 cm^4 | |
| Iy-y: 5.149759 cm^4 | |
| J: 10.299519 cm^4 | |
| rx-x: 0.800100 cm | |
| ry-y: 0.800100 cm | |
| Sx-x (min): 3.218197 cm^3 | |
| Sy-y (min): 3.218197 cm^3 | |
| Face<4> (Annulus) | |
| ---------------------------------------- | |
| Outer R: 3.175000 cm | |
| Inner R: 1.905000 cm | |
| Area: 20.268299 cm^2 | |
| Ix-x: 69.467822 cm^4 | |
| Iy-y: 69.467822 cm^4 | |
| J: 138.935644 cm^4 | |
| rx-x: 1.851327 cm | |
| ry-y: 1.851327 cm | |
| Sx-x (min): 21.879629 cm^3 | |
| Sy-y (min): 21.879629 cm^3 | |
| Face<5> (Polygon (4 sides) with Hole) | |
| ---------------------------------------- | |
| Outer W: 7.620000 cm | |
| Outer H: 7.620000 cm | |
| Hole R: 3.175000 cm | |
| Area: 26.395183 cm^2 | |
| Ix-x: 201.144836 cm^4 | |
| Iy-y: 201.144836 cm^4 | |
| J: 402.289672 cm^4 | |
| rx-x: 2.760528 cm | |
| ry-y: 2.760528 cm | |
| Sx-x (min): 52.793920 cm^3 | |
| Sy-y (min): 52.793920 cm^3 | |
| Face<6> (Rectangle) | |
| ---------------------------------------- | |
| Width: 21.581941 cm | |
| Height: 21.822288 cm | |
| Area: 470.967331 cm^2 | |
| Ix-x: 18690.033702 cm^4 | |
| Iy-y: 18280.604657 cm^4 | |
| J: 36970.638359 cm^4 | |
| rx-x: 6.299552 cm | |
| ry-y: 6.230170 cm | |
| Sx-x (min): 1712.930753 cm^3 | |
| Sy-y (min): 1694.064893 cm^3 | |
| Face<7> (Polygon (4 sides)) | |
| ---------------------------------------- | |
| Area: 136.435040 cm^2 | |
| Ix-x: 900.845517 cm^4 | |
| Iy-y: 3037.252230 cm^4 | |
| J: 3938.097746 cm^4 | |
| rx-x: 2.569580 cm | |
| ry-y: 4.718212 cm | |
| Sx-x (min): 167.471688 cm^3 | |
| Sy-y (min): 278.362406 cm^3 | |
| Face<8> (Polygon (4 sides)) | |
| ---------------------------------------- | |
| Area: 136.647815 cm^2 | |
| Ix-x: 921.386819 cm^4 | |
| Iy-y: 2982.592485 cm^4 | |
| J: 3903.979304 cm^4 | |
| rx-x: 2.596687 cm | |
| ry-y: 4.671922 cm | |
| Sx-x (min): 169.835357 cm^3 | |
| Sy-y (min): 276.397051 cm^3 | |
| Face<9> (Polygon (4 sides)) | |
| ---------------------------------------- | |
| Area: 136.435040 cm^2 | |
| Ix-x: 900.845517 cm^4 | |
| Iy-y: 3037.252230 cm^4 | |
| J: 3938.097746 cm^4 | |
| rx-x: 2.569580 cm | |
| ry-y: 4.718212 cm | |
| Sx-x (min): 167.471688 cm^3 | |
| Sy-y (min): 278.362406 cm^3 | |
| ====================================================================== | |
| RESULTS IN M | |
| ====================================================================== | |
| Face<10> (Polygon (4 sides)) | |
| ---------------------------------------- | |
| Area: 0.013665 m^2 | |
| Ix-x: 9.2139e-06 m^4 | |
| Iy-y: 2.9826e-05 m^4 | |
| J: 3.9040e-05 m^4 | |
| rx-x: 0.025967 m | |
| ry-y: 0.046719 m | |
| Sx-x (min): 1.6984e-04 m^3 | |
| Sy-y (min): 2.7640e-04 m^3 | |
| Face<1> (Annulus) | |
| ---------------------------------------- | |
| Outer R: 0.019050 m | |
| Inner R: 0.016002 m | |
| Area: 3.3564e-04 m^2 | |
| Ix-x: 5.1938e-08 m^4 | |
| Iy-y: 5.1938e-08 m^4 | |
| J: 1.0388e-07 m^4 | |
| rx-x: 0.012440 m | |
| ry-y: 0.012440 m | |
| Sx-x (min): 2.7264e-06 m^3 | |
| Sy-y (min): 2.7264e-06 m^3 | |
| Face<2> (Circle) | |
| ---------------------------------------- | |
| Radius: 0.019050 m | |
| Area: 0.001140 m^2 | |
| Ix-x: 1.0344e-07 m^4 | |
| Iy-y: 1.0344e-07 m^4 | |
| J: 2.0687e-07 m^4 | |
| rx-x: 0.009525 m | |
| ry-y: 0.009525 m | |
| Sx-x (min): 5.4297e-06 m^3 | |
| Sy-y (min): 5.4297e-06 m^3 | |
| Face<3> (Circle) | |
| ---------------------------------------- | |
| Radius: 0.016002 m | |
| Area: 8.0445e-04 m^2 | |
| Ix-x: 5.1498e-08 m^4 | |
| Iy-y: 5.1498e-08 m^4 | |
| J: 1.0300e-07 m^4 | |
| rx-x: 0.008001 m | |
| ry-y: 0.008001 m | |
| Sx-x (min): 3.2182e-06 m^3 | |
| Sy-y (min): 3.2182e-06 m^3 | |
| Face<4> (Annulus) | |
| ---------------------------------------- | |
| Outer R: 0.031750 m | |
| Inner R: 0.019050 m | |
| Area: 0.002027 m^2 | |
| Ix-x: 6.9468e-07 m^4 | |
| Iy-y: 6.9468e-07 m^4 | |
| J: 1.3894e-06 m^4 | |
| rx-x: 0.018513 m | |
| ry-y: 0.018513 m | |
| Sx-x (min): 2.1880e-05 m^3 | |
| Sy-y (min): 2.1880e-05 m^3 | |
| Face<5> (Polygon (4 sides) with Hole) | |
| ---------------------------------------- | |
| Outer W: 0.076200 m | |
| Outer H: 0.076200 m | |
| Hole R: 0.031750 m | |
| Area: 0.002640 m^2 | |
| Ix-x: 2.0114e-06 m^4 | |
| Iy-y: 2.0114e-06 m^4 | |
| J: 4.0229e-06 m^4 | |
| rx-x: 0.027605 m | |
| ry-y: 0.027605 m | |
| Sx-x (min): 5.2794e-05 m^3 | |
| Sy-y (min): 5.2794e-05 m^3 | |
| Face<6> (Rectangle) | |
| ---------------------------------------- | |
| Width: 0.215819 m | |
| Height: 0.218223 m | |
| Area: 0.047097 m^2 | |
| Ix-x: 1.8690e-04 m^4 | |
| Iy-y: 1.8281e-04 m^4 | |
| J: 3.6971e-04 m^4 | |
| rx-x: 0.062996 m | |
| ry-y: 0.062302 m | |
| Sx-x (min): 0.001713 m^3 | |
| Sy-y (min): 0.001694 m^3 | |
| Face<7> (Polygon (4 sides)) | |
| ---------------------------------------- | |
| Area: 0.013644 m^2 | |
| Ix-x: 9.0085e-06 m^4 | |
| Iy-y: 3.0373e-05 m^4 | |
| J: 3.9381e-05 m^4 | |
| rx-x: 0.025696 m | |
| ry-y: 0.047182 m | |
| Sx-x (min): 1.6747e-04 m^3 | |
| Sy-y (min): 2.7836e-04 m^3 | |
| Face<8> (Polygon (4 sides)) | |
| ---------------------------------------- | |
| Area: 0.013665 m^2 | |
| Ix-x: 9.2139e-06 m^4 | |
| Iy-y: 2.9826e-05 m^4 | |
| J: 3.9040e-05 m^4 | |
| rx-x: 0.025967 m | |
| ry-y: 0.046719 m | |
| Sx-x (min): 1.6984e-04 m^3 | |
| Sy-y (min): 2.7640e-04 m^3 | |
| Face<9> (Polygon (4 sides)) | |
| ---------------------------------------- | |
| Area: 0.013644 m^2 | |
| Ix-x: 9.0085e-06 m^4 | |
| Iy-y: 3.0373e-05 m^4 | |
| J: 3.9381e-05 m^4 | |
| rx-x: 0.025696 m | |
| ry-y: 0.047182 m | |
| Sx-x (min): 1.6747e-04 m^3 | |
| Sy-y (min): 2.7836e-04 m^3 | |
| ====================================================================== | |
| RESULTS IN IN | |
| ====================================================================== | |
| Face<10> (Polygon (4 sides)) | |
| ---------------------------------------- | |
| Area: 21.180454 in^2 | |
| Ix-x: 22.136407 in^4 | |
| Iy-y: 71.657071 in^4 | |
| J: 93.793478 in^4 | |
| rx-x: 1.022318 in | |
| ry-y: 1.839339 in | |
| Sx-x (min): 10.363989 in^3 | |
| Sy-y (min): 16.866783 in^3 | |
| Face<1> (Annulus) | |
| ---------------------------------------- | |
| Outer R: 0.750000 in | |
| Inner R: 0.630000 in | |
| Area: 0.520248 in^2 | |
| Ix-x: 0.124781 in^4 | |
| Iy-y: 0.124781 in^4 | |
| J: 0.249563 in^4 | |
| rx-x: 0.489745 in | |
| ry-y: 0.489745 in | |
| Sx-x (min): 0.166375 in^3 | |
| Sy-y (min): 0.166375 in^3 | |
| Face<2> (Circle) | |
| ---------------------------------------- | |
| Radius: 0.750000 in | |
| Area: 1.767146 in^2 | |
| Ix-x: 0.248505 in^4 | |
| Iy-y: 0.248505 in^4 | |
| J: 0.497010 in^4 | |
| rx-x: 0.375000 in | |
| ry-y: 0.375000 in | |
| Sx-x (min): 0.331340 in^3 | |
| Sy-y (min): 0.331340 in^3 | |
| Face<3> (Circle) | |
| ---------------------------------------- | |
| Radius: 0.630000 in | |
| Area: 1.246898 in^2 | |
| Ix-x: 0.123723 in^4 | |
| Iy-y: 0.123723 in^4 | |
| J: 0.247447 in^4 | |
| rx-x: 0.315000 in | |
| ry-y: 0.315000 in | |
| Sx-x (min): 0.196386 in^3 | |
| Sy-y (min): 0.196386 in^3 | |
| Face<4> (Annulus) | |
| ---------------------------------------- | |
| Outer R: 1.250000 in | |
| Inner R: 0.750000 in | |
| Area: 3.141593 in^2 | |
| Ix-x: 1.668971 in^4 | |
| Iy-y: 1.668971 in^4 | |
| J: 3.337942 in^4 | |
| rx-x: 0.728869 in | |
| ry-y: 0.728869 in | |
| Sx-x (min): 1.335177 in^3 | |
| Sy-y (min): 1.335177 in^3 | |
| Face<5> (Polygon (4 sides) with Hole) | |
| ---------------------------------------- | |
| Outer W: 3.000000 in | |
| Outer H: 3.000000 in | |
| Hole R: 1.250000 in | |
| Area: 4.091261 in^2 | |
| Ix-x: 4.832524 in^4 | |
| Iy-y: 4.832524 in^4 | |
| J: 9.665048 in^4 | |
| rx-x: 1.086822 in | |
| ry-y: 1.086822 in | |
| Sx-x (min): 3.221683 in^3 | |
| Sy-y (min): 3.221683 in^3 | |
| Face<6> (Rectangle) | |
| ---------------------------------------- | |
| Width: 8.496827 in | |
| Height: 8.591452 in | |
| Area: 73.000082 in^2 | |
| Ix-x: 449.029856 in^4 | |
| Iy-y: 439.193284 in^4 | |
| J: 888.223139 in^4 | |
| rx-x: 2.480138 in | |
| ry-y: 2.452823 in | |
| Sx-x (min): 104.529448 in^3 | |
| Sy-y (min): 103.378183 in^3 | |
| Face<7> (Polygon (4 sides)) | |
| ---------------------------------------- | |
| Area: 21.147473 in^2 | |
| Ix-x: 21.642900 in^4 | |
| Iy-y: 72.970277 in^4 | |
| J: 94.613177 in^4 | |
| rx-x: 1.011646 in | |
| ry-y: 1.857564 in | |
| Sx-x (min): 10.219749 in^3 | |
| Sy-y (min): 16.986716 in^3 | |
| Face<8> (Polygon (4 sides)) | |
| ---------------------------------------- | |
| Area: 21.180454 in^2 | |
| Ix-x: 22.136407 in^4 | |
| Iy-y: 71.657071 in^4 | |
| J: 93.793478 in^4 | |
| rx-x: 1.022318 in | |
| ry-y: 1.839339 in | |
| Sx-x (min): 10.363989 in^3 | |
| Sy-y (min): 16.866783 in^3 | |
| Face<9> (Polygon (4 sides)) | |
| ---------------------------------------- | |
| Area: 21.147473 in^2 | |
| Ix-x: 21.642900 in^4 | |
| Iy-y: 72.970277 in^4 | |
| J: 94.613177 in^4 | |
| rx-x: 1.011646 in | |
| ry-y: 1.857564 in | |
| Sx-x (min): 10.219749 in^3 | |
| Sy-y (min): 16.986716 in^3 | |
| ====================================================================== | |
| RESULTS IN FT | |
| ====================================================================== | |
| Face<10> (Polygon (4 sides)) | |
| ---------------------------------------- | |
| Area: 0.147086 ft^2 | |
| Ix-x: 0.001068 ft^4 | |
| Iy-y: 0.003456 ft^4 | |
| J: 0.004523 ft^4 | |
| rx-x: 0.085193 ft | |
| ry-y: 0.153278 ft | |
| Sx-x (min): 0.005998 ft^3 | |
| Sy-y (min): 0.009761 ft^3 | |
| Face<1> (Annulus) | |
| ---------------------------------------- | |
| Outer R: 0.062500 ft | |
| Inner R: 0.052500 ft | |
| Area: 0.003613 ft^2 | |
| Ix-x: 6.0176e-06 ft^4 | |
| Iy-y: 6.0176e-06 ft^4 | |
| J: 1.2035e-05 ft^4 | |
| rx-x: 0.040812 ft | |
| ry-y: 0.040812 ft | |
| Sx-x (min): 9.6282e-05 ft^3 | |
| Sy-y (min): 9.6282e-05 ft^3 | |
| Face<2> (Circle) | |
| ---------------------------------------- | |
| Radius: 0.062500 ft | |
| Area: 0.012272 ft^2 | |
| Ix-x: 1.1984e-05 ft^4 | |
| Iy-y: 1.1984e-05 ft^4 | |
| J: 2.3968e-05 ft^4 | |
| rx-x: 0.031250 ft | |
| ry-y: 0.031250 ft | |
| Sx-x (min): 1.9175e-04 ft^3 | |
| Sy-y (min): 1.9175e-04 ft^3 | |
| Face<3> (Circle) | |
| ---------------------------------------- | |
| Radius: 0.052500 ft | |
| Area: 0.008659 ft^2 | |
| Ix-x: 5.9666e-06 ft^4 | |
| Iy-y: 5.9666e-06 ft^4 | |
| J: 1.1933e-05 ft^4 | |
| rx-x: 0.026250 ft | |
| ry-y: 0.026250 ft | |
| Sx-x (min): 1.1365e-04 ft^3 | |
| Sy-y (min): 1.1365e-04 ft^3 | |
| Face<4> (Annulus) | |
| ---------------------------------------- | |
| Outer R: 0.104167 ft | |
| Inner R: 0.062500 ft | |
| Area: 0.021817 ft^2 | |
| Ix-x: 8.0487e-05 ft^4 | |
| Iy-y: 8.0487e-05 ft^4 | |
| J: 1.6097e-04 ft^4 | |
| rx-x: 0.060739 ft | |
| ry-y: 0.060739 ft | |
| Sx-x (min): 7.7267e-04 ft^3 | |
| Sy-y (min): 7.7267e-04 ft^3 | |
| Face<5> (Polygon (4 sides) with Hole) | |
| ---------------------------------------- | |
| Outer W: 0.250000 ft | |
| Outer H: 0.250000 ft | |
| Hole R: 0.104167 ft | |
| Area: 0.028412 ft^2 | |
| Ix-x: 2.3305e-04 ft^4 | |
| Iy-y: 2.3305e-04 ft^4 | |
| J: 4.6610e-04 ft^4 | |
| rx-x: 0.090568 ft | |
| ry-y: 0.090568 ft | |
| Sx-x (min): 0.001864 ft^3 | |
| Sy-y (min): 0.001864 ft^3 | |
| Face<6> (Rectangle) | |
| ---------------------------------------- | |
| Width: 0.708069 ft | |
| Height: 0.715954 ft | |
| Area: 0.506945 ft^2 | |
| Ix-x: 0.021655 ft^4 | |
| Iy-y: 0.021180 ft^4 | |
| J: 0.042835 ft^4 | |
| rx-x: 0.206678 ft | |
| ry-y: 0.204402 ft | |
| Sx-x (min): 0.060492 ft^3 | |
| Sy-y (min): 0.059825 ft^3 | |
| Face<7> (Polygon (4 sides)) | |
| ---------------------------------------- | |
| Area: 0.146857 ft^2 | |
| Ix-x: 0.001044 ft^4 | |
| Iy-y: 0.003519 ft^4 | |
| J: 0.004563 ft^4 | |
| rx-x: 0.084304 ft | |
| ry-y: 0.154797 ft | |
| Sx-x (min): 0.005914 ft^3 | |
| Sy-y (min): 0.009830 ft^3 | |
| Face<8> (Polygon (4 sides)) | |
| ---------------------------------------- | |
| Area: 0.147086 ft^2 | |
| Ix-x: 0.001068 ft^4 | |
| Iy-y: 0.003456 ft^4 | |
| J: 0.004523 ft^4 | |
| rx-x: 0.085193 ft | |
| ry-y: 0.153278 ft | |
| Sx-x (min): 0.005998 ft^3 | |
| Sy-y (min): 0.009761 ft^3 | |
| Face<9> (Polygon (4 sides)) | |
| ---------------------------------------- | |
| Area: 0.146857 ft^2 | |
| Ix-x: 0.001044 ft^4 | |
| Iy-y: 0.003519 ft^4 | |
| J: 0.004563 ft^4 | |
| rx-x: 0.084304 ft | |
| ry-y: 0.154797 ft | |
| Sx-x (min): 0.005914 ft^3 | |
| Sy-y (min): 0.009830 ft^3 | |
| ====================================================================== | |
| END OF REPORT | |
| ====================================================================== |
stephensmitchell
commented
Dec 28, 2025
Author
Author
This is a debug script, so the length isn't as important, but it shouldn't grow more than this.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment