Skip to content

Commit

Permalink
Add some generic filters
Browse files Browse the repository at this point in the history
  • Loading branch information
sgenoud committed Sep 27, 2024
1 parent fc4244f commit 6a027a0
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 52 deletions.
13 changes: 6 additions & 7 deletions packages/replicad/src/finders/definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,13 @@ export const PLANE_TO_DIR: Record<StandardPlane, [number, number, number]> = {

export type FaceOrEdge = Face | Edge;

export type FilterFcn<Type> = {
element: Type;
normal: Vector | null;
};

export abstract class Finder<Type, FilterType> {
protected filters: (({
element,
normal,
}: {
element: Type;
normal: Vector | null;
}) => boolean)[];
protected filters: (({ element, normal }: FilterFcn<Type>) => boolean)[];

protected abstract applyFilter(shape: FilterType): Type[];

Expand Down
97 changes: 54 additions & 43 deletions packages/replicad/src/finders/generic3dfinder.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,31 @@
import { Direction, DIRECTIONS, FaceOrEdge, Finder } from "./definitions";

import { Vector, asPnt, Point } from "../geom";
import {
Direction,
DIRECTIONS,
FaceOrEdge,
FilterFcn,
Finder,
} from "./definitions";

import { Vector, Point } from "../geom";
import { DEG2RAD } from "../constants";
import { AnyShape } from "../shapes";
import { getOC } from "../oclib";
import { GCWithObject, GCWithScope } from "../register";
import { makeBox, makeVertex } from "../shapeHelpers";
import { DistanceQuery } from "../measureShape";

export abstract class Finder3d<Type extends FaceOrEdge> extends Finder<
Type,
AnyShape
> {
/**
* Filter to find elements following a custom function.
*
* @category Filter
*/
when(filter: (filter: FilterFcn<Type>) => boolean): this {
this.filters.push(filter);
return this;
}

/**
* Filter to find elements that are in the list.
*
Expand Down Expand Up @@ -60,28 +76,14 @@ export abstract class Finder3d<Type extends FaceOrEdge> extends Finder<
* @category Filter
*/
atDistance(distance: number, point: Point = [0, 0, 0]): this {
const pnt = asPnt(point);

const oc = getOC();
const vertexMaker = new oc.BRepBuilderAPI_MakeVertex(pnt);
const vertex = vertexMaker.Vertex();
vertexMaker.delete();

const distanceBuilder = new oc.BRepExtrema_DistShapeShape_1();
distanceBuilder.LoadS1(vertex);
const vertex = makeVertex(point);
const query = new DistanceQuery(vertex);

const checkPoint = ({ element }: { element: Type }) => {
const r = GCWithScope();
distanceBuilder.LoadS2(element.wrapped);
const progress = r(new oc.Message_ProgressRange_1());
distanceBuilder.Perform(progress);

return Math.abs(distanceBuilder.Value() - distance) < 1e-6;
return Math.abs(query.distanceTo(element) - distance) < 1e-6;
};

this.filters.push(checkPoint);
GCWithObject(checkPoint)(distanceBuilder);

return this;
}

Expand All @@ -94,6 +96,23 @@ export abstract class Finder3d<Type extends FaceOrEdge> extends Finder<
return this.atDistance(0, point);
}

/**
* Filter to find elements that are within a certain distance from a point.
*
* @category Filter
*/
withinDistance(distance: number, point: Point = [0, 0, 0]): this {
const vertex = makeVertex(point);
const query = new DistanceQuery(vertex);

const checkPoint = ({ element }: { element: Type }) => {
return query.distanceTo(element) - distance < 1e-6;
};

this.filters.push(checkPoint);
return this;
}

/**
* Filter to find elements that are within a box
*
Expand All @@ -102,33 +121,25 @@ export abstract class Finder3d<Type extends FaceOrEdge> extends Finder<
* @category Filter
*/
inBox(corner1: Point, corner2: Point) {
const oc = getOC();
const boxMaker = new oc.BRepPrimAPI_MakeBox_4(
asPnt(corner1),
asPnt(corner2)
);
const box = boxMaker.Solid();
boxMaker.delete();
const box = makeBox(corner1, corner2);
return this.inShape(box);
}

const distanceBuilder = new oc.BRepExtrema_DistShapeShape_1();
distanceBuilder.LoadS1(box);
/**
* Filter to find elements that are within a generic shape
*
* The elements that are not fully contained in the shape are also found.
*
* @category Filter
*/
inShape(shape: AnyShape) {
const query = new DistanceQuery(shape);

const checkPoint = ({ element }: { element: Type }) => {
const r = GCWithScope();
distanceBuilder.LoadS2(element.wrapped);
const progress = r(new oc.Message_ProgressRange_1());
distanceBuilder.Perform(progress);

return distanceBuilder.Value() < 1e-6;
return query.distanceTo(element) < 1e-6;
};

// We cleanup the box and the distance builder when the function disappears
const gc = GCWithObject(checkPoint);
gc(box);
gc(distanceBuilder);

this.filters.push(checkPoint);

return this;
}
}
4 changes: 3 additions & 1 deletion packages/replicad/src/finders/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { Finder } from "./definitions";
import { Finder, FilterFcn } from "./definitions";

export type { FilterFcn };

/**
* Combine a set of finder filters (defined with radius) to pass as a filter
Expand Down
63 changes: 62 additions & 1 deletion packages/replicad/src/measureShape.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { getOC } from "./oclib";
import { AnyShape, Face, Shape3D } from "./shapes";

import type { GProp_GProps } from "replicad-opencascadejs";
import type {
BRepExtrema_DistShapeShape,
GProp_GProps,
} from "replicad-opencascadejs";
import { GCWithScope, WrappingObj } from "./register";
import { ProgressRange } from "./utils/ProgressRange";

class PhysicalProperties extends WrappingObj<GProp_GProps> {
get centerOfMass(): [number, number, number] {
Expand Down Expand Up @@ -63,14 +67,71 @@ export function measureShapeVolumeProperties(
return new VolumePhysicalProperties(properties);
}

/**
* Measure the volume of a shape
*
* @category Measure
*/
export function measureVolume(shape: Shape3D) {
return measureShapeVolumeProperties(shape).volume;
}

/**
* Measure the area of a shape
*
* @category Measure
*/
export function measureArea(shape: Face | Shape3D) {
return measureShapeSurfaceProperties(shape).area;
}

/**
* Measure the length of a shape
*
* @category Measure
*/
export function measureLength(shape: AnyShape) {
return measureShapeLinearProperties(shape).length;
}

export class DistanceTool extends WrappingObj<BRepExtrema_DistShapeShape> {
constructor() {
const oc = getOC();
super(new oc.BRepExtrema_DistShapeShape_1());
}

distanceBetween(shape1: AnyShape, shape2: AnyShape): number {
this.wrapped.LoadS1(shape1.wrapped);
this.wrapped.LoadS2(shape2.wrapped);
const progress = new ProgressRange();
this.wrapped.Perform(progress.wrapped);
return this.wrapped.Value();
}
}

/**
* Measure the distance between two shapes
*
* @category Measure
*/
export function measureDistanceBetween(
shape1: AnyShape,
shape2: AnyShape
): number {
return new DistanceTool().distanceBetween(shape1, shape2);
}

export class DistanceQuery extends WrappingObj<BRepExtrema_DistShapeShape> {
constructor(shape: AnyShape) {
const oc = getOC();
super(new oc.BRepExtrema_DistShapeShape_1());
this.wrapped.LoadS1(shape.wrapped);
}

distanceTo(shape: AnyShape): number {
this.wrapped.LoadS2(shape.wrapped);
const progress = new ProgressRange();
this.wrapped.Perform(progress.wrapped);
return this.wrapped.Value();
}
}
8 changes: 8 additions & 0 deletions packages/replicad/src/shapeHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,14 @@ export const makeSphere = (radius: number): Solid => {
return sphere;
};

export const makeBox = (corner1: Point, corner2: Point): Solid => {
const oc = getOC();
const boxMaker = new oc.BRepPrimAPI_MakeBox_4(asPnt(corner1), asPnt(corner2));
const box = new Solid(boxMaker.Solid());
boxMaker.delete();
return box;
};

export const makeVertex = (point: Point): Vertex => {
const oc = getOC();
const pnt = asPnt(point);
Expand Down
10 changes: 10 additions & 0 deletions packages/replicad/src/utils/ProgressRange.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import type { Message_ProgressRange } from "replicad-opencascadejs";
import { WrappingObj } from "../register";
import { getOC } from "../oclib";

export class ProgressRange extends WrappingObj<Message_ProgressRange> {
constructor() {
const oc = getOC();
super(new oc.Message_ProgressRange_1());
}
}

0 comments on commit 6a027a0

Please sign in to comment.