diff --git a/dist/solver.wasm b/dist/solver.wasm index c8b4163..2a16e2e 100755 Binary files a/dist/solver.wasm and b/dist/solver.wasm differ diff --git a/lib/STLExporter.js b/lib/STLExporter.js new file mode 100644 index 0000000..606b17c --- /dev/null +++ b/lib/STLExporter.js @@ -0,0 +1,209 @@ +import { + Vector3 +} from '../../../build/three.module.js'; + +/** + * Usage: + * var exporter = new STLExporter(); + * + * // second argument is a list of options + * var data = exporter.parse( mesh, { binary: true } ); + * + */ + +var STLExporter = function () {}; + +STLExporter.prototype = { + + constructor: STLExporter, + + parse: function ( scene, options ) { + + if ( options === undefined ) options = {}; + + var binary = options.binary !== undefined ? options.binary : false; + + // + + var objects = []; + var triangles = 0; + + scene.traverse( function ( object ) { + + if ( object.isMesh ) { + + var geometry = object.geometry; + + if ( geometry.isBufferGeometry !== true ) { + + throw new Error( 'THREE.STLExporter: Geometry is not of type THREE.BufferGeometry.' ); + + } + + var index = geometry.index; + var positionAttribute = geometry.getAttribute( 'position' ); + + triangles += ( index !== null ) ? ( index.count / 3 ) : ( positionAttribute.count / 3 ); + + objects.push( { + object3d: object, + geometry: geometry + } ); + + } + + } ); + + var output; + var offset = 80; // skip header + + if ( binary === true ) { + + var bufferLength = triangles * 2 + triangles * 3 * 4 * 4 + 80 + 4; + var arrayBuffer = new ArrayBuffer( bufferLength ); + output = new DataView( arrayBuffer ); + output.setUint32( offset, triangles, true ); offset += 4; + + } else { + + output = ''; + output += 'solid exported\n'; + + } + + var vA = new Vector3(); + var vB = new Vector3(); + var vC = new Vector3(); + var cb = new Vector3(); + var ab = new Vector3(); + var normal = new Vector3(); + + for ( var i = 0, il = objects.length; i < il; i ++ ) { + + var object = objects[ i ].object3d; + var geometry = objects[ i ].geometry; + + var index = geometry.index; + var positionAttribute = geometry.getAttribute( 'position' ); + + if ( index !== null ) { + + // indexed geometry + + for ( var j = 0; j < index.count; j += 3 ) { + + var a = index.getX( j + 0 ); + var b = index.getX( j + 1 ); + var c = index.getX( j + 2 ); + + writeFace( a, b, c, positionAttribute, object ); + + } + + } else { + + // non-indexed geometry + + for ( var j = 0; j < positionAttribute.count; j += 3 ) { + + var a = j + 0; + var b = j + 1; + var c = j + 2; + + writeFace( a, b, c, positionAttribute, object ); + + } + + } + + } + + if ( binary === false ) { + + output += 'endsolid exported\n'; + + } + + return output; + + function writeFace( a, b, c, positionAttribute, object ) { + + vA.fromBufferAttribute( positionAttribute, a ); + vB.fromBufferAttribute( positionAttribute, b ); + vC.fromBufferAttribute( positionAttribute, c ); + + if ( object.isSkinnedMesh === true ) { + + object.boneTransform( a, vA ); + object.boneTransform( b, vB ); + object.boneTransform( c, vC ); + + } + + vA.applyMatrix4( object.matrixWorld ); + vB.applyMatrix4( object.matrixWorld ); + vC.applyMatrix4( object.matrixWorld ); + + writeNormal( vA, vB, vC ); + + writeVertex( vA ); + writeVertex( vB ); + writeVertex( vC ); + + if ( binary === true ) { + + output.setUint16( offset, 0, true ); offset += 2; + + } else { + + output += '\t\tendloop\n'; + output += '\tendfacet\n'; + + } + + } + + function writeNormal( vA, vB, vC ) { + + cb.subVectors( vC, vB ); + ab.subVectors( vA, vB ); + cb.cross( ab ).normalize(); + + normal.copy( cb ).normalize(); + + if ( binary === true ) { + + output.setFloat32( offset, normal.x, true ); offset += 4; + output.setFloat32( offset, normal.y, true ); offset += 4; + output.setFloat32( offset, normal.z, true ); offset += 4; + + } else { + + output += '\tfacet normal ' + normal.x + ' ' + normal.y + ' ' + normal.z + '\n'; + output += '\t\touter loop\n'; + + } + + } + + function writeVertex( vertex ) { + + if ( binary === true ) { + + output.setFloat32( offset, vertex.x, true ); offset += 4; + output.setFloat32( offset, vertex.y, true ); offset += 4; + output.setFloat32( offset, vertex.z, true ); offset += 4; + + } else { + + output += '\t\t\tvertex ' + vertex.x + ' ' + vertex.y + ' ' + vertex.z + '\n'; + + } + + } + + } + +}; + +export { STLExporter }; diff --git a/lib/stl.js b/lib/stl.js new file mode 100644 index 0000000..937fb47 --- /dev/null +++ b/lib/stl.js @@ -0,0 +1,209 @@ +import { + Vector3 +} from '../node_modules/three/src/Three'; + +/** + * Usage: + * var exporter = new STLExporter(); + * + * // second argument is a list of options + * var data = exporter.parse( mesh, { binary: true } ); + * + */ + +var STLExporter = function () {}; + +STLExporter.prototype = { + + constructor: STLExporter, + + parse: function ( scene, options ) { + + if ( options === undefined ) options = {}; + + var binary = options.binary !== undefined ? options.binary : false; + + // + + var objects = []; + var triangles = 0; + + scene.traverse( function ( object ) { + + if ( object.isMesh ) { + + var geometry = object.geometry; + + if ( geometry.isBufferGeometry !== true ) { + + throw new Error( 'THREE.STLExporter: Geometry is not of type THREE.BufferGeometry.' ); + + } + + var index = geometry.index; + var positionAttribute = geometry.getAttribute( 'position' ); + + triangles += ( index !== null ) ? ( index.count / 3 ) : ( positionAttribute.count / 3 ); + + objects.push( { + object3d: object, + geometry: geometry + } ); + + } + + } ); + + var output; + var offset = 80; // skip header + + if ( binary === true ) { + + var bufferLength = triangles * 2 + triangles * 3 * 4 * 4 + 80 + 4; + var arrayBuffer = new ArrayBuffer( bufferLength ); + output = new DataView( arrayBuffer ); + output.setUint32( offset, triangles, true ); offset += 4; + + } else { + + output = ''; + output += 'solid exported\n'; + + } + + var vA = new Vector3(); + var vB = new Vector3(); + var vC = new Vector3(); + var cb = new Vector3(); + var ab = new Vector3(); + var normal = new Vector3(); + + for ( var i = 0, il = objects.length; i < il; i ++ ) { + + var object = objects[ i ].object3d; + var geometry = objects[ i ].geometry; + + var index = geometry.index; + var positionAttribute = geometry.getAttribute( 'position' ); + + if ( index !== null ) { + + // indexed geometry + + for ( var j = 0; j < index.count; j += 3 ) { + + var a = index.getX( j + 0 ); + var b = index.getX( j + 1 ); + var c = index.getX( j + 2 ); + + writeFace( a, b, c, positionAttribute, object ); + + } + + } else { + + // non-indexed geometry + + for ( var j = 0; j < positionAttribute.count; j += 3 ) { + + var a = j + 0; + var b = j + 1; + var c = j + 2; + + writeFace( a, b, c, positionAttribute, object ); + + } + + } + + } + + if ( binary === false ) { + + output += 'endsolid exported\n'; + + } + + return output; + + function writeFace( a, b, c, positionAttribute, object ) { + + vA.fromBufferAttribute( positionAttribute, a ); + vB.fromBufferAttribute( positionAttribute, b ); + vC.fromBufferAttribute( positionAttribute, c ); + + if ( object.isSkinnedMesh === true ) { + + object.boneTransform( a, vA ); + object.boneTransform( b, vB ); + object.boneTransform( c, vC ); + + } + + vA.applyMatrix4( object.matrixWorld ); + vB.applyMatrix4( object.matrixWorld ); + vC.applyMatrix4( object.matrixWorld ); + + writeNormal( vA, vB, vC ); + + writeVertex( vA ); + writeVertex( vB ); + writeVertex( vC ); + + if ( binary === true ) { + + output.setUint16( offset, 0, true ); offset += 2; + + } else { + + output += '\t\tendloop\n'; + output += '\tendfacet\n'; + + } + + } + + function writeNormal( vA, vB, vC ) { + + cb.subVectors( vC, vB ); + ab.subVectors( vA, vB ); + cb.cross( ab ).normalize(); + + normal.copy( cb ).normalize(); + + if ( binary === true ) { + + output.setFloat32( offset, normal.x, true ); offset += 4; + output.setFloat32( offset, normal.y, true ); offset += 4; + output.setFloat32( offset, normal.z, true ); offset += 4; + + } else { + + output += '\tfacet normal ' + normal.x + ' ' + normal.y + ' ' + normal.z + '\n'; + output += '\t\touter loop\n'; + + } + + } + + function writeVertex( vertex ) { + + if ( binary === true ) { + + output.setFloat32( offset, vertex.x, true ); offset += 4; + output.setFloat32( offset, vertex.y, true ); offset += 4; + output.setFloat32( offset, vertex.z, true ); offset += 4; + + } else { + + output += '\t\t\tvertex ' + vertex.x + ' ' + vertex.y + ' ' + vertex.z + '\n'; + + } + + } + + } + +}; + +export { STLExporter }; diff --git a/src/Scene.js b/src/Scene.js index 8e62d4a..d905c23 100644 --- a/src/Scene.js +++ b/src/Scene.js @@ -1,22 +1,16 @@ - - - import * as THREE from '../node_modules/three/src/Three'; -import { TrackballControls } from '../lib/trackball' -import { Sketch } from './Sketch' -import Stats from '../lib/stats.module.js'; +import { Sketch } from './Sketch' import { extrude, flipBufferGeometryNormals } from './extrude' import { onHover, onPick, clearSelection } from './mouseEvents'; import { _vec2, _vec3, color, awaitSelection, ptObj, setHover } from './shared' - import { AxesHelper } from './axes' +import { TrackballControls } from '../lib/trackball' import CSG from "../lib/three-csg" - -import { STLExporter } from '../node_modules/three/examples/jsm/exporters/STLExporter' - +import { STLExporter } from '../lib/stl' +import Stats from '../lib/stats.module.js'; @@ -376,37 +370,34 @@ function render() { } -async function addSketch() { +function addSketch() { let sketch; - const references = await this.awaitSelection({ selpoint: 3 }, { plane: 1 }); - - if (!references) return; - - if (references[0].userData.type == 'plane') { - sketch = new Sketch(this) - sketch.obj3d.matrix = references[0].matrix - sketch.plane.applyMatrix4(sketch.obj3d.matrix) - sketch.obj3d.inverse = sketch.obj3d.matrix.clone().invert() - this.obj3d.add(sketch.obj3d) - } else { + if (this.selected.length == 3 && this.selected.every(e=>e.userData.type == 'selpoint')) { sketch = new Sketch(this) this.obj3d.add(sketch.obj3d) sketch.align( - ...references.map( + ...this.selected.map( el => new THREE.Vector3(...el.geometry.attributes.position.array).applyMatrix4(el.matrixWorld) ) ) + } else if (this.selected.length && this.selected[0].userData.type == 'plane') { + sketch = new Sketch(this) + sketch.obj3d.matrix = this.selected[0].matrix + sketch.plane.applyMatrix4(sketch.obj3d.matrix) + sketch.obj3d.inverse = sketch.obj3d.matrix.clone().invert() + this.obj3d.add(sketch.obj3d) + + } else { + return } + this.newSketch = true this.clearSelection() - sketch.obj3d.addEventListener('change', this.render); - return sketch - } window.sc = new Scene(store) diff --git a/src/Sketch.js b/src/Sketch.js index d6c2d45..9b3780e 100644 --- a/src/Sketch.js +++ b/src/Sketch.js @@ -5,7 +5,7 @@ import * as THREE from '../node_modules/three/src/Three'; import { _vec2, _vec3, raycaster, awaitSelection, ptObj, setHover } from './shared' import { drawOnClick1, drawOnClick2, drawPreClick2, drawOnClick3, drawPreClick3, drawClear, drawPoint } from './drawEvents' -import { onHover, onDrag, onPick, onRelease, clearSelection} from './mouseEvents' +import { onHover, onDrag, onPick, onRelease, clearSelection } from './mouseEvents' import { setCoincident, setOrdinate, setTangent } from './constraintEvents' import { get3PtArc } from './drawArc' import { replacer, reviver } from './utils' @@ -197,6 +197,9 @@ class Sketch { this.obj3d.traverse(e => e.layers.disable(2)) this.scene.axes.visible = false this.scene.activeSketch = null + if (this.scene.newSketch) { + this.scene.newSketch = false + } this.clearSelection() @@ -255,8 +258,11 @@ class Sketch { this.canvas.addEventListener('pointerdown', this.drawOnClick1, { once: true }) break; case 'd': - drawClear.call(this) - this.drawDimension() + if (this.mode != 'dimension') { + drawClear.call(this) + this.mode = "dimension" + this.drawDimension() + } break; case 'c': drawClear.call(this) @@ -284,6 +290,7 @@ class Sketch { console.log('undo would be nice') break; } + // console.log('this mode:', this.mode) } deleteSelected() { diff --git a/src/drawArc.js b/src/drawArc.js index 6c4c954..d2cc392 100644 --- a/src/drawArc.js +++ b/src/drawArc.js @@ -1,6 +1,8 @@ -import { Vector2 } from 'three'; +import { + Vector2 +} from '../node_modules/three/src/Three'; import { ptObj, lineObj } from './shared' const n = 30 diff --git a/src/drawDimension.js b/src/drawDimension.js index ea7b5fe..ca6a468 100644 --- a/src/drawDimension.js +++ b/src/drawDimension.js @@ -138,7 +138,7 @@ export async function drawDimension() { } else { - this.dimGroup.children.splice(this.dimGroup.length - 2, 2).forEach( + this.dimGroup.children.splice(this.dimGroup.children.length - 2, 2).forEach( e => { e.geometry.dispose() e.material.dispose() @@ -147,6 +147,10 @@ export async function drawDimension() { this.labelContainer.removeChild(this.labelContainer.lastChild); sc.render() } + if (this.mode=="dimension") { + this.drawDimension() + } + return } diff --git a/src/mouseEvents.js b/src/mouseEvents.js index f611e2b..d4fd2d4 100644 --- a/src/mouseEvents.js +++ b/src/mouseEvents.js @@ -5,7 +5,7 @@ import { onDimMoveEnd } from './drawDimension' let ptLoc export function onHover(e) { - if (this.mode || e.buttons) return + if (( this.mode && this.mode!='dimension') || e.buttons) return raycaster.setFromCamera( new THREE.Vector2( @@ -114,7 +114,7 @@ export function onHover(e) { let draggedLabel; export function onPick(e) { - if (this.mode || e.buttons != 1) return + if (( this.mode && this.mode!='dimension') || e.buttons != 1) return // if (this.mode || e.buttons != 1 || e.ctrlKey || e.metaKey) return if (this.hovered.length) { diff --git a/src/react/app.css b/src/react/app.css index ee2f663..807aa48 100644 --- a/src/react/app.css +++ b/src/react/app.css @@ -57,6 +57,13 @@ body { hover:bg-gray-500 hover:text-gray-200; } +.active-btn { + cursor: pointer; + @apply fill-current + bg-green-400 text-gray-200 +} + + .btn-green { cursor: pointer; diff --git a/src/react/app.jsx b/src/react/app.jsx index 4120d03..5e292a7 100644 --- a/src/react/app.jsx +++ b/src/react/app.jsx @@ -1,9 +1,8 @@ - import ReactDOM from 'react-dom' -import React, { } from 'react' +import React from 'react' import { createStore, applyMiddleware } from 'redux' -import { Provider, useSelector } from 'react-redux' +import { Provider } from 'react-redux' import { reducer } from './reducer' import logger from 'redux-logger' @@ -11,27 +10,19 @@ import { Tree } from './tree' import { NavBar } from './navBar' import { ToolTip } from './toolTip' - import './app.css' -const preloadedState = { - treeEntries: { - byId: {}, - allIds: [], - tree: {}, - order: {}, - visible: {}, - activeSketchId: "" - }, + + + +let store +if (process.env.NODE_ENV === 'production') { + store = createStore(reducer) +} else { + const { logger } = require(`redux-logger`); + store = createStore(reducer, {}, applyMiddleware(logger)) } -// const store = createStore(reducer, preloadedState, applyMiddleware(logger)) - - -const store = createStore(reducer, {}, applyMiddleware(logger)) -// const store = createStore(reducer, sc.loadState(), applyMiddleware(logger)) - - const App = ({ store }) => { return diff --git a/src/react/dialog.jsx b/src/react/dialog.jsx index bc78010..7ff8c26 100644 --- a/src/react/dialog.jsx +++ b/src/react/dialog.jsx @@ -111,10 +111,14 @@ export const Dialog = () => { || sc.activeSketch.idOnActivate != id || sc.activeSketch.c_idOnActivate != sc.activeSketch.c_id ) { - dispatch({ type: "restore-sketch" }) - // dispatch({ type: 'set-modified', status: false }) + if (sc.newSketch) { + dispatch({ type: 'delete-node', id: sc.activeSketch.obj3d.name }) + sc.sid -= 1 + } else { + dispatch({ type: "restore-sketch" }) + } } - + dispatch({ type: 'finish-sketch' }) sc.activeSketch.deactivate() diff --git a/src/react/fileHelpers.js b/src/react/fileHelpers.js index 1273704..e0fa7ac 100644 --- a/src/react/fileHelpers.js +++ b/src/react/fileHelpers.js @@ -15,16 +15,12 @@ var tzoffset = (new Date()).getTimezoneOffset() * 60000; export function STLExport(filename) { - if (sc.selected[0] && sc.selected[0].userData.type == 'mesh') { - const result = STLexp.parse(sc.selected[0], { binary: true }); + const result = STLexp.parse(sc.selected[0], { binary: true }); - const time = (new Date(Date.now() - tzoffset)).toISOString().slice(0, -5).replace(/:/g, '-'); + const time = (new Date(Date.now() - tzoffset)).toISOString().slice(0, -5).replace(/:/g, '-'); - saveLegacy(new Blob([result], { type: 'model/stl' }), `${filename}_${time}.stl`); - } else { - alert('please select one body to export') - } + saveLegacy(new Blob([result], { type: 'model/stl' }), `${filename}_${time}.stl`); } @@ -41,7 +37,6 @@ export async function saveFile(fileHandle, file, dispatch) { console.error(msg, ex); alert(msg); } - // app.setFocus(); }; export async function saveFileAs(file, dispatch) { @@ -83,16 +78,11 @@ export async function saveFileAs(file, dispatch) { alert(msg); return; } - - // app.setFocus(); }; export async function openFile(dispatch) { - // if (!app.confirmDiscard()) { - // return; - // } let fileHandle // If a fileHandle is provided, verify we have permission to read/write it, @@ -143,7 +133,7 @@ export function confirmDiscard(modified) { export async function verifyPermission(fileHandle) { const opts = { - mode:'readwrite' + mode: 'readwrite' }; // Check if we already have permission, if so, return true. diff --git a/src/react/navBar.jsx b/src/react/navBar.jsx index 7d0d547..b1a0e3a 100644 --- a/src/react/navBar.jsx +++ b/src/react/navBar.jsx @@ -4,16 +4,13 @@ import React, { useEffect, useReducer } from 'react'; import { useDispatch, useSelector } from 'react-redux' -import { FaEdit } from 'react-icons/fa' +import { FaEdit, FaLinkedin, FaGithub } from 'react-icons/fa' import { MdSave, MdFolder, MdInsertDriveFile } from 'react-icons/md' import * as Icon from "./icons"; import { Dialog } from './dialog' import { STLExport, saveFile, openFile, verifyPermission } from './fileHelpers' - - - export const NavBar = () => { const dispatch = useDispatch() const sketchActive = useSelector(state => state.ui.sketchActive) @@ -22,7 +19,10 @@ export const NavBar = () => { const modified = useSelector(state => state.ui.modified) const boolOp = (code) => { - if (sc.selected.length != 2 || !sc.selected.every(e => e.userData.type == 'mesh')) return + if (sc.selected.length != 2 || !sc.selected.every(e => e.userData.type == 'mesh')) { + alert('please first select two bodies for boolean operation') + return + } const [m1, m2] = sc.selected const mesh = sc.boolOp(m1, m2, code) @@ -46,8 +46,12 @@ export const NavBar = () => { forceUpdate() } - const addSketch = async () => { - const sketch = await sc.addSketch() + const addSketch = () => { + const sketch = sc.addSketch() + if (!sketch) { + alert('please select a plane or 3 points to define sketch plane') + return + } dispatch({ type: 'rx-sketch', obj: sketch }) @@ -100,16 +104,16 @@ export const NavBar = () => { dispatch({ type: 'set-dialog', action: 'extrude', target: sc.activeSketch }) }, 'Extrude [e]'], - [Icon.Dimension, () => sc.activeSketch.command('d'), 'Dimension [d]'], - [Icon.Line, () => sc.activeSketch.command('l'), 'Line [l]'], - [Icon.Arc, () => sc.activeSketch.command('a'), 'Arc [a]'], - [Icon.Coincident, () => sc.activeSketch.command('c'), 'Coincident [c]'], - [Icon.Vertical, () => sc.activeSketch.command('v'), 'Vertical [v]'], - [Icon.Horizontal, () => sc.activeSketch.command('h'), 'Horizontal [h]'], - [Icon.Tangent, () => sc.activeSketch.command('t'), 'Tangent [t]'], + [Icon.Dimension, () => sc.activeSketch.command('d'), 'Dimension [D]'], + [Icon.Line, () => sc.activeSketch.command('l'), 'Line [L]'], + [Icon.Arc, () => sc.activeSketch.command('a'), 'Arc [A]'], + [Icon.Coincident, () => sc.activeSketch.command('c'), 'Coincident [C]'], + [Icon.Vertical, () => sc.activeSketch.command('v'), 'Vertical [V]'], + [Icon.Horizontal, () => sc.activeSketch.command('h'), 'Horizontal [H]'], + [Icon.Tangent, () => sc.activeSketch.command('t'), 'Tangent [T]'], [MdSave, async () => { - if(await verifyPermission(fileHandle) === false) return + if (await verifyPermission(fileHandle) === false) return sc.refreshNode(sc.activeSketch.obj3d.name, treeEntries) sc.activeSketch.clearSelection() saveFile(fileHandle, JSON.stringify([id, sc.sid, sc.mid, treeEntries]), dispatch) @@ -121,9 +125,14 @@ export const NavBar = () => { const partModeButtons = [ - [FaEdit, addSketch, 'Sketch [s]'], + [FaEdit, addSketch, 'Sketch'], [Icon.Extrude, () => { - dispatch({ type: 'set-dialog', action: 'extrude', target: treeEntries.byId[sc.selected[0].name] }) + if (sc.selected[0] && treeEntries.byId[sc.selected[0].name].userData.type == 'sketch') { + dispatch({ type: 'set-dialog', action: 'extrude', target: treeEntries.byId[sc.selected[0].name] }) + } else { + alert('please select a sketch from the left pane extrude') + } + }, 'Extrude'], [Icon.Union, () => boolOp('u'), 'Union'], @@ -147,9 +156,12 @@ export const NavBar = () => { ) }, 'Open'], [Icon.Stl, () => { - STLExport('box') - }, - , 'Export STL'], + if (sc.selected[0] && sc.selected[0].userData.type == 'mesh') { + STLExport(fileHandle ? fileHandle.name.replace(/\.[^/.]+$/, "") : 'untitled') + } else { + alert('please first select one body to export') + } + }, 'Export to STL'], ] const [_, forceUpdate] = useReducer(x => x + 1, 0); @@ -175,30 +187,16 @@ export const NavBar = () => { )) } -
+
+ + + + + +
} -// app.saveFile = async () => { -// try { -// if (!app.file.handle) { -// return await app.saveFileAs(); -// } -// gaEvent('FileAction', 'Save'); -// await writeFile(app.file.handle, app.getText()); -// app.setModified(false); -// } catch (ex) { -// gaEvent('Error', 'FileSave', ex.name); -// const msg = 'Unable to save file'; -// console.error(msg, ex); -// alert(msg); -// } -// app.setFocus(); -// }; - - - - diff --git a/src/react/tree.jsx b/src/react/tree.jsx index b75acc6..fc83c29 100644 --- a/src/react/tree.jsx +++ b/src/react/tree.jsx @@ -11,7 +11,7 @@ export const Tree = () => { const fileHandle = useSelector(state => state.ui.fileHandle) return
-
+
{fileHandle ? fileHandle.name.replace(/\.[^/.]+$/, "") : 'untitled'}
{treeEntries.allIds.map((entId, idx) => ( diff --git a/src/shared.js b/src/shared.js index 696f1da..9737c63 100644 --- a/src/shared.js +++ b/src/shared.js @@ -128,6 +128,7 @@ async function awaitSelection(...criteria) { references.push(pt) const type = pt.userData.type + if (counter[type]) { counter[type] += 1; } else { @@ -144,7 +145,7 @@ async function awaitSelection(...criteria) { window.removeEventListener('keydown', onKey) } - console.log('fail') + // console.log('fail') return null } diff --git a/todo.txt b/todo.txt index b0e0dc5..c905819 100644 --- a/todo.txt +++ b/todo.txt @@ -35,48 +35,49 @@ dim tag delete //resolved auto update extrude // done extrude edit dialog // done file save, stl export// done +seperate scene from init logic only init cam and rendere // not an issue , ended up just splicing (1) +add download button, different from save button // done -unable cancel out of new sketches //fixed seemingly +-unable to delete arc // fixed seemingly -sometimes unable to hit return and change dimensionk --unable to delete arc hover not clearing sometimes in sketch 0.000 artifact lighting messed up -seperate scene from init logic only init cam and rendere + + + + + + + reattach sketch auto snap - +vertical and horzontal baseline to dimension to / or just smart ordinate dir dimenensing highlight button to indicate active mode - add cancle soft button for line arc - - constraint labels,equal - -add download button, different from save button parallel // need to add antoher button to feature ,or empty placeholder - - tree relation tool tip tree ent renaming -vertical and horzontal baseline to dimension to set pieces +wasm data structure + hover state for sketch await selection 3 point arc implementation - +local file save and mark dirty saerch tree for loop finding // need dev effor - dep tree for biuidling design treee diff --git a/wasm/solver.c b/wasm/solver.c index bab0f14..813d323 100644 --- a/wasm/solver.c +++ b/wasm/solver.c @@ -174,8 +174,7 @@ int main(int argc, char *argv[]) sys.failed = CheckMalloc(500 * sizeof(sys.failed[0])); sys.faileds = 500; - // Example2d(150.0); - printf("hello\n"); + // printf("hello\n"); return 0; } diff --git a/webpack.prod.js b/webpack.prod.js index 1d1feb9..1c143d3 100644 --- a/webpack.prod.js +++ b/webpack.prod.js @@ -1,10 +1,16 @@ const { merge } = require('webpack-merge'); const common = require('./webpack.common.js'); - +const webpack = require('webpack') module.exports = merge(common, { mode: 'production', - + plugins: [ + new webpack.DefinePlugin({ + // 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV) + 'process.env.NODE_ENV': 'production' + }), + new webpack.IgnorePlugin(/redux-logger/) + ] }); \ No newline at end of file