Seed repository: rev-8.0.0 reference, frozen oracle, toolchain, test harness
Reference implementation of the strap-beam generators at revision 8.0.0, kept so the acceptance oracle can be regenerated. Not a live target; the running application has no OpenSCAD dependency. The oracle holds 123 frozen cases, 113 accepted and 10 rejected, produced by OpenSCAD 2021.01 with BOSL2 at 92d697c2. The ten rejections are part of the contract: a port that accepts them is wrong. tests/test_oracle.py specifies the port API and was written before the port, so the interface follows from what must be verified rather than what is convenient to implement. Proven by adversarial stub: a build() that rejects everything passes all 10 rejection tests and fails all 226 acceptance tests.
This commit is contained in:
@@ -0,0 +1,471 @@
|
||||
/*
|
||||
strap-beam-3x.scad — Three-strap longitudinal beam enclosures
|
||||
=============================================================
|
||||
Revision 8. Replaces triangle-strap-enclosure_v7.scad.
|
||||
|
||||
Three pallet-strap bundles run parallel to one longitudinal axis (Z).
|
||||
A profile decides only how the three cross-sections are arranged in XY;
|
||||
that arrangement is swept along Z. A "member" here is the end view of
|
||||
one 10-100 ft strap bundle, so its length in the cross-section is the
|
||||
strap's WIDTH.
|
||||
|
||||
Profiles
|
||||
1. Equilateral Triangle ring, three equal sides
|
||||
2. General Triangle ring, caller-shaped triangle
|
||||
3. A Frame two legs meeting at a gable apex, plus a
|
||||
crossbar butted between them
|
||||
4. Y three radial spokes about a plugged centre
|
||||
5. T two-strap flange with a perpendicular stem
|
||||
6. Three-Fin tangential triangle whose members are slid
|
||||
cyclically so each projects one fin
|
||||
|
||||
Everything reusable lives in lib/sb-core.scad and is shared unchanged
|
||||
with strap-beam-4x.scad. This file contains only the six arrangements
|
||||
and their parameters.
|
||||
|
||||
---------------------------------------------------------------------
|
||||
Changes from v7 that alter dimensions
|
||||
---------------------------------------------------------------------
|
||||
* Every gap parameter is now a WEB: the PLA+ that survives between two
|
||||
strap cavities. v7 stated gaps strap-to-strap and then inflated the
|
||||
cavities by the fit clearance afterwards, which quietly removed
|
||||
2 x clearance from every junction. A declared 1.2 mm web is now
|
||||
1.2 mm of plastic.
|
||||
* Ring profiles size themselves. Straps have a fixed width, so on a
|
||||
polygon of a given size the corner webs are whatever they are; sliding
|
||||
members along their edges cannot raise all three at once because each
|
||||
edge shares its budget with two corners. The polygon is therefore
|
||||
grown about its centroid until the tightest corner reaches the
|
||||
declared web. Caller-supplied triangle dimensions set the SHAPE; the
|
||||
size follows from the strap width.
|
||||
* Ring members are centred on their edges rather than shifted
|
||||
cyclically, so the triangle profiles are now mirror-symmetric.
|
||||
* Junctions are structural. Members butt through their neighbours and
|
||||
are cut flush on the far face; fillets are applied on top of that
|
||||
overlap rather than in place of it. In v7 the Three-Fin was held
|
||||
together by a 0.4 mm corner touch that the fillet happened to bridge.
|
||||
* Members with no enclosed side (Y spokes, T stem and flange) take the
|
||||
outside wall on both faces. v7 hard-coded an interior direction for
|
||||
these, which made the Y a pinwheel whenever the two wall thicknesses
|
||||
differed.
|
||||
* Validation measures the finished section. Connectivity is necessary
|
||||
but not sufficient - v7 passed cross-sections joined by 0.13 mm.
|
||||
* Checks are scoped to the selected profile. In v7 every assert was
|
||||
unconditional, so an A Frame slider could kill the Y profile.
|
||||
*/
|
||||
|
||||
include <lib/sb-core.scad>
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Parameters
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/* [Profile] */
|
||||
profile_type = "Equilateral Triangle"; // ["Equilateral Triangle","General Triangle","A Frame","Y","T","Three-Fin"]
|
||||
|
||||
/* [Pallet strap] */
|
||||
strap_width_mm = 15.875; // ULINE 5/8 in nominal width
|
||||
strap_thickness_mm = 0.508; // ULINE .020 in nominal thickness
|
||||
bundle_count = 1; // [1:1:3]
|
||||
|
||||
/* [Longitudinal axis] */
|
||||
member_length_ft = 10; // [10:1:100]
|
||||
length_view = "Preview"; // ["Preview","Full Length"]
|
||||
preview_length_mm = 100;
|
||||
|
||||
/* [PLA+ enclosure] */
|
||||
// Clearance is added to every cavity face. Declared webs are unaffected by
|
||||
// it; the library compensates internally.
|
||||
fit_clearance_mm = 0.25;
|
||||
inside_wall_thickness_mm = 1.20; // faces that look into an enclosed bore
|
||||
outside_wall_thickness_mm = 1.20; // faces exposed to the outside world
|
||||
edge_wall_thickness_mm = 1.20; // caps over a strap's narrow edges
|
||||
// Nothing anywhere in the section is allowed to be thinner than this.
|
||||
min_wall_mm = 1.20;
|
||||
|
||||
/* [Ring profiles] */
|
||||
// Applies to both triangle profiles. The polygon grows until its tightest
|
||||
// corner reaches this web.
|
||||
ring_corner_web_mm = 1.20;
|
||||
// Rounding of the complete outer envelope, never of individual sleeves.
|
||||
ring_corner_radius_mm = 2.00;
|
||||
|
||||
/* [General Triangle shape] */
|
||||
// These set proportions only; absolute size is solved from the strap width.
|
||||
general_triangle_base = 17.50;
|
||||
general_triangle_height = 15.50;
|
||||
general_triangle_apex_offset = 1.50;
|
||||
|
||||
/* [A Frame] */
|
||||
a_frame_leg_angle_deg = 45; // leg angle measured from horizontal
|
||||
a_frame_apex_web_mm = 1.20; // PLA+ between the two leg cavities
|
||||
a_frame_crossbar_web_mm = 1.20; // PLA+ between crossbar and leg cavities
|
||||
a_frame_crossbar_offset_mm = 0;
|
||||
a_frame_junction_round_mm = 1.50;
|
||||
|
||||
/* [Y Profile] */
|
||||
y_rotation_deg = 90;
|
||||
y_junction_web_mm = 1.20; // PLA+ between neighbouring spoke cavities
|
||||
y_junction_round_mm = 1.50;
|
||||
|
||||
/* [T Profile] */
|
||||
t_stem_web_mm = 1.20; // PLA+ between stem and flange cavities
|
||||
t_flange_web_mm = 1.20; // PLA+ between the two flange cavities
|
||||
t_junction_round_mm = 1.50;
|
||||
|
||||
/* [Three-Fin Profile] */
|
||||
// Fin projection past the corner it overhangs. The core triangle is solved
|
||||
// from this plus the web and bore minimums below.
|
||||
three_fin_fin_mm = 6.25;
|
||||
three_fin_web_mm = 1.20; // PLA+ at each cyclic junction
|
||||
three_fin_bore_side_mm = 7.50; // minimum central opening
|
||||
three_fin_rotation_deg = 0;
|
||||
three_fin_junction_round_mm = 2.00;
|
||||
|
||||
/* [Display] */
|
||||
render_mode = "3D"; // ["3D","Section"]
|
||||
show_straps = true;
|
||||
show_enclosure = true;
|
||||
|
||||
/* [Quality] */
|
||||
facets = 48; // [12:4:128]
|
||||
|
||||
/* [Reporting] */
|
||||
material_density_g_cm3 = 1.24; // PLA+ nominal
|
||||
|
||||
$fn = facets;
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Derived
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
SB_FAMILY = "3x";
|
||||
// Generator revision. Qualification attestations bind to this, so any change
|
||||
// that alters emitted geometry MUST bump it. Cosmetic or comment-only edits
|
||||
// must not. See sb-report.scad for what is published.
|
||||
SB_REVISION = "8.0.0";
|
||||
SB_MEMBER_COUNT = 3;
|
||||
|
||||
geo = sb_geo(
|
||||
strap_width_mm, strap_thickness_mm, bundle_count, fit_clearance_mm,
|
||||
inside_wall_thickness_mm, outside_wall_thickness_mm,
|
||||
edge_wall_thickness_mm, min_wall_mm
|
||||
);
|
||||
|
||||
model_length_mm = length_view == "Full Length"
|
||||
? member_length_ft * 304.8
|
||||
: preview_length_mm;
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 1-2. Ring profiles
|
||||
// ---------------------------------------------------------------------------
|
||||
/*
|
||||
Both triangle profiles are the same construction: a centreline polygon,
|
||||
grown until its corners are legal, wrapped in one envelope with solid
|
||||
rounded corners, with the bore taken from the members' real inside walls.
|
||||
|
||||
The 4x generator gets these for free by handing sb_ring_profile() a
|
||||
quadrilateral instead.
|
||||
*/
|
||||
|
||||
function sb3_equilateral(g) =
|
||||
let(s = sb_width(g), a = s / (2 * SB_SQRT3))
|
||||
sb_ring_polygon_profile([[-s / 2, -a], [s / 2, -a], [0, 2 * a]],
|
||||
g, ring_corner_web_mm, ring_corner_radius_mm,
|
||||
"Equilateral Triangle");
|
||||
|
||||
function sb3_general_triangle(g) =
|
||||
sb_ring_polygon_profile(
|
||||
[[-general_triangle_base / 2, -general_triangle_height / 2],
|
||||
[ general_triangle_base / 2, -general_triangle_height / 2],
|
||||
[ general_triangle_apex_offset, general_triangle_height / 2]],
|
||||
g, ring_corner_web_mm, ring_corner_radius_mm, "General Triangle");
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 3. A Frame
|
||||
// ---------------------------------------------------------------------------
|
||||
/*
|
||||
The apex is a real meeting point: both leg centrelines pass through it and
|
||||
each leg is set back along its own axis until the two cavities are exactly
|
||||
a_frame_apex_web_mm apart. v7 instead offset both legs from the origin by
|
||||
a fixed radius, which delivered apex_gap x cos(leg_angle) and collapsed to
|
||||
nothing as the legs approached vertical.
|
||||
|
||||
The crossbar is likewise solved by depth against the measured web and then
|
||||
butted flush between the two legs' outer faces. v7 measured to the leg
|
||||
CENTRELINE, so its declared 1.40 mm arrived as 0.16 mm.
|
||||
*/
|
||||
|
||||
function sb3_a_frame_legs(g, setback) =
|
||||
let(
|
||||
a = a_frame_leg_angle_deg,
|
||||
target = [0, -sb_width(g)], // deep inside the counter
|
||||
d = sb_cavity_w(g) / 2 + setback,
|
||||
angL = 180 + a,
|
||||
angR = -a,
|
||||
cL = [d * cos(angL), d * sin(angL)],
|
||||
cR = [d * cos(angR), d * sin(angR)]
|
||||
)
|
||||
[
|
||||
sb_member(cL.x, cL.y, angL, sb_face_toward(cL, angL, target)),
|
||||
sb_member(cR.x, cR.y, angR, sb_face_toward(cR, angR, target))
|
||||
];
|
||||
|
||||
function sb3_a_frame_apex_web(g, setback) =
|
||||
let(l = sb3_a_frame_legs(g, setback))
|
||||
sb_path_gap(sb_cavity_path(l[0], g), sb_cavity_path(l[1], g));
|
||||
|
||||
function sb3_a_frame_crossbar(g, depth) =
|
||||
let(c = [a_frame_crossbar_offset_mm, -depth])
|
||||
sb_member(c.x, c.y, 0, sb_face_toward(c, 0, [0, 0]));
|
||||
|
||||
function sb3_a_frame_bar_web(g, legs, depth) =
|
||||
let(cb = sb_cavity_path(sb3_a_frame_crossbar(g, depth), g))
|
||||
min(sb_path_gap(cb, sb_cavity_path(legs[0], g)),
|
||||
sb_path_gap(cb, sb_cavity_path(legs[1], g)));
|
||||
|
||||
function sb3_a_frame(g) =
|
||||
let(
|
||||
W = sb_width(g),
|
||||
f_apex = function(s) sb3_a_frame_apex_web(g, s),
|
||||
feasible = sb_solvable(f_apex, 6 * W, a_frame_apex_web_mm)
|
||||
)
|
||||
!feasible
|
||||
? sb_profile_failed(str(
|
||||
"A Frame: at ", a_frame_leg_angle_deg,
|
||||
" degrees the legs are too close to parallel to open a ",
|
||||
a_frame_apex_web_mm,
|
||||
" mm apex web. Reduce a_frame_leg_angle_deg."))
|
||||
: let(
|
||||
setback = sb_solve(f_apex, 0, 6 * W, a_frame_apex_web_mm),
|
||||
legs = sb3_a_frame_legs(g, setback),
|
||||
f_bar = function(d) sb3_a_frame_bar_web(g, legs, d),
|
||||
bar_ok = sb_solvable(f_bar, 8 * W, a_frame_crossbar_web_mm)
|
||||
)
|
||||
!bar_ok
|
||||
? sb_profile_failed(
|
||||
"A Frame: the crossbar cannot reach a legal web against the legs. Reduce a_frame_crossbar_web_mm or the crossbar offset.")
|
||||
: let(
|
||||
depth = sb_solve(f_bar, 0, 8 * W, a_frame_crossbar_web_mm),
|
||||
bar = sb3_a_frame_crossbar(g, depth),
|
||||
ms = [legs[0], bar, legs[1]],
|
||||
|
||||
// Legs run up to the apex; the wedge between their end faces
|
||||
// is plugged with their convex hull, which leaves no spike
|
||||
// and no V-notch.
|
||||
ext = max(0, setback - sb_wall_edge(g)),
|
||||
legL = sb_sleeve_path(legs[0], g, 0, ext),
|
||||
legR = sb_sleeve_path(legs[1], g, 0, ext),
|
||||
cap = sb_hull_cap([sb_end_face(legs[0], g, -1, ext),
|
||||
sb_end_face(legs[1], g, -1, ext)]),
|
||||
|
||||
// Crossbar spans flush between the legs' outer faces.
|
||||
lineL = sb_far_face_line(legs[0], g, sb_mc(bar)),
|
||||
lineR = sb_far_face_line(legs[1], g, sb_mc(bar)),
|
||||
barP = sb_sleeve_span(bar, g, lineL[0], lineL[1],
|
||||
lineR[0], lineR[1]),
|
||||
|
||||
paths = [legL, barP, legR],
|
||||
raw = union(concat([[legL], [legR], [barP]],
|
||||
len(cap) > 0 ? [cap] : [])),
|
||||
shell = sb_fillet_junctions(raw, [[0, 1], [1, 2], [0, 2]],
|
||||
paths, a_frame_junction_round_mm),
|
||||
bore = sb_bore_from_members(ms, g),
|
||||
leg_end_depth = (setback + sb_cavity_w(g)) * sin(a_frame_leg_angle_deg)
|
||||
)
|
||||
sb_profile(
|
||||
ms, shell, bore,
|
||||
[
|
||||
sb_check(depth < leg_end_depth,
|
||||
str("A Frame: the crossbar sits at ", depth,
|
||||
" mm below the apex but the legs only reach ",
|
||||
leg_end_depth,
|
||||
" mm. Reduce a_frame_crossbar_web_mm or the leg angle.")),
|
||||
sb_check(sb_bore_valid(bore, ms, g),
|
||||
"A Frame: the enclosed counter has collapsed. Reduce inside_wall_thickness_mm or open the frame out."),
|
||||
sb_check(a_frame_junction_round_mm > 0,
|
||||
"A Frame: a_frame_junction_round_mm must be greater than zero. A butt joint with no fillet meets its neighbour along an exactly tangent boundary, which is a valid outline but cannot be tessellated."),
|
||||
sb_check(abs(a_frame_crossbar_offset_mm) < sb_width(g) / 2,
|
||||
"A Frame: a_frame_crossbar_offset_mm has pushed the crossbar off the frame.")
|
||||
],
|
||||
[
|
||||
sb_kv("AF_APEX_SETBACK_MM", setback),
|
||||
sb_kv("AF_CROSSBAR_DEPTH_MM", depth),
|
||||
sb_kv("AF_APEX_WEB_MM", sb3_a_frame_apex_web(g, setback)),
|
||||
sb_kv("AF_CROSSBAR_WEB_MM", sb3_a_frame_bar_web(g, legs, depth))
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 4. Y
|
||||
// ---------------------------------------------------------------------------
|
||||
/*
|
||||
Three spokes pointing away from a common centre. A spoke's broad faces
|
||||
both look at open air, so both get the outside wall - the profile stays
|
||||
three-fold symmetric and non-chiral under any wall settings. The centre
|
||||
is plugged with the convex hull of the three inner end faces rather than
|
||||
left to whatever the crossing rectangles happened to produce.
|
||||
*/
|
||||
|
||||
function sb3_y(g) =
|
||||
sb_spoke_profile(3, y_rotation_deg, y_junction_web_mm,
|
||||
y_junction_round_mm, g, "Y");
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 5. T
|
||||
// ---------------------------------------------------------------------------
|
||||
/*
|
||||
Two straps form the flange, separated by their own web so each keeps a
|
||||
private channel - in v7 they touched edge to edge and shared one slot.
|
||||
The stem is placed so its cavity clears the flange cavities by exactly
|
||||
t_stem_web_mm and is then butted flush into the flange's far face.
|
||||
*/
|
||||
|
||||
function sb3_t_members(g) =
|
||||
let(
|
||||
half = t_flange_web_mm / 2 + sb_cavity_w(g) / 2,
|
||||
top = -sb_cavity_t(g) / 2 - t_stem_web_mm,
|
||||
stemy = top - sb_cavity_w(g) / 2
|
||||
)
|
||||
[
|
||||
sb_member(-half, 0, 0, SB_FACE_BOTH_OUT),
|
||||
sb_member( half, 0, 0, SB_FACE_BOTH_OUT),
|
||||
sb_member(0, stemy, -90, SB_FACE_BOTH_OUT) // leading end points down
|
||||
];
|
||||
|
||||
function sb3_t(g) =
|
||||
let(
|
||||
ms = sb3_t_members(g),
|
||||
flL = sb_sleeve_path(ms[0], g),
|
||||
flR = sb_sleeve_path(ms[1], g),
|
||||
stem = sb_sleeve_butt(ms[2], g, ms[0]),
|
||||
paths = [flL, flR, stem],
|
||||
raw = union([[flL], [flR], [stem]]),
|
||||
shell = sb_fillet_junctions(raw, [[0, 2], [1, 2]], paths,
|
||||
t_junction_round_mm),
|
||||
flange_overlap = 2 * sb_wall_edge(g) - t_flange_web_mm
|
||||
)
|
||||
sb_profile(ms, shell, [], [
|
||||
sb_check(flange_overlap > 0,
|
||||
str("T: t_flange_web_mm of ", t_flange_web_mm,
|
||||
" mm exceeds twice the edge wall, so the two flange sleeves no longer meet. Reduce it or raise edge_wall_thickness_mm.")),
|
||||
sb_check(t_stem_web_mm >= sb_min_wall(g) - 1e-9,
|
||||
str("T: t_stem_web_mm of ", t_stem_web_mm, " mm is below min_wall_mm.")),
|
||||
sb_check(t_flange_web_mm >= sb_min_wall(g) - 1e-9,
|
||||
str("T: t_flange_web_mm of ", t_flange_web_mm, " mm is below min_wall_mm.")),
|
||||
sb_check(t_junction_round_mm > 0,
|
||||
"T: t_junction_round_mm must be greater than zero. A butt joint with no fillet meets the flange along an exactly tangent boundary, which is a valid outline but cannot be tessellated.")
|
||||
], [
|
||||
sb_kv("T_FLANGE_SPAN_MM", 2 * sb_cavity_w(g) + t_flange_web_mm
|
||||
+ 2 * sb_wall_edge(g)),
|
||||
sb_kv("T_NOTE", "inside_wall unused: no enclosed bore")
|
||||
]);
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 6. Three-Fin
|
||||
// ---------------------------------------------------------------------------
|
||||
/*
|
||||
Tangential, not radial. Three straight members lie on the sides of a core
|
||||
triangle and are slid cyclically along those sides, so each stops short of
|
||||
the corner behind it and overhangs the corner ahead of it. The three
|
||||
overhangs are the fins.
|
||||
|
||||
Y three radial arms leaving a common centre
|
||||
Three-Fin three tangential sides around a core, one fin each
|
||||
|
||||
The core triangle is not a free parameter. It is solved so that the
|
||||
cyclic junctions carry the declared web AND the bore reaches its declared
|
||||
minimum, whichever demands more. The fin projection stays exactly as
|
||||
asked, because it is measured against the same solved triangle.
|
||||
|
||||
Each member's trailing end is run through the member behind it and cut off
|
||||
flush on its far face. That gives every junction a full-width overlap;
|
||||
the fillet that follows is cosmetic. In v7 the junctions were a 0.4 mm
|
||||
corner touch and the fillet was the only thing holding the part together.
|
||||
*/
|
||||
|
||||
function sb3_three_fin(g) =
|
||||
sb_fin_profile(3, three_fin_fin_mm, three_fin_web_mm,
|
||||
three_fin_bore_side_mm, three_fin_rotation_deg,
|
||||
three_fin_junction_round_mm, g, "Three-Fin");
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Catalogue
|
||||
// ---------------------------------------------------------------------------
|
||||
/*
|
||||
Only the selected builder runs, so a parameter belonging to one entry can
|
||||
never invalidate another. A 4x generator supplies its own table here and
|
||||
nothing else changes.
|
||||
*/
|
||||
|
||||
function sb3_build(name, g) =
|
||||
name == "Equilateral Triangle" ? sb3_equilateral(g)
|
||||
: name == "General Triangle" ? sb3_general_triangle(g)
|
||||
: name == "A Frame" ? sb3_a_frame(g)
|
||||
: name == "Y" ? sb3_y(g)
|
||||
: name == "T" ? sb3_t(g)
|
||||
: name == "Three-Fin" ? sb3_three_fin(g)
|
||||
: sb_profile_failed(str("Unknown profile_type: ", name));
|
||||
|
||||
profile = sb3_build(profile_type, geo);
|
||||
|
||||
// Parameters that apply to every profile, so they are checked once here.
|
||||
base_checks = [
|
||||
sb_check(strap_width_mm > 0, "strap_width_mm must be greater than zero."),
|
||||
sb_check(strap_thickness_mm > 0, "strap_thickness_mm must be greater than zero."),
|
||||
sb_check(bundle_count >= 1 && bundle_count == floor(bundle_count),
|
||||
"bundle_count must be a whole number of at least 1."),
|
||||
sb_check(fit_clearance_mm >= 0, "fit_clearance_mm cannot be negative."),
|
||||
sb_check(inside_wall_thickness_mm > 0, "inside_wall_thickness_mm must be positive."),
|
||||
sb_check(outside_wall_thickness_mm > 0, "outside_wall_thickness_mm must be positive."),
|
||||
sb_check(edge_wall_thickness_mm > 0, "edge_wall_thickness_mm must be positive."),
|
||||
sb_check(min_wall_mm > 0, "min_wall_mm must be positive."),
|
||||
sb_check(preview_length_mm > 0, "preview_length_mm must be greater than zero.")
|
||||
];
|
||||
|
||||
// Fail on the profile's own checks before touching geometry, so an
|
||||
// unbuildable arrangement reports its cause instead of a library error.
|
||||
build_status = sb_require(concat(base_checks, sb_p_checks(profile)));
|
||||
|
||||
centred = sb_centred(profile, geo);
|
||||
section = centred[SB_C_SECTION];
|
||||
members = sb_centred_members(profile, centred[SB_C_SHIFT]);
|
||||
metrics = sb_metrics(section, centred[SB_C_SHELL], members, geo);
|
||||
|
||||
status = sb_require(sb_universal_checks(section, metrics, SB_MEMBER_COUNT, geo));
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Report
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
sb_report(SB_FAMILY, profile_type, status, geo, metrics,
|
||||
model_length_mm, material_density_g_cm3,
|
||||
concat([sb_kv("REVISION", SB_REVISION),
|
||||
sb_kv("LENGTH_FT", member_length_ft),
|
||||
sb_kv("LENGTH_VIEW", length_view)],
|
||||
sb_p_info(profile)));
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Output
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
if (render_mode == "Section") {
|
||||
if (show_enclosure)
|
||||
color([0.20, 0.55, 0.95]) sb_draw_section(section);
|
||||
if (show_straps)
|
||||
color([0.96, 0.72, 0.05]) sb_draw_section(centred[SB_C_STRAPS]);
|
||||
} else {
|
||||
if (show_enclosure)
|
||||
color([0.20, 0.55, 0.95, 0.55]) sb_extrude_section(section, model_length_mm);
|
||||
if (show_straps)
|
||||
color([0.96, 0.72, 0.05, 0.82]) sb_extrude_straps(members, geo, model_length_mm);
|
||||
}
|
||||
Reference in New Issue
Block a user