| name | thatopen-impl-clipping-plans |
| description | Use when adding clipping planes, floor plan views, or cross-section visualization to a ThatOpen BIM viewer. Prevents using deprecated v2 Plans/ClipEdges patterns. Covers Clipper (create, delete, drag), ClipStyler (styles, createFromView, createFromClipping), View system, Plan camera mode, edge visualization, programmatic plane creation. Keywords: clipper, clipping, plane, section, floor plan, clip edges, clip styler, view, cut, cross section, slice model, cut through building, show floor plan.
|
| license | MIT |
| compatibility | Designed for Claude Code. Requires @thatopen/components 3.3.x. |
| metadata | {"author":"OpenAEC-Foundation","version":"1.0"} |
ThatOpen Clipping Planes & Floor Plans
Overview
Clipping planes slice through 3D BIM geometry to reveal internal structure.
Floor plan views combine clipping planes with styled edge visualization and
a top-down camera. In ThatOpen v3, three components work together:
| Component | Package | Role |
|---|
Clipper | @thatopen/components | Creates and manages clipping planes |
ClipStyler | @thatopen/components-front | Adds styled edge/fill visualization to clips |
Views | @thatopen/components | Manages named section views with camera sync |
v2 to v3 BREAKING CHANGE: The Plans component and standalone ClipEdges
component from v2 are removed. ALWAYS use ClipStyler + Views in v3.
See the migration section at the bottom of this file.
Prerequisites
- World with
OrthoPerspectiveCamera and renderer (see thatopen-impl-viewer)
- Model loaded via
FragmentsManager (see thatopen-syntax-ifc-loading)
- For styled edges:
@thatopen/components-front and LineMaterial from
three/examples/jsm/lines/LineMaterial.js
import * as OBC from "@thatopen/components";
import * as OBF from "@thatopen/components-front";
import * as THREE from "three";
import { LineMaterial } from "three/examples/jsm/lines/LineMaterial.js";
1. Clipper: Creating Clipping Planes
The Clipper component creates and manages SimplePlane instances that clip
the scene geometry. It lives in @thatopen/components (works in browser and
Node.js).
Setup
const clipper = components.get(OBC.Clipper);
clipper.enabled = true;
Interactive Creation (Raycast-Based)
Create a clipping plane where the user clicks on geometry:
container.ondblclick = () => {
if (clipper.enabled) {
clipper.create(world);
}
};
create(world) casts a ray from the current mouse position, finds the
intersection point and surface normal, and places a draggable plane there.
Returns Promise<SimplePlane | null> (null if no intersection).
Programmatic Creation
Create a plane at an exact position and orientation:
const normal = new THREE.Vector3(0, -1, 0);
const point = new THREE.Vector3(0, 3.5, 0);
const planeId = clipper.createFromNormalAndCoplanarPoint(world, normal, point);
Returns the string ID of the created plane. Use this ID with
ClipStyler.createFromClipping() to add edge visualization.
Deletion
await clipper.delete(world);
await clipper.delete(world, planeId);
clipper.deleteAll();
clipper.deleteAll(new Set(["floor-plans"]));
Keyboard Shortcut Pattern
window.onkeydown = (event) => {
if (event.code === "Delete" || event.code === "Backspace") {
clipper.delete(world);
}
};
Properties
| Property | Type | Default | Description |
|---|
enabled | boolean | false | Enables/disables the clipper |
visible | boolean | true | Shows/hides all plane helpers |
size | number | 5 | Geometric size of plane helpers |
material | MeshBasicMaterial | — | Material for plane helpers |
orthogonalY | boolean | false | Forces planes orthogonal to Y |
toleranceOrthogonalY | number | 0.7 | Threshold for Y orthogonality |
autoScalePlanes | boolean | true | Scale planes based on camera distance |
Events
Key events (see references/methods.md for full list):
| Event | Payload | When |
|---|
onAfterCreate | SimplePlane | After plane is created |
onBeforeDrag | SimplePlane | Drag operation starts |
onAfterDrag | SimplePlane | Drag operation ends |
onAfterDelete | SimplePlane | After plane is deleted |
clipper.onAfterCreate.add((plane) => {
console.log("Created plane:", plane.three.normal, plane.three.constant);
});
SimplePlane Instance
Each plane in clipper.list is a SimplePlane with properties: three
(THREE.Plane), origin, normal, enabled, visible, size, type,
controls (TransformControls). Key method:
setFromNormalAndCoplanarPoint(normal, point) to reposition.
See references/methods.md for full API.
2. ClipStyler: Styled Edge Visualization
ClipStyler adds colored edge outlines and fill materials to clipping planes.
It lives in @thatopen/components-front (browser-only).
Setup
const clipStyler = components.get(OBF.ClipStyler);
clipStyler.world = world;
ALWAYS set .world before creating any styled edges.
Defining Styles
Styles are named combinations of line material and fill material:
clipStyler.styles.set("ArchBlue", {
linesMaterial: new LineMaterial({ color: 0x000000, linewidth: 2 }),
fillsMaterial: new THREE.MeshBasicMaterial({
color: 0xadd8e6,
side: THREE.DoubleSide,
}),
});
clipStyler.styles.set("StructRed", {
linesMaterial: new LineMaterial({ color: 0xff0000, linewidth: 3 }),
fillsMaterial: new THREE.MeshBasicMaterial({
color: 0xffcccc,
side: THREE.DoubleSide,
}),
});
ALWAYS define styles BEFORE calling any create* method.
Creating Styled Edges from a Clipping Plane
Link edge visualization to an existing Clipper plane by its ID:
clipper.list.onItemSet.add(({ key }) => {
clipStyler.createFromClipping(key, {
items: {
All: { style: "ArchBlue" },
},
});
});
Creating Styled Edges from a View
Link edge visualization to a View (camera-synced section):
const views = components.get(OBC.Views);
const sectionView = views.create(
new THREE.Vector3(0, -1, 0),
new THREE.Vector3(0, 1.5, 0),
);
clipStyler.createFromView(sectionView, {
items: {
Walls: {
style: "ArchBlue",
data: { "BuildingElement.Class": ["IFCWALL", "IFCWALLSTANDARDCASE"] },
},
Structure: {
style: "StructRed",
data: { "BuildingElement.Class": ["IFCSLAB", "IFCCOLUMN"] },
},
},
});
Creating Styled Edges from a Raw Plane
const rawPlane = new THREE.Plane(new THREE.Vector3(0, -1, 0), 3.5);
const edges = clipStyler.create(rawPlane, {
items: { All: { style: "ArchBlue" } },
});
ClipEdgesCreationConfig
interface ClipEdgesCreationConfig {
link?: boolean;
id?: string;
world?: OBC.World;
items?: Record<string, ClipEdgesItemStyle>;
}
interface ClipEdgesItemStyle {
style: string;
data?: OBC.ClassifierIntersectionInput;
}
Visibility Control
clipStyler.visible = false;
clipStyler.visible = true;
See references/methods.md for full ClipEdges instance API.
3. Views: Named Section Views
The Views component manages named orthogonal section views. Each view has
a primary clipping plane, a far clipping plane, and a camera configuration.
Setup
const views = components.get(OBC.Views);
views.world = world;
Creating Views
const floorView = views.create(
new THREE.Vector3(0, -1, 0),
new THREE.Vector3(0, 1.5, 0),
{ id: "floor-1" },
);
const plane = new THREE.Plane(new THREE.Vector3(0, -1, 0), 1.5);
const sectionView = views.createFromPlane(plane, { id: "section-A" });
const storeyViews = await views.createFromIfcStoreys({
offset: 0.25,
});
const elevationViews = await views.createElevations({
combine: true,
});
Opening and Closing Views
views.open("floor-1");
views.close("floor-1");
views.close();
if (views.hasOpenViews) { }
View Instance
Key properties: id, plane (THREE.Plane), farPlane, camera
(OrthoPerspectiveCamera), open (boolean), range (distance between
front/back planes, default 15), planesEnabled, helpersVisible.
Methods: update(), flip(), dispose().
See references/methods.md for full View API.
4. Complete Floor Plan Workflow
This is the canonical pattern for creating a floor plan view with styled edges.
import * as OBC from "@thatopen/components";
import * as OBF from "@thatopen/components-front";
import * as THREE from "three";
import { LineMaterial } from "three/examples/jsm/lines/LineMaterial.js";
const clipStyler = components.get(OBF.ClipStyler);
clipStyler.world = world;
clipStyler.styles.set("Default", {
linesMaterial: new LineMaterial({ color: 0x000000, linewidth: 2 }),
fillsMaterial: new THREE.MeshBasicMaterial({
color: 0xf0f0f0,
side: THREE.DoubleSide,
}),
});
const views = components.get(OBC.Views);
views. = world;
storeyViews = views.({
: ,
});
( [id, view] views.) {
clipStyler.(view, {
: {
: { : },
},
});
}
views.();
world...();
Returning to 3D
views.close();
await world.camera.projection.set("Perspective");
world.camera.set("Orbit");
5. Programmatic Section Workflow
For a quick section cut without the View system:
const clipper = components.get(OBC.Clipper);
clipper.enabled = true;
const planeId = clipper.createFromNormalAndCoplanarPoint(
world,
new THREE.Vector3(0, -1, 0),
new THREE.Vector3(0, 3.0, 0),
);
const clipStyler = components.get(OBF.ClipStyler);
clipStyler.world = world;
clipStyler.styles.set("Section", {
linesMaterial: new LineMaterial({ color: 0x000000, linewidth: 2 }),
});
clipStyler.createFromClipping(planeId, {
items: { All: { style: "Section" } },
});
clipper.visible = false;
6. Per-Category Styling
Use multiple styles and ClipEdgesItemStyle.data to apply different edge
colors per IFC element type. The data field uses
ClassifierIntersectionInput (same format as Classifier.find()).
See references/examples.md example 6 for full code.
7. v2 to v3 Migration
| v2 Pattern | v3 Replacement | Notes |
|---|
Plans component | Views + ClipStyler.createFromView() | Complete redesign |
ClipEdges component (standalone) | ClipStyler.create/createFromClipping() | Now managed by ClipStyler |
plans.create(planConfig) | views.create(normal, point) | Different API shape |
plans.goTo(planId) | views.open(viewId) | Renamed |
plans.exitPlanView() | views.close() | Renamed |
| Manual edge geometry | ClipEdgesCreationConfig | Declarative config |
clipEdges.visible = true | clipStyler.visible = true | Managed through ClipStyler |
NEVER use Plans or standalone ClipEdges imports — they do not exist in v3.
ALWAYS use Views + ClipStyler for floor plan and section visualization.
Critical Rules
- ALWAYS set
clipStyler.world = world before creating styled edges.
- ALWAYS define styles in
clipStyler.styles before calling create*.
- NEVER use
Plans or standalone ClipEdges from v2 — they are removed.
- ALWAYS use
ClipStyler for edge visualization in v3.
- ALWAYS call
clipper.enabled = true before creating planes.
- ALWAYS use
views.open(id) to activate a view — it handles camera
switching and plane activation automatically.
- NEVER manually position the camera for floor plans when using Views —
views.open() handles this.
- ALWAYS dispose clipping resources when done:
clipper.deleteAll() and
clipStyler.dispose().
- ALWAYS use
LineMaterial from three/examples/jsm/lines/LineMaterial.js
for edge line styles — regular LineBasicMaterial does not support linewidth.
- NEVER forget to await
projection.set() — it returns a Promise.
Reference Files
- references/methods.md — Full API signatures for
Clipper, ClipStyler, ClipEdges, Views, View, SimplePlane
- references/examples.md — Basic clipping, floor
plan, styled edges, programmatic sections
- references/anti-patterns.md — v2 patterns,
missing ClipStyler setup, common mistakes
Source Verification
All API signatures verified against:
- GitHub:
ThatOpen/engine_components main branch
(packages/core/src/core/Clipper/, packages/front/src/core/ClipStyler/,
packages/core/src/core/Views/)
- Examples:
Clipper/example.ts, ClipStyler/example.ts
- Research:
docs/research/vooronderzoek-thatopen.md Sections 2.6, 2.8, 6