FCS Classes, Blocks & Distributions
This document covers parametric geometry classes, instantiation, and distribution patterns.
GClass (Geometry Class)
A gclass defines a reusable parametric component loaded from an external file.
Basic Syntax
gclass {name} filename "<file.fcs>" parameters { param1 := value1, param2 := value2 }
Components
| Part | Description |
|---|---|
{name} |
Identifier for the class |
filename |
Path to .fcs file (relative or absolute) |
parameters |
Optional parameter overrides |
Examples
# Simple class from file
gclass 1 filename ("Hoop.fcs") parameters {D = D, aC = aC, bC = bC, rC = rC}
# Named class
gclass {gCss} filename "css\I_profile_rotated.fcs"
# Class with dynamic filename
gclass {gCss} filename ("css\"+Css_ID+".fcs")
# Hierarchical loading (relative paths)
gclass {gBeamPartDistribution} filename "BeamPartDistribution.fcs"
Resources Pattern
Common pattern for loading shared resources:
gclass {res} filename "_FcsComponentResources.fcs"
# Then access resources via:
myStyle := res.defaults.LabelStyle
GBlock (Geometry Block)
A gblock instantiates a gclass with a specific local coordinate system and parameters.
Basic Syntax
gblock {name} gclass {gclass_name} lcs <coordinate_system> parameters { ... }
With Conditional
gblock {name} gclass {class} lcs (Lcs) if (condition) parameters { ... }
LCS (Local Coordinate System) Options
# Global coordinate system
lcs GCS
# Explicit origin and axes
lcs {Origin={0,0,0}, Axes=GCS.Axes}
# Transformed GCS
lcs (GCS.Tz(height).Rx(angle))
# Complex transformation
lcs {Origin={x,y,z}, Axes=GCS.Axes.Ry(-PI/2)}
Parameter Binding
# Direct values
parameters {h := 0.3}
# Expression values
parameters {length := BeamLength.Sum, angle := RoofAngle}
# Array element binding
parameters {Length := BeamLength[i], Height := Heights[i+1]}
Complete Examples
# Positioned cross-section
gclass {gCss} filename "css\I_profile_rotated.fcs"
gblock {gbCss1} gclass {gCss} lcs {Origin={gbCss1.h/2,0,0},Axes={GCS.Axes}} parameters {h:=0.3}
# Multiple instances with different positions
gblock {gbColumn} gclass {gBeamPart} lcs {Origin={0,0,0}, Axes=GCS.Axes.Ry(-PI/2)} parameters {BeamLength:=ColumnLength}
gblock {gbRafter} gclass {gBeamPart} lcs {Origin={0,0,ColumnLength.Sum}, Axes=GCS.Axes.Ry(RoofAngle)} parameters {BeamLength:=RafterLength}
# Mirrored instance
gblock {gbFramePartLeft} gclass {gFramePart} lcs GCS
gblock {gbFramePartRight} gclass {gFramePart} lcs {Origin={Span,0,0},Axes={GCS.Axes.Rz(PI)}}
# Conditional instantiation
gblock {gbArrow} gclass {ArrowForce} lcs (Lcs.Ry(-PI/2)) if (Fx != 0) parameters { Length := Fx/maxFM*Length }
Self-Reference Pattern
GBlocks can reference their own exported properties:
gblock {gbCss1} gclass {gCss} lcs {Origin={gbCss1.h/2,0,0},Axes={GCS.Axes}} parameters {h:=0.3}
# ^^^^^^^^^ self-reference to h property
Distribution
Distributions create repeated instances of geometry with specified transformations.
Basic Syntax
distribution {name} geometries {geom1} {geom2} repetitions count <n>
Full Syntax
distribution {name} gclass {class} lcs {lcs}
transformation translation direction {x,y,z}
repetitions count (expression) spacings <array>
specialization ithparameters { ... }
Components
| Part | Description |
|---|---|
geometries |
List of geometries to distribute |
gclass |
Class to instantiate repeatedly |
transformation |
Type: translation, rotation |
direction |
Direction vector for translation |
repetitions count |
Number of repetitions |
spacings |
Array of spacing distances |
ithparameters |
Parameters varying per instance |
Simple Distribution
# Distribute geometries between two endpoints
distribution 1 geometries {hoopTop} {hoopBottom} repetitions count nHoops
Linear Array Distribution
distribution {dBeam} gclass {gBeam}
lcs {Origin={0,0,0}, Axes=GCS.Axes}
transformation translation direction {1,0,0}
repetitions count (BeamLength.Count)
spacings BeamLength
specialization ithparameters {
Length := BeamLength[ith.i],
HeadCut := ((ith.i==0) ? (HeadCut) : 0),
Headh := Heights[ith.i],
Endh := Heights[ith.i+1]
}
The ith Object
Inside ithparameters, the special ith object provides iteration context:
ith.i- Current iteration index (0-based)ith.n- Total count
ithparameters {
index := ith.i,
isFirst := (ith.i == 0),
isLast := (ith.i == ith.n - 1)
}
Distribution Examples
# Cage structure with distributed vertical bars
distribution 5 geometries {b2} {v10} repetitions count 4
distribution 6 geometries {b3} {v11} repetitions count 4
# Variable-spaced beam segments
BeamLength := [2.25, 2, 2, 2]
distribution {dBeam} gclass {gBeam}
transformation translation direction {1,0,0}
repetitions count (BeamLength.Count)
spacings BeamLength
Traction (Lofted Geometry)
Tractions create swept/lofted geometry between cross-sections.
Syntax
traction {name} sections {section1, section2, ...} layer {layer}
Example
# Variable I-beam with changing cross-sections
gblock {gbCss1} gclass {gCss} parameters {h := 0.3}
gblock {gbCss2} gclass {gCss} parameters {h := 0.8}
gblock {gbCss3} gclass {gCss} parameters {h := 0.3}
traction {tBeam1} sections {gbCss1, gbCss2} layer {Primary}
traction {tBeam2} sections {gbCss2, gbCss3} layer {Primary}
This creates a beam with web height varying from 0.3 to 0.8 to 0.3.
Label
Labels create 3D text annotations.
Syntax
label {name} lcs { Origin, Axes } text "<format>" arguments {arg1, arg2} layer (layer) styles [style1, style2]
Format Strings
Uses .NET composite formatting:
{0}- First argument{1}- Second argument{0:0.00}- Number with 2 decimal places{0:#,##0}- Number with thousand separators
Example
LabelString := "GA 15"
label {lLabel} lcs {
Origin = { 0, 0, 0 },
Axes = GCS.Axes
} text "{1}{0:0}" arguments {LabelString, ""} layer (LabelStyle.Layer) styles [ LabelStyle.TextStyle, LabelStyle.ViewStyle ]
Style
Styles define visual properties for geometry.
Text Style Properties
TextStyle := {
Size := 12,
Font := "Arial",
Color := Red
}
View Style Properties
ViewStyle := {
LineWidth := 2,
LineType := Solid
}
Usage with Labels
styles [ TextStyle, ViewStyle ]
Layer
Layers organize geometry and control visibility/appearance.
Syntax
layer {name} color <color>
Colors
Built-in color names: Red, Green, Blue, Orange, Yellow, White, Black, Lime, etc.
Examples
layer {Primary} color Orange
layer {lLoadLayer} color Lime
layer {structural} color Blue
# Assign geometry to layer
vertex {v1} xyz 0 0 0 layer {Primary}
Filleted Polyline Curves
Creates polyline curves with optional filleted corners.
Syntax
curve {name} filletedpoly radiusmultiplier <mult> vertexes {v1} {v2} ... fillets <r1> <r2> ...
Components
| Part | Description |
|---|---|
radiusmultiplier |
Scales all fillet radii |
vertexes |
Ordered list of vertices |
fillets |
Fillet radius at each vertex (0 = sharp corner) |
Examples
# I-beam cross-section with rounded corners
curve 1 filletedpoly radiusmultiplier 1
vertexes 1 2 3 4 5 6 7 8 9 10 11 12 1
fillets 0 0 r2 r1 r1 r2 0 0 r2 r1 r1 r2 0
# Rectangle with rounded corners
curve {c1} filletedpoly radiusmultiplier 0
vertexes {v1} {v2} {v3} {v4} {v1}
fillets 1 1 1 1 1
# Polyline with selective filleting
curve 1 filletedpoly radiusmultiplier 0.15
vertexes 1 2 3
fillets 0 1 0 # Only middle vertex is filleted
Complete Parametric Example
# Welded portal frame with variable cross-sections
# Parameters
L := 8 # Span
hL := 4 # Left column height
hP := 5 # Peak height
hR := 6 # Right column height
alfaL := Atan((hP-hL)/(L/2))
alfaR := Atan((hP-hR)/(L/2))
# Layer
layer {Primary} color Orange
# Frame geometry
vertex 1 xyz 0 0 0
vertex 2 xyz 0 0 hL
vertex 3 xyz (L/2) 0 hP
vertex 4 xyz L 0 hR
vertex 5 xyz L 0 0
curve 1 vertex 1 2
curve 2 vertex 2 3
curve 3 vertex 3 4
curve 4 vertex 4 5
# Cross-section class
gclass {gCss} filename "css\I_profile_rotated.fcs"
# Variable cross-sections at key locations
gblock {gbCss1} gclass {gCss} lcs {Origin={0.15,0,0}, Axes=GCS.Axes} parameters {h:=0.3}
gblock {gbCss2} gclass {gCss} lcs {Origin={0,0,hL}, Axes=GCS.Axes.Ry(-alfaL/2)} parameters {h:=0.8}
gblock {gbCss3} gclass {gCss} lcs {Origin={L/2,0,hP}, Axes=GCS.Axes.Ry(PI/2)} parameters {h:=0.3}
gblock {gbCss4} gclass {gCss} lcs {Origin={L,0,hR}, Axes=GCS.Axes.Ry(PI+alfaR/2)} parameters {h:=0.8}
gblock {gbCss5} gclass {gCss} lcs {Origin={L-0.15,0,0}, Axes=GCS.Axes.Ry(PI)} parameters {h:=0.3}
# Lofted beam segments between cross-sections
traction {tBeam1} sections {gbCss1, gbCss2} layer {Primary}
traction {tBeam2} sections {gbCss2, gbCss3} layer {Primary}
traction {tBeam3} sections {gbCss3, gbCss4} layer {Primary}
traction {tBeam4} sections {gbCss4, gbCss5} layer {Primary}
Best Practices
1. Parameter Organization
Group related parameters and use descriptive names:
# Geometry parameters
BeamLength := [2.25, 2, 2, 2]
BeamCssHeights := [0.54, 0.28, 0.24, 0.28, 0.36]
# Analysis parameters
meshSize := 0.1
loadCase := "Dead"
2. Class Hierarchy
Structure components in folders:
project/
├── main.fcs
├── css/ # Cross-sections
│ ├── I_profile.fcs
│ └── 2C_profile.fcs
├── components/ # Reusable components
│ ├── BeamPart.fcs
│ └── Connection.fcs
└── _Resources.fcs # Shared resources
3. Conditional Instantiation
Use if to conditionally create geometry:
gblock {beam} gclass {gBeam} lcs (Lcs) if (isBeamEnabled) parameters { ... }
4. Array-Driven Distributions
Use arrays for variable repetitions:
lengths := [2.0, 2.5, 3.0, 2.5, 2.0]
distribution {d} gclass {gc}
transformation translation direction {1,0,0}
repetitions count (lengths.Count)
spacings lengths
Summary Table
| Keyword | Purpose |
|---|---|
gclass |
Define parametric component from file |
gblock |
Instantiate gclass with position/params |
distribution |
Create repeated instances |
traction |
Loft geometry between sections |
layer |
Organize geometry, control appearance |
label |
Create 3D text annotation |
style |
Define visual properties |
filletedpoly |
Polyline curve with rounded corners |
Zero-Spacing Distribution (Absolute Coordinate Trick)
When each distribution segment computes its own absolute world coordinates from its index (e.g. helix, spiral staircase), you do not want the distribution to add any translation. Use an array of zeros as the spacings:
# nSeg segments; array length = nSeg - 1 (one fewer than count)
spacingIndices := Fcs.Converters.EnumerableRange(nSeg - 1)
zeroSpacings := spacingIndices.Select(i => 0.0)
distribution {dSpring} gclass {gcSeg} lcs (GCS)
transformation translation direction {0, 0, 1}
repetitions count (nSeg)
spacings (zeroSpacings)
specialization ithparameters {idx := ith.i, R := R, dTheta := dTheta, dZ := dZ}
Inside gcSeg each segment uses idx to compute its own helix coordinates:
# HelixSegment.fcs (the gcSeg gclass)
theta0 := idx * dTheta
x0 := R * Cos(theta0)
y0 := R * Sin(theta0)
z0 := idx * dZ
vertex {vStart} xyz x0 y0 z0
Key points:
Fcs.Converters.EnumerableRange(n)returns[0, 1, 2, …, n-1](n elements).spacingslength must equalrepetitions count - 1, so passEnumerableRange(count - 1).Select(…).- The distribution still applies the LCS origin once; the spacings just add no further translation.
Per-Index Parameter Arrays
Use Fcs.Converters.EnumerableRange + .Select() to compute per-instance arrays for
tapered or otherwise varying distributions:
# TrussTower.fcs — tapered lattice tower with nPanels panels
panelIndices := Fcs.Converters.EnumerableRange(nPanels)
# Width at bottom and top of each panel (linear taper)
panelWBots := panelIndices.Select(i => baseWidth - (baseWidth - topWidth) * i / nPanels)
panelWTops := panelIndices.Select(i => baseWidth - (baseWidth - topWidth) * (i + 1) / nPanels)
# Spacing array for distribution (uniform panel height)
panelHeights := panelIndices.Select(i => panelHeight)
distribution {dTower} gclass {gPanel} lcs (GCS)
transformation translation direction {0, 0, 1}
repetitions count (nPanels)
spacings (panelHeights)
specialization ithparameters {
wBot := panelWBots[ith.i],
wTop := panelWTops[ith.i],
hPanel := panelHeight,
}
The [ith.i] subscript inside ithparameters is the standard way to look up the
i-th element of a pre-computed array.
Profile Orientation Reference
Cross-section profiles are defined in the local XZ plane (Y = 0, normal = local Y)
by convention. The Axes= parameter on a gblock rotates that local frame into world
space so the profile face is perpendicular to the intended member axis.
Member along Y (default beam axis)
No rotation needed — local Y is the beam axis, profile lies in XZ plane:
gblock {gbRoot} gclass {gXCss} lcs {Origin={0,0,0}, Axes=GCS.Axes} parameters {…}
Member along Z (vertical leg)
Rx(PI/2) rotates the local frame so local Y → global Z. The profile (still in the
local XZ plane) ends up in the global XY plane — perpendicular to the Z axis:
gblock {csBot} gclass {gXCss} lcs {Origin={x, y, 0}, Axes=GCS.Axes.Rx(PI/2)} parameters {…}
Member along a slope (rafter at angle α to horizontal)
Ry(α) tilts the local Y axis from horizontal to the slope direction. The profile
stays perpendicular to the rafter axis:
gblock {gbCss} gclass {gHEA} lcs {Origin={…}, Axes=GCS.Axes.Ry(roofAngle)} parameters {…}
Cladding panels (wall / roof sheets)
Wall panels in the YZ plane (X = const face, running along Y):
distribution {dWall} … lcs {Origin={0,0,0}, Axes=GCS.Axes.Rz(PI/2)} …
Roof left slope (tilt from vertical by roofAngle, then swing to Y direction):
distribution {dRoofL} … lcs {Origin={0,0,wallH}, Axes=GCS.Axes.Ry(PI/2 - roofAngle).Rz(PI/2)} …
Roof right slope (opposite tilt):
distribution {dRoofR} … lcs {Origin={span,0,wallH}, Axes=GCS.Axes.Ry(roofAngle - PI/2).Rz(PI/2)} …
Matrix form LCS (arbitrary rotation)
For profiles that require a fully arbitrary orientation, use the lcs … matrix form:
vertex {v0} xyz 0 0 0
lcs {lcsFrame} origin {v0} matrix 0 0 1 (-1) 0 0 0 (-1) 0
gblock {gb1} gclass {gHEA} lcs {lcsFrame} parameters {h=h}
The nine numbers are the rows of the 3×3 rotation matrix: [row0] [row1] [row2].
Directional Placement with Rz
Objects typically face local −Y by default (backrest / opening at +Y). Rz rotations re-orient placed instances:
# Faces +Y (object rotated 180°)
gblock {gbSW} gclass {gcChair} lcs (GCS.Ty(swY).Rz(PI))
# Faces −X (rotate 90° clockwise when viewed from above)
gblock {gbD1} gclass {gcChair} lcs (GCS.Tx(x).Ty(y).Rz(-PI/2))
# Faces +X (rotate 90° anticlockwise)
gblock {gbD4} gclass {gcChair} lcs (GCS.Tx(x).Ty(y).Rz(PI/2))
# Faces −Y (default, no rotation needed)
gblock {gbD7} gclass {gcChair} lcs (GCS.Ty(d7Y))
Imperial Unit Constants (for Benchmarking)
When validating against RISA/AISC results in US units:
ft := 0.3048 # feet → metres
ksi := 6894757.0 # ksi → Pa
kft := 14593.903 # kips/ft → N/m
kip := 4448.222 # kips → N
in2 := 6.4516E-4 # in² → m²
in4 := 4.162314E-7 # in⁴ → m⁴
Power Operator
FCS supports the ** operator for exponentiation (in addition to Pow()):
rafterLength := Sqrt(halfSpan**2 + ridgeRise**2)