mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-07 08:53:25 +01:00
move face evolve to a module / fix UI
This commit is contained in:
parent
b1d37daa6f
commit
9a699cdf1d
17 changed files with 252 additions and 134 deletions
|
|
@ -1,7 +1,7 @@
|
|||
import {Matrix3, BasisForPlane, ORIGIN} from '../../../math/l3space'
|
||||
import * as math from '../../../math/math'
|
||||
import Vector from '../../../math/vector'
|
||||
import {enclose, iterateSegments} from '../../../brep/brep-builder'
|
||||
import {enclose, iterateSegments} from '../../../brep/brep-enclose'
|
||||
import * as stitching from '../../../brep/stitching'
|
||||
import {Loop} from '../../../brep/topo/loop'
|
||||
import {incRefCounter} from '../../../brep/topo/topo-object'
|
||||
|
|
@ -30,21 +30,11 @@ export function doOperation(app, params, cut) {
|
|||
|
||||
const sketch = ReadSketchFromFace(app, face);
|
||||
const details = getEncloseDetails(params, sketch.fetchContours(), face.surface(), !cut, false);
|
||||
const operand = combineShells(details.map(d => enclose(d.basePath, d.lidPath, d.baseSurface, d.lidSurface, wallJoiner)));
|
||||
const operand = combineShells(details.map(d => enclose(d.basePath, d.lidPath, d.baseSurface, d.lidSurface)));
|
||||
return BooleanOperation(face, solid, operand, cut ? 'subtract' : 'union');
|
||||
}
|
||||
|
||||
export function wallJoiner(wall, group) {
|
||||
if (group && group.constructor.name != 'Segment') {
|
||||
const wallFace = wall.faces[0];
|
||||
if (!group.stitchedSurface) {
|
||||
group.stitchedSurface = new stitching.StitchedSurface();
|
||||
}
|
||||
group.stitchedSurface.addFace(wallFace);
|
||||
}
|
||||
}
|
||||
|
||||
export function getEncloseDetails(params, contours, sketchSurface, invert, forceApproximation) {
|
||||
export function getEncloseDetails(params, contours, sketchSurface, invert) {
|
||||
let value = params.value;
|
||||
if (value < 0) {
|
||||
value = Math.abs(value);
|
||||
|
|
@ -54,7 +44,9 @@ export function getEncloseDetails(params, contours, sketchSurface, invert, force
|
|||
const baseSurface = invert ? sketchSurface.invert() : sketchSurface;
|
||||
|
||||
let target;
|
||||
const targetDir = baseSurface.normal.negate();
|
||||
let baseSurfaceNormal = baseSurface.normalInMiddle ? baseSurface.normalInMiddle() : baseSurface.normal;
|
||||
|
||||
const targetDir = baseSurfaceNormal.negate();
|
||||
|
||||
if (params.rotation != 0) {
|
||||
const basis = sketchSurface.basis();
|
||||
|
|
@ -70,34 +62,18 @@ export function getEncloseDetails(params, contours, sketchSurface, invert, force
|
|||
let details = [];
|
||||
for (let contour of contours) {
|
||||
if (invert) contour.reverse();
|
||||
const basePath = contour.transferOnSurface(sketchSurface, forceApproximation);
|
||||
const basePath = contour.transferOnSurface(sketchSurface);
|
||||
if (invert) contour.reverse();
|
||||
|
||||
const lidPath = new CompositeCurve();
|
||||
|
||||
let lidPoints = basePath.points;
|
||||
var applyPrism = !math.equal(params.prism, 1);
|
||||
if (applyPrism) {
|
||||
const _3D = sketchSurface.get3DTransformation();
|
||||
const _2D = _3D.invert();
|
||||
lidPoints = math.polygonOffset(lidPoints.map(p => _2D.apply(p)) , params.prism).map(p => _3D._apply(p));
|
||||
}
|
||||
lidPoints = lidPoints.map(p => p.plus(target));
|
||||
for (let i = 0; i < basePath.points.length; ++i) {
|
||||
const curve = basePath.curves[i];
|
||||
const point = lidPoints[i];
|
||||
const group = basePath.groups[i];
|
||||
let lidCurve;
|
||||
if (curve.isLine) {
|
||||
//TODO: breaks test_TR_OUT_TR_INNER
|
||||
lidCurve = Line.fromSegment(point, lidPoints[(i + 1) % lidPoints.length]);
|
||||
} else {
|
||||
lidCurve = curve.translate(target);
|
||||
if (applyPrism) {
|
||||
lidCurve = lidCurve.offset(params.prism);
|
||||
}
|
||||
const lidPath = [];
|
||||
var applyPrism = !math.equal(params.prism, 1);
|
||||
for (let i = 0; i < basePath.length; ++i) {
|
||||
const curve = basePath[i];
|
||||
let lidCurve = curve.translate(target);
|
||||
if (applyPrism) {
|
||||
lidCurve = lidCurve.offset(params.prism);
|
||||
}
|
||||
lidPath.add(lidCurve, point, group);
|
||||
lidPath.push(lidCurve);
|
||||
}
|
||||
|
||||
const lidSurface = baseSurface.translate(target).invert();
|
||||
|
|
|
|||
|
|
@ -52,23 +52,34 @@ export class ExtrudePreviewer extends SketchBasedPreviewer {
|
|||
}
|
||||
|
||||
createImpl(app, params, sketch, face) {
|
||||
const encloseDetails = getEncloseDetails(params, sketch, face.surface(), !this.inversed, true);
|
||||
const encloseDetails = getEncloseDetails(params, sketch, face.surface(), !this.inversed);
|
||||
const triangles = [];
|
||||
for (let d of encloseDetails) {
|
||||
const base = d.basePath.points;
|
||||
const lid = d.lidPath.points;
|
||||
const n = base.length;
|
||||
for (let p = n - 1, q = 0; q < n; p = q ++) {
|
||||
triangles.push([ base[p], base[q], lid[q] ]);
|
||||
triangles.push([ lid[q], lid[p], base[p] ]);
|
||||
|
||||
for (let {basePath, lidPath, baseSurface, lidSurface} of encloseDetails) {
|
||||
const basePoints = [];
|
||||
const lidPoints = [];
|
||||
for (let i = 0; i < basePath.length; ++i) {
|
||||
let baseNurbs = basePath[i];
|
||||
let lidNurbs = lidPath[i];
|
||||
const params = verb.eval.Tess.rationalCurveAdaptiveSample(baseNurbs.verb._data,1,true).map(p => p[0]);
|
||||
const base = params.map(u => baseNurbs.point(u));
|
||||
const lid = params.map(u => lidNurbs.point(u));
|
||||
const n = base.length;
|
||||
for (let p = n - 1, q = 0; q < n; p = q ++) {
|
||||
triangles.push([ base[p], base[q], lid[q] ]);
|
||||
triangles.push([ lid[q], lid[p], base[p] ]);
|
||||
}
|
||||
base.forEach(p => basePoints.push(new Vector().set3(p)));
|
||||
lid.forEach(p => lidPoints.push(new Vector().set3(p)));
|
||||
|
||||
}
|
||||
|
||||
function collectOnSurface(points, normal) {
|
||||
TriangulatePolygons([points], normal, (v) => v.toArray(), (arr) => new Vector().set3(arr))
|
||||
.forEach(tr => triangles.push(tr));
|
||||
}
|
||||
collectOnSurface(base, d.baseSurface.normal);
|
||||
collectOnSurface(lid, d.lidSurface.normal);
|
||||
collectOnSurface(basePoints, baseSurface.normal);
|
||||
collectOnSurface(lidPoints, lidSurface.normal);
|
||||
}
|
||||
return triangles;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ export class RevolvePreviewer extends SketchBasedNurbsPreviewer {
|
|||
const nurbses = [];
|
||||
const contours = sketch.fetchContours();
|
||||
for (let contour of contours) {
|
||||
const basePath = contour.transferOnSurface(surface);
|
||||
const basePath = contour.approximateOnSurface(surface);
|
||||
revolveToWallNurbs(basePath, surface, pivot.p0, pivot.v, params.angle).forEach(nurbs => nurbses.push(nurbs));
|
||||
}
|
||||
return nurbses;
|
||||
|
|
|
|||
|
|
@ -224,16 +224,6 @@ export class Ellipse extends SketchPrimitive {
|
|||
}
|
||||
}
|
||||
|
||||
const USE_APPROX_FOR = new Set();
|
||||
//USE_APPROX_FOR.add('Arc');
|
||||
|
||||
const USE_NURBS_FOR = new Set();
|
||||
USE_NURBS_FOR.add('Arc');
|
||||
USE_NURBS_FOR.add('Circle');
|
||||
//USE_NURBS_FOR.add('Ellipse');
|
||||
//USE_NURBS_FOR.add('EllipticalArc');
|
||||
//USE_NURBS_FOR.add('BezierCurve');
|
||||
|
||||
export class Contour {
|
||||
|
||||
constructor() {
|
||||
|
|
@ -244,7 +234,7 @@ export class Contour {
|
|||
this.segments.push(obj);
|
||||
}
|
||||
|
||||
transferOnSurface(surface, forceApproximation) {
|
||||
approximateOnSurface(surface) {
|
||||
const cc = new CompositeCurve();
|
||||
const tr = to3DTrFunc(surface);
|
||||
|
||||
|
|
@ -265,19 +255,27 @@ export class Contour {
|
|||
approximation[n - 1] = firstPoint;
|
||||
}
|
||||
|
||||
if (!forceApproximation && USE_APPROX_FOR.has(segment.constructor.name)) {
|
||||
cc.add(new ApproxCurve(approximation, segment), prev, segment);
|
||||
prev = approximation[n - 1];
|
||||
} else if (!forceApproximation && USE_NURBS_FOR.has(segment.constructor.name)) {
|
||||
cc.add(segment.toNurbs(surface), prev, segment);
|
||||
prev = approximation[n - 1];
|
||||
} else {
|
||||
for (let i = 1; i < n; ++i) {
|
||||
const curr = approximation[i];
|
||||
cc.add(new Line.fromSegment(prev, curr), prev, segment);
|
||||
prev = curr;
|
||||
}
|
||||
}
|
||||
cc.add(segment.toNurbs(surface), prev, segment);
|
||||
prev = approximation[n - 1];
|
||||
|
||||
//It might be an optimization for segments
|
||||
// for (let i = 1; i < n; ++i) {
|
||||
// const curr = approximation[i];
|
||||
// cc.add(new Line.fromSegment(prev, curr), prev, segment);
|
||||
// prev = curr;
|
||||
// }
|
||||
}
|
||||
return cc;
|
||||
}
|
||||
|
||||
transferOnSurface(surface) {
|
||||
const cc = [];
|
||||
|
||||
let prev = null;
|
||||
let firstPoint = null;
|
||||
for (let segIdx = 0; segIdx < this.segments.length; ++segIdx) {
|
||||
let segment = this.segments[segIdx];
|
||||
cc.push(segment.toNurbs(surface));
|
||||
}
|
||||
return cc;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,7 +131,9 @@ function addGlobalDebugActions(app) {
|
|||
scale = scale || 100;
|
||||
__DEBUG__.AddSegment(atPoint, atPoint.plus(normal.multiply(scale)), color);
|
||||
},
|
||||
|
||||
AddSurfaceNormal: (surface) => {
|
||||
__DEBUG__.AddNormal(surface.point(0.5, 0.5), surface.normalInMiddle());
|
||||
},
|
||||
HideSolids: () => {
|
||||
app.findAllSolidsOnScene().forEach(s => s.cadGroup.traverse(o => o.visible = false));
|
||||
app.viewer.render();
|
||||
|
|
|
|||
|
|
@ -109,6 +109,13 @@ App.prototype.test1 = function() {
|
|||
this.addShellOnScene(result);
|
||||
}
|
||||
|
||||
|
||||
App.prototype.cylTest = function() {
|
||||
|
||||
const cylinder1 = BREPPrimitives.cylinder(200, 500);
|
||||
this.addShellOnScene(cylinder1);
|
||||
}
|
||||
|
||||
App.prototype.test2 = function() {
|
||||
|
||||
function square() {
|
||||
|
|
@ -149,10 +156,10 @@ App.prototype.test3 = function() {
|
|||
|
||||
const box3 = app.TPI.brep.primitives.box(150, 600, 350, new Matrix3().translate(25, 25, -250));
|
||||
// let result = app.TPI.brep.bool.union(box1, box2);
|
||||
// let result = app.TPI.brep.bool.subtract(box1, box2);
|
||||
// result = app.TPI.brep.bool.subtract(result, box3);
|
||||
app.addShellOnScene(box1);
|
||||
// app.addShellOnScene(result);
|
||||
let result = app.TPI.brep.bool.subtract(box1, box2);
|
||||
result = app.TPI.brep.bool.subtract(result, box3);
|
||||
// app.addShellOnScene(box1);
|
||||
app.addShellOnScene(result);
|
||||
|
||||
};
|
||||
|
||||
|
|
@ -207,7 +214,7 @@ App.prototype.test5 = function() {
|
|||
|
||||
App.prototype.scratchCode = function() {
|
||||
const app = this;
|
||||
this.test5();
|
||||
this.cylTest();
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ export class BREPSceneSolid extends SceneSolid {
|
|||
createVertices() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class BREPSceneFace extends SceneFace {
|
||||
constructor(brepFace, solid) {
|
||||
super(solid, brepFace.id);
|
||||
|
|
@ -70,7 +70,7 @@ class BREPSceneFace extends SceneFace {
|
|||
|
||||
|
||||
normal() {
|
||||
return this.brepFace.surface.normal;
|
||||
return this.brepFace.surface.normalInMiddle();
|
||||
}
|
||||
|
||||
depth() {
|
||||
|
|
|
|||
|
|
@ -3,20 +3,6 @@ import earcut from 'earcut'
|
|||
import Vector from "../../math/vector";
|
||||
|
||||
export default function A(face) {
|
||||
function uv(p) {
|
||||
return face.surface.verb.closestParam(p);
|
||||
}
|
||||
|
||||
const workingPt = (uv, pt3d) => {
|
||||
let wpt = new Vector(uv[0], uv[1], 0);
|
||||
wpt._multiply(1000);
|
||||
wpt.__3D = pt3d;
|
||||
return wpt;
|
||||
};
|
||||
|
||||
const pt = (pt3d) => workingPt(uv(pt3d), pt3d);
|
||||
// throw 1
|
||||
const mirrored = isMirrored(face.surface);
|
||||
|
||||
let loops = [];
|
||||
for (let loop of face.loops) {
|
||||
|
|
@ -24,13 +10,12 @@ export default function A(face) {
|
|||
loops.push(pipLoop);
|
||||
for (let e of loop.halfEdges) {
|
||||
let curvePoints = e.edge.curve.verb.tessellate(100000);
|
||||
let inverted = mirrored !== e.inverted;
|
||||
if (inverted) {
|
||||
if (e.inverted) {
|
||||
curvePoints.reverse();
|
||||
}
|
||||
curvePoints.pop();
|
||||
for (let point of curvePoints) {
|
||||
let p = pt(point);
|
||||
let p = face.surface.workingPoint(Vector.fromData(point));
|
||||
pipLoop.push(p);
|
||||
}
|
||||
}
|
||||
|
|
@ -39,7 +24,7 @@ export default function A(face) {
|
|||
let steinerPoints = [];
|
||||
let tess = face.surface.verb.tessellate({maxDepth: 3});
|
||||
for (let i = 0; i < tess.points.length; i++) {
|
||||
steinerPoints.push(workingPt(tess.uvs[i], tess.points[i]));
|
||||
steinerPoints.push(face.surface.createWorkingPoint(tess.uvs[i], Vector.fromData(tess.points[i])));
|
||||
}
|
||||
|
||||
let [outer, ...inners] = loops;
|
||||
|
|
@ -73,7 +58,7 @@ export default function A(face) {
|
|||
for (let i = 0; i < trs.length; i += 3) {
|
||||
const tr = [trs[i], trs[i + 1], trs[i + 2]];
|
||||
|
||||
// __DEBUG__.AddPointPolygon(tr.map( ii => new Vector(pointsData[ii * 2], pointsData[ii * 2 + 1], 0) ));
|
||||
__DEBUG__.AddPointPolygon(tr.map( ii => new Vector(pointsData[ii * 2], pointsData[ii * 2 + 1], 0) ));
|
||||
|
||||
triangles.push(tr.map(i => points[i]));
|
||||
}
|
||||
|
|
@ -84,7 +69,7 @@ export default function A(face) {
|
|||
|
||||
for (let tr of triangles) {
|
||||
for (let i = 0; i < tr.length; i++) {
|
||||
tr[i] = new Vector().set3(tr[i].__3D);
|
||||
tr[i] = tr[i].__3D;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -93,7 +78,7 @@ export default function A(face) {
|
|||
|
||||
function splitTriangles(triangles, steinerPoints) {
|
||||
for (let sp of steinerPoints) {
|
||||
// __DEBUG__.AddPoint(sp);
|
||||
__DEBUG__.AddPoint(sp);
|
||||
let newTrs = [];
|
||||
for (let i = 0; i < triangles.length; ++i) {
|
||||
let tr = triangles[i];
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ export default class BrepBuilder {
|
|||
loop.link();
|
||||
}
|
||||
if (face.surface === null) {
|
||||
face.surface = createBoundingNurbs(face.outerLoop.asPolygon());
|
||||
face.surface = createBoundingNurbs(face.outerLoop.tess());
|
||||
}
|
||||
}
|
||||
for (let face of this._shell.faces) {
|
||||
|
|
@ -101,7 +101,6 @@ export function createBoundingNurbs(points, plane) {
|
|||
points2d.forEach(p => bBox.checkPoint(p));
|
||||
|
||||
let to3D = plane.get3DTransformation();
|
||||
|
||||
let polygon = bBox.toPolygon();
|
||||
polygon = polygon.map(p => to3D._apply(p));
|
||||
|
||||
|
|
|
|||
|
|
@ -35,29 +35,28 @@ export function createPrism(basePoints, height) {
|
|||
const extrudeVector = baseSurface.normal.multiply( - height);
|
||||
const lidSurface = baseSurface.translate(extrudeVector).invert();
|
||||
const lidPoints = basePoints.map(p => p.plus(extrudeVector));
|
||||
const basePath = new CompositeCurve();
|
||||
const lidPath = new CompositeCurve();
|
||||
const basePath = [];
|
||||
const lidPath = [];
|
||||
|
||||
for (let i = 0; i < basePoints.length; i++) {
|
||||
let j = (i + 1) % basePoints.length;
|
||||
basePath.add(NurbsCurve.createLinearNurbs(basePoints[i], basePoints[j]), basePoints[i], null);
|
||||
lidPath.add(NurbsCurve.createLinearNurbs(lidPoints[i], lidPoints[j]), lidPoints[i], null);
|
||||
basePath.push(NurbsCurve.createLinearNurbs(basePoints[i], basePoints[j]));
|
||||
lidPath.push(NurbsCurve.createLinearNurbs(lidPoints[i], lidPoints[j]));
|
||||
}
|
||||
return enclose(basePath, lidPath, baseSurface, lidSurface);
|
||||
}
|
||||
|
||||
export function enclose(basePath, lidPath, basePlane, lidPlane) {
|
||||
|
||||
if (basePath.points.length !== lidPath.points.length) {
|
||||
if (basePath.length !== lidPath.length) {
|
||||
throw 'illegal arguments';
|
||||
}
|
||||
|
||||
const walls = [];
|
||||
|
||||
const n = basePath.points.length;
|
||||
const n = basePath.length;
|
||||
for (let i = 0; i < n; i++) {
|
||||
let j = (i + 1) % n;
|
||||
const wall = createWall(basePath.curves[i], lidPath.curves[i]);
|
||||
const wall = createWall(basePath[i], lidPath[i]);
|
||||
walls.push(wall);
|
||||
}
|
||||
return assemble(walls, basePlane, lidPlane)
|
||||
|
|
@ -104,8 +103,8 @@ function assemble(walls, basePlane, lidPlane) {
|
|||
base.outerLoop.link();
|
||||
lid.outerLoop.link();
|
||||
|
||||
base.surface = createBoundingNurbs(base.outerLoop.asPolygon(), basePlane);
|
||||
lid.surface = createBoundingNurbs(lid.outerLoop.asPolygon(), lidPlane);
|
||||
base.surface = createBoundingNurbs(base.outerLoop.tess(), basePlane);
|
||||
lid.surface = createBoundingNurbs(lid.outerLoop.tess(), lidPlane);
|
||||
|
||||
shell.faces.push(base, lid);
|
||||
shell.faces.forEach(f => f.shell = shell);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import {Point} from './geom/point'
|
||||
import {createPrism} from './brep-enclose'
|
||||
import {Plane} from './geom/impl/plane'
|
||||
import {createPrism, enclose} from './brep-enclose'
|
||||
import {Matrix3} from '../math/l3space'
|
||||
import {Circle} from '../3d/craft/sketch/sketch-model'
|
||||
|
||||
export function box(w, h, d, tr) {
|
||||
const wh = w * 0.5;
|
||||
|
|
@ -17,4 +19,12 @@ export function box(w, h, d, tr) {
|
|||
], d);
|
||||
}
|
||||
|
||||
|
||||
export function cylinder(r, h, tr) {
|
||||
let circle1 = new Circle(-1, new Point(0,0,0), r).toNurbs(Plane.XY);
|
||||
let circle2 = circle1.translate(new Point(0,h,0))
|
||||
return enclose(circle1, circle2);
|
||||
}
|
||||
|
||||
|
||||
const IDENTITY = new Matrix3();
|
||||
|
|
@ -36,6 +36,11 @@ export class NurbsCurve extends Curve {
|
|||
}
|
||||
|
||||
splitByParam(u) {
|
||||
const split = this.verb.split(u);
|
||||
if (!math.equal(this.verb.closestParam(split[0].point(0)),0)) {
|
||||
// throw 'wrong split';
|
||||
console.error('wrong split')
|
||||
}
|
||||
return this.verb.split(u).map(v => new NurbsCurve(v));
|
||||
}
|
||||
|
||||
|
|
@ -110,10 +115,11 @@ NurbsCurve.createLinearNurbs = function(a, b) {
|
|||
|
||||
export class NurbsSurface extends Surface {
|
||||
|
||||
constructor(verbSurface) {
|
||||
constructor(verbSurface, inverted) {
|
||||
super();
|
||||
this.verb = verbSurface;
|
||||
this.inverted = false;
|
||||
this.inverted = inverted === true;
|
||||
this.mirrored = NurbsSurface.isMirrored(this);
|
||||
}
|
||||
|
||||
toNurbs() {
|
||||
|
|
@ -147,6 +153,26 @@ export class NurbsSurface extends Surface {
|
|||
return pt(this.verb.point(u, v));
|
||||
}
|
||||
|
||||
workingPoint(point) {
|
||||
return this.createWorkingPoint(this.verb.closestParam(point.data()), point);
|
||||
}
|
||||
|
||||
createWorkingPoint(uv, pt3d) {
|
||||
const wp = new Vector(uv[0], uv[1], 0)._multiply(1000);
|
||||
if (this.mirrored) {
|
||||
wp.x *= -1;
|
||||
}
|
||||
wp.__3D = pt3d;
|
||||
return wp;
|
||||
}
|
||||
|
||||
static isMirrored(surface) {
|
||||
let a = surface.point(0, 0);
|
||||
let b = surface.point(1, 0);
|
||||
let c = surface.point(1, 1);
|
||||
return b.minus(a).cross(c.minus(a))._normalize().dot(surface.normalUV(0, 0)) < 0;
|
||||
}
|
||||
|
||||
intersectSurfaceForSameClass(other, tol) {
|
||||
const curves = verb_surface_isec(this.verb, other.verb, tol);
|
||||
let inverted = this.inverted !== other.inverted;
|
||||
|
|
@ -154,9 +180,7 @@ export class NurbsSurface extends Surface {
|
|||
}
|
||||
|
||||
invert() {
|
||||
let inverted = new NurbsSurface(this.verb);
|
||||
inverted.inverted = !this.inverted;
|
||||
return inverted;
|
||||
return new NurbsSurface(this.verb, !this.inverted);
|
||||
}
|
||||
|
||||
isoCurve(param, useV) {
|
||||
|
|
|
|||
|
|
@ -87,18 +87,14 @@ export class Plane extends Surface {
|
|||
return [Number.MIN_VALUE, Number.MAX_VALUE];
|
||||
}
|
||||
|
||||
classifyCognateCurve(line, tol) {
|
||||
const parallel = math.areEqual(line.v.dot(this.normal), 0, tol);
|
||||
const pointOnPlane = math.areEqual(this.normal.dot(line.p0), this.w, tol);
|
||||
return {
|
||||
hit: !parallel || pointOnPlane,
|
||||
parallel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Plane.prototype.isPlane = true;
|
||||
|
||||
Plane.XY = new Plane(AXIS.Z, 0);
|
||||
Plane.XZ = new Plane(AXIS.Y, 0);
|
||||
Plane.YZ = new Plane(AXIS.X, 0);
|
||||
|
||||
class ParametricPlane {
|
||||
|
||||
constructor(r0, r1, r2) {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import {Loop} from '../topo/loop';
|
|||
import {Face} from '../topo/face';
|
||||
import {Shell} from '../topo/shell';
|
||||
import {Vertex} from '../topo/vertex';
|
||||
import {evolveFace} from './evolve-face'
|
||||
import Vector from '../../math/vector';
|
||||
import * as math from '../../math/math';
|
||||
|
||||
|
|
@ -220,13 +221,12 @@ function traverseFaces(face, validFaces, callback) {
|
|||
}
|
||||
|
||||
export function loopsToFaces(originFace, loops, out) {
|
||||
const face = new Face(originFace.surface);
|
||||
face.innerLoops = loops;
|
||||
loops.forEach(loop => loop.face = face);
|
||||
out.push(face);
|
||||
const newFaces = evolveFace(originFace, loops);
|
||||
for (let newFace of newFaces) {
|
||||
out.push(newFace);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function initSolveData(shell, facesData) {
|
||||
for (let face of shell.faces) {
|
||||
const solveData = new FaceSolveData(face);
|
||||
|
|
|
|||
90
web/app/brep/operations/evolve-face.js
Normal file
90
web/app/brep/operations/evolve-face.js
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
import {Face} from '../topo/face';
|
||||
import {Vertex} from '../topo/vertex';
|
||||
import Vector from '../../math/vector';
|
||||
import {isCCW} from '../../math/math';
|
||||
import PIP from '../../3d/tess/pip';
|
||||
|
||||
export function evolveFace(originFace, loops) {
|
||||
let out = [];
|
||||
const originSurface = originFace.surface;
|
||||
let invertedSurface = null;
|
||||
function invertSurface() {
|
||||
if (invertedSurface == null) {
|
||||
invertedSurface = originSurface.invert();
|
||||
}
|
||||
return invertedSurface;
|
||||
}
|
||||
|
||||
function createFaces(nestedLoop, level) {
|
||||
let surface;
|
||||
__DEBUG__.AddPointPolygon(nestedLoop.workingPolygon)
|
||||
if (nestedLoop.inverted) {
|
||||
surface = invertSurface(surface);
|
||||
} else {
|
||||
surface = originSurface;
|
||||
}
|
||||
|
||||
const loop = nestedLoop.loop;
|
||||
const newFace = new Face(surface);
|
||||
Object.assign(newFace.data, originFace.data);
|
||||
newFace.outerLoop = loop;
|
||||
loop.face = newFace;
|
||||
out.push(newFace);
|
||||
|
||||
for (let child of nestedLoop.nesting) {
|
||||
if (child.level == level + 2) {
|
||||
createFaces(child, level + 2);
|
||||
} else if (child.level == level + 1) {
|
||||
if (nestedLoop.inverted !== child.inverted) {
|
||||
child.loop.face = newFace;
|
||||
newFace.innerLoops.push(child.loop);
|
||||
} else {
|
||||
createFaces(child, level + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const nestedLoops = getNestedLoops(originFace, loops);
|
||||
for (let nestedLoop of nestedLoops) {
|
||||
if (nestedLoop.level == 0) {
|
||||
createFaces(nestedLoop, 0);
|
||||
}
|
||||
}
|
||||
if (out.length !== 0) {
|
||||
out[0].id = originFace.id;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function getNestedLoops(face, brepLoops) {
|
||||
function NestedLoop(loop) {
|
||||
this.loop = loop;
|
||||
this.workingPolygon = loop.asPolygon().map(p => face.surface.workingPoint(p));
|
||||
this.inverted = !isCCW(this.workingPolygon);
|
||||
this.pip = PIP(this.workingPolygon);
|
||||
this.nesting = [];
|
||||
this.level = 0;
|
||||
}
|
||||
|
||||
const loops = brepLoops.map(loop => new NestedLoop(loop));
|
||||
function contains(loop, other) {
|
||||
for (let point of other.workingPolygon) {
|
||||
if (!loop.pip(point).inside) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
for (let i = 0; i < loops.length; ++i) {
|
||||
const loop = loops[i];
|
||||
for (let j = 0; j < loops.length; ++j) {
|
||||
if (i == j) continue;
|
||||
const other = loops[j];
|
||||
if (contains(loop, other)) {
|
||||
loop.nesting.push(other);
|
||||
other.level ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return loops.filter(l => l.level == 0);
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
import {TopoObject} from './topo-object'
|
||||
import {Point} from '../geom/point'
|
||||
|
||||
import * as math from '../../math/math'
|
||||
|
||||
|
|
@ -30,6 +31,22 @@ export class Loop extends TopoObject {
|
|||
curr.loop = this;
|
||||
}
|
||||
}
|
||||
|
||||
tess() {
|
||||
let out = [];
|
||||
for (let e of this.halfEdges) {
|
||||
let curvePoints = e.edge.curve.verb.tessellate(100000);
|
||||
if (e.inverted) {
|
||||
curvePoints.reverse();
|
||||
}
|
||||
curvePoints.pop();
|
||||
for (let point of curvePoints) {
|
||||
let p = Point.fromData(point);
|
||||
out.push(p);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
Loop.isPolygonCCWOnSurface = function(polygon, surface) {
|
||||
|
|
|
|||
|
|
@ -136,4 +136,8 @@ Vector.prototype.three = function() {
|
|||
return new THREE.Vector3(this.x, this.y, this.z);
|
||||
};
|
||||
|
||||
Vector.fromData = function(arr) {
|
||||
return new Vector().set3(arr);
|
||||
}
|
||||
|
||||
export default Vector;
|
||||
Loading…
Reference in a new issue