Skip to content

Instantly share code, notes, and snippets.

@stephensmitchell
Created December 30, 2025 23:25
Show Gist options
  • Select an option

  • Save stephensmitchell/b8b2bf0391bdcf40713e2a777069a910 to your computer and use it in GitHub Desktop.

Select an option

Save stephensmitchell/b8b2bf0391bdcf40713e2a777069a910 to your computer and use it in GitHub Desktop.
AREA MOMENTS REPORT (CM)
from __future__ import division
import sys
import math
from AlibreScript import *
# --- USER CONFIGURATION ---
TARGET_ID = 69
Units.Current = UnitTypes.Centimeters
# --- SCRIPT CONSTANTS ---
ScriptName = "Targeted Area Moments - Full Data"
ScriptVersion = "1.6"
CURVE_SEGMENTS = 360
VERTEX_TOLERANCE = 1e-6
# --- REPLACED LOGIC ---
def run():
part = CurrentPart()
if part is None:
print "No part found."
return
faces = part.GetFaces()
if not faces:
print "No faces found."
return
try:
target_face = faces[TARGET_ID]
except IndexError:
print "Error: Face ID %d does not exist. Total faces: %d" % (TARGET_ID, len(faces))
return
raw_area = target_face.GetArea()
# Your Math Logic
if raw_area > 1000:
actual_area_cm2 = raw_area / 100.0
else:
actual_area_cm2 = raw_area
# Calculate Full Moments using the original engine
shape_type, props, alibre_area = analyze_face_geometry(target_face, CURVE_SEGMENTS)
if props is not None:
# Scale properties based on your logic area vs calculated area
# This ensures all derived values (I, S, J) follow your custom area scaling
scale_factor = actual_area_cm2 / props.area
props.area = actual_area_cm2
props.Ix_centroid *= (scale_factor**2)
props.Iy_centroid *= (scale_factor**2)
props.Ixy_centroid *= (scale_factor**2)
props.J_centroid = props.Ix_centroid + props.Iy_centroid
face_name = target_face.Name if target_face.Name else "Face<%d>" % TARGET_ID
print "=" * 70
print " COMPLETE AREA MOMENTS REPORT (CM)"
print "=" * 70
print "Face: %s" % face_name
print "Raw Alibre Area: %.6f" % raw_area
print "Applied Logic Area: %.6f cm^2" % actual_area_cm2
print ""
print generate_face_section(face_name, props, actual_area_cm2, "cm")
print "=" * 70
else:
print "Could not analyze geometry for face %d" % TARGET_ID
# --- FULL GEOMETRY ENGINE (RESTORED FROM ORIGINAL) ---
def vec_subtract(a, b): return [a[0]-b[0], a[1]-b[1], a[2]-b[2]]
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)
return [v[0]/L, v[1]/L, v[2]/L] if L > 1e-12 else [0.0, 0.0, 0.0]
class PolygonProperties:
def __init__(self, vertices_2d, shape_name="Polygon"):
self.shape_type = shape_name
self.vertices = vertices_2d
self.n = len(vertices_2d)
self._compute_all()
def _compute_all(self):
verts = self.vertices
n = self.n
signed_area, cx, cy = 0.0, 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]
signed_area += cross
cx += (verts[i][0] + verts[j][0]) * cross
cy += (verts[i][1] + verts[j][1]) * cross
self.area = abs(signed_area * 0.5)
factor = 1.0 / (6.0 * (signed_area if abs(signed_area) > 1e-12 else 1.0))
self.centroid_x, self.centroid_y = cx * factor, 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**2 + y0*y1 + y1**2) * cross
Iy += (x0**2 + x0*x1 + x1**2) * cross
Ixy += (x0*y1 + 2*x0*y0 + 2*x1*y1 + x1*y0) * cross
self.Ix_centroid = abs(Ix / 12.0) - self.area * self.centroid_y**2
self.Iy_centroid = abs(Iy / 12.0) - self.area * self.centroid_x**2
self.Ixy_centroid = (Ixy / 24.0) - self.area * self.centroid_x * self.centroid_y
self.J_centroid = self.Ix_centroid + self.Iy_centroid
# Principal Moments
I_avg = (self.Ix_centroid + self.Iy_centroid) / 2.0
I_diff = (self.Ix_centroid - self.Iy_centroid) / 2.0
R = math.sqrt(I_diff**2 + self.Ixy_centroid**2)
self.I_max = I_avg + R
self.I_min = max(0.0, I_avg - R)
self.theta_principal_deg = math.degrees(0.5 * math.atan2(-2.0 * self.Ixy_centroid, self.Ix_centroid - self.Iy_centroid))
# Radii of Gyration
self.rx = math.sqrt(max(0, self.Ix_centroid / self.area))
self.ry = math.sqrt(max(0, self.Iy_centroid / self.area))
# Section Modulus (min)
y_rel = [v[1] - self.centroid_y for v in verts]
x_rel = [v[0] - self.centroid_x for v in verts]
self.Sx_min = self.Ix_centroid / max(abs(min(y_rel)), abs(max(y_rel)))
self.Sy_min = self.Iy_centroid / max(abs(min(x_rel)), abs(max(x_rel)))
def project_to_2d(points_3d):
if len(points_3d) < 3: return []
p0 = points_3d[0]
v1 = vec_normalize(vec_subtract(points_3d[1], p0))
v2 = vec_normalize(vec_subtract(points_3d[2], p0))
normal = vec_normalize(vec_cross(v1, v2))
u_axis = v1
v_axis = vec_cross(normal, u_axis)
return [[vec_dot(vec_subtract(p, p0), u_axis), vec_dot(vec_subtract(p, p0), v_axis)] for p in points_3d]
def analyze_face_geometry(face, num_segments):
try:
verts = face.GetVertices()
pts_3d = [[v.X, v.Y, v.Z] for v in verts]
pts_2d = project_to_2d(pts_3d)
shape_name = "Polygon (%d sides)" % len(pts_2d)
return shape_name, PolygonProperties(pts_2d, shape_name), face.GetArea()
except:
return "Unknown", None, face.GetArea()
def fmt(value, decimals=6):
return ("%%.%df" % decimals) % value if value is not None else "N/A"
def generate_face_section(face_name, p, area, unit):
u1, u2, u3, u4 = unit, unit+"^2", unit+"^3", unit+"^4"
return "\n".join([
" %s (%s)" % (face_name, p.shape_type),
" " + "-" * 40,
" Area: %s %s" % (fmt(p.area), u2),
" Ix-x: %s %s" % (fmt(p.Ix_centroid), u4),
" Iy-y: %s %s" % (fmt(p.Iy_centroid), u4),
" Ixy: %s %s" % (fmt(p.Ixy_centroid), u4),
" J: %s %s" % (fmt(p.J_centroid), u4),
" rx-x: %s %s" % (fmt(p.rx), u1),
" ry-y: %s %s" % (fmt(p.ry), u1),
" Sx-x (min): %s %s" % (fmt(p.Sx_min), u3),
" Sy-y (min): %s %s" % (fmt(p.Sy_min), u3),
" I (max): %s %s" % (fmt(p.I_max), u4),
" I (min): %s %s" % (fmt(p.I_min), u4),
" Angle: %s deg" % (fmt(p.theta_principal_deg, 2))
])
run()
======================================================================
COMPLETE AREA MOMENTS REPORT (CM)
======================================================================
Face: Face<70>
Raw Alibre Area: 40.393149
Applied Logic Area: 40.393149 cm^2
Face<70> (Polygon (68 sides))
----------------------------------------
Area: 40.393149 cm^2
Ix-x: 1015.007063 cm^4
Iy-y: 1465.689893 cm^4
Ixy: -642.240400 cm^4
J: 2480.696956 cm^4
rx-x: 5.012803 cm
ry-y: 6.023753 cm
Sx-x (min): 124.963115 cm^3
Sy-y (min): 156.657131 cm^3
I (max): 1920.974282 cm^4
I (min): 559.722674 cm^4
Angle: 54.67 deg
======================================================================
@stephensmitchell
Copy link
Copy Markdown
Author

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment