Geometry Calculations
About 4 min
Geometry Calculations
Distance, angle, intersection, area, spatial index, and other geometry calculations.
Common Geometry Calculations
Distance Calculation
const { distance, Point2D } = vjcad;
const p1 = new Point2D(0, 0);
const p2 = new Point2D(100, 100);
// Use the distance function
const dist = distance(p1, p2);
// Manual calculation
const dx = p2.x - p1.x;
const dy = p2.y - p1.y;
const dist2 = Math.sqrt(dx * dx + dy * dy);
// Line length
const line = new LineEnt([0, 0], [100, 100]);
console.log('Length:', line.Length);Angle Calculation
const { getAngleBetweenPoints, radToDeg, degToRad, Point2D } = vjcad;
const origin = new Point2D(0, 0);
const target = new Point2D(100, 100);
// Get angle (returns radians in the range 0 to 2π)
const angleRad = getAngleBetweenPoints(origin, target);
const angleDeg = radToDeg(angleRad); // Convert to degrees
// Convert degrees to radians
const rad = degToRad(45); // 45° → π/4
console.log(`Angle: ${angleDeg}°`); // 45°Midpoint Calculation
const { getMidPoint, Point2D } = vjcad;
const p1 = new Point2D(0, 0);
const p2 = new Point2D(100, 100);
const mid = getMidPoint(p1, p2);
console.log(`Midpoint: (${mid.x}, ${mid.y})`); // (50, 50)
// Manual calculation
const midX = (p1.x + p2.x) / 2;
const midY = (p1.y + p2.y) / 2;Intersection Calculation
GeometryCalculator Class
const { GeometryCalculator, LineEnt, CircleEnt, ArcEnt, PolylineEnt } = vjcad;Line and Line
const line1 = new LineEnt([0, 0], [100, 100]);
const line2 = new LineEnt([0, 100], [100, 0]);
const intersections = GeometryCalculator.LineToLine(line1, line2);
intersections.forEach(pt => {
console.log(`Intersection: (${pt.x}, ${pt.y})`);
});Line and Circle
const line = new LineEnt([0, 50], [100, 50]);
const circle = new CircleEnt([50, 50], 30);
const intersections = GeometryCalculator.LineToCircle(line, circle);
// There may be 0, 1, or 2 intersectionsCircle and Circle
const circle1 = new CircleEnt([30, 50], 25);
const circle2 = new CircleEnt([70, 50], 25);
const intersections = GeometryCalculator.CircleToCircle(circle1, circle2);
// There may be 0, 1, or 2 intersectionsArc and Arc
const arc1 = new ArcEnt([0, 0], 50, 0, Math.PI / 2);
const arc2 = new ArcEnt([50, 0], 50, Math.PI / 2, Math.PI);
const intersections = GeometryCalculator.ArcToArc(arc1, arc2);Polyline and Polyline
const pline1 = new PolylineEnt();
pline1.setPoints([[0, 0], [100, 0], [100, 100]]);
const pline2 = new PolylineEnt();
pline2.setPoints([[50, -50], [50, 150]]);
const intersections = GeometryCalculator.PlineToPline(pline1, pline2);Extended Intersections
// Intersection of line extension with line extension
const intersections = GeometryCalculator.LineExtToLineExt(line1, line2);
// Intersection of line extension with circle
const intersections = GeometryCalculator.LineExtToCircle(line, circle);Bounding Box Calculation
Single Entity Bounding Box
const pline = new PolylineEnt();
pline.setPoints([[0, 0], [100, 0], [100, 60], [0, 60]]);
const bbox = pline.boundingBox();
console.log('Min point:', bbox.pt1); // Point2D
console.log('Max point:', bbox.pt2); // Point2D
console.log('Width:', bbox.width);
console.log('Height:', bbox.height);
console.log('Center:', bbox.center); // Point2DMulti-Entity Bounding Box
const { mergeBoundingBoxes, Engine } = vjcad;
// Method 1: use mergeBoundingBoxes
const bbox1 = entity1.boundingBox();
const bbox2 = entity2.boundingBox();
const merged = mergeBoundingBoxes([bbox1, bbox2]);
// Method 2: use Engine.getBoundsByEntities
const bbox = Engine.getBoundsByEntities([entity1, entity2], "WCS");Bounding Box Operations
// Check whether two bounding boxes intersect
function bboxIntersects(bbox1, bbox2) {
return !(
bbox1.pt2.x < bbox2.pt1.x || // bbox1 is on the left
bbox1.pt1.x > bbox2.pt2.x || // bbox1 is on the right
bbox1.pt2.y < bbox2.pt1.y || // bbox1 is below
bbox1.pt1.y > bbox2.pt2.y // bbox1 is above
);
}
// Check whether a point is inside a bounding box
function pointInBbox(point, bbox) {
return point.x >= bbox.pt1.x && point.x <= bbox.pt2.x &&
point.y >= bbox.pt1.y && point.y <= bbox.pt2.y;
}Point-in-Polygon Test
Ray Casting Method
const { pointInPolygon, Point2D } = vjcad;
const polygon = [
new Point2D(0, 0),
new Point2D(100, 0),
new Point2D(100, 100),
new Point2D(0, 100)
];
const testPoint = new Point2D(50, 50);
const inside = pointInPolygon(testPoint, polygon);
console.log(inside ? 'Point is inside the polygon' : 'Point is outside the polygon');Point Position Relative to a Line
const { GeometryCalculator, Point2D } = vjcad;
const lineStart = new Point2D(0, 0);
const lineEnd = new Point2D(100, 0);
const point = new Point2D(50, 50);
// Return value: -1=left, 0=on line, 1=right
const side = GeometryCalculator.witchSidePointToLine(lineStart, lineEnd, point);Area Calculation
Polygon Area
const { calculatePolygonArea, Point2D } = vjcad;
const points = [
new Point2D(0, 0),
new Point2D(100, 0),
new Point2D(100, 60),
new Point2D(0, 60)
];
// Use the Shoelace formula
const doubleArea = calculatePolygonArea(points);
const area = Math.abs(doubleArea) / 2;
console.log('Area:', area); // 6000Entity Area
// Circle area
const circle = new CircleEnt([50, 50], 30);
console.log('Circle area:', circle.area); // π × 30² ≈ 2827.43
// Closed polyline area
const pline = new PolylineEnt();
pline.setPoints([[0, 0], [100, 0], [100, 60], [0, 60]]);
pline.isClosed = true;
console.log('Polyline area:', pline.area); // 6000Spatial Index
Used for efficient spatial queries on large numbers of entities.
const { SpatialIndex } = vjcad;
// Create spatial index
const spatialIndex = new SpatialIndex();
// Insert data (must include minX, minY, maxX, maxY properties)
spatialIndex.insert({
minX: 10, minY: 10, maxX: 40, maxY: 40,
name: "RegionA",
data: { /* custom data */ }
});
// Bulk load (best performance)
const items = [
{ minX: 0, minY: 0, maxX: 50, maxY: 50, id: 1 },
{ minX: 30, minY: 30, maxX: 80, maxY: 80, id: 2 },
{ minX: 60, minY: 60, maxX: 100, maxY: 100, id: 3 }
];
spatialIndex.load(items);
// Region query
const searchBounds = { minX: 25, minY: 25, maxX: 75, maxY: 75 };
const found = spatialIndex.search(searchBounds);
console.log('Found:', found.length, 'items');
// Collision detection
const hasCollision = spatialIndex.collides(searchBounds);
// Remove item
spatialIndex.remove(item, (a, b) => a.id === b.id);
// Clear index
spatialIndex.clear();
// Get all items
const all = spatialIndex.all();Geometric Transformations
Offset
const { offsetLine, expandArc, LineEnt, ArcEnt, CircleEnt } = vjcad;
// Line offset
const line = new LineEnt([0, 0], [100, 0]);
const offsetUp = offsetLine(line, 20); // Offset upward
const offsetDown = offsetLine(line, -20); // Offset downward
// Arc offset
const arc = new ArcEnt([50, 50], 30, 0, Math.PI);
const arcOut = expandArc(arc, 10); // Offset outward
const arcIn = expandArc(arc, -10); // Offset inward
// Circle offset (change radius)
const circle = new CircleEnt([50, 50], 30);
const newRadius = circle.radius + 10;
const newCircle = new CircleEnt(circle.center, newRadius);Trim and Extend
Trim and extend are usually implemented through intersection calculation plus endpoint modification.
// Calculate intersections
const intersections = GeometryCalculator.LineToLine(targetLine, boundaryLine);
// Trim: split the segment at the intersection and delete the unwanted part
// Extend: extend the endpoint to the intersection pointBreak
const { LineEnt, ArcEnt, getAngleBetweenPoints } = vjcad;
// Break line
function breakLine(line, breakPoint) {
const line1 = new LineEnt(line.startPoint, breakPoint);
const line2 = new LineEnt(breakPoint, line.endPoint);
line1.setDefaults();
line2.setDefaults();
return [line1, line2];
}
// Break arc
function breakArc(arc, breakPoint) {
const breakAngle = getAngleBetweenPoints(arc.center, breakPoint);
const arc1 = new ArcEnt(arc.center, arc.radius, arc.startAngle, breakAngle);
const arc2 = new ArcEnt(arc.center, arc.radius, breakAngle, arc.endAngle);
arc1.setDefaults();
arc2.setDefaults();
return [arc1, arc2];
}Coordinate System Conversion
const { Engine, Point2D } = vjcad;
// Canvas coordinates → world coordinates
const canvasPoint = { x: 100, y: 200 };
const wcsPoint = Engine.CanvasToWcs(canvasPoint);
// World coordinates → user coordinates
const ucsPoint = Engine.wcsToUcs(wcsPoint);
// User coordinates → world coordinates
const wcsPoint2 = Engine.ucsToWcs(ucsPoint);
// World coordinates → display coordinates
const dcsPoint = Engine.wcsToDcs(wcsPoint);Coordinate System Types
| Coordinate System | Description |
|---|---|
| WCS | World Coordinate System (absolute coordinates) |
| UCS | User Coordinate System (custom origin and rotation) |
| DCS | Display Coordinate System (screen pixel coordinates) |
| Canvas | Canvas coordinates (HTML Canvas pixels) |