Boundary Detector
Boundary Detector
This chapter introduces the BoundaryDetector in WebCAD. It is used to automatically detect closed boundaries from an interior point and is mainly applied to the boundary-picking feature of the Hatch command.
Overview
BoundaryDetector is implemented based on the ODA GeLoopsBuilder algorithm and uses WASM for high-performance boundary tracing. It can automatically detect the smallest closed boundary around a specified point from entities on the canvas.
import { BoundaryDetector, BoundaryDetectorOptions, BoundaryDetectionResult } from 'vjcad';Quick Start
Basic Usage
import { BoundaryDetector, Point2D } from 'vjcad';
// Create boundary detector
const detector = new BoundaryDetector();
// Specify interior point
const pickPoint = new Point2D(50, 50);
// Run detection
const result = detector.detectBoundary(pickPoint);
if (result.success) {
console.log('Outer boundary:', result.outerBoundary);
console.log('Island count:', result.islands.length);
console.log('All boundaries:', result.edges);
} else {
console.log('Detection failed:', result.errorMessage);
}Usage with Configuration
const detector = new BoundaryDetector({
gapTolerance: 0.5, // Allowed gap
detectIslands: true, // Detect islands
islandMode: 'normal', // Island mode
maxTraceSteps: 10000, // Maximum tracing steps
useViewportClipping: true // Use only entities inside viewport
});
const result = detector.detectBoundary(pickPoint);BoundaryDetectorOptions
Configuration Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
gapTolerance | number | 0.1 | Gap tolerance, the maximum allowed gap distance |
detectIslands | boolean | true | Whether to detect islands (inner holes) |
islandMode | string | 'normal' | Island handling mode |
maxTraceSteps | number | 10000 | Maximum tracing steps to prevent infinite loops |
useViewportClipping | boolean | true | Whether to use only entities inside the viewport |
gapTolerance
Similar to AutoCAD's HPGAPTOL, it allows a certain gap in the boundary:
// Allow a 0.5-unit gap
const detector = new BoundaryDetector({
gapTolerance: 0.5
});islandMode
| Value | Description |
|---|---|
'normal' | Standard mode, detect all islands |
'outer' | Detect only the outer boundary and ignore islands |
'ignore' | Ignore island detection |
// Detect only outer boundary
const detector = new BoundaryDetector({
islandMode: 'outer'
});
// Ignore islands
const detector2 = new BoundaryDetector({
detectIslands: false
});BoundaryDetectionResult
Result Structure
interface BoundaryDetectionResult {
success: boolean; // Whether detection succeeded
errorMessage?: string; // Error message on failure
outerBoundary: Edge | null; // Outer boundary
islands: Edge[]; // Array of island boundaries
edges: Edges | null; // Edges collection for all boundaries
}Using the Result
const result = detector.detectBoundary(pickPoint);
if (!result.success) {
console.error('Detection failed:', result.errorMessage);
return;
}
// Outer boundary
if (result.outerBoundary) {
const outerPoints = result.outerBoundary.bulgePoints;
console.log('Outer boundary point count:', outerPoints.items.length);
}
// Islands (inner holes)
for (const island of result.islands) {
const islandPoints = island.bulgePoints;
console.log('Island point count:', islandPoints.items.length);
}
// Use directly in a hatch entity
if (result.edges) {
const hatch = new HatchEnt();
hatch.edges = result.edges;
}detectBoundary() - Run Detection
Method Signature
detectBoundary(pickPoint: Point2D, entities?: EntityBase[]): BoundaryDetectionResultParameters
| Parameter | Type | Description |
|---|---|---|
pickPoint | Point2D | Pick point in WCS |
entities | EntityBase[] | Optional, candidate entity array |
Automatic Entity Retrieval
If the entities parameter is not provided, the detector retrieves entities automatically:
- If
useViewportClippingistrue, use entities inside the viewport - Otherwise use all entities in the current space
// Automatically retrieve entities
const result = detector.detectBoundary(pickPoint);
// Specify entity range
const selectedEntities = Engine.getSelectedEntities();
const result2 = detector.detectBoundary(pickPoint, selectedEntities);Supported Entity Types
Basic Geometry Entities
| Type | Description |
|---|---|
LINE | Line |
ARC | Arc |
CIRCLE | Circle |
PLINE / LWPOLYLINE | Polyline |
ELLIPSE | Ellipse |
SPLINE | Spline |
BEZIER | Bezier curve |
Container Entities
The detector automatically expands sub-entities in container entities:
| Type | Description |
|---|---|
INSERT | Block reference |
GROUP | Group |
CUSTOM | Custom entity |
// Entities inside a block reference are also detected
const insertEnt = new InsertEnt();
// ...
const result = detector.detectBoundary(pickPoint, [insertEnt]);
// Sub-entities inside insertEnt are expanded automaticallyAlgorithm Principle
Core Steps
- Build curve info - convert entities into curve info arrays (start point, end point, bulge)
- Calculate intersections - compute intersections between all curves
- Split curves - split curves at intersection points
- Build graph structure - create a graph of vertices and edges
- Merge vertices - merge nearby vertices according to gap tolerance
- Remove dangling ends - delete hanging edges that cannot form closed loops
- Split connected components - divide the graph into independent connected regions
- Trace boundaries - trace the smallest closed boundary using polar-angle sorting
- Validate result - verify boundary validity
WASM Acceleration
The core boundary-detection algorithm is implemented in WebAssembly for high-performance tracing:
// The detector automatically checks whether WASM is available
const detector = new BoundaryDetector();
// An error is reported if WASM is unavailable
const result = detector.detectBoundary(pickPoint);
if (!result.success && result.errorMessage?.includes('WASM')) {
console.log('Make sure the WebCadCore WASM module is loaded');
}Application Examples
Use in Hatch Command
import { BoundaryDetector, HatchEnt, Point2D, Engine } from 'vjcad';
async function createHatchFromPoint(pickPoint: Point2D) {
// Create detector
const detector = new BoundaryDetector({
gapTolerance: 0.1,
detectIslands: true
});
// Detect boundary
const result = detector.detectBoundary(pickPoint);
if (!result.success) {
console.error('Unable to detect a valid boundary');
return null;
}
// Create hatch entity
const hatch = new HatchEnt();
hatch.edges = result.edges!;
hatch.patternName = 'SOLID';
hatch.setDefaults();
// Add to canvas
Engine.pcanvas.addEntity(hatch);
return hatch;
}Batch Boundary Detection
async function detectMultipleBoundaries(points: Point2D[]): BoundaryDetectionResult[] {
const detector = new BoundaryDetector();
const results: BoundaryDetectionResult[] = [];
for (const point of points) {
const result = detector.detectBoundary(point);
results.push(result);
}
return results;
}Custom Entity Scope
// Detect boundaries only within entities on a specific layer
function detectInLayer(pickPoint: Point2D, layerName: string) {
const entities = Engine.currentSpace.items.filter(
e => e.layer === layerName
);
const detector = new BoundaryDetector();
return detector.detectBoundary(pickPoint, entities);
}Error Handling
Common Errors
| Error Message | Cause | Solution |
|---|---|---|
No available boundary entities found | No entities near the pick point | Check pick-point position or entity visibility |
Unable to generate curve info | Unsupported entity type | Check whether the entity type is supported |
WASM module unavailable | WASM not loaded | Ensure WebCadCore is initialized correctly |
No outer boundary | No closed boundary found | Increase gap tolerance or check whether entities are closed |
Error Handling Example
const result = detector.detectBoundary(pickPoint);
if (!result.success) {
switch (true) {
case result.errorMessage?.includes('boundary entities'):
// Prompt user to choose the correct position
break;
case result.errorMessage?.includes('WASM'):
// Prompt WASM loading issue
break;
case result.errorMessage?.includes('outer boundary'):
// Prompt boundary is not closed
break;
default:
// Other errors
console.error(result.errorMessage);
}
}Performance Optimization
Limit Entity Scope
// Use only viewport entities (default)
const detector = new BoundaryDetector({
useViewportClipping: true
});
// Or manually specify nearby entities
const nearbyEntities = getEntitiesNearPoint(pickPoint, 100);
detector.detectBoundary(pickPoint, nearbyEntities);Adjust Trace Steps
// More complex geometry may require more steps
const detector = new BoundaryDetector({
maxTraceSteps: 50000
});Next Steps
- Selection Detection - selection-rectangle intersection tests
- Hatch Entity -
HatchEnt - Entity System -
EntityBasebase class