Array 4-Point Adaptive Family
on TWO Curves
Select a source 3D Mass or Adaptive Component, pick two edges as array paths, configure independent spacing for each curve, then place repeated 4-adaptive-point families spanning between both curves in a single Revit transaction.
What Does This Tool Do?
The Adaptive 3D 4-Point Array tool (ArraytAdaptive3D4Points, 772 × 707 px) places repeated instances of a 4-adaptive-point Revit family spanning across two selected curves from the same 3D Mass or Adaptive Component. Every instance is anchored to four computed station points — two on Curve 1 and two on Curve 2 — so the family stretches and orients precisely between the two edges.
🔗 2-Point Tool (reference)
- 1 curve selected
- 2 adaptive points per instance (P1, P2)
- Family spans along one edge
- 1 parameter panel
🔗🔗 4-Point Tool (this guide)
- 2 curves selected — Curve 1 & Curve 2
- 4 adaptive points per instance (P1, P2, P3, P4)
- Family spans across both edges
- 2 parameter panels — one per curve
The Four Adaptive Points Explained
Each placed instance has exactly four reference points set in this order:
| Point | Source Curve | Position | Colour in docs |
|---|---|---|---|
| P1 | Curve 1 | Span start station on Curve 1 | ■ Red |
| P2 | Curve 1 | Span end station on Curve 1 (= P1 + Space − Gap) | ■ Orange |
| P3 | Curve 2 | Corresponding start point on Curve 2 | ■ Yellow |
| P4 | Curve 2 | Corresponding end point on Curve 2 | ■ Green |
3D Mass Source
Extracts all solid edges from any conceptual mass placed in the project.
Two-Curve Path
Select two independent edges as Curve 1 and Curve 2 — the family spans across both.
Live 3D Preview
Click directly on edges in the canvas to select Curve 1 then Curve 2 interactively.
Control Mode
Drive stations from Curve 1 only (auto-project onto Curve 2), or control both curves independently.
4-Point Validated
The family is confirmed to have exactly 4 adaptive points before any placement begins.
- The target family must be an Adaptive Component with exactly 4 adaptive placement points.
- The family must be loaded as a Generic Model in the Revit project before opening this tool.
comboBox3) pre-filters to show only families that pass this check.
Form Layout — Six Zones
| # | Zone | Location | Purpose |
|---|---|---|---|
| 1 | Source + Curve Selector Bar (Row 1) | Top strip, 30 px | 5 controls: Source mass picker · Curve 1 picker · ⇄ Reverse 1 · Curve 2 picker · ⇄ Reverse 2 |
| 2 | Family + Control Mode Row (Row 2) | 46 px below selector bar | Left 55%: family picker (comboBox3). Right 45%: Control option radio — "Control First Curve Only" vs "Control Both Curves" |
| 3 | 3D Canvas (Row 3 left, ~82%) | Main body left | Interactive perspective viewport. Click to select Curve 1 then Curve 2. Both selected curves highlighted live. |
| 4 | Dual Parameter Panel (Row 3 right, ~18%) | Main body right | Two stacked GroupBoxes: Curve 01 and Curve 02. Each: Start, End, Interval Space, Gap. Curve 02 disabled unless "Control Both" is selected. |
| 5 | Alignment Info (Row 4 left) | Bottom bar | Confirms source element name, both selected curve names, and instance count. |
| 6 | RUN Button (Row 4 right) | Bottom-right, 120×40 px | Cyan button — triggers 4-point validation and placement transaction. |
Select Source & Two Curves
The top selector bar has five controls in a single row. Unlike the 2-point tool which has one curve picker, this tool has two independent curve pickers — one for each rail of the array.
Select the Source Mass or Adaptive Component
The leftmost dropdown (comboBox1) lists every Adaptive Component (FamilyInstance), Wall, and Floor placed in the project. Selecting an item triggers UpdateCurveCache() which walks the element's full geometry tree — unpacking GeometryInstance objects recursively — and extracts all Solid edges via edge.AsCurve(). Curves are sorted longest first then both Curve 1 and Curve 2 dropdowns are populated from the same shared list.
Select Curve 1 — the Primary Rail
comboBox2 (red border) lists all extracted edges labelled Curve N (Length: X.XXX m, FamilyInstance) — or Edge N for mass geometry. Select the edge that will carry the P1–P2 side of each instance.
Selecting Curve 1 auto-fills the End field in the Curve 01 parameter panel: End = curve.Length × 0.3048 − 0.001 (m). The selected curve is highlighted red in the 3D canvas. A Reset button appears in the canvas area.
comboBox2), the second selects Curve 2 (sets comboBox4), then the toggle resets — so alternating clicks fill both pickers.
Select Curve 2 — the Secondary Rail
comboBox4 (yellow border) is populated with the same curve list. Select the edge that will carry the P3–P4 side of each instance — this is typically the opposite edge of the deck form (e.g., the far fascia of the cross-section).
Selecting Curve 2 auto-fills the End2 field in the Curve 02 parameter panel. The selected curve is highlighted yellow in the canvas. Both highlighted curves are now visible simultaneously for visual confirmation.
Optionally Reverse Either Curve
The two ⇄ buttons — checkBoxReverse1 (after comboBox2) and checkBoxReverse2 (after comboBox4) — are styled checkboxes that reverse their respective curve via curve.CreateReversed(). The canvas and station dots update immediately.
Select the 4-Point Adaptive Family
comboBox3 in the left half of Row 2 shows only families that have already been pre-validated to have exactly 4 adaptive points. This pre-filtering happens at form load inside PopulateComboBox3(): a rolled-back temporary transaction tests each Generic Model symbol and counts its GetInstancePlacementPointElementRefIds() result — only symbols returning count = 4 are added to the list.
Pick the 4-Point Family
The family picker (comboBox3) sits in the left 55% of Row 2, inside a GroupBox labelled "Select Family". Select the adaptive family whose four points will be set to the computed station positions. The list is sorted alphabetically and deduplicated by family name.
Runtime 4-Point Re-Validation at RUN
Even though the dropdown pre-filters, RUN performs a second check before placing anything. The steps are identical to the pre-filter: open a temporary transaction → create a test instance → count GetInstancePlacementPointElementRefIds() → roll back. If the count ≠ 4, placement is blocked with a clear error message and the model remains unchanged.
Choose the Control Mode
The Control option GroupBox (right 45% of Row 2) contains two radio buttons that determine how the Curve 2 points are computed. This is the most important conceptual choice in the whole form — it controls whether you independently drive both rails or let AutoBRIDGE project Curve 2 automatically.
Curve 2 points (P3, P4) are computed automatically by projecting perpendicular planes from Curve 1 stations onto Curve 2. You only set parameters for Curve 1. The Curve 02 parameter panel is greyed out / disabled.
- Best for parallel or near-parallel edges where cross-sectional slicing makes sense
- The form slices Curve 2 at the perpendicular cutting plane from each Curve 1 station
- Simpler to configure — only one set of Start/End/Space/Gap needed
Curve 2 points are computed from its own independent Start2/End2/Space2/Gap2 parameters. The Curve 02 parameter panel becomes fully enabled.
- Use when Curve 1 and Curve 2 have different lengths or need offset spacing
- Curve 2 uses
FindCorrespondingStation()to match nearest station then applies its own spacing - Requires careful tuning of both parameter sets to avoid twisted panels
How "Control First Curve Only" Projects Curve 2
For each Curve 1 span, the algorithm creates a perpendicular cutting plane at each station using CreatePerpendicularPlane() — the plane's normal is the local tangent of Curve 1 at that point. It then calls FindIntersectionWithPlane() which tessellates Curve 2 into line segments and finds the segment that crosses the plane. The closest intersection to the Curve 1 point is used as the Curve 2 position.
How "Control Both Curves" Drives Curve 2 Independently
When enabled, Curve 2 uses FindCorrespondingStation(): the algorithm projects each Curve 1 station onto Curve 2 to find the closest parameter, then checks if it falls within a tolerance of ½×Space2 of the suggested station. If within tolerance, it uses the projected point; if outside, it falls back to the regular incremental station. An additional offset can shift all Curve 2 stations along the curve. The result is applied within [Start2, End2] bounds.
Configure Array Parameters
The right side of the form (≈18% width) contains two stacked GroupBoxes — Curve 01 and Curve 02. Each has six fields. By default, only Curve 01 is active; Curve 02 becomes enabled when "Control Both Curves" is selected.
Set Curve 1 — Start, End, Interval Space, Gap
Start (default: 0) — station along Curve 1 where the first instance begins. End — auto-filled from curve length, can be reduced to restrict the array range. Interval Space (default: 2 m) — arc length each instance spans (distance between P1 and P2). Gap (default: 0.2 m) — empty space between consecutive instances.
After each instance, the algorithm advances by Space + Gap on Curve 1. The station componentSize = Space − Gap must be positive (enforced with an error if not).
Invalid entries turn the text box background light pink and block RUN until corrected. Valid entries restore the white background. The canvas station dots refresh on every keystroke.
Set Curve 2 Parameters (Control Both mode only)
When "Control Both Curves" is active, the Curve 02 GroupBox enables. It exposes the same four fields — Start2, End2, Interval Space2, Gap2 — but they independently control how stations are computed on Curve 2. Curve 2 can have different spacing, start offset, or sub-range from Curve 1.
The algorithm matches each Curve 1 station to the nearest Curve 2 station using FindCorrespondingStation(). If the suggested station is within ½×Space2 of the projected intersection, it snaps to the projected point. Otherwise it uses the regular incremental value.
Parameter Reference
| Parameter | Panel | Default | Unit | Description |
|---|---|---|---|---|
| Start | Curve 01 | 0 | m | First station on Curve 1. Must be ≥ 0 and < End. |
| End | Curve 01 | auto (curve length) | m | Last station on Curve 1. Auto-filled from curve length. Must be ≤ curve length. |
| Interval Space | Curve 01 | 2 | m | Arc length of each instance on Curve 1 (P1–P2 distance). Must be > 0. |
| Gap | Curve 01 | 0.2 | m | Empty gap between consecutive instances on Curve 1. Must be ≥ 0 and < Space. |
| Start2 | Curve 02 | 0 | m | First station on Curve 2 (Control Both mode only). Must be ≥ 0. |
| End2 | Curve 02 | auto (curve 2 length) | m | Last station on Curve 2 (Control Both mode only). Auto-filled from Curve 2 length. |
| Interval Space2 | Curve 02 | 2 | m | Arc length of each instance on Curve 2 (P3–P4 distance). |
| Gap2 | Curve 02 | 0.2 | m | Empty gap between consecutive instances on Curve 2. |
Reading the 3D Preview Canvas
The large pictureBox2 GDI+ canvas (background: #7D7D7D) shows a real-time perspective view of all extracted edges. In this form it renders two selected curves simultaneously in different colours, and canvas clicks alternate between selecting Curve 1 and Curve 2.
Visual Layers in the Canvas
- Fine grid — grey lines at 10 m spacing on the XY ground plane
- Coarse grid — slightly darker lines at 50 m spacing
- All form edges — white, all extracted curves before selection
- Curve 1 — highlighted red, 3 px — the edge selected in comboBox2
- Curve 2 — highlighted yellow, 3 px — the edge selected in comboBox4
- Station dots — yellow, 4 px radius — one dot per station on Curve 1 and Curve 2
- XYZ axis indicator — pinned bottom-right (X=red, Y=green, Z=blue)
Canvas Interaction — Alternating Curve Selection
Clicking on an edge in the canvas uses a selectingFirstCurve toggle flag. The first click sets Curve 1 (comboBox2), the second click sets Curve 2 (comboBox4), and the flag resets. This means clicks alternate — first selection, second selection, first selection, etc.
| Action | Input | Effect |
|---|---|---|
| Select Curve 1 | 1st left-click near any edge | Sets comboBox2, highlights red, toggles to "select Curve 2 next" |
| Select Curve 2 | 2nd left-click near any edge | Sets comboBox4, highlights yellow, resets toggle to "select Curve 1 next" |
| Orbit | Ctrl + left-drag | Rotates azimuth (0.5°/px) and elevation (0.5°/px, clamped 0.1°–179.9°) |
| Pan | Middle-button drag | Shifts viewport offset in screen space |
| Zoom | Scroll wheel | Adjusts radius by 10% per step × radius factor |
| Reset view | Double-click | Resets to azimuth=45°, elevation=70°, restores fit-radius |
fitRadius = max(extentX, extentY, extentZ) / 1.5.
Run the Placement & Validate
The cyan RUN button (120 × 40 px, button4) in the bottom-right runs a multi-stage sequence: input validation → 4-point family check → station generation → point computation → Revit transaction.
Pre-Run Checklist — What RUN Validates
Before opening any Revit transaction, RUN checks all of these in order — failing any one stops execution immediately with a clear error:
- Both curves selected —
cachedSelectedCurvePoints1andcachedSelectedCurvePoints2must both be non-null and non-empty. Error: "Please select two curves from the form edges." - Family selected —
comboBox3.SelectedItemmust not be null. Error: "Please select an adaptive family with 4 points." - Family found in document — searches by exact name match. Error if not found.
- Family symbol exists — retrieves the first FamilySymbol from the Family's symbol IDs.
- 4-point re-validation — rolls back a temporary transaction. If adaptive point count ≠ 4: "The family must be an adaptive component with exactly 4 adaptive points."
- Valid station ranges — Start/End/Space/Gap are parsed and checked for logical validity. Invalid values show specific error dialogs.
Review the Alignment Info Bar and Click RUN
The Alignment info GroupBox at the bottom confirms the active mass element name and both selected curves. Verify this before clicking RUN.
Placement — One Transaction, Four Points Per Instance
Inside the transaction "Place Multiple Adaptive Components", for each station range the code retrieves 4 XYZ positions from the pre-computed list — indices i×4, i×4+1, i×4+2, i×4+3 — and assigns them:
rp1.Position = point1→ P1 — Curve 1 span startrp2.Position = point2→ P2 — Curve 1 span endrp3.Position = point3→ P3 — Curve 2 corresponding startrp4.Position = point4→ P4 — Curve 2 corresponding end
A progress bar tracks execution from 0→30% (station computation) → 30→80% (instance placement loop) → 100% (commit). If a single instance fails due to geometry, it is silently skipped via continue and placement resumes with the next span.
Troubleshooting
| Symptom | Likely Cause | Fix |
|---|---|---|
| comboBox1 is empty | No 3D Mass, Adaptive Component, Wall, or Floor in the project | Place at least one mass or adaptive family instance before opening the form |
| comboBox2 / comboBox4 empty after selecting source | Element geometry has no extractable solid edges | Ensure the mass has a resolved solid form. The tool uses IncludeNonVisibleObjects=true but still needs a valid active view. |
| comboBox3 is empty | No Generic Model family with exactly 4 adaptive points is loaded | Load a 4-point adaptive family into the project before opening the form |
| RUN rejects — "Please select two curves" | Only one or zero curves are selected | Select both Curve 1 (comboBox2) and Curve 2 (comboBox4) — or use two canvas clicks |
| Instances are twisted / diagonal | Curve 1 and Curve 2 run in opposite directions | Tick the ⇄ Reverse checkbox for one of the curves until the canvas shows parallel station dots |
| Only P1/P2 placed correctly; P3/P4 at wrong position | Curves have very different lengths; "Control First Curve Only" perpendicular projection misses Curve 2 | Switch to "Control Both Curves" and set independent Start2/End2 parameters |
| Curve 02 parameter panel is greyed out | "Control First Curve Only" radio is active (default) | Select "Control Both Curves" radio button to enable the Curve 02 panel |
| Station dots visible only on Curve 1, not Curve 2 | Curve 2 not yet selected | Select Curve 2 from comboBox4, or click a second edge in the canvas |
| "Spacing must be greater than Gap" error | Gap ≥ Space (componentSize ≤ 0) | Ensure Interval Space > Gap for the affected curve panel |
| Progress bar stalls; no result dialog | Station point generation returned 0 ranges | Check that Start < End and Space fits at least once within the range; verify curve lengths in the Alignment info bar |
Complete Workflow Summary
| Step | Action | Result |
|---|---|---|
| 1 | Select source from comboBox1 | Canvas draws all edges; both curve dropdowns populated |
| 2 | Select Curve 1 (comboBox2 or 1st canvas click) | Red highlight; End auto-filled in Curve 01 panel |
| 3 | Select Curve 2 (comboBox4 or 2nd canvas click) | Yellow highlight; End2 auto-filled in Curve 02 panel |
| 4 | Optionally reverse either curve with ⇄ | Highlight direction flips; station dots update |
| 5 | Select 4-point family from comboBox3 | Family confirmed to have 4 points at form load |
| 6 | Choose Control mode (radio buttons) | "Control First Only" — Curve 02 disabled; "Control Both" — Curve 02 enabled |
| 7 | Set Curve 01 parameters (Start/End/Space/Gap) | Station dots update live; pink background on invalid entry |
| 8 | If "Control Both" — set Curve 02 parameters | Curve 2 station dots update; must be logically valid |
| 9 | Orbit/pan canvas; verify both highlighted curves and dot pattern | Faint blue rectangles show each instance's four-corner span |
| 10 | Verify Alignment info bar (element · Curve 1 ↔ Curve 2 · count) | Confirms configuration before committing |
| 11 | Click RUN | 6-stage validation → station computation → Revit transaction → N instances placed |