Skip to content

Commit c878d75

Browse files
Solid Shapes and Doc Update
1 parent 7132db8 commit c878d75

56 files changed

Lines changed: 2331 additions & 686 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
---
2626

27-
> **Actively under development.** We're building OpenGeometry in the open. APIs, examples, and package structure are evolving — breaking changes are still possible. Star the repo to follow along.
27+
> **Actively maintained and growing.** We're building OpenGeometry in the open. APIs, examples, and package structure are evolving, we are actively improving and expanding the project. Star the repo to follow along. If you have questions or want to get involved, join the [Discord](https://discord.com/invite/cZY2Vm6E) or check out the [issues](https://github.com/OpenGeometry-io/OpenGeometry/issues)
2828
2929
---
3030

docs/api/export/pdf.mdx

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -226,14 +226,34 @@ The OGSceneManager provides a convenience method that projects and exports in on
226226
**Example (Node.js):**
227227

228228
```javascript
229-
const { OGSceneManager, OGCuboid, Vector3 } = require("opengeometry");
229+
import { OpenGeometry, OGSceneManager, Cuboid, Vector3 } from "opengeometry";
230+
231+
await OpenGeometry.create({ wasmURL: "/opengeometry_bg.wasm" });
232+
233+
function toBrepSerialized(source) {
234+
const value =
235+
source && typeof source.getBrepSerialized === "function"
236+
? source.getBrepSerialized()
237+
: source && typeof source.getBrepData === "function"
238+
? source.getBrepData()
239+
: source && typeof source.getBrep === "function"
240+
? source.getBrep()
241+
: source;
242+
243+
return typeof value === "string" ? value : JSON.stringify(value);
244+
}
230245

231246
const manager = new OGSceneManager();
232247
const sceneId = manager.createScene("My Model");
233248

234-
const cuboid = new OGCuboid("origin");
235-
cuboid.set_config(new Vector3(0, 0, 0), 10.0, 8.0, 6.0);
236-
manager.addCuboidToScene(sceneId, "box", cuboid);
249+
const cuboid = new Cuboid({
250+
center: new Vector3(0, 0, 0),
251+
width: 10.0,
252+
height: 8.0,
253+
depth: 6.0,
254+
color: 0x10b981,
255+
});
256+
manager.addBrepEntityToScene(sceneId, "box", "Cuboid", toBrepSerialized(cuboid));
237257

238258
const camera = {
239259
position: { x: 15, y: 12, z: 15 },

docs/api/export/projection.mdx

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -257,14 +257,34 @@ Projects a 3D BRep to a 2D scene.
257257
**Example:**
258258

259259
```javascript
260-
import { OGCuboid, OGSceneManager, Vector3 } from "opengeometry";
260+
import { OpenGeometry, Cuboid, OGSceneManager, Vector3 } from "opengeometry";
261+
262+
await OpenGeometry.create({ wasmURL: "/opengeometry_bg.wasm" });
263+
264+
function toBrepSerialized(source) {
265+
const value =
266+
source && typeof source.getBrepSerialized === "function"
267+
? source.getBrepSerialized()
268+
: source && typeof source.getBrepData === "function"
269+
? source.getBrepData()
270+
: source && typeof source.getBrep === "function"
271+
? source.getBrep()
272+
: source;
273+
274+
return typeof value === "string" ? value : JSON.stringify(value);
275+
}
261276

262277
const manager = new OGSceneManager();
263278
const sceneId = manager.createScene("Projection Test");
264279

265-
const cuboid = new OGCuboid("origin");
266-
cuboid.set_config(new Vector3(0, 0, 0), 5.0, 3.0, 2.0);
267-
manager.addCuboidToScene(sceneId, "box", cuboid);
280+
const cuboid = new Cuboid({
281+
center: new Vector3(0, 0, 0),
282+
width: 5.0,
283+
height: 3.0,
284+
depth: 2.0,
285+
color: 0x10b981,
286+
});
287+
manager.addBrepEntityToScene(sceneId, "box", "Cuboid", toBrepSerialized(cuboid));
268288

269289
const camera = {
270290
position: { x: 8, y: 6, z: 8 },

docs/api/operations/boolean-operations.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ Each boolean helper accepts a `BooleanOperand` in any of these forms:
6060
- `getBrep(): unknown`
6161

6262
This means you can pass OpenGeometry shape wrappers (like `Cuboid` and `Opening`) directly.
63+
`Solid` also works directly here, which makes `polygon.extrude(height)` a first-class boolean input.
6364

6465
### BooleanExecutionOptions
6566

@@ -212,3 +213,4 @@ scene.add(union, intersection);
212213

213214
- [Boolean operations demo](https://demo.opengeometry.io/operations/boolean-operations.html)
214215
- [Polygon boolean operations demo](https://demo.opengeometry.io/operations/polygon-boolean-operations.html)
216+
- [Extruded boolean operations demo](https://demo.opengeometry.io/operations/extruded-boolean-operations.html)

docs/api/operations/extrude.mdx

Lines changed: 103 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -1,121 +1,137 @@
11
---
22
title: 'Extrude'
3-
description: 'Transform 2D polygons into 3D geometry by extruding them along a vertical axis'
3+
description: 'Create closed solids by extruding a face-like BRep profile through the kernel'
44
icon: 'cubes'
55
---
66

77
## Overview
88

9-
The extrude operation transforms a 2D polygon into a 3D solid by extending it along a height vector. This creates a prismatic geometry with the original polygon as the base, vertical side faces connecting the base to the top, and a parallel top face.
9+
OpenGeometry's production extrusion path is BRep-first. The kernel extrudes a face or wire into a
10+
closed solid while preserving loop structure, which means concave profiles and holes are supported.
1011

11-
## Function Signature
12+
In the Three.js API, the most common public entrypoint is:
1213

13-
### extrude_polygon_by_buffer_geometry
14-
15-
```rust
16-
pub fn extrude_polygon_by_buffer_geometry(geom_buf: BaseGeometry, height: f64) -> Geometry
14+
```ts
15+
const solid = polygon.extrude(height);
1716
```
1817

19-
Extrudes a polygon defined by buffer geometry to create a 3D mesh.
18+
That path uses the same kernel face-extrusion primitive described on this page.
2019

21-
<ParamField path="geom_buf" type="BaseGeometry" required>
22-
The base geometry containing the polygon vertices to extrude. Must have at least 3 vertices to form a valid polygon.
23-
</ParamField>
20+
## Three.js API
2421

25-
<ParamField path="height" type="f64" required>
26-
The extrusion height in the vertical (Y) direction. Positive values extrude upward, negative values extrude downward.
27-
</ParamField>
22+
### polygon.extrude()
2823

29-
### extrude_brep_face
24+
Extrudes a `Polygon` and returns a renderable [`Solid`](/api/shapes/solid).
3025

31-
```rust
32-
pub fn extrude_brep_face(brep_face: Brep, height: f64) -> Brep
26+
```ts
27+
const solid = polygon.extrude(height);
3328
```
3429

35-
Extrudes a BREP (Boundary Representation) face to create a new BREP object with topological information.
30+
### Solid.extrude()
3631

37-
<ParamField path="brep_face" type="Brep" required>
38-
The BREP face to extrude. Must contain at least 3 vertices.
39-
</ParamField>
32+
Extrudes a face-like BRep source and wraps the result as a `Solid`.
4033

41-
<ParamField path="height" type="f64" required>
42-
The extrusion height in the Y direction.
43-
</ParamField>
44-
45-
## Return Type
46-
47-
### Geometry Structure
48-
49-
The `extrude_polygon_by_buffer_geometry` function returns a `Geometry` object with:
34+
```ts
35+
const solid = Solid.extrude(source, height, options);
36+
```
5037

51-
- **vertices**: Complete vertex list including both base and top vertices
52-
- **edges**: All edges forming the bottom face, top face, and vertical connections
53-
- **faces**: Bottom face, all side faces (one per edge of the original polygon), and top face
38+
### extrudeBrepFace()
5439

55-
### Brep Structure
40+
Low-level helper that calls the wasm export directly and returns serialized BRep JSON.
5641

57-
The `extrude_brep_face` function returns a `Brep` using OpenGeometry's current half-edge topology
58-
schema (see [BRep](/concepts/brep)).
42+
```ts
43+
import { extrudeBrepFace } from "opengeometry";
5944

60-
At a high level, the result contains the base face, the top face, and side faces, and it is marked
61-
as a closed shell.
45+
const brepSerialized = extrudeBrepFace(source, height);
46+
```
6247

63-
## How It Works
48+
Accepted `source` forms:
6449

65-
1. **Winding Order**: The input vertices are sorted to counter-clockwise (CCW) order to ensure consistent face normals
66-
2. **Bottom Face**: Creates edges and a face from the original polygon vertices
67-
3. **Vertical Edges**: Generates new vertices offset by the height vector (0, height, 0) and connects them to base vertices
68-
4. **Side Faces**: Creates quadrilateral faces connecting each edge of the base to the corresponding edge on top
69-
5. **Top Face**: Constructs the top face with reversed vertex order for correct normal orientation
50+
- Serialized local BRep JSON
51+
- Parsed BRep object
52+
- Another wrapper exposing `getLocalBrepSerialized()`
53+
- Another wrapper exposing `getLocalBrepData()`
54+
- Another wrapper exposing `getBrepSerialized()` or `getBrepData()`
7055

71-
## Code Examples
56+
## Rust API
7257

73-
### Basic Extrusion
58+
### extrude_brep_face
7459

7560
```rust
76-
use opengeometry::{
77-
geometry::basegeometry::BaseGeometry,
78-
operations::extrude::extrude_polygon_by_buffer_geometry,
79-
};
80-
use openmaths::Vector3;
81-
82-
// Create a square base polygon
83-
let vertices = vec![
84-
Vector3::new(0.0, 0.0, 0.0),
85-
Vector3::new(1.0, 0.0, 0.0),
86-
Vector3::new(1.0, 0.0, 1.0),
87-
Vector3::new(0.0, 0.0, 1.0),
88-
];
61+
pub fn extrude_brep_face(brep_face: Brep, height: f64) -> Brep
62+
```
8963

90-
let base_geom = BaseGeometry::from_vertices(vertices);
64+
This is implemented in:
9165

92-
// Extrude 2 units upward
93-
let extruded = extrude_polygon_by_buffer_geometry(base_geom, 2.0);
66+
`main/opengeometry/src/operations/extrude.rs`
9467

95-
// Result: A rectangular box with base at Y=0 and top at Y=2
68+
## Behavior
69+
70+
- The kernel extrudes along the current local Y direction.
71+
- The source must contain a face-like profile, wire, or at minimum a usable point loop.
72+
- Outer loops and hole loops are preserved, so polygons with holes stay hole-aware after extrusion.
73+
- Concave profiles are supported.
74+
- `height` must be finite and non-zero.
75+
- The result is a closed-shell BRep suitable for boolean operations.
76+
77+
## Usage Examples
78+
79+
### Polygon to solid workflow
80+
81+
```ts
82+
import * as THREE from "three";
83+
import { OpenGeometry, Polygon, Vector3 } from "opengeometry";
84+
85+
await OpenGeometry.create({ wasmURL: "/opengeometry_bg.wasm" });
86+
87+
const scene = new THREE.Scene();
88+
89+
const wallProfile = new Polygon({
90+
vertices: [
91+
new Vector3(-2.2, 0, -0.18),
92+
new Vector3(2.2, 0, -0.18),
93+
new Vector3(2.2, 0, 0.18),
94+
new Vector3(-2.2, 0, 0.18),
95+
],
96+
color: 0x60a5fa,
97+
});
98+
99+
const openingProfile = new Polygon({
100+
vertices: [
101+
new Vector3(-0.7, 0, -0.34),
102+
new Vector3(0.9, 0, -0.34),
103+
new Vector3(0.9, 0, 0.34),
104+
new Vector3(-0.7, 0, 0.34),
105+
],
106+
color: 0xf97316,
107+
});
108+
109+
const wall = wallProfile.extrude(2.8);
110+
const opening = openingProfile.extrude(1.35);
111+
opening.setTranslation(new Vector3(0, 0.85, 0));
112+
113+
const cut = wall.subtract(opening, {
114+
outline: true,
115+
kernel: { mergeCoplanarFaces: true },
116+
});
117+
118+
scene.add(cut);
96119
```
97120

98-
### Extruding a Triangle
99-
100-
```rust
101-
use opengeometry::operations::extrude::extrude_polygon_by_buffer_geometry;
102-
use opengeometry::geometry::basegeometry::BaseGeometry;
103-
use openmaths::Vector3;
121+
### Direct low-level helper
104122

105-
// Create a triangular base
106-
let triangle = vec![
107-
Vector3::new(0.0, 0.0, 0.0),
108-
Vector3::new(1.0, 0.0, 0.0),
109-
Vector3::new(0.5, 0.0, 1.0),
110-
];
123+
```ts
124+
import { Solid, extrudeBrepFace } from "opengeometry";
111125

112-
let base_geom = BaseGeometry::from_vertices(triangle);
113-
let prism = extrude_polygon_by_buffer_geometry(base_geom, 1.5);
126+
const extrudedBrep = extrudeBrepFace(localFaceBrepSerialized, 3.0);
114127

115-
// Result: A triangular prism
128+
const solid = new Solid({
129+
brep: extrudedBrep,
130+
color: 0x10b981,
131+
});
116132
```
117133

118-
### Using BREP Extrusion
134+
### Rust kernel usage
119135

120136
```rust
121137
use opengeometry::{
@@ -125,7 +141,6 @@ use opengeometry::{
125141
use openmaths::Vector3;
126142
use uuid::Uuid;
127143

128-
// Build a single face B-Rep (a surface) with BrepBuilder.
129144
let mut builder = BrepBuilder::new(Uuid::new_v4());
130145
builder.add_vertices(&[
131146
Vector3::new(0.0, 0.0, 0.0),
@@ -134,50 +149,19 @@ builder.add_vertices(&[
134149
Vector3::new(0.0, 0.0, 1.0),
135150
]);
136151
builder.add_face(&[0, 1, 2, 3], &[]).unwrap();
137-
let brep_face = builder.build().unwrap();
152+
let profile = builder.build().unwrap();
138153

139-
// Extrude to create a 3D BREP with topological data
140-
let extruded_brep = extrude_brep_face(brep_face, 3.0);
141-
142-
// Access topological information
143-
println!("Vertices: {}", extruded_brep.get_vertex_count());
144-
println!("Edges: {}", extruded_brep.get_edge_count());
145-
println!("Faces: {}", extruded_brep.get_face_count());
154+
let solid = extrude_brep_face(profile, 3.0);
155+
assert!(solid.shells.iter().any(|shell| shell.is_closed));
146156
```
147157

148-
## Visual Examples
149-
150-
```
151-
Input Polygon (Top View): Extruded Result (3D):
152-
153-
v3────v2 v7────v6
154-
│ │ ╱│ ╱│
155-
│ │ +height ╱ │ ╱ │
156-
v0────v1 ────────> v4─┼─v5 │
157-
│ v3──┼─v2
158-
│╱ │╱
159-
v0────v1
160-
```
161-
162-
## Implementation Details
163-
164-
### Source Location
165-
166-
`main/opengeometry/src/operations/extrude.rs`
167-
168-
### Edge Cases
169-
170-
- **Minimum Vertices**: Polygons with fewer than 3 vertices are technically invalid, but the function proceeds (returns incomplete geometry)
171-
- **Direction**: Currently extrudes only in the Y direction; future versions may support arbitrary extrusion vectors
172-
- **Winding Order**: Automatically corrects to CCW to ensure proper face orientation
173-
174158
## See Also
175159

176-
- [Sweep](/api/operations/sweep) - Extrude a profile along an arbitrary path
177-
- [Offset](/api/operations/offset) - Create parallel offset curves
178-
- [Triangulate](/api/operations/triangulate) - Convert polygons to triangle meshes
160+
- [Polygon](/api/shapes/polygon)
161+
- [Solid](/api/shapes/solid)
162+
- [Sweep](/api/operations/sweep)
163+
- [Boolean operations](/api/operations/boolean-operations)
179164

180165
## Live demo
181166

182-
There is no dedicated extrude demo page yet. Start from the demo index:
183-
[OpenGeometry demos](https://demo.opengeometry.io/).
167+
- [Extruded boolean operations demo](https://demo.opengeometry.io/operations/extruded-boolean-operations.html)

docs/api/scene/scene-management.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ pub struct SceneEntity {
171171

172172
Each entity in a scene has:
173173
- **id**: Unique identifier for the entity
174-
- **kind**: Type descriptor (e.g., "OGCuboid", "OGSphere")
174+
- **kind**: Type descriptor (for example `"Cuboid"`, `"Sphere"`, or any app-defined label)
175175
- **brep**: The boundary representation of the geometry
176176

177177
## OGSceneManager

0 commit comments

Comments
 (0)