diff --git a/dist/solver.wasm b/dist/solver.wasm index c46e8f1..04fd3bc 100755 Binary files a/dist/solver.wasm and b/dist/solver.wasm differ diff --git a/icon/svg-to-jsx.js b/icon/svg-to-jsx.js index d8f5696..49c1c6a 100644 --- a/icon/svg-to-jsx.js +++ b/icon/svg-to-jsx.js @@ -17,7 +17,10 @@ try { let name = file.split('.')[0] name = name[0].toUpperCase() + name.slice(1) names.push(name) - const jsx = await svgr(res, { icon: true, plugins: ['@svgr/plugin-svgo', '@svgr/plugin-jsx', '@svgr/plugin-prettier'] }, { componentName: name }) + const jsx = await svgr(res, { icon: true, + plugins: ['@svgr/plugin-svgo', '@svgr/plugin-jsx', '@svgr/plugin-prettier'], + replaceAttrValues: { '#000': 'currentColor' } + }, { componentName: name }) const split = jsx.split('\n') output.push(split.slice(1,split.length-2).join('\n')) } diff --git a/icon/svgr_raw/dimension.svg b/icon/svgr_raw/dimension.svg new file mode 100644 index 0000000..31cb9a1 --- /dev/null +++ b/icon/svgr_raw/dimension.svg @@ -0,0 +1,182 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Scene.js b/src/Scene.js index 095e392..1df6b30 100644 --- a/src/Scene.js +++ b/src/Scene.js @@ -11,12 +11,14 @@ import Stats from './utils/stats.module.js'; import { add3DPoint } from './datums' import { extrude } from './extrude' import { onHover, onPick } from './utils/mouseEvents'; -import { _vec2, _vec3, color } from './utils/static' +import { _vec2, _vec3, color, awaitPts } from './utils/shared' import { Vector3 } from 'three/src/Three'; import {AxesHelper} from './utils/axes' import CSG from "./utils/three-csg.js" +window.BoolOp = CSG + const eq = (a1, a2) => { if (a1.length != a2.length) return false for (let i = 0; i < a1.length; i++) { @@ -102,6 +104,7 @@ export class Scene { this.extrude = extrude.bind(this); this.onHover = onHover.bind(this); this.onPick = onPick.bind(this); + this.awaitPts = awaitPts.bind(this); this.obj3d.addEventListener('change', this.render); controls.addEventListener('change', this.render); @@ -183,33 +186,11 @@ function render() { + + async function addSketch() { - let references = this.selected.slice() - if (references.length == 0) { - while (references.length < 3) { - let pt; - try { - pt = await new Promise((res, rej) => { - this.canvas.addEventListener('pointerdown', () => res(this.hovered[0]), { once: true }) - window.addEventListener('keydown', (e) => rej(e), { once: true }) - }) - - if (pt.name[0] == 'p') { - references.push(pt) - } else if (pt.name[0] == 'd') { - references = [pt] - break; - } - - } catch (e) { - if (e.key == 'Escape') { - console.log('cancelled') - return; - } - } - } - } + let references = await this.awaitPts(3) const sketch = new Sketch(this.camera, this.canvas, this.store) @@ -240,7 +221,7 @@ async function addSketch() { } window.sc = new Scene(store) -sc.loadState() +// sc.loadState() @@ -248,17 +229,4 @@ sc.loadState() -// //Create a bsp tree from each of the meshes -// let bspA = CSG.fromMesh( mm[0] ) -// let bspB = CSG.fromMesh( mm[2] ) - -// // Subtract one bsp from the other via .subtract... other supported modes are .union and .intersect - -// let bspResult = bspA.subtract(bspB) - -// //Get the resulting mesh from the result bsp, and assign meshA.material to the resulting mesh - -// let meshResult = CSG.toMesh( bspResult, mm[0].matrix, mm[0].material ) - -// sc.add(meshResult) diff --git a/src/app.jsx b/src/app.jsx index 9a9e882..a315c70 100644 --- a/src/app.jsx +++ b/src/app.jsx @@ -7,8 +7,8 @@ import { Provider, useDispatch, useSelector } from 'react-redux' import { FaCube, FaEdit } from 'react-icons/fa' import { MdEdit, MdDone, MdVisibilityOff, MdVisibility } from 'react-icons/md' import { RiShape2Fill } from 'react-icons/ri' -import { Union, Subtract, Intersect, Line, Arc } from './icons' -import { color } from './utils/static' +import * as Icon from "./icons"; +import { color } from './utils/shared' export const Root = ({ store }) => ( @@ -48,11 +48,12 @@ const App = () => { [FaEdit, sc.addSketch, 'Sketch'] , [FaCube, () => sc.extrude(treeEntries.byNid[activeSketchNid]), 'Extrude'], - [Union, () => sc.extrude(treeEntries.byNid[activeSketchNid]), 'Union'], - [Subtract, () => sc.extrude(treeEntries.byNid[activeSketchNid]), 'Subtract'], - [Intersect, () => sc.extrude(treeEntries.byNid[activeSketchNid]), 'Intersect'], - [Line, () => sc.extrude(treeEntries.byNid[activeSketchNid]), 'Line'], - [Arc, () => sc.extrude(treeEntries.byNid[activeSketchNid]), 'Arc'], + [Icon.Union, () => sc.extrude(treeEntries.byNid[activeSketchNid]), 'Union'], + [Icon.Subtract, subtract, 'Subtract'], + [Icon.Intersect, () => sc.extrude(treeEntries.byNid[activeSketchNid]), 'Intersect'], + [Icon.Dimension, () => sc.extrude(treeEntries.byNid[activeSketchNid]), 'Dimension'], + [Icon.Line, () => sc.extrude(treeEntries.byNid[activeSketchNid]), 'Line'], + [Icon.Arc, () => sc.extrude(treeEntries.byNid[activeSketchNid]), 'Arc'], ] return
@@ -83,16 +84,19 @@ const TreeEntry = ({ entId }) => { const activeSketchNid = useSelector(state => state.activeSketchNid) - let entry; - if (entId[0]=="s") { - entry = treeEntries[entId].obj3d + let obj3d, entry; + + entry = treeEntries[entId] + + if (entId[0] == "s") { + obj3d = treeEntries[entId].obj3d } else { - entry = treeEntries[entId] + obj3d = treeEntries[entId] } const [_, forceUpdate] = useReducer(x => x + 1, 0); - const vis = entry.visible + const vis = obj3d.visible return
{ vis ?
{ - entry.visible = false; + obj3d.visible = false; sc.render() forceUpdate() }} @@ -118,7 +122,7 @@ const TreeEntry = ({ entId }) => { :
{ - entry.visible = true; + obj3d.visible = true; sc.render() forceUpdate() }} @@ -156,6 +160,28 @@ const TreeEntry = ({ entId }) => { } -const DesignLeaf = () => { +const subtract = () => { + // //Create a bsp tree from each of the meshes + console.log(sc.selected.length !=2 || !sc.selected.every(e=>e.name && e.name[0]=='m'),"wtf") + if (sc.selected.length !=2 || !sc.selected.every(e=>e.name && e.name[0]=='m')) return + console.log('here') + const [m1, m2] = sc.selected + + let bspA = BoolOp.fromMesh( m1 ) + let bspB = BoolOp.fromMesh( m2 ) + m1.visible = false + m2.visible = false + + // // Subtract one bsp from the other via .subtract... other supported modes are .union and .intersect + + let bspResult = bspA.subtract(bspB) + + // //Get the resulting mesh from the result bsp, and assign meshA.material to the resulting mesh + + let meshResult = BoolOp.toMesh( bspResult, m1.matrix, m1.material ) + + sc.obj3d.add(meshResult) + sc.render() + +} -} \ No newline at end of file diff --git a/src/extrude.js b/src/extrude.js index 4c6b045..24c84e9 100644 --- a/src/extrude.js +++ b/src/extrude.js @@ -1,5 +1,5 @@ import * as THREE from 'three/src/Three'; -import { color, ptObj } from './utils/static' +import { color, ptObj } from './utils/shared' export function extrude(sketch) { let constraints = sketch.constraints; diff --git a/src/icons.jsx b/src/icons.jsx index 882f6ce..a4bdcf9 100644 --- a/src/icons.jsx +++ b/src/icons.jsx @@ -23,6 +23,67 @@ function Arc(props) { ); } +function Dimension(props) { + return ( + + + + + + + + + + + + + ); +} + function Intersect(props) { return ( ); } -export { Arc, Intersect, Line, Subtract, Union }; \ No newline at end of file +export { Arc, Dimension, Intersect, Line, Subtract, Union }; \ No newline at end of file diff --git a/src/sketcher/Sketch.js b/src/sketcher/Sketch.js index ed78a8d..f0e2167 100644 --- a/src/sketcher/Sketch.js +++ b/src/sketcher/Sketch.js @@ -6,10 +6,10 @@ import { drawOnClick1, drawOnClick2, drawPreClick2, drawClear } from './drawEven import { onHover, onDrag, onPick, onRelease } from '../utils/mouseEvents' import { addDimension, setCoincident } from './constraintEvents' import { get3PtArc } from './drawArc' -import { _vec2, _vec3, raycaster } from '../utils/static' +import { _vec2, _vec3, raycaster, awaitPts } from '../utils/shared' import { replacer, reviver } from '../utils/mapJSONReplacer' -import {AxesHelper} from '../utils/axes' - +import { AxesHelper } from '../utils/axes' +import { drawDimensionPre } from './drawDimension' @@ -108,6 +108,9 @@ class Sketch { this.drawPreClick2 = drawPreClick2.bind(this); this.drawOnClick2 = drawOnClick2.bind(this); + this.awaitPts = awaitPts.bind(this); + this.drawDimensionPre = drawDimensionPre.bind(this); + this.onHover = onHover.bind(this); this.onPick = onPick.bind(this); this.onDrag = onDrag.bind(this); @@ -176,6 +179,10 @@ class Sketch { this.canvas.addEventListener('pointerdown', this.drawOnClick1) this.mode = "arc" break; + case 'd': + this.drawDimensionPre() + this.mode = "arc" + break; case 'x': this.deleteSelected() break; @@ -333,7 +340,7 @@ class Sketch { */ for (let i = 1, ptr = (pts_buffer >> 2) + 3; i < this.obj3d.children.length; i += 1, ptr += 3) { - // for (let i = 0, ptr = (pts_buffer >> 2) + 3; i < this.obj3d.children.length; i += 1, ptr += 3) { + // for (let i = 0, ptr = (pts_buffer >> 2) + 3; i < this.obj3d.children.length; i += 1, ptr += 3) { const pos = this.obj3d.children[i].geometry.attributes.position; if (isNaN(Module.HEAPF32[ptr])) { @@ -393,8 +400,40 @@ Object.assign(Sketch.prototype, 'arc': 1 }, constraintNum: { - 'coincident': 0, - 'distance': 1 + points_coincident: 0, + pt_pt_distance: 1, + pt_plane_distance: 2, + pt_line_distance: 3, + pt_face_distance: 4, + pt_in_plane: 5, + pt_on_line: 6, + pt_on_face: 7, + equal_length_lines: 8, + length_ratio: 9, + eq_len_pt_line_d: 10, + eq_pt_ln_distances: 11, + equal_angle: 12, + equal_line_arc_len: 13, + symmetric: 14, + symmetric_horiz: 15, + symmetric_vert: 16, + symmetric_line: 17, + at_midpoint: 18, + horizontal: 19, + vertical: 20, + diameter: 21, + pt_on_circle: 22, + same_orientation: 23, + angle: 24, + parallel: 25, + perpendicular: 26, + arc_line_tangent: 27, + cubic_line_tangent: 28, + equal_radius: 29, + proj_pt_distance: 30, + where_dragged: 31, + curve_curve_tangent: 32, + length_difference: 33, }, max_pts: 1000, max_links: 1000, @@ -404,4 +443,6 @@ Object.assign(Sketch.prototype, -export { Sketch } \ No newline at end of file +export { Sketch } + + diff --git a/src/sketcher/constraintEvents.js b/src/sketcher/constraintEvents.js index b65fb02..521334f 100644 --- a/src/sketcher/constraintEvents.js +++ b/src/sketcher/constraintEvents.js @@ -31,7 +31,7 @@ export function setCoincident() { for (let i = 1; i < toComb.length; i++) { this.constraints.set(++this.c_id, [ - 'coincident', -1, + 'points_coincident', -1, [toComb[i - 1].name, toComb[i].name, -1, -1] /////// ] ) diff --git a/src/sketcher/drawArc.js b/src/sketcher/drawArc.js index c15db17..58b01b3 100644 --- a/src/sketcher/drawArc.js +++ b/src/sketcher/drawArc.js @@ -1,8 +1,8 @@ import * as THREE from '../../node_modules/three/src/Three'; -import {lineMaterial, pointMaterial} from '../utils/static' +import {lineMaterial, pointMaterial} from '../utils/shared' -import {ptObj, lineObj} from '../utils/static' +import {ptObj, lineObj} from '../utils/shared' const n = 30 diff --git a/src/sketcher/drawDimension.js b/src/sketcher/drawDimension.js new file mode 100644 index 0000000..11a36aa --- /dev/null +++ b/src/sketcher/drawDimension.js @@ -0,0 +1,160 @@ +import * as THREE from '../../node_modules/three/src/Three'; +import { ptObj, lineObj, awaitPts } from '../utils/shared' + +const DptObj = (n) => { + const ret = new THREE.Points( + new THREE.BufferGeometry().setAttribute('position', + new THREE.Float32BufferAttribute(n || 3, 3) + ), + pointMaterial.clone() + ); + ret.name = 'p' + nid++ + + ret.matrixAutoUpdate = false; + ret.userData.constraints = [] + + return ret +} + +const DlineObj = (n = 1) => { + const ret = new THREE.Line( + new THREE.BufferGeometry().setAttribute('position', + new THREE.Float32BufferAttribute(3 * (n + 1), 3) + ), + lineMaterial.clone() + ); + ret.name = 'l' + nid++ + + ret.matrixAutoUpdate = false; + ret.userData.constraints = [] + + return ret +} + + + +export async function drawDimensionPre() { + let [p1, p2] = await this.awaitPts(2) + + const lines = [ + DlineObj(), // 0: + DlineObj(), // 1: + DlineObj(), // 2: + ] + + const points = [ + p1, // 0: + DptObj(), // 1: | + DptObj(), // 2: | + DptObj(), // 3: | + DptObj(), // 4: | + DptObj(), // 5: | + DptObj(), // 6: | + p2, // 7: + ] + + this.constraints.set(++this.c_id, //??? + [ + 'pt_pt_distance', 10, + [p1.name, p2.name, -1, -1] + ] + ) + p1.userData.constraints.push(this.c_id) + p2.userData.constraints.push(this.c_id) + + + for (let i = 1; i++; i < points.length) { + if (i % 2) { + this.constraints.set(++this.c_id, //??? increment investigation + [ + 'coincident', -1, + [points[i - 1].name, points[i].name, -1, -1] + ] + ) + points[i - 1].userData.constraints.push(this.c_id) + points[i].userData.constraints.push(this.c_id) + + + } else { + + const toPush = [...points.slice(i - 2, i), lines[i / 2 - 1]] + this.linkedObjs.set(this.l_id, ['line', toPush.map(e => e.name)]) + for (let obj of toPush) { + obj.userData.l_id = this.l_id + } + this.l_id += 1 + + if (i == 4 || i == 6) { + this.constraints.set(++this.c_id, //??? + [ + 'perpendicular', -1, + [-1, -1, lines[i / 2 - 2].name, lines[i / 2 - 1].name] + ] + ) + lines[i / 2 - 2].userData.constraints.push(this.c_id) + lines[i / 2 - 1].userData.constraints.push(this.c_id) + } + + + } + + } + + // line[1].geometry.attributes.position.set(p1.geometry.attributes.position.array) + // line[1].geometry.attributes.position.set(p1.geometry.attributes.position.array, 3) + + // line[0].geometry.attributes.position.set(p1.geometry.attributes.position.array) + // line[0].geometry.attributes.position.set(p2.geometry.attributes.position.array, 3) + + + // line[2].geometry.attributes.position.set(p2.geometry.attributes.position.array) + // line[2].geometry.attributes.position.set(p2.geometry.attributes.position.array, 3) + + + + + + + + + return [p1, p2, line]; +} + +export function drawLine(mouseLoc) { + + + + + line.geometry.attributes.position.set(mouseLoc) + p1.geometry.attributes.position.set(mouseLoc) + + if (this.subsequent) { + + this.constraints.set(++this.c_id, + [ + 'coincident', -1, + [this.obj3d.children[this.obj3d.children.length - 2].name, p1.name, -1, -1] + ] + ) + + p1.userData.constraints.push(this.c_id) + this.obj3d.children[this.obj3d.children.length - 2].userData.constraints.push(this.c_id) + + } + + + + return [p1, p2, line]; +} + +export function drawLine2(mouseLoc, toPush) { + + const [p1, p2, line] = toPush + + p2.geometry.attributes.position.set(mouseLoc); + p2.geometry.attributes.position.needsUpdate = true; + p2.geometry.computeBoundingSphere(); + + line.geometry.attributes.position.set(mouseLoc, 3) + line.geometry.attributes.position.needsUpdate = true; +} \ No newline at end of file diff --git a/src/sketcher/drawLine.js b/src/sketcher/drawLine.js index f46daaf..11a6248 100644 --- a/src/sketcher/drawLine.js +++ b/src/sketcher/drawLine.js @@ -1,5 +1,5 @@ import * as THREE from '../../node_modules/three/src/Three'; -import {ptObj, lineObj} from '../utils/static' +import {ptObj, lineObj} from '../utils/shared' export function drawLine(mouseLoc) { @@ -23,9 +23,9 @@ export function drawLine(mouseLoc) { if (this.subsequent) { - this.constraints.set(++this.c_id, + this.constraints.set(++this.c_id, //??? why incremennt before not after [ - 'coincident', -1, + 'points_coincident', -1, [this.obj3d.children[this.obj3d.children.length - 2].name, p1.name, -1, -1] ] ) diff --git a/src/utils/mouseEvents.js b/src/utils/mouseEvents.js index 059850b..67aeb85 100644 --- a/src/utils/mouseEvents.js +++ b/src/utils/mouseEvents.js @@ -1,5 +1,5 @@ import * as THREE from 'three/src/Three'; -import { raycaster, color } from './static'; +import { raycaster, color } from './shared'; export function onHover(e) { if (this.mode || e.buttons) return diff --git a/src/utils/static.js b/src/utils/shared.js similarity index 58% rename from src/utils/static.js rename to src/utils/shared.js index 336930f..0e04b1b 100644 --- a/src/utils/static.js +++ b/src/utils/shared.js @@ -1,4 +1,4 @@ -import * as THREE from '../../node_modules/three/src/Three'; +import * as THREE from 'three/src/Three'; @@ -56,4 +56,36 @@ const lineObj = (n = 1) => { } -export { lineMaterial, pointMaterial, _vec2, _vec3, raycaster, color, ptObj, lineObj } \ No newline at end of file +async function awaitPts(n) { + let references = this.selected.slice() + + if (references.length == 0) { + while (references.length < n) { + let pt; + try { + pt = await new Promise((res, rej) => { + this.canvas.addEventListener('pointerdown', () => res(this.hovered[0]), { once: true }) + window.addEventListener('keydown', (e) => rej(e), { once: true }) + }) + + if (pt.name[0] == 'p') { + references.push(pt) + } else if (pt.name[0] == 'd') { + references = [pt] + break; + } + + } catch (e) { + if (e.key == 'Escape') { + console.log('cancelled') + return; + } + } + } + } + return references +} + + + +export { lineMaterial, pointMaterial, _vec2, _vec3, raycaster, color, ptObj, lineObj, awaitPts } \ No newline at end of file diff --git a/wasm/solver.c b/wasm/solver.c index c2b52bb..4cffe5a 100644 --- a/wasm/solver.c +++ b/wasm/solver.c @@ -110,8 +110,12 @@ int solver(int nPts, float *p_ptr, int nConst, float *c_ptr, int nLinks, float * for (int i = 0; i < nConst; i++) { - if ((int)*c_ptr == 0) + + + + switch ((int)*c_ptr + 100000) { + case SLVS_C_POINTS_COINCIDENT: c_ptr += 2; sys.constraint[sys.constraints++] = Slvs_MakeConstraint( con_id++, g, @@ -121,11 +125,33 @@ int solver(int nPts, float *p_ptr, int nConst, float *c_ptr, int nLinks, float * (int)*c_ptr, (int)*(c_ptr + 1), 0, 0); c_ptr += 4; - } - else - { + break; + case 1: + + break; + default: c_ptr += 6; + break; } + + + + // if ((int)*c_ptr + 100000 == SLVS_C_POINTS_COINCIDENT) + // { + // c_ptr += 2; + // sys.constraint[sys.constraints++] = Slvs_MakeConstraint( + // con_id++, g, + // SLVS_C_POINTS_COINCIDENT, + // 200, + // 0.0, + // (int)*c_ptr, (int)*(c_ptr + 1), 0, 0); + + // c_ptr += 4; + // } + // else + // { + // c_ptr += 6; + // } } /* And solve. */