From 4e0706211fce10797566e8c24f3b506928c5da7a Mon Sep 17 00:00:00 2001 From: howard Date: Sat, 17 Apr 2021 06:32:14 -0700 Subject: [PATCH] workiing file expoort --- src/Scene.js | 10 +++++- src/Sketch.js | 5 ++- src/extrude.js | 1 + src/react/dialog.jsx | 66 +++++++++++++++++++++++++-------------- src/react/fileExporter.js | 39 +++++++++++++++++++++++ src/react/navBar.jsx | 33 +++++++++++++++++--- src/react/reducer.js | 5 ++- src/react/tree.jsx | 26 ++++++++------- todo.txt | 16 +++++++--- 9 files changed, 151 insertions(+), 50 deletions(-) create mode 100644 src/react/fileExporter.js diff --git a/src/Scene.js b/src/Scene.js index 2fbbbf7..54a81df 100644 --- a/src/Scene.js +++ b/src/Scene.js @@ -15,10 +15,14 @@ import { AxesHelper } from './axes' import CSG from "../lib/three-csg" +import { STLExporter } from '../node_modules/three/examples/jsm/exporters/STLExporter' + window.loader = new THREE.ObjectLoader(); +window.STLexp = new STLExporter(); + window.id = 0 window.sid = 1 window.mid = 1 @@ -173,6 +177,10 @@ export class Scene { ) } + + saveString() { + return JSON.stringify([id, this.sid, this.mid, this.store.getState().treeEntries]) + } loadState() { //uglyyy const [curid, cursid, curmid, state] = JSON.parse( @@ -218,7 +226,7 @@ export class Scene { let entry = JSON.parse(string) entry.obj3d = loader.parse(entry.obj3d) - this.obj3d.add(entry.obj3d) + // this.obj3d.add(entry.obj3d) entry = new Sketch(this, entry) entry.obj3d.addEventListener('change', this.render) diff --git a/src/Sketch.js b/src/Sketch.js index bac77aa..49cd3cb 100644 --- a/src/Sketch.js +++ b/src/Sketch.js @@ -175,9 +175,9 @@ class Sketch { // overkill but good solution if this check was more costly this.hasChanged = false this.idOnActivate = id + this.c_idOnActivate = this.c_id // console.log(this,this.selected) const changeDetector = (e) => { - console.log(this.selected.length, e.buttons) if (this.selected.length && e.buttons) { this.canvas.removeEventListener('pointermove', changeDetector) this.hasChanged = true @@ -187,11 +187,10 @@ class Sketch { } deactivate() { - console.log('deactivateeeeeeee') window.removeEventListener('keydown', this.onKeyPress) this.canvas.removeEventListener('pointerdown', this.onPick) this.canvas.removeEventListener('pointermove', this.onHover) - this.store.dispatch({ type: 'finish-sketch' }) + this.labelContainer.innerHTML = "" this.obj3d.visible = false this.obj3d.traverse(e => e.layers.disable(2)) diff --git a/src/extrude.js b/src/extrude.js index c69fb3e..2175731 100644 --- a/src/extrude.js +++ b/src/extrude.js @@ -116,6 +116,7 @@ export function extrude(sketch, depth, refresh=false) { this.store.dispatch({ type: 'rx-extrusion', mesh, sketchId: sketch.obj3d.name }) if (this.activeSketch == sketch) { + this.store.dispatch({ type: 'finish-sketch' }) sketch.deactivate() } this.render() diff --git a/src/react/dialog.jsx b/src/react/dialog.jsx index 13a98f5..0234d75 100644 --- a/src/react/dialog.jsx +++ b/src/react/dialog.jsx @@ -1,14 +1,12 @@ -import React, { useEffect, useReducer, useRef, useState } from 'react'; +import React, { useEffect, useRef } from 'react'; import { useDispatch, useSelector } from 'react-redux' import { MdDone, MdClose } from 'react-icons/md' import * as Icon from "./icons"; - - export const Dialog = () => { const dialog = useSelector(state => state.ui.dialog) @@ -17,6 +15,7 @@ export const Dialog = () => { const ref = useRef() useEffect(() => { + console.log(dialog) if (!ref.current) return ref.current.focus() }, [dialog]) @@ -29,7 +28,18 @@ export const Dialog = () => { } - const [_, forceUpdate] = useReducer(x => x + 1, 0); + const extrudeEdit = () => { + + + dialog.target.userData.featureInfo[1] = ref.current.value + + sc.refreshNode(dialog.target.name) + + sc.render() + dispatch({ type: "clear-dialog" }) + + } + switch (dialog.action) { case 'extrude': @@ -46,44 +56,54 @@ export const Dialog = () => { onClick={() => dispatch({ type: "clear-dialog" })} /> + case 'extrude-edit': + return <> + + ref.current.value *= -1} + /> + + dispatch({ type: "clear-dialog" })} + /> + case 'sketch': return <> { - if (sc.activeSketch.hasChanged || sc.activeSketch.idOnActivate != id) { - - // for (let k in sc.store.getState().treeEntries.tree[sc.activeSketch.obj3d.name]) { - // console.log('circlllles',k) - // } - + if (sc.activeSketch.hasChanged + || sc.activeSketch.idOnActivate != id + || sc.activeSketch.c_idOnActivate != sc.activeSketch.c_id + ) { sc.refreshNode(sc.activeSketch.obj3d.name) } - // dispatch({ type: 'update-descendents', sketch}) + + dispatch({ type: 'finish-sketch' }) + sc.activeSketch.deactivate() sc.render() - dispatch({ type: "clear-dialog" }) }} /> { - console.log('cancle',sc.activeSketch.hasChanged, sc.activeSketch.idOnActivate, id) - if (sc.activeSketch.hasChanged || sc.activeSketch.idOnActivate != id) { - console.log('has changed') - dispatch({ type: "cancel-sketch" }) - sc.store.getState().treeEntries.byId[sc.activeSketch.obj3d.name].deactivate() + if (sc.activeSketch.hasChanged + || sc.activeSketch.idOnActivate != id + || sc.activeSketch.c_idOnActivate != sc.activeSketch.c_id + ) { + dispatch({ type: "restore-sketch" }) } else { - - sc.activeSketch.deactivate() + dispatch({ type: 'finish-sketch' }) } - + sc.activeSketch.deactivate() sc.render() dispatch({ type: "clear-dialog" }) - - } - } + }} /> default: diff --git a/src/react/fileExporter.js b/src/react/fileExporter.js new file mode 100644 index 0000000..ce19e82 --- /dev/null +++ b/src/react/fileExporter.js @@ -0,0 +1,39 @@ +const link = document.createElement( 'a' ); +link.style.display = 'none'; +document.body.appendChild( link ); + +function save(blob, filename) { + + link.href = URL.createObjectURL(blob); + link.download = filename; + link.click(); + +} + + +function saveArrayBuffer( buffer, filename ) { + + save( new Blob( [ buffer ], { type: 'application/octet-stream' } ), filename ); + +} + +function saveString( text, filename ) { + + save( new Blob( [ text ], { type: 'text/plain' } ), filename ); + +} + +export function STLExport() { + if (sc.selected[0] && sc.selected[0].userData.type == 'mesh') { + const result = STLexp.parse( sc.selected[0], { binary: true } ); + saveArrayBuffer( result, 'box.stl' ); + } +} + + +export function savePart() { + const string = sc.saveString() + + saveString( LZString.compress(string), 'test2.bin' ); + +} \ No newline at end of file diff --git a/src/react/navBar.jsx b/src/react/navBar.jsx index bdfeb71..461ba6c 100644 --- a/src/react/navBar.jsx +++ b/src/react/navBar.jsx @@ -5,11 +5,35 @@ import React, { useEffect, useReducer } from 'react'; import { useDispatch, useSelector } from 'react-redux' import { FaEdit } from 'react-icons/fa' -import { MdSave, MdFolder } from 'react-icons/md' +import { MdSave } from 'react-icons/md' import { FaFolderOpen } from 'react-icons/fa' import * as Icon from "./icons"; import { Dialog } from './dialog' +import { STLExport, savePart } from './fileExporter' + + +const link = document.createElement('a'); +link.style.display = 'none'; +document.body.appendChild(link); + +function save(blob, filename) { + + link.href = URL.createObjectURL(blob); + link.download = filename; + link.click(); + +} + + +function saveArrayBuffer(buffer, filename) { + + save(new Blob([buffer], { type: 'application/octet-stream' }), filename); + +} + + + export const NavBar = () => { const dispatch = useDispatch() @@ -44,8 +68,9 @@ export const NavBar = () => { const sketchModeButtons = [ [Icon.Extrude, () => { - sc.activeSketch.deactivate() + dispatch({ type: 'finish-sketch' }) 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]'], @@ -66,9 +91,9 @@ export const NavBar = () => { [Icon.Union, () => boolOp('u'), 'Union'], [Icon.Subtract, () => boolOp('s'), 'Subtract'], [Icon.Intersect, () => boolOp('i'), 'Intersect'], - [MdSave, () => boolOp('i'), 'Save [ctrl+s]'], + [MdSave, savePart, 'Save [ctrl+s]'], [FaFolderOpen, () => boolOp('i'), 'Load'], - [Icon.Stl, () => boolOp('i'), 'Export STL'], + [Icon.Stl, STLExport, 'Export STL'], ] const [_, forceUpdate] = useReducer(x => x + 1, 0); diff --git a/src/react/reducer.js b/src/react/reducer.js index 8c833f6..413a33c 100644 --- a/src/react/reducer.js +++ b/src/react/reducer.js @@ -43,21 +43,20 @@ export function treeEntries(state = defaultState, action) { activeSketchId: { $set: "" }, visible: { [state.activeSketchId]: { $set: false } }, }) - case 'cancel-sketch': + case 'restore-sketch': const sketch = sc.loadSketch(cache) const deletedObj = sc.obj3d.children.splice(state.order[state.activeSketchId] + 1, 1, sketch.obj3d )[0] - console.log('spliced and starting to delete') deletedObj.traverse((obj) => { if (obj.geometry) obj.geometry.dispose() if (obj.material) obj.material.dispose() }) - // sketch.deactivate() + sc.activeSketch = sketch return update(state, { activeSketchId: { $set: "" }, diff --git a/src/react/tree.jsx b/src/react/tree.jsx index 2e849e3..9da94bb 100644 --- a/src/react/tree.jsx +++ b/src/react/tree.jsx @@ -11,7 +11,7 @@ export const Tree = () => { return
{treeEntries.allIds.map((entId, idx) => ( - + ))}
@@ -28,19 +28,18 @@ const TreeEntry = ({ entId }) => { - const state = useSelector(state => state.treeEntries) - const treeEntries = useSelector(state => state.treeEntries.byId) + const treeEntriesById = useSelector(state => state.treeEntries.byId) const dispatch = useDispatch() const visible = useSelector(state => state.treeEntries.visible[entId]) let obj3d, sketch; - if (treeEntries[entId].obj3d) { - obj3d = treeEntries[entId].obj3d - sketch = treeEntries[entId] + if (treeEntriesById[entId].obj3d) { + obj3d = treeEntriesById[entId].obj3d + sketch = treeEntriesById[entId] } else { - obj3d = treeEntries[entId] + obj3d = treeEntriesById[entId] } let Icon = treeIcons[obj3d.userData.type] @@ -50,14 +49,17 @@ const TreeEntry = ({ entId }) => { return
{ if (obj3d.userData.type == 'sketch') { - sc.activeSketch && sc.activeSketch.deactivate() - + if (sc.activeSketch) { + dispatch({ type: 'finish-sketch' }) + sc.activeSketch.deactivate() + } sketch.activate() - sc.clearSelection() sc.activeSketch = sketch; dispatch({ type: 'set-dialog', action: 'sketch' }) sc.render() + } else if (obj3d.userData.featureInfo.length == 2) { + dispatch({ type: 'set-dialog', action: 'extrude-edit', target: treeEntriesById[entId] }) } }} @@ -116,14 +118,14 @@ const TreeEntry = ({ entId }) => { e.stopPropagation() }} /> - { e.stopPropagation() sc.refreshNode(entId) sc.render() }} - /> + /> */} { visible ? diff --git a/todo.txt b/todo.txt index cd9b45a..8215d91 100644 --- a/todo.txt +++ b/todo.txt @@ -32,28 +32,36 @@ 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 +auto update extrude // done +extrude edit dialog // done - +-sometimes unable to hit return and change dimensionk -unable to delete arc hover not clearing sometimes in sketch +0.000 artifact + -auto update extrude file save, stl export +reattach sketch + +highlight button to indicate active mode + add cancle soft button for line arc -reattach sketch auto snap constraint labels,equal -parallel + +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