semi working angle
parent
67d6bf8090
commit
8aeb5409c4
27
src/Scene.js
27
src/Scene.js
|
@ -111,8 +111,8 @@ export class Scene {
|
||||||
helpersGroup.add(this.axes);
|
helpersGroup.add(this.axes);
|
||||||
|
|
||||||
|
|
||||||
const dist = 50
|
const dist = 15
|
||||||
const light1 = new THREE.PointLight(color.lighting, 0.7);
|
const light1 = new THREE.PointLight(color.lighting, 0.6);
|
||||||
light1.position.set(dist, dist, dist);
|
light1.position.set(dist, dist, dist);
|
||||||
helpersGroup.add(light1);
|
helpersGroup.add(light1);
|
||||||
const light2 = new THREE.PointLight(color.lighting, 0.6);
|
const light2 = new THREE.PointLight(color.lighting, 0.6);
|
||||||
|
@ -292,7 +292,7 @@ export class Scene {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
subtract(m1, m2) {
|
subtract(m1, m2, op) {
|
||||||
let bspA = CSG.fromMesh(m1)
|
let bspA = CSG.fromMesh(m1)
|
||||||
let bspB = CSG.fromMesh(m2)
|
let bspB = CSG.fromMesh(m2)
|
||||||
m1.visible = false
|
m1.visible = false
|
||||||
|
@ -302,13 +302,30 @@ export class Scene {
|
||||||
|
|
||||||
// // Subtract one bsp from the other via .subtract... other supported modes are .union and .intersect
|
// // Subtract one bsp from the other via .subtract... other supported modes are .union and .intersect
|
||||||
|
|
||||||
let bspResult = bspA.subtract(bspB)
|
let bspResult, opChar;
|
||||||
|
switch (op) {
|
||||||
|
case 's':
|
||||||
|
bspResult = bspA.subtract(bspB)
|
||||||
|
opChar = "-"
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
bspResult = bspA.union(bspB)
|
||||||
|
opChar = "\u222a"
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
bspResult = bspA.intersect(bspB)
|
||||||
|
opChar = "\u2229"
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// //Get the resulting mesh from the result bsp, and assign meshA.material to the resulting mesh
|
// //Get the resulting mesh from the result bsp, and assign meshA.material to the resulting mesh
|
||||||
|
|
||||||
let mesh = CSG.toMesh(bspResult, m1.matrix, m1.material)
|
let mesh = CSG.toMesh(bspResult, m1.matrix, m1.material)
|
||||||
mesh.userData.type = 'mesh'
|
mesh.userData.type = 'mesh'
|
||||||
mesh.name = `${m1.name}-${m2.name}`
|
|
||||||
|
mesh.name = `(${m1.name}${opChar}${m2.name})`
|
||||||
mesh.layers.enable(1)
|
mesh.layers.enable(1)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { get3PtArc } from './drawArc'
|
||||||
import { replacer, reviver } from './utils'
|
import { replacer, reviver } from './utils'
|
||||||
import { AxesHelper } from './sketchAxes'
|
import { AxesHelper } from './sketchAxes'
|
||||||
import { drawDimension, _onMoveDimension, setDimLines, updateDim } from './drawDimension';
|
import { drawDimension, _onMoveDimension, setDimLines, updateDim } from './drawDimension';
|
||||||
|
import { drawAngle, _onMoveAngle, setAngLines, updateAng } from './drawAngle';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -128,9 +129,13 @@ class Sketch {
|
||||||
this.drawOnClick2 = drawOnClick2.bind(this);
|
this.drawOnClick2 = drawOnClick2.bind(this);
|
||||||
|
|
||||||
this.drawDimension = drawDimension.bind(this)
|
this.drawDimension = drawDimension.bind(this)
|
||||||
|
this.drawAngle = drawAngle.bind(this)
|
||||||
this._onMoveDimension = _onMoveDimension.bind(this)
|
this._onMoveDimension = _onMoveDimension.bind(this)
|
||||||
|
this._onMoveAngle = _onMoveAngle.bind(this)
|
||||||
this.setDimLines = setDimLines.bind(this)
|
this.setDimLines = setDimLines.bind(this)
|
||||||
|
this.setAngLines = setAngLines.bind(this)
|
||||||
this.updateDim = updateDim.bind(this)
|
this.updateDim = updateDim.bind(this)
|
||||||
|
this.updateAng = updateAng.bind(this)
|
||||||
|
|
||||||
this.awaitSelection = awaitSelection.bind(this);
|
this.awaitSelection = awaitSelection.bind(this);
|
||||||
|
|
||||||
|
@ -152,7 +157,7 @@ class Sketch {
|
||||||
|
|
||||||
this.setDimLines()
|
this.setDimLines()
|
||||||
|
|
||||||
this.obj3d.traverse(e=>e.layers.enable(2))
|
this.obj3d.traverse(e => e.layers.enable(2))
|
||||||
this.obj3d.visible = true
|
this.obj3d.visible = true
|
||||||
this.scene.axes.matrix = this.obj3d.matrix
|
this.scene.axes.matrix = this.obj3d.matrix
|
||||||
this.scene.axes.visible = true
|
this.scene.axes.visible = true
|
||||||
|
@ -168,7 +173,7 @@ class Sketch {
|
||||||
this.store.dispatch({ type: 'exit-sketch' })
|
this.store.dispatch({ type: 'exit-sketch' })
|
||||||
this.labelContainer.innerHTML = ""
|
this.labelContainer.innerHTML = ""
|
||||||
this.obj3d.visible = false
|
this.obj3d.visible = false
|
||||||
this.obj3d.traverse(e=>e.layers.disable(2))
|
this.obj3d.traverse(e => e.layers.disable(2))
|
||||||
this.scene.axes.visible = false
|
this.scene.axes.visible = false
|
||||||
this.scene.activeSketch = null
|
this.scene.activeSketch = null
|
||||||
}
|
}
|
||||||
|
@ -221,6 +226,10 @@ class Sketch {
|
||||||
this.drawDimension()
|
this.drawDimension()
|
||||||
this.mode = ""
|
this.mode = ""
|
||||||
break;
|
break;
|
||||||
|
case 'q':
|
||||||
|
this.drawAngle()
|
||||||
|
this.mode = ""
|
||||||
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
this.canvas.addEventListener('pointerdown', this.drawOnClick1)
|
this.canvas.addEventListener('pointerdown', this.drawOnClick1)
|
||||||
this.mode = "point"
|
this.mode = "point"
|
||||||
|
@ -427,9 +436,9 @@ class Sketch {
|
||||||
this.linkedObjs.size, links_buffer)
|
this.linkedObjs.size, links_buffer)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
- loop to update all the children that are points
|
- loop to update all the children that are points
|
||||||
- why +6? we skip first two triplets because it refers to a non-geometry children
|
- why +6? we skip first two triplets because it refers to a non-geometry children
|
||||||
- we also sneak in updating lines children as well, by checking when ptsBuf[ptr] is NaN
|
- we also sneak in updating lines children as well, by checking when ptsBuf[ptr] is NaN
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (let i = 3, ptr = (pts_buffer >> 2) + 9; i < this.obj3d.children.length; i += 1, ptr += 3) {
|
for (let i = 3, ptr = (pts_buffer >> 2) + 9; i < this.obj3d.children.length; i += 1, ptr += 3) {
|
||||||
|
@ -457,6 +466,7 @@ class Sketch {
|
||||||
arcs were not updated in above loop, we go through all arcs linkedObjs
|
arcs were not updated in above loop, we go through all arcs linkedObjs
|
||||||
and updated based on the control pts (which were updated in loop above)
|
and updated based on the control pts (which were updated in loop above)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (let [k, obj] of this.linkedObjs) {
|
for (let [k, obj] of this.linkedObjs) {
|
||||||
if (obj[0] != 'arc') continue;
|
if (obj[0] != 'arc') continue;
|
||||||
const [p1, p2, c, arc] = obj[1].map(e => this.obj3d.children[this.objIdx.get(e)])
|
const [p1, p2, c, arc] = obj[1].map(e => this.obj3d.children[this.objIdx.get(e)])
|
||||||
|
@ -472,7 +482,8 @@ class Sketch {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
this.setDimLines()
|
// this.setDimLines()
|
||||||
|
this.setAngLines()
|
||||||
|
|
||||||
this.obj3d.dispatchEvent({ type: 'change' })
|
this.obj3d.dispatchEvent({ type: 'change' })
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,395 @@
|
||||||
|
import * as THREE from '../node_modules/three/src/Three';
|
||||||
|
import { color } from './shared'
|
||||||
|
|
||||||
|
const lineMaterial = new THREE.LineBasicMaterial({
|
||||||
|
linewidth: 2,
|
||||||
|
color: color.dimension,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const pointMaterial = new THREE.PointsMaterial({
|
||||||
|
color: color.dimension,
|
||||||
|
size: 4,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const divisions = 12
|
||||||
|
|
||||||
|
export async function drawAngle() {
|
||||||
|
let selection = await this.awaitSelection({ line: 2 })
|
||||||
|
|
||||||
|
if (selection == null) return;
|
||||||
|
|
||||||
|
const line = new THREE.LineSegments(
|
||||||
|
new THREE.BufferGeometry().setAttribute('position',
|
||||||
|
new THREE.Float32BufferAttribute(Array((divisions + 2) * 2 * 3).fill(-0.001), 3)
|
||||||
|
),
|
||||||
|
lineMaterial.clone()
|
||||||
|
);
|
||||||
|
|
||||||
|
const point = new THREE.Points(
|
||||||
|
new THREE.BufferGeometry().setAttribute('position',
|
||||||
|
new THREE.Float32BufferAttribute(3, 3)
|
||||||
|
),
|
||||||
|
pointMaterial.clone()
|
||||||
|
)
|
||||||
|
|
||||||
|
line.userData.ids = selection.map(e => e.name)
|
||||||
|
|
||||||
|
line.layers.enable(2)
|
||||||
|
point.layers.enable(2)
|
||||||
|
|
||||||
|
let angle = getAngle(selection)
|
||||||
|
|
||||||
|
|
||||||
|
this.obj3d.children[1].add(line).add(point)
|
||||||
|
|
||||||
|
const onMove = this._onMoveAngle(point, line)
|
||||||
|
|
||||||
|
point.label = document.createElement('div');
|
||||||
|
point.label.textContent = angle.toFixed(3);
|
||||||
|
point.label.contentEditable = true;
|
||||||
|
this.labelContainer.append(point.label)
|
||||||
|
|
||||||
|
let onEnd, onKey;
|
||||||
|
let add = await new Promise((res) => {
|
||||||
|
onEnd = (e) => res(true)
|
||||||
|
onKey = (e) => e.key == 'Escape' && res(false)
|
||||||
|
|
||||||
|
this.canvas.addEventListener('pointermove', onMove)
|
||||||
|
this.canvas.addEventListener('pointerdown', onEnd)
|
||||||
|
window.addEventListener('keydown', onKey)
|
||||||
|
})
|
||||||
|
|
||||||
|
this.canvas.removeEventListener('pointermove', onMove)
|
||||||
|
this.canvas.removeEventListener('pointerdown', onEnd)
|
||||||
|
window.removeEventListener('keydown', onKey)
|
||||||
|
point.geometry.computeBoundingSphere()
|
||||||
|
line.geometry.computeBoundingSphere()
|
||||||
|
|
||||||
|
if (add) {
|
||||||
|
|
||||||
|
this.constraints.set(++this.c_id,
|
||||||
|
[
|
||||||
|
'angle', angle,
|
||||||
|
[-1, -1, selection[0].name, selection[1].name]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
selection[0].userData.constraints.push(this.c_id)
|
||||||
|
selection[1].userData.constraints.push(this.c_id)
|
||||||
|
|
||||||
|
this.updateOtherBuffers()
|
||||||
|
|
||||||
|
line.name = this.c_id
|
||||||
|
line.userData.type = 'dimension'
|
||||||
|
point.name = this.c_id
|
||||||
|
point.userData.type = 'dimension'
|
||||||
|
|
||||||
|
point.label.addEventListener('focus', this.updateAng(this.c_id))
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
this.obj3d.children[1].children.splice(this.obj3d.children[1].length - 2, 2).forEach(
|
||||||
|
e => {
|
||||||
|
e.geometry.dispose()
|
||||||
|
e.material.dispose()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
this.labelContainer.removeChild(this.labelContainer.lastChild);
|
||||||
|
sc.render()
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export function updateAng(c_id) {
|
||||||
|
return (ev_focus) => {
|
||||||
|
let value = ev_focus.target.textContent
|
||||||
|
document.addEventListener('keydown', (e) => {
|
||||||
|
if (e.key == 'Enter') {
|
||||||
|
e.preventDefault()
|
||||||
|
const ent = this.constraints.get(c_id)
|
||||||
|
ent[1] = parseFloat(ev_focus.target.textContent)
|
||||||
|
value = ent[1]
|
||||||
|
this.constraints.set(c_id, ent)
|
||||||
|
this.updateOtherBuffers()
|
||||||
|
this.solve()
|
||||||
|
sc.render()
|
||||||
|
ev_focus.target.blur()
|
||||||
|
this.updateBoundingSpheres()
|
||||||
|
} else if (e.key == 'Escape') {
|
||||||
|
ev_focus.target.textContent = value
|
||||||
|
getSelection().empty()
|
||||||
|
ev_focus.target.blur()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let ids, _l1, _l2
|
||||||
|
export function _onMoveAngle(point, line) {
|
||||||
|
|
||||||
|
ids = line.userData.ids
|
||||||
|
|
||||||
|
_l1 = this.obj3d.children[this.objIdx.get(ids[0])].geometry.attributes.position.array
|
||||||
|
_l2 = this.obj3d.children[this.objIdx.get(ids[1])].geometry.attributes.position.array
|
||||||
|
|
||||||
|
let loc;
|
||||||
|
|
||||||
|
return (e) => {
|
||||||
|
loc = this.getLocation(e)
|
||||||
|
|
||||||
|
p3.set(loc.x, loc.y)
|
||||||
|
|
||||||
|
update(
|
||||||
|
line.geometry.attributes.position,
|
||||||
|
point.geometry.attributes.position,
|
||||||
|
_l1, _l2
|
||||||
|
)
|
||||||
|
|
||||||
|
// point.userData.offset = tagOffset.toArray() // save offset vector from center
|
||||||
|
point.userData.offset = tagOffset // save offset vector from center
|
||||||
|
tagOffset = undefined
|
||||||
|
|
||||||
|
sc.render()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function setAngLines() {
|
||||||
|
|
||||||
|
const restoreLabels = this.labelContainer.childElementCount == 0;
|
||||||
|
|
||||||
|
const dims = this.obj3d.children[1].children
|
||||||
|
|
||||||
|
let point, dist;
|
||||||
|
for (let i = 0; i < dims.length; i += 2) {
|
||||||
|
if (restoreLabels) {
|
||||||
|
point = dims[i + 1] // point node is at i+1
|
||||||
|
dist = this.constraints.get(point.name)[1]
|
||||||
|
point.label = document.createElement('div');
|
||||||
|
point.label.textContent = dist.toFixed(3);
|
||||||
|
point.label.contentEditable = true;
|
||||||
|
this.labelContainer.append(point.label)
|
||||||
|
|
||||||
|
point.label.addEventListener('focus', this.updateAng(this.c_id))
|
||||||
|
}
|
||||||
|
|
||||||
|
ids = dims[i].userData.ids
|
||||||
|
|
||||||
|
_l1 = this.obj3d.children[this.objIdx.get(ids[0])].geometry.attributes.position.array
|
||||||
|
_l2 = this.obj3d.children[this.objIdx.get(ids[1])].geometry.attributes.position.array
|
||||||
|
|
||||||
|
|
||||||
|
tagOffset = dims[i + 1].userData.offset
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
update(
|
||||||
|
dims[i].geometry.attributes.position,
|
||||||
|
dims[i + 1].geometry.attributes.position,
|
||||||
|
_l1,
|
||||||
|
_l2
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export function findIntersection(q, s, p, r) {
|
||||||
|
/*
|
||||||
|
Based on: https://stackoverflow.com/questions/563198/
|
||||||
|
|
||||||
|
q+s p+r
|
||||||
|
\/__________ q+u*s
|
||||||
|
/\
|
||||||
|
/ \
|
||||||
|
p q
|
||||||
|
|
||||||
|
u = (q − p) × r / (r × s)
|
||||||
|
when r × s = 0, the lines are either colinear or parallel
|
||||||
|
|
||||||
|
function returns u
|
||||||
|
for "real" intersection to exist, 0<u<1
|
||||||
|
*/
|
||||||
|
const q_minus_p = q.clone().sub(p);
|
||||||
|
const r_cross_s = r.cross(s);
|
||||||
|
if (r_cross_s === 0) return null; //either colinear or parallel
|
||||||
|
return q_minus_p.cross(r) / r_cross_s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
_l2:[x0,y0,z0,x1,y1,z1]
|
||||||
|
/
|
||||||
|
p3:tag-""/-.
|
||||||
|
tagOffset[1]-->| \
|
||||||
|
|__ . _|__ _l1:[x0,y0,z0,x1,y1,z1]
|
||||||
|
tagOffset[0]----^ ^--center
|
||||||
|
|
||||||
|
vecArr = [
|
||||||
|
0: _l1 origin
|
||||||
|
1: _l1 disp
|
||||||
|
2: _l2 origin
|
||||||
|
3: _l2 disp
|
||||||
|
4: center
|
||||||
|
5: tag disp from center
|
||||||
|
]
|
||||||
|
*/
|
||||||
|
|
||||||
|
const vecArr = Array(6)
|
||||||
|
for (var i = 0; i < vecArr.length; i++) vecArr[i] = new THREE.Vector2();
|
||||||
|
const a = Array(3)
|
||||||
|
const p3 = new THREE.Vector2()
|
||||||
|
let tagOffset
|
||||||
|
|
||||||
|
const getAngle = (Obj3dLines) => {
|
||||||
|
for (let i = 0; i < 2; i++) {
|
||||||
|
const arr = Obj3dLines[i].geometry.attributes.position.array
|
||||||
|
vecArr[2 * i].set(...arr.slice(0, 2))
|
||||||
|
vecArr[2 * i + 1].set(arr[3] - arr[0], arr[4] - arr[1])
|
||||||
|
}
|
||||||
|
const a1 = Math.atan2(vecArr[1].y, vecArr[1].x)
|
||||||
|
const a2 = Math.atan2(vecArr[3].y, vecArr[3].x)
|
||||||
|
|
||||||
|
let deltaAngle = Math.abs(a2 - a1)
|
||||||
|
if (deltaAngle > Math.PI) {
|
||||||
|
deltaAngle = Math.PI * 2 - deltaAngle
|
||||||
|
}
|
||||||
|
return deltaAngle / Math.PI * 180
|
||||||
|
}
|
||||||
|
|
||||||
|
function update(linegeom, pointgeom, _l1, _l2) {
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
for (; i < 4;) {
|
||||||
|
const arr = i == 0 ? _l1 : _l2
|
||||||
|
vecArr[i++].set(arr[0], arr[1])
|
||||||
|
vecArr[i++].set(arr[3] - arr[0], arr[4] - arr[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
const centerScalar = findIntersection(...vecArr.slice(0, 4))
|
||||||
|
const center = vecArr[i++].addVectors(vecArr[0], vecArr[1].clone().multiplyScalar(centerScalar))
|
||||||
|
|
||||||
|
// tagOffset = vecArr[i++].subVectors(p3, center)
|
||||||
|
|
||||||
|
if (tagOffset === undefined) {
|
||||||
|
tagOffset = vecArr[i++].subVectors(p3, center)
|
||||||
|
// } else if (Array.isArray(tagOffset)) {
|
||||||
|
// tagOffset = new THREE.Vector2(tagOffset[0],tagOffset[1])
|
||||||
|
} else {
|
||||||
|
p3.addVectors(center, tagOffset)
|
||||||
|
}
|
||||||
|
|
||||||
|
// console.log(p3, center, 'vr')
|
||||||
|
// console.log(vecArr, 'vecArr')
|
||||||
|
|
||||||
|
// console.log(tagOffset, xx)
|
||||||
|
// console.log(tagOffset.length())
|
||||||
|
const tagRadius = tagOffset.length()
|
||||||
|
|
||||||
|
/*
|
||||||
|
if tag is more than 90 deg away from midline, we shift everything by 180
|
||||||
|
|
||||||
|
a: array that describes absolute angular position of angle start, angle end, and tag
|
||||||
|
|
||||||
|
a[2]:
|
||||||
|
tag a[1]:angle end
|
||||||
|
\ | /
|
||||||
|
\ | /
|
||||||
|
___\|/___ a[0]+dA/2:midline
|
||||||
|
/ \
|
||||||
|
/ \
|
||||||
|
/ \
|
||||||
|
a[0]:angle start
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (let j = 1, i = 0; j < vecArr.length; j += 2, i++) {
|
||||||
|
a[i] = Math.atan2(vecArr[j].y, vecArr[j].x)
|
||||||
|
}
|
||||||
|
|
||||||
|
let dA = unreflex(a[1] - a[0])
|
||||||
|
|
||||||
|
|
||||||
|
let tagtoMidline = unreflex(a[2] - (a[0] + dA / 2))
|
||||||
|
|
||||||
|
let shift = Math.abs(tagtoMidline) < Math.PI / 2 ? 0 : Math.PI;
|
||||||
|
|
||||||
|
let tA1 = unreflex(a[2] - (a[0] + shift))
|
||||||
|
let tA2 = unreflex(a[2] - (a[0] + dA + shift))
|
||||||
|
|
||||||
|
|
||||||
|
let a1, deltaAngle;
|
||||||
|
if (dA * tA1 < 0) {
|
||||||
|
a1 = a[0] + tA1 + shift
|
||||||
|
deltaAngle = dA - tA1
|
||||||
|
} else if (dA * tA2 > 0) {
|
||||||
|
a1 = a[0] + shift
|
||||||
|
deltaAngle = dA + tA2
|
||||||
|
} else {
|
||||||
|
a1 = a[0] + shift
|
||||||
|
deltaAngle = dA
|
||||||
|
}
|
||||||
|
|
||||||
|
let points = linegeom.array
|
||||||
|
|
||||||
|
let d = 0;
|
||||||
|
points[d++] = center.x + tagRadius * Math.cos(a1)
|
||||||
|
points[d++] = center.y + tagRadius * Math.sin(a1)
|
||||||
|
d++
|
||||||
|
|
||||||
|
const angle = a1 + (1 / divisions) * deltaAngle
|
||||||
|
points[d++] = center.x + tagRadius * Math.cos(angle)
|
||||||
|
points[d++] = center.y + tagRadius * Math.sin(angle)
|
||||||
|
d++
|
||||||
|
|
||||||
|
for (i = 2; i <= divisions; i++) {
|
||||||
|
points[d++] = points[d - 4]
|
||||||
|
points[d++] = points[d - 4]
|
||||||
|
d++
|
||||||
|
const angle = a1 + (i / divisions) * deltaAngle
|
||||||
|
points[d++] = center.x + tagRadius * Math.cos(angle)
|
||||||
|
points[d++] = center.y + tagRadius * Math.sin(angle)
|
||||||
|
d++
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
points[d++] = vecArr[2 * i].x
|
||||||
|
points[d++] = vecArr[2 * i].y
|
||||||
|
d++
|
||||||
|
points[d++] = center.x + tagRadius * Math.cos(a[i] + shift)
|
||||||
|
points[d++] = center.y + tagRadius * Math.sin(a[i] + shift)
|
||||||
|
d++
|
||||||
|
}
|
||||||
|
|
||||||
|
linegeom.needsUpdate = true;
|
||||||
|
|
||||||
|
pointgeom.array.set(p3.toArray())
|
||||||
|
pointgeom.needsUpdate = true;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const twoPi = Math.PI * 2
|
||||||
|
const negTwoPi = - Math.PI * 2
|
||||||
|
const negPi = - Math.PI
|
||||||
|
|
||||||
|
function unreflex(angle) {
|
||||||
|
if (angle > Math.PI) {
|
||||||
|
angle = negTwoPi + angle
|
||||||
|
} else if (angle < negPi) {
|
||||||
|
angle = twoPi + angle
|
||||||
|
}
|
||||||
|
return angle
|
||||||
|
}
|
|
@ -83,9 +83,38 @@ export function get3PtArc(p1, p2, c, divisions = n) {
|
||||||
|
|
||||||
const radius = Math.sqrt(v1[0] ** 2 + v1[1] ** 2)
|
const radius = Math.sqrt(v1[0] ** 2 + v1[1] ** 2)
|
||||||
|
|
||||||
|
|
||||||
let deltaAngle = a2 - a1
|
let deltaAngle = a2 - a1
|
||||||
if (deltaAngle <=0) deltaAngle += Math.PI*2
|
if (deltaAngle <=0) deltaAngle += Math.PI*2
|
||||||
// console.log(deltaAngle)
|
|
||||||
|
// let deltaAngle = a2 - a1
|
||||||
|
// if (deltaAngle > Math.PI ){
|
||||||
|
// deltaAngle = - Math.PI*2 + deltaAngle
|
||||||
|
// } else if (deltaAngle < -Math.PI) {
|
||||||
|
// deltaAngle = Math.PI*2 + deltaAngle
|
||||||
|
// }
|
||||||
|
|
||||||
|
// let deltaAngle = Math.abs(a2 - a1)
|
||||||
|
// if (deltaAngle > Math.PI){
|
||||||
|
// deltaAngle = Math.PI*2 - deltaAngle
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
let points = new Float32Array((divisions + 1) * 3)
|
||||||
|
|
||||||
|
for (let d = 0; d <= divisions; d++) {
|
||||||
|
const angle = a1 + (d / divisions) * deltaAngle;
|
||||||
|
points[3 * d] = c[0] + radius * Math.cos(angle);
|
||||||
|
points[3 * d + 1] = c[1] + radius * Math.sin(angle);
|
||||||
|
}
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function getAngleArc(a1, a2, c, radius, divisions = n) {
|
||||||
|
|
||||||
|
|
||||||
|
let deltaAngle = a2 - a1
|
||||||
|
|
||||||
let points = new Float32Array((divisions + 1) * 3)
|
let points = new Float32Array((divisions + 1) * 3)
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as THREE from '../node_modules/three/src/Three';
|
import * as THREE from '../node_modules/three/src/Three';
|
||||||
import { color, ptObj } from './shared'
|
import { color} from './shared'
|
||||||
export function extrude(sketch) {
|
export function extrude(sketch) {
|
||||||
|
|
||||||
let constraints = sketch.constraints;
|
let constraints = sketch.constraints;
|
||||||
|
@ -36,7 +36,7 @@ export function extrude(sketch) {
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
if (d == -1 || d == node) continue;
|
if (d == -1 || d == node) continue;
|
||||||
if (d == children[1]) {
|
if (d == children[4]) {
|
||||||
console.log('pair found')
|
console.log('pair found')
|
||||||
};
|
};
|
||||||
findTouching(d)
|
findTouching(d)
|
||||||
|
@ -52,7 +52,7 @@ export function extrude(sketch) {
|
||||||
if (c == -1) continue;
|
if (c == -1) continue;
|
||||||
const d = children[objIdx.get(c)]
|
const d = children[objIdx.get(c)]
|
||||||
if (d == node) continue;
|
if (d == node) continue;
|
||||||
if (d == children[1]) {
|
if (d == children[4]) {
|
||||||
console.log('loop found')
|
console.log('loop found')
|
||||||
} else {
|
} else {
|
||||||
if (!visited.has(d)) {
|
if (!visited.has(d)) {
|
||||||
|
|
|
@ -11,7 +11,7 @@ body {
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
--topNavH: 48px;
|
--topNavH: 48px;
|
||||||
--sideNavW: 200px;
|
--sideNavW: 240px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#c {
|
#c {
|
||||||
|
|
|
@ -15,6 +15,20 @@ export const NavBar = () => {
|
||||||
const treeEntries = useSelector(state => state.treeEntries)
|
const treeEntries = useSelector(state => state.treeEntries)
|
||||||
const activeSketchId = useSelector(state => state.treeEntries.activeSketchId)
|
const activeSketchId = useSelector(state => state.treeEntries.activeSketchId)
|
||||||
|
|
||||||
|
|
||||||
|
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.subtract(m1, m2, code)
|
||||||
|
dispatch({ type: 'rx-boolean', mesh, deps: [m1.name, m2.name] })
|
||||||
|
sc.render()
|
||||||
|
forceUpdate()
|
||||||
|
}
|
||||||
|
const extrude = () => {
|
||||||
|
console.log(treeEntries.tree[activeSketchId])
|
||||||
|
sc.extrude(treeEntries.byId[activeSketchId])
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!activeSketchId) {
|
if (!activeSketchId) {
|
||||||
sc.canvas.addEventListener('pointermove', sc.onHover)
|
sc.canvas.addEventListener('pointermove', sc.onHover)
|
||||||
|
@ -39,19 +53,10 @@ export const NavBar = () => {
|
||||||
}, 'Finish'] :
|
}, 'Finish'] :
|
||||||
[FaEdit, sc.addSketch, 'Sketch [s]']
|
[FaEdit, sc.addSketch, 'Sketch [s]']
|
||||||
,
|
,
|
||||||
[FaCube, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Extrude [e]'],
|
[FaCube, extrude , 'Extrude [e]'],
|
||||||
[Icon.Union, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Union'],
|
[Icon.Union, ()=>boolOp('u'), 'Union'],
|
||||||
[Icon.Subtract, () => {
|
[Icon.Subtract, ()=>boolOp('s'), 'Subtract'],
|
||||||
if (sc.selected.length != 2 || !sc.selected.every(e => e.userData.type == 'mesh')) return
|
[Icon.Intersect, ()=>boolOp('i'), 'Intersect'],
|
||||||
// console.log('here')
|
|
||||||
const [m1, m2] = sc.selected
|
|
||||||
const mesh = sc.subtract(m1, m2)
|
|
||||||
|
|
||||||
dispatch({ type: 'rx-boolean', mesh, deps: [m1.name, m2.name] })
|
|
||||||
sc.render()
|
|
||||||
forceUpdate()
|
|
||||||
}, 'Subtract'],
|
|
||||||
[Icon.Intersect, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Intersect'],
|
|
||||||
[Icon.Dimension, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Dimension [d]'],
|
[Icon.Dimension, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Dimension [d]'],
|
||||||
[Icon.Line, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Line [l]'],
|
[Icon.Line, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Line [l]'],
|
||||||
[Icon.Arc, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Arc [a]'],
|
[Icon.Arc, () => sc.extrude(treeEntries.byId[activeSketchId]), 'Arc [a]'],
|
||||||
|
|
|
@ -92,7 +92,7 @@ export function reducer(state = {}, action) {
|
||||||
|
|
||||||
|
|
||||||
return update(state, {
|
return update(state, {
|
||||||
treeEntries: { $set: obj }
|
treeEntries: { $merge: obj }
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -48,12 +48,10 @@ const TreeEntry = ({ entId }) => {
|
||||||
const [_, forceUpdate] = useReducer(x => x + 1, 0);
|
const [_, forceUpdate] = useReducer(x => x + 1, 0);
|
||||||
|
|
||||||
|
|
||||||
// const vis = obj3d.layers.mask & 1
|
|
||||||
|
|
||||||
return <div className='btn select-none flex justify-start w-full h-7 items-center text-sm'
|
return <div className='btn select-none flex justify-start w-full h-7 items-center text-sm'
|
||||||
|
|
||||||
onDoubleClick={() => {
|
onDoubleClick={() => {
|
||||||
if (entId[0] == 's') {
|
if (obj3d.userData.type == 'sketch') {
|
||||||
activeSketchId && treeEntries[activeSketchId].deactivate()
|
activeSketchId && treeEntries[activeSketchId].deactivate()
|
||||||
sketch.activate()
|
sketch.activate()
|
||||||
sc.clearSelection()
|
sc.clearSelection()
|
||||||
|
@ -67,14 +65,13 @@ const TreeEntry = ({ entId }) => {
|
||||||
sc.render()
|
sc.render()
|
||||||
}}
|
}}
|
||||||
onPointerLeave={() => {
|
onPointerLeave={() => {
|
||||||
// console.log('activeid',activeSketchId,'visstate',visState)
|
if (visible & obj3d.userData.type == 'sketch') return
|
||||||
if (visible & entId[0] == 's') return
|
|
||||||
if (sc.selected.includes(obj3d) || activeSketchId == obj3d.name) return
|
if (sc.selected.includes(obj3d) || activeSketchId == obj3d.name) return
|
||||||
sc.setHover(obj3d, 0)
|
sc.setHover(obj3d, 0)
|
||||||
sc.render()
|
sc.render()
|
||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (entId[0] == 'm') {
|
if (obj3d.userData.type == 'mesh') {
|
||||||
sc.selected.push(
|
sc.selected.push(
|
||||||
obj3d
|
obj3d
|
||||||
)
|
)
|
||||||
|
|
14
todo.txt
14
todo.txt
|
@ -14,26 +14,30 @@ boolean flesh out refresh / replace mesh
|
||||||
- consume skeches after extrude // done
|
- consume skeches after extrude // done
|
||||||
- selection hover disspates when rehovered //fixed
|
- selection hover disspates when rehovered //fixed
|
||||||
- boolean unable to select click //fixed
|
- boolean unable to select click //fixed
|
||||||
|
- hover sync between tree and work area // done, punt on stretch
|
||||||
|
|
||||||
|
|
||||||
vertical // done
|
vertical // done
|
||||||
horizontal // done
|
horizontal // done
|
||||||
|
- select sketch for extrusion, punt, leverage current sketch modality
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- hover sync between tree and work area
|
|
||||||
- select sketch for extrusion
|
|
||||||
|
|
||||||
auto update extrude
|
auto update extrude
|
||||||
extrude dialogue
|
extrude dialogue
|
||||||
|
|
||||||
loopfind
|
loopfind
|
||||||
button panel cleanup
|
|
||||||
file save, stl export
|
file save, stl export
|
||||||
|
|
||||||
constriant buttons ,tangent, angle
|
button panel cleanup
|
||||||
|
|
||||||
|
constraint angle
|
||||||
|
3 pt arc
|
||||||
|
|
||||||
|
|
||||||
constraint labels
|
|
||||||
reattach sketch
|
reattach sketch
|
||||||
|
constraint labels, tangent
|
||||||
auto snap
|
auto snap
|
||||||
tree ent renaming and better default names
|
tree ent renaming and better default names
|
Loading…
Reference in New Issue