diff --git a/src/Scene.js b/src/Scene.js index be438ea..4f2546a 100644 --- a/src/Scene.js +++ b/src/Scene.js @@ -194,10 +194,10 @@ export class Scene { } else if (k[0] == 'e') { entries[k] = loader.parse(state.byId[k]) - + if (entries[k].userData.inverted) { flipBufferGeometryNormals(entries[k].geometry) - } + } this.obj3d.add(entries[k]) @@ -235,7 +235,7 @@ export class Scene { } - boolOp(m1, m2, op) { + boolOp(m1, m2, op, refresh = false) { let bspA = CSG.fromMesh(m1) let bspB = CSG.fromMesh(m2) m1.visible = false @@ -275,18 +275,51 @@ export class Scene { mesh.add(vertices) - sc.obj3d.add(mesh) + if (!refresh) { + sc.obj3d.add(mesh) - this.store.dispatch({ - type: 'set-entry-visibility', obj: { - [m1.name]: false, - [m2.name]: false, - [mesh.name]: true, - } - }) + this.store.dispatch({ + type: 'set-entry-visibility', obj: { + [m1.name]: false, + [m2.name]: false, + [mesh.name]: true, + } + }) + + this.store.dispatch({ + type: 'rx-boolean', mesh, deps: [m1.name, m2.name] + }) + } else { + return mesh + } - return mesh } + + refreshNode(id) { + let curId + let que = [id] + let idx = 0 + + const { byId, tree } = this.store.getState().treeEntries + while (idx < que.length) { + curId = que[idx++] + + const info = byId[curId].userData.featureInfo + let newNode + if (info.length == 2) { + newNode = this.extrude(byId[info[0]], info[1], true) + } else if (info.length == 3) { + newNode = this.boolOp(byId[info[0]], byId[info[1]], info[2], true) + } + + byId[curId].geometry.copy(newNode.geometry) + + for (let k in tree[curId]) { + que.push(k) + } + } + } + } diff --git a/src/Sketch.js b/src/Sketch.js index d563f60..d5670a9 100644 --- a/src/Sketch.js +++ b/src/Sketch.js @@ -310,12 +310,36 @@ class Sketch { for (let j = 0; j < link.length; j++) { const obj = this.obj3d.children[i + j] - obj.geometry.dispose() - obj.material.dispose() + // obj.geometry.dispose() + // obj.material.dispose() - for (let c_id of obj.userData.constraints.slice()) { // i hate js + obj.traverse((ob) => { + if (ob.geometry) ob.geometry.dispose() + if (ob.material) ob.material.dispose() + }) + + // collect all coincident constraints to be reconnected + // after deleting this point + let arr = [] + let cons + for (let c_id of obj.userData.constraints.slice()) { + // i hate js, slice is important because deleteContraints mutates constraints array + cons = this.constraints.get(c_id) + if (cons[0] == 'points_coincident') { + arr.push(cons[2][0] == obj.name ? + cons[2][1] : cons[2][0] + ) + } this.deleteConstraints(c_id) } + + for (let i = 0; i < arr.length - 1; i++) { + setCoincident.call(this,[ + this.obj3d.children[this.objIdx.get(arr[i])], + this.obj3d.children[this.objIdx.get(arr[i+1])] + ]) + } + obj.userData.constraints = [] } diff --git a/src/constraintEvents.js b/src/constraintEvents.js index 3690dba..6d5ae21 100644 --- a/src/constraintEvents.js +++ b/src/constraintEvents.js @@ -1,8 +1,15 @@ import { color } from './shared' -export async function setCoincident() { - let selection = await this.awaitSelection({ point: 2 }, { point: 1, line: 1 }) - if (selection == null) return; +export async function setCoincident(sel) { + let selection + if (sel === undefined) { + selection = await this.awaitSelection({ point: 2 }, { point: 1, line: 1 }) + if (selection == null) return; + } else { + selection = sel + } + + if (selection.every(e => e.userData.type == 'point')) { this.constraints.set(++this.c_id, [ diff --git a/src/extrude.js b/src/extrude.js index 585b41c..c69fb3e 100644 --- a/src/extrude.js +++ b/src/extrude.js @@ -1,6 +1,6 @@ import * as THREE from '../node_modules/three/src/Three'; import { color } from './shared' -export function extrude(sketch, depth) { +export function extrude(sketch, depth, refresh=false) { let constraints = sketch.constraints; let linkedObjs = sketch.linkedObjs; @@ -10,7 +10,7 @@ export function extrude(sketch, depth) { let v2s = [] function findPair(node) { - console.log(node.name,'xx') + // console.log(node.name, 'xx') if (node.userData.construction) return; visited.add(node) let linkedObj = linkedObjs.get(node.userData.l_id) @@ -43,7 +43,7 @@ export function extrude(sketch, depth) { ) ] if (d == children[2]) { - console.log('pair found') + // console.log('pair found') }; findTouching(d) @@ -51,19 +51,19 @@ export function extrude(sketch, depth) { function findTouching(node) { - console.log(node.name,'yy') + // console.log(node.name, 'yy') for (let t of node.userData.constraints) { - console.log(constraints.get(t)[2],node.name ) + // console.log(constraints.get(t)[2], node.name) if (constraints.get(t)[0] != 'points_coincident') continue for (let c of constraints.get(t)[2]) { if (c == -1) continue; const d = children[objIdx.get(c)] if (d == node) continue; if (d == children[2]) { - console.log('loop found') + // console.log('loop found') } else { // if (!visited.has(d)) { - findPair(d) + findPair(d) // } }; } @@ -71,7 +71,7 @@ export function extrude(sketch, depth) { } - findPair(children[2]) //??? need fixing + findPair(children[sketch.geomStartIdx + 1]) // ?? possibly allow user select search start point const shape = new THREE.Shape(v2s); // const extrudeSettings = { depth: Math.abs(depth), bevelEnabled: false }; @@ -88,27 +88,9 @@ export function extrude(sketch, depth) { const mesh = new THREE.Mesh(geometry, material) - // const material = new THREE.MeshPhongMaterial({ - // color: color.mesh, - // }); - - // const wireframe = new THREE.WireframeGeometry( geometry ); - // const mesh = new THREE.LineSegments( wireframe ); - // mesh.material.depthTest = true; - // mesh.material.opacity = 0.8; - // mesh.material.transparent = true; - - // const edges = new THREE.EdgesGeometry( geometry, 15 ); - // edges.type = 'BufferGeometry' - // edges.parameters = undefined - - // const mesh = new THREE.LineSegments( edges, new THREE.LineBasicMaterial( { color: 0x000000 } ) ); - mesh.name = 'e' + this.mid++ - // mesh.name = 'm' + sketch.obj3d.name.slice(1) - // mesh.name = 'e' + sketch.obj3d.name.slice(1) mesh.userData.type = 'mesh' mesh.userData.featureInfo = [sketch.obj3d.name, depth] mesh.layers.enable(1) @@ -119,12 +101,6 @@ export function extrude(sketch, depth) { mesh.add(vertices) - - - - - - mesh.matrixAutoUpdate = false; mesh.matrix.multiply(sketch.obj3d.matrix) @@ -134,25 +110,22 @@ export function extrude(sketch, depth) { } - this.obj3d.add(mesh) + if (!refresh) { + this.obj3d.add(mesh) - this.store.dispatch({ type: 'rx-extrusion', mesh, sketchId: sketch.obj3d.name }) + this.store.dispatch({ type: 'rx-extrusion', mesh, sketchId: sketch.obj3d.name }) - // sketch.userData - if (this.activeSketch == sketch) { - this.activeSketch = null - sketch.deactivate() + if (this.activeSketch == sketch) { + sketch.deactivate() + } + this.render() + } else { + return mesh } - // this.clearSelection() - this.render() } - - - - export function flipBufferGeometryNormals(geometry) { //https://stackoverflow.com/a/54496265 const tempXYZ = [0, 0, 0]; diff --git a/src/react/depTree.mjs b/src/react/depTree.mjs index 626f581..755b99f 100644 --- a/src/react/depTree.mjs +++ b/src/react/depTree.mjs @@ -1,20 +1,15 @@ + export class DepTree { constructor(obj) { - if (obj) { - this.order = { ...obj.order } - this.byId = { ...obj.byId } - this.allIds = [...obj.allIds] + this.order = { ...obj.order } + this.byId = { ...obj.byId } + this.allIds = [...obj.allIds] - this.tree = {} - for (let k in obj.tree) { - this.tree[k] = { ...obj.tree[k] } - } - - } else { - this.tree = {} - this.order = {} - this.allIds = [] + this.tree = {} + for (let k in obj.tree) { + this.tree[k] = { ...obj.tree[k] } } + } addParent(id) { @@ -71,7 +66,7 @@ export class DepTree { const deletedObj = sc.obj3d.children.splice(spliceIdx + 1, 1)[0] // first 1 elements are non geom - deletedObj.traverse((obj)=>{ + deletedObj.traverse((obj) => { if (obj.geometry) obj.geometry.dispose() if (obj.material) obj.material.dispose() }) @@ -95,6 +90,9 @@ export class DepTree { } return this } + + + } @@ -103,7 +101,7 @@ export class DepTree { // const dt = new DepTree() // dt.addParent('r1') // dt.addParent('r2') -// dt.addChild('r3', 'r1', 'r2') +// dt.addChild('r3', 'r1', 'r2')s // dt.addParent('r4') // dt.addChild('r5', 'r4', 'r3') // dt.addChild('r6', 'r1', 'r5') @@ -128,3 +126,6 @@ export class DepTree { // allIds: [ 'r1', 'r2', 'r3', 'r4', 'r8' ] // } + + + diff --git a/src/react/dialog.jsx b/src/react/dialog.jsx index 404e0ce..4967b90 100644 --- a/src/react/dialog.jsx +++ b/src/react/dialog.jsx @@ -22,21 +22,28 @@ export const Dialog = ({ dialog, setDialog }) => { }, []) const extrude = () => { + let sketch if (sc.activeSketch) { - sc.extrude(sc.activeSketch, ref.current.value) - setDialog(null) + sketch = sc.activeSketch } else if (sc.selected.length === 1 && sc.selected[0].userData.type == 'sketch') { - sc.extrude(treeEntriesById[sc.selected[0].name], ref.current.value) - setDialog(null) + sketch = treeEntriesById[sc.selected[0].name] } else { console.log('invalid selection') + return } + + setDialog(null) + sc.extrude(sketch, ref.current.value) + + sc.render() + forceUpdate() } const [_, forceUpdate] = useReducer(x => x + 1, 0); return
+ {/* return
*/} ref.current.value *= -1} diff --git a/src/react/navBar.jsx b/src/react/navBar.jsx index a665bd5..5e0a29d 100644 --- a/src/react/navBar.jsx +++ b/src/react/navBar.jsx @@ -17,8 +17,7 @@ export const NavBar = ({ setDialog }) => { const boolOp = (code) => { if (sc.selected.length != 2 || !sc.selected.every(e => e.userData.type == 'mesh')) return const [m1, m2] = sc.selected - const mesh = sc.boolOp(m1, m2, code) - dispatch({ type: 'rx-boolean', mesh, deps: [m1.name, m2.name] }) + sc.boolOp(m1, m2, code) sc.render() forceUpdate() } @@ -65,8 +64,7 @@ export const NavBar = ({ setDialog }) => { const btnz2 = [ - [FaEdit, addSketch, 'Sketch [s]'] - , + [FaEdit, addSketch, 'Sketch [s]'], [Icon.Extrude, extrude, 'Extrude [e]'], [Icon.Union, () => boolOp('u'), 'Union'], [Icon.Subtract, () => boolOp('s'), 'Subtract'], diff --git a/src/react/reducer.js b/src/react/reducer.js index dd96053..36fd3af 100644 --- a/src/react/reducer.js +++ b/src/react/reducer.js @@ -48,7 +48,7 @@ export function treeEntries(state = defaultState, action) { }, allIds: { $push: [action.mesh.name] }, tree: { - [action.sketchId]: { [action.mesh.name]: { $set: true} }, + [action.sketchId]: { [action.mesh.name]: { $set: true } }, [action.mesh.name]: { $set: {} } }, order: { [action.mesh.name]: { $set: state.allIds.length } }, diff --git a/src/react/tree.jsx b/src/react/tree.jsx index 46171cb..d186cda 100644 --- a/src/react/tree.jsx +++ b/src/react/tree.jsx @@ -2,10 +2,12 @@ import React, { useReducer, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux' -import { MdVisibilityOff, MdVisibility, MdDelete } from 'react-icons/md' +import { MdVisibilityOff, MdVisibility, MdDelete, MdRefresh } from 'react-icons/md' import { FaCube, FaEdit } from 'react-icons/fa' +import { DepTree } from './depTree.mjs' + export const Tree = () => { const treeEntries = useSelector(state => state.treeEntries) @@ -26,6 +28,7 @@ const treeIcons = { const TreeEntry = ({ entId }) => { + const state = useSelector(state => state.treeEntries) const treeEntries = useSelector(state => state.treeEntries.byId) const dispatch = useDispatch() @@ -110,6 +113,14 @@ const TreeEntry = ({ entId }) => { e.stopPropagation() }} /> + { + e.stopPropagation() + + sc.refreshNode(entId) + sc.render() + }} + /> { visible ? diff --git a/src/shared.js b/src/shared.js index a94afce..696f1da 100644 --- a/src/shared.js +++ b/src/shared.js @@ -166,7 +166,7 @@ function setHover(obj, state, meshHover = true) { break; case 'mesh': if (meshHover) { - // obj.material.emissive.set(colObj.emissive) + obj.material.emissive.set(colObj.emissive) } else { break } diff --git a/todo.txt b/todo.txt index e45f9e0..cd9b45a 100644 --- a/todo.txt +++ b/todo.txt @@ -30,16 +30,15 @@ tangent // done to the best of my ability extrude dialogue / done better default ent names / done +loopfind especially arc, // fixed for single looop, good enough, maybe stretch goal of selecting search start pt +dim tag delete //resolved -unable to delete arc hover not clearing sometimes in sketch -dim tags are not clearing - auto update extrude -loopfind especially arc file save, stl export