mirror of
https://github.com/xibyte/jsketcher
synced 2025-12-25 01:45:26 +01:00
fix face filtering
This commit is contained in:
parent
7b5a547755
commit
7ae9190587
7 changed files with 77 additions and 33 deletions
|
|
@ -161,8 +161,8 @@ function addGlobalDebugActions(app) {
|
|||
app.findAllSolidsOnScene().forEach(s => s.cadGroup.traverse(o => o.visible = false));
|
||||
app.viewer.render();
|
||||
},
|
||||
Solids: () => {
|
||||
app.findAllSolidsOnScene().forEach(s => s.cadGroup.traverse(o => o.visible = false));
|
||||
ShowSolids: () => {
|
||||
app.findAllSolidsOnScene().forEach(s => s.cadGroup.traverse(o => o.visible = true));
|
||||
app.viewer.render();
|
||||
},
|
||||
Clear: () => {
|
||||
|
|
|
|||
|
|
@ -50,6 +50,11 @@ class BRepDebug {
|
|||
transferEdge(edge, face, chosenEdge) {
|
||||
this.currentBooleanSession.transferedEdges.push({edge, face, chosenEdge});
|
||||
}
|
||||
|
||||
faceFilter(connectedToAffectedFaces, allFaces) {
|
||||
this.currentBooleanSession.faceFilter.connectedToAffectedFaces = connectedToAffectedFaces;
|
||||
this.currentBooleanSession.faceFilter.allFaces = allFaces;
|
||||
}
|
||||
}
|
||||
|
||||
class BooleanSession {
|
||||
|
|
@ -63,6 +68,10 @@ class BooleanSession {
|
|||
this.transferedEdges = [];
|
||||
this.mergeFacesLoopDetection = [];
|
||||
this.currentLoopDetection = null;
|
||||
this.faceFilter = {
|
||||
connectedToAffectedFaces: null,
|
||||
allFaces: null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import ShellExplorer from './shellExplorer';
|
|||
import LoopDetectionExplorer from './loopDetectionExplorer';
|
||||
import Section from './section'
|
||||
import {EdgeTransferExplorer} from "./edgeTransferExplorer";
|
||||
import {FaceFilterExplorer} from "./faceFilterExplorer";
|
||||
|
||||
export default class BrepDebugger extends React.PureComponent {
|
||||
|
||||
|
|
@ -85,11 +86,9 @@ export default class BrepDebugger extends React.PureComponent {
|
|||
<Section name='loops validation' accent>
|
||||
loops validation...
|
||||
</Section>
|
||||
<Section name='loops filter' accent>
|
||||
loops filter...
|
||||
<Section name='face filter' accent>
|
||||
{session.faceFilter && <FaceFilterExplorer {...session.faceFilter} group3d={brepDebugGroup} /> }
|
||||
</Section>
|
||||
|
||||
|
||||
</Section>)}
|
||||
</div>
|
||||
</div>;
|
||||
|
|
|
|||
28
web/app/brep/debug/debugger/faceFilterExplorer.jsx
Normal file
28
web/app/brep/debug/debugger/faceFilterExplorer.jsx
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import React from 'react';
|
||||
import {FaceExplorer} from "./shellExplorer";
|
||||
import Section from './section';
|
||||
import {
|
||||
getFacesViewObjects, InteractiveSection, TAB,
|
||||
} from "./utils";
|
||||
|
||||
|
||||
export function FaceFilterExplorer({connectedToAffectedFaces, allFaces, group3d}) {
|
||||
connectedToAffectedFaces = connectedToAffectedFaces || [];
|
||||
allFaces = allFaces || [];
|
||||
let notConnectedToAffectedFaces = allFaces.filter(f => connectedToAffectedFaces.indexOf(f) === -1);
|
||||
let category = 'face-filter';
|
||||
let context = {connectedToAffectedFaces, notConnectedToAffectedFaces};
|
||||
return <InteractiveSection name='analyzed faces' closable defaultClosed={false}
|
||||
{...{viewObjectsProvider: getFacesViewObjects, topoObj: allFaces, group3d, category, context}}>
|
||||
|
||||
<Section name='connected to affected' tabs={TAB} accent>
|
||||
{connectedToAffectedFaces.length === 0 ? '<empty>' : null }
|
||||
{connectedToAffectedFaces.map((face, i) => <FaceExplorer key={i} {...{face, group3d, category, context}} />)}
|
||||
</Section>
|
||||
<Section name='not connected to affected' tabs={TAB} accent>
|
||||
{notConnectedToAffectedFaces.length === 0 ? '<empty>' : null }
|
||||
{notConnectedToAffectedFaces.map((face, i) => <FaceExplorer key={i} {...{face, group3d, category, context}} />)}
|
||||
</Section>
|
||||
</InteractiveSection>
|
||||
|
||||
}
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
import React, {Fragment as FR} from 'react';
|
||||
import Section from "./section";
|
||||
import {
|
||||
ActiveLabel, Controls, getEdgesViewObjects, getEdgeViewObjects, getFaceViewObjects, getLoopsViewObjects,
|
||||
ActiveLabel, Controls, getEdgesViewObjects, getEdgeViewObjects, getFacesViewObjects, getFaceViewObjects,
|
||||
getLoopsViewObjects,
|
||||
getLoopViewObjects,
|
||||
getVertexViewObjects, InteractiveSection, mapIterable,
|
||||
TAB
|
||||
|
|
@ -11,12 +12,15 @@ export default class ShellExplorer extends React.PureComponent {
|
|||
|
||||
render() {
|
||||
let {shell, group3d} = this.props;
|
||||
|
||||
let category='default';
|
||||
let context = null;
|
||||
let faces = shell ? shell.faces : [];
|
||||
|
||||
return <div className='shell-explorer'>
|
||||
<Section name={`shell ${shell ? shell.refId : 'UNAVAILABLE'}`} closable>
|
||||
{shell && shell.faces.map(face => <FaceExplorer key={face.refId} {...{face, group3d}} category='default' context={null} />)}
|
||||
</Section>
|
||||
</div>;
|
||||
return <InteractiveSection name={`shell ${shell ? shell.refId : 'UNAVAILABLE'}`} closable defaultClosed={false}
|
||||
{...{viewObjectsProvider: getFacesViewObjects, topoObj: faces, group3d, category, context}}>
|
||||
{faces.map(face => <FaceExplorer key={face.refId} {...{face, group3d, category, context}} />)}
|
||||
</InteractiveSection>;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,10 @@ import {AQUA, BLACK, BLUE, cycleColor, DETECTED_EDGE, DISCARDED_EDGE, GREEN, RED
|
|||
import {distanceAB3} from "../../../math/math";
|
||||
import Section from "./section";
|
||||
|
||||
export function getFacesViewObjects(group3d, category, context, out, faces) {
|
||||
forEach(faces, getFaceViewObjects.bind(null, group3d, category, context, out));
|
||||
}
|
||||
|
||||
export function getFaceViewObjects(group3d, category, context, out, face) {
|
||||
return getLoopsViewObjects(group3d, category, context, out, face.loops);
|
||||
}
|
||||
|
|
@ -137,6 +141,14 @@ export function getInitColor(category, obj, context) {
|
|||
return BLACK;
|
||||
}
|
||||
}
|
||||
case 'face-filter': {
|
||||
let {connectedToAffectedFaces, notConnectedToAffectedFaces} = context;
|
||||
if (connectedToAffectedFaces.indexOf(obj.loop.face) > -1) {
|
||||
return WHITE;
|
||||
} else {
|
||||
return BLACK;
|
||||
}
|
||||
}
|
||||
default:
|
||||
switch (obj.constructor.name) {
|
||||
case 'HalfEdge': return SALMON;
|
||||
|
|
|
|||
|
|
@ -137,7 +137,6 @@ export function BooleanAlgorithm( shellA, shellB, type ) {
|
|||
|
||||
faces = filterFaces(faces, shellA, shellB, type !== TYPE.UNION);
|
||||
|
||||
|
||||
const result = new Shell();
|
||||
faces.forEach(face => {
|
||||
face.shell = result;
|
||||
|
|
@ -403,6 +402,7 @@ function mergeFaces(facesA, facesB, opType) {
|
|||
let detectedLoops = detectLoops(originFace.surface, graph);
|
||||
for (let loop of detectedLoops) {
|
||||
for (let edge of loop.halfEdges) {
|
||||
EdgeSolveData.setPriority(edge, 1);
|
||||
discardedEdges.delete(edge);
|
||||
}
|
||||
}
|
||||
|
|
@ -561,39 +561,40 @@ function filterFaces(faces, a, b, isIntersection) {
|
|||
if (FILTER_STRATEGY === FILTER_STRATEGIES.RAY_CAST) {
|
||||
return filterByRayCast(faces, a, b, isIntersection);
|
||||
} else if (FILTER_STRATEGY === FILTER_STRATEGIES.NEW_EDGES) {
|
||||
return filterFacesByNewEdges(faces, a, b, isIntersection);
|
||||
return filterFacesByNewEdges(faces);
|
||||
} else {
|
||||
throw 'unsupported';
|
||||
}
|
||||
}
|
||||
|
||||
function filterFacesByNewEdges(faces) {
|
||||
|
||||
function isFaceContainNewEdge(face) {
|
||||
|
||||
function doesFaceContainNewEdge(face) {
|
||||
for (let e of face.edges) {
|
||||
if (getPriority(e) > 0) {
|
||||
if (getPriority(e) > 0 || getPriority(e.twin()) > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const validFaces = new Set(faces);
|
||||
const result = new Set();
|
||||
const resultSet = new Set();
|
||||
for (let face of faces) {
|
||||
// __DEBUG__.Clear();
|
||||
// __DEBUG__.AddFace(face);
|
||||
traverseFaces(face, validFaces, (it) => {
|
||||
if (result.has(it) || isFaceContainNewEdge(it)) {
|
||||
result.add(face);
|
||||
traverseFaces(face, (it) => {
|
||||
if (resultSet.has(it) || doesFaceContainNewEdge(it)) {
|
||||
resultSet.add(face);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
const result = Array.from(resultSet)
|
||||
BREP_DEBUG.faceFilter(result, faces);
|
||||
return result;
|
||||
}
|
||||
|
||||
function traverseFaces(face, validFaces, callback) {
|
||||
function traverseFaces(face, callback) {
|
||||
const stack = [face];
|
||||
const seen = new Set();
|
||||
while (stack.length !== 0) {
|
||||
|
|
@ -603,14 +604,9 @@ function traverseFaces(face, validFaces, callback) {
|
|||
if (callback(face) === true) {
|
||||
return;
|
||||
}
|
||||
if (!validFaces.has(face)) continue;
|
||||
for (let loop of face.loops) {
|
||||
for (let halfEdge of loop.halfEdges) {
|
||||
for (let twin of halfEdge.twins()) {
|
||||
if (validFaces.has(twin.loop.face)) {
|
||||
stack.push(twin.loop.face)
|
||||
}
|
||||
}
|
||||
stack.push(halfEdge.twin().loop.face);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -822,10 +818,6 @@ function transferEdges(faceSource, faceDest, operationType) {
|
|||
continue;
|
||||
}
|
||||
if (edgeCollinearToFace(edge, faceDest)) {
|
||||
//not coincide with an edge
|
||||
if (!faceDest.rayCast(edge.edge.curve.middlePoint()).strictInside) {
|
||||
continue;
|
||||
}
|
||||
let validEdge = chooseValidEdge(edge, faceDest, operationType);
|
||||
BREP_DEBUG.transferEdge(edge, faceDest, validEdge);
|
||||
let twin = validEdge.twin();
|
||||
|
|
|
|||
Loading…
Reference in a new issue