fix extrude from sketch tests

This commit is contained in:
Val Erastov 2022-06-10 22:30:10 -07:00
parent e6c9eb4ca4
commit 7df876df50
10 changed files with 152 additions and 98 deletions

View file

@ -107,6 +107,18 @@ export class Shell extends TopoObject {
});
}
}
traverse(callback: (child: TopoObject) => any) {
for (let face of this.faces) {
callback(face);
}
for (let edge of this.edges) {
callback(edge);
}
for (let vertex of this.vertices) {
callback(vertex);
}
}
}
export function* verticesGenerator(shell: Shell): Generator<Vertex> {

View file

@ -11,8 +11,8 @@ import {FaceRef} from "cad/craft/e0/OCCUtils";
import {GetRef} from "cad/craft/e0/interact";
import {
FromMObjectProductionAnalyzer,
FromSketchProductionAnalyzer,
ProductionAnalyzer
FromSketchProductionAnalyzer, NULL_ANALYZER,
ProductionAnalyzer, PushPullFaceProductionAnalyzer
} from "cad/craft/production/productionAnalyzer";
@ -53,76 +53,37 @@ export const ExtrudeOperation: OperationDescriptor<ExtrudeParams> = {
if (!sketch) {
if (face instanceof MBrepFace) {
occ.io.pushModel(face, face.id)
const edges = face.edges;
edges.forEach(e => occ.io.pushModel(e, e.id));
sweepSources = [{
face: face.id,
edges: edges.map(e => e.id)
}];
oci.prism("FaceTool", face, ...extrusionVector.data());
return occ.utils.applyBooleanModifier([occ.io.getShell("FaceTool")], params.boolean, face, [],
(targets, tools) => new PushPullFaceProductionAnalyzer(targets, face.brepFace));
} else {
throw "can't extrude an empty surface";
}
} else {
let csys = face.csys;
if (params.doubleSided) {
csys = csys.clone();
csys.origin._minus(extrusionVector);
extrusionVector._scale(2);
}
sweepSources = occ.utils.sketchToFaces(sketch, csys)
}
let csys = face.csys;
if (params.doubleSided) {
csys = csys.clone();
csys.origin._minus(extrusionVector);
extrusionVector._scale(2);
}
sweepSources = occ.utils.sketchToFaces(sketch, csys)
const productionAnalyzer = new FromSketchProductionAnalyzer(sweepSources);
const tools = sweepSources.map((faceRef, i) => {
const faceName = faceRef.face;
const shapeName = "Tool/" + i;
// for (let i = 0; i < faceRef.edges.length; ++i) {
// const edge = faceRef.edges[i];
// const seg = faceRef.contour.segments[i];
// const ref = GetRef(edge);
// productionAnalyzer.mapRef(ref, `SK[${sketchId}:${seg.id}]`);
// }
oci.prism(shapeName, faceName, ...extrusionVector.data());
// occIterateFaces(oc, shape, face => {
// let role;
// if (face.IsSame(prismAPI.FirstShape())) {
// role = "bottom";
// } else if (face.IsSame(prismAPI.LastShape())) {
// role = "top";
// } else {
// role = "sweep";
// }
// getProductionInfo(face).role = role;
// });
//
// occIterateEdges(oc, wire, edge => {
// const generatedList = prismAPI.Generated(edge);
// occIterateListOfShape(oc, generatedList, face => {
// console.log(face);
// })
// })
return shapeName;
});
}).map(shapeName => occ.io.getShell(shapeName, productionAnalyzer));
// const productionAnalyzer = new ProductionAnalyzer();
// ctx.cadRegistry.models.forEach(m => productionAnalyzer.preRegister(m));
return occ.utils.applyBooleanModifier(tools, params.boolean, productionAnalyzer, [face]);
return occ.utils.applyBooleanModifier(tools, params.boolean, face, [face]);
},
// useBoolean: {
// booleanField: 'boolean',
// impliedTargetField: 'face'
// },
form: [
{

View file

@ -4,8 +4,8 @@ import {createPlaneAndOpenSketcher} from '../utils/scripts';
export const TEST_MODE = 'modellerUI';
export async function testExtrudeFromSketch(env, ui) {
let sketcherUI = await createPlaneAndOpenSketcher(ui);
let sketchedFace = ui.context.services.selection.face.single;
let [sketcherUI, sketchedFace] = await createPlaneAndOpenSketcher(ui);
let seg1 = sketcherUI.addSegment(-100, -100, 100, -100);
let seg2 = sketcherUI.addSegment(100, -100, 100, 100);
let seg3 = sketcherUI.addSegment(100, 100, -100, 100);
@ -17,7 +17,7 @@ export async function testExtrudeFromSketch(env, ui) {
ui.openWizard('EXTRUDE');
ui.wizardContext.updateParam('value', 200);
ui.wizardContext.updateParam('length', 200);
await ui.wizardOK();
let [leftFace] = ui.rayCastFaces([-110, 0, 100], [-90, 0, 100]);
@ -34,8 +34,8 @@ export async function testExtrudeFromSketch(env, ui) {
assertFaceRole(rightFace, "sweep");
assertFaceRole(topFace, "sweep");
assertFaceRole(bottomFace, "sweep");
assertFaceRole(frontFace, "top");
assertFaceRole(backFace, "bottom");
assertFaceRole(frontFace, "lid");
assertFaceRole(backFace, "base");
let sketchId = sketchedFace.defaultSketchId;
@ -76,8 +76,8 @@ export async function testExtrudeArc(env, ui) {
assertFaceRole(curvedFace, "sweep");
assertFaceRole(flatFace, "sweep");
assertFaceRole(topFace, "top");
assertFaceRole(bottomFace, "bottom");
assertFaceRole(topFace, "lid");
assertFaceRole(bottomFace, "base");
let sketchId = sketchedFace.defaultSketchId;
@ -107,8 +107,8 @@ export async function testExtrudeCircle(env, ui) {
assertFaceRole(curvedFace, "sweep");
assertFaceRole(topFace, "top");
assertFaceRole(bottomFace, "bottom");
assertFaceRole(topFace, "lid");
assertFaceRole(bottomFace, "base");
let sketchId = sketchedFace.defaultSketchId;
@ -137,8 +137,8 @@ export async function testExtrudeEllipse(env, ui) {
assertFaceRole(curvedFace, "sweep");
assertFaceRole(topFace, "top");
assertFaceRole(bottomFace, "bottom");
assertFaceRole(topFace, "lid");
assertFaceRole(bottomFace, "base");
let sketchId = sketchedFace.defaultSketchId;
@ -148,8 +148,7 @@ export async function testExtrudeEllipse(env, ui) {
}
export async function testExtrudeEllipticalArc(env, ui) {
let sketcherUI = await createPlaneAndOpenSketcher(ui);
let sketchedFace = ui.context.services.selection.face.single;
let [sketcherUI, sketchedFace] = await createPlaneAndOpenSketcher(ui);
let eArc = sketcherUI.addEllipticalArc(-100, 100, 100, 100, 0, 150);
sketcherUI.move(100, 100, -50, 170);
sketcherUI.addSegment(eArc.a.x, eArc.a.y, eArc.b.x, eArc.b.y);
@ -169,8 +168,8 @@ export async function testExtrudeEllipticalArc(env, ui) {
assertFaceRole(curvedFace, "sweep");
assertFaceRole(topFace, "top");
assertFaceRole(bottomFace, "bottom");
assertFaceRole(topFace, "lid");
assertFaceRole(bottomFace, "base");
let sketchId = sketchedFace.defaultSketchId;
@ -203,8 +202,8 @@ export async function testExtrudeBezier(env, ui) {
assertFaceRole(curvedFace, "sweep");
assertFaceRole(topFace, "top");
assertFaceRole(bottomFace, "bottom");
assertFaceRole(topFace, "lid");
assertFaceRole(bottomFace, "base");
let sketchId = sketchedFace.defaultSketchId;

View file

@ -57,7 +57,7 @@ export function assertFaceIsPlane(face) {
export function assertFaceOrigination(face, sketchId, primitiveId) {
assertEquals(sketchObjectGlobalId(sketchId, primitiveId),
face.productionInfo.originatedFromPrimitive);
face.productionInfo.originatingPrimitive);
}
export function assertFaceRole(face, expectedRole) {

View file

@ -3,7 +3,9 @@ export async function createPlaneAndOpenSketcher(ui) {
ui.openWizard('PLANE');
await ui.wizardOK();
ui.selectFaces([0, 0, -10], [0, 0, 10]);
return ui.openSketcher();
let sketchedFace = ui.context.services.selection.face.single;
let sketcher = ui.openSketcher();
return [sketcher, sketchedFace];
}
export async function extrudeCube(ui) {

View file

@ -7,6 +7,7 @@ import {WireRef} from "cad/craft/e0/occSketchLoader";
import {FromMObjectProductionAnalyzer, ProductionAnalyzer} from "cad/craft/production/productionAnalyzer";
import {MObject} from "cad/model/mobject";
import {Shell} from "brep/topo/shell";
import {MOpenFaceShell} from "cad/model/mopenFace";
export interface OCCUtils {
@ -14,10 +15,11 @@ export interface OCCUtils {
sketchToFaces(sketch: SketchGeom, csys: CSys): FaceRef[];
// applyBoolean(tools: string[], kind: BooleanKind): string[];
applyBooleanModifier(tools: string[], booleanDef?: BooleanDefinition, productionAnalyzer?: ProductionAnalyzer,
mustAdvance? : MObject[]): OperationResult;
applyBooleanModifier(tools: MObject[],
booleanDef: BooleanDefinition,
sketchSource: MObject,
mustAdvance? : MObject[],
analyzerCreator?: (targets: MObject[], tools: MObject[]) => ProductionAnalyzer): OperationResult;
}
export interface FaceRef extends WireRef {
@ -48,20 +50,29 @@ export function createOCCUtils(ctx: CoreContext): OCCUtils {
});
}
function applyBooleanModifier(tools: string[], booleanDef?: BooleanDefinition,
productionAnalyzer?: ProductionAnalyzer, mustAdvance? : MObject[]): OperationResult {
function applyBooleanModifier(tools: MObject[],
booleanDef: BooleanDefinition,
sketchSource: MObject,
mustAdvance? : MObject[],
analyzerCreator?: (targets: MObject[], tools: MObject[]) => ProductionAnalyzer): OperationResult {
const occ = ctx.occService;
const oci = ctx.occService.commandInterface;
const consumed = [];
if (sketchSource.parent instanceof MOpenFaceShell) {
consumed.push(sketchSource.parent);
}
if (!booleanDef || booleanDef.kind === 'NONE') {
return {
created: tools.map(shapeName => occ.io.getShell(shapeName, productionAnalyzer)),
consumed: []
created: tools,
consumed
}
} else {
const toolsMobj = tools.map(shapeName => occ.io.getShell(shapeName, productionAnalyzer));
const kind = booleanDef.kind;
@ -87,15 +98,19 @@ export function createOCCUtils(ctx: CoreContext): OCCUtils {
oci.bcleartools();
targetNames.forEach(targetName => oci.baddobjects(targetName));
tools.forEach(toolName => oci.baddtools(toolName));
tools.forEach(tool => oci.baddtools(tool));
oci.bcheckinverted(1);
oci.bfillds();
oci.bapibop("BooleanResult", booleanKindToOCCBopType(kind));
const booleanProdAnalyzer = new FromMObjectProductionAnalyzer([...toolsMobj, ...targets], mustAdvance);
targets.forEach(t => consumed.push(t));
tools.forEach(t => consumed.push(t));
const booleanProdAnalyzer = analyzerCreator ? analyzerCreator(targets, tools)
: new FromMObjectProductionAnalyzer([...targets, ...tools], mustAdvance);
return {
consumed: targets,
consumed,
created: [occ.io.getShell("BooleanResult", booleanProdAnalyzer)]
}
}

View file

@ -88,18 +88,41 @@ export class NullProductionAnalyzer implements ProductionAnalyzer {
export const NULL_ANALYZER = new NullProductionAnalyzer();
export class FromSketchProductionAnalyzer implements ProductionAnalyzer {
abstract class BasicProductionAnalyzer implements ProductionAnalyzer {
abstract assignIdentificationImpl(createdShell: Shell);
assignIdentification(createdShell: Shell) {
classifier.prepare(createdShell);
this.assignIdentificationImpl(createdShell);
createdShell.traverse(obj => {
if (!obj.data.productionInfo) {
obj.data.productionInfo = {
unstable: true
}
}
});
}
}
export class FromSketchProductionAnalyzer extends BasicProductionAnalyzer {
profiles: FaceRef[];
constructor(profiles: FaceRef[]) {
super();
this.profiles = profiles;
for (let originFace of this.profiles) {
classifier.prepare(originFace.topoShape);
}
}
assignIdentification(createdShell: Shell) {
assignIdentificationImpl(createdShell: Shell) {
classifier.prepare(createdShell);
@ -253,12 +276,13 @@ function forceAdvance(idToAssign: string): string {
}
}
export class FromMObjectProductionAnalyzer implements ProductionAnalyzer {
export class FromMObjectProductionAnalyzer extends BasicProductionAnalyzer {
consumed: MObject[] = [];
mustAdvance: Set<string>;
constructor(consumed: MObject[], mustAdvance: MObject[] = []) {
super();
this.consumed = consumed;
this.mustAdvance = new Set<string>(mustAdvance&&mustAdvance.map(o => o.id));
consumed.forEach(mShell => {
@ -269,7 +293,7 @@ export class FromMObjectProductionAnalyzer implements ProductionAnalyzer {
}
assignIdentification(createdShell: Shell) {
assignIdentificationImpl(createdShell: Shell) {
classifier.prepare(createdShell);
@ -393,6 +417,10 @@ export class FromMObjectProductionAnalyzer implements ProductionAnalyzer {
}
});
});
if (edgeCreators.length < 2) {
//dangled edge - random id will be assigned
return;
}
const edgeCreatorIds = edgeCreators.map(f => f.id).sort();
const id = '[' + edgeCreatorIds.join('|') + ']';
addToListInMap(newEdges, id, edge);
@ -416,4 +444,44 @@ export class FromMObjectProductionAnalyzer implements ProductionAnalyzer {
}
}
}
export class PushPullFaceProductionAnalyzer extends FromMObjectProductionAnalyzer {
baseFace: Face;
constructor(consumed: MObject[], baseFace: Face) {
super(consumed, []);
this.baseFace = baseFace;
}
assignIdentificationImpl(createdShell: Shell) {
super.assignIdentificationImpl(createdShell);
const edgeMap = new Map();
for (let he of this.baseFace.edges) {
debugger
const twin = he.twin();
if (twin) {
edgeMap.set(twin.loop.face.data.id, twin.edge);
}
}
for (let face of createdShell.faces) {
if (!face.data.productionInfo) {
face.data.id = this.baseFace.id;
face.data.productionInfo = this.baseFace.data.productionInfo;
for (let he of face.edges) {
const twin = he.twin();
if (twin) {
const originEdge = edgeMap.get(twin.loop.face.data.id);
he.edge.data.id = originEdge.data.id;
he.edge.data.productionInfo = originEdge.data.productionInfo;
}
}
}
}
}
}

View file

@ -158,14 +158,6 @@ export class MFace extends MObject {
return this._worldToSketchTransformation;
}
get productionInfo() {
if (this._productionInfo === undefined) {
this._productionInfo = !this.brepFace?.data?.productionInfo ? null :
ProductionInfo.fromRawData(this.brepFace.data.productionInfo);
}
return this._productionInfo;
}
traverse(callback: (obj: MObject) => void) {
callback(this);
this.traverseSketchRelatedEntities(callback);

View file

@ -3,6 +3,7 @@ import {EntityKind} from "cad/model/entities";
import Vector, {UnitVector} from "math/vector";
import {TopoObject} from "brep/topo/topo-object";
import Axis from "math/axis";
import {ProductionInfo} from "cad/model/productionInfo";
export abstract class MObject {
@ -47,6 +48,9 @@ export abstract class MObject {
return null;
}
get productionInfo() {
return this.topology.data?.productionInfo;
}
}
export const MObjectIdGenerator = {

View file

@ -227,6 +227,7 @@ export function activate(context) {
if (LOG_FLAGS.PICK) {
initRayCastDebug();
}
initRayCastDebug();
}
export function traversePickResults(event, pickResults, kind, visitor) {