add ordinate dimension and fix tangent

master
howard 2021-04-21 03:54:57 -07:00
parent fec6a75aeb
commit 6ef53e5a7c
25 changed files with 287 additions and 111 deletions

View File

@ -0,0 +1 @@
[0,1,1,{"byId":{},"allIds":[],"tree":{},"order":{},"visible":{}}]

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,10 +0,0 @@
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'production',
});

BIN
dist/solver.wasm vendored

Binary file not shown.

View File

@ -25,7 +25,7 @@ var TrackballControls = function ( object, domElement ) {
this.rotateSpeed = 3.0;
this.zoomSpeed = 1.2;
this.panSpeed = 41.6;
this.panSpeed = 2;
this.noRotate = false;
this.noZoom = false;

View File

@ -44,11 +44,11 @@ export class Scene {
this.store = store
const size = 1;
const near = 0;
const far = 100;
const near = -1;
const far = 1000;
this.camera = new THREE.OrthographicCamera(-size, size, size, -size, near, far);
this.camera.zoom = 0.1;
const cameraDist = 50
this.camera.zoom = 0.008;
const cameraDist = 500
const xzAngle = 30 * Math.PI / 180
this.camera.position.set(
cameraDist * Math.sin(xzAngle),
@ -94,7 +94,7 @@ export class Scene {
this.fptObj = {}
const planeGeom = new THREE.PlaneGeometry(5, 5)
const planeGeom = new THREE.PlaneGeometry(50, 50)
const pxy = new THREE.Mesh(
planeGeom,
new THREE.MeshBasicMaterial({
@ -128,7 +128,7 @@ export class Scene {
helpersGroup.add(this.axes);
const dist = 15
const dist = 500
const light1 = new THREE.PointLight(color.lighting, 0.7);
light1.position.set(dist, dist, dist);
helpersGroup.add(light1);

View File

@ -24,8 +24,8 @@ class Sketch {
// [0]:type, [1]:pt1, [2]:pt2, [3]:pt3, [4]:pt4
this.linksBuf = new Float32Array(this.max_links * 5).fill(NaN)
// [0]:type, [1]:val, [2]:pt1, [3]:pt2, [4]:lk1, [5]:lk2
this.constraintsBuf = new Float32Array(this.max_constraints * 6).fill(NaN)
// [0]:type, [1]:val, [2]:pt1, [3]:pt2, [4]:lk1, [5]:lk2, [6]: other, [7]: other
this.constraintsBuf = new Float32Array(this.max_constraints * 8).fill(NaN)
this.plane = new THREE.Plane(new THREE.Vector3(0, 0, 1), 0);
@ -401,9 +401,9 @@ class Sketch {
this.constraintsBuf.set(
[
this.constraintNum[obj[0]], obj[1],
...obj[2].map(ele => this.objIdx.get(ele) ?? 0),
...obj[2].map(ele => this.objIdx.get(ele) ?? 0), obj[3], obj[4]
],
(i) * 6
(i) * 8
)
i++
}
@ -587,6 +587,8 @@ Object.assign(Sketch.prototype,
where_dragged: 31,
curve_curve_tangent: 32,
length_difference: 33,
h_dist: 34,
v_dist: 35,
},
max_pts: 1000,
max_links: 1000,

View File

@ -9,9 +9,9 @@ class AxesHelper extends THREE.Object3D {
super()
this.matrixAutoUpdate = false
this.initialZoom = initialZoom
this.length = [0.55, 1]
this.headLength = 0.25
this.headWidth = 0.12
this.length = [5.5, 10]
this.headLength = 2.5
this.headWidth = 1.2
this.dirs = [
[1, 0, 0],

View File

@ -81,24 +81,66 @@ export async function setTangent() {
let selection = await this.awaitSelection({ line: 2 })
if (selection == null) return;
let idx = -1
const res = {} // this helps us find the relavant coincident constraint connecting the 2 entities
let idx = -1 // -1: both are arcs, 0: selection[0] is line, 1 selection[1] is line
const others = [] // length 2 arr of the other flag
let type, arr
/**
* a this.constraints entry:
* [0]: constraint type
* [1]: float value, -1 if not needed
* [2]: [pointA, pointB, entityA, entityB]
* [3]: other
* [4]: other2
*
* a this.linkedObjs entry:
* [0]: type: arc or line
* [1]: [point1_id, point2_id, line_id]
*/
for (let i = 0; i < 2; i++) {
if (selection[i].userData.ccw == undefined) {
if (selection[i].userData.ccw == undefined) { // quick dirty way to check if entity is a arc
idx = i
break
}
const l_id = selection[i].userData.l_id
const ids = this.linkedObjs.get(l_id)[1]
for (let j = 0; j < 2; j++) {
const constraintsArr = this.obj3d.children[this.objIdx.get(ids[j])].userData.constraints
for (let k = 0; k < constraintsArr.length; k++) {
const constraint = this.constraints.get(constraintsArr[k])
if (constraint[0] == 'points_coincident') {
if (res[constraintsArr[k]]) { // if we've seen this constraint already, it means its the relevant constraint
for (let m = 0; m < 2; m++) {
others[m] = this.obj3d.children[this.objIdx.get(constraint[2][m])].userData.start ? 0 : 1
}
let arr = idx == 0 ?
arr = idx == 0 ?
[-1, -1, selection[1].name, selection[0].name] :
[-1, -1, selection[0].name, selection[1].name];
type = idx == -1 ? 'curve_curve_tangent' : 'arc_line_tangent'
let type = idx == -1 ? 'curve_curve_tangent' : 'arc_line_tangent'
if (
(ids.includes(constraint[2][1]) && idx == 0) ||
(!ids.includes(constraint[2][1]) && idx != 0)
) { // if selection[1] includes the first entitity
let temp = others[0]
others[0] = others[1]
others[1] = temp
}
break
} else {
res[constraintsArr[k]] = true
}
}
}
}
}
this.constraints.set(++this.c_id,
[
type, -1,
arr
arr, others[0], others[1]
]
)
selection.forEach(element => {

View File

@ -106,12 +106,16 @@ export function drawArc4(mouseLoc, toPush) {
p2.geometry.attributes.position.array,
p3.geometry.attributes.position.array
)
p1.userData.start = true
p2.userData.start = false
} else {
points = get3PtArc(
p2.geometry.attributes.position.array,
p1.geometry.attributes.position.array,
p3.geometry.attributes.position.array
)
p2.userData.start = true
p1.userData.start = false
}
arc.geometry.attributes.position.set(

View File

@ -12,12 +12,12 @@ const pointMaterial = new THREE.PointsMaterial({
size: 4,
})
let dimVal
export async function drawDimension() {
let selection = await this.awaitSelection({ point: 2 }, { point: 1, line: 1 }, { line: 2 })
if (selection == null) return;
let line, dimVal, constraint, dimType
let line, constraint, dimType
if (selection.every(e => e.userData.type == 'line')) {
line = new THREE.LineSegments(
new THREE.BufferGeometry().setAttribute('position',
@ -49,6 +49,13 @@ export async function drawDimension() {
dimVal += (selection[0].geometry.attributes.position.array[i] - selection[1].geometry.attributes.position.array[i]) ** 2
}
dimVal = Math.sqrt(dimVal)
constraint = [
'pt_pt_distance', dimVal,
// 'smart_dist', dimVal,
[selection[0].name, selection[1].name, -1, -1]
]
} else {
ptLineOrder = selection[0].userData.type == 'point' ? [0, 1] : [1, 0]
const ptArr = selection[ptLineOrder[0]].geometry.attributes.position.array
@ -61,19 +68,14 @@ export async function drawDimension() {
proj = dir.multiplyScalar(disp.dot(dir))
perpOffset = disp.clone().sub(proj)
dimVal = Math.sqrt(perpOffset.x ** 2 + perpOffset.y ** 2)
}
if (ptLineOrder) {
constraint = [
'pt_line_distance', dimVal,
[selection[ptLineOrder[0]].name, -1, selection[ptLineOrder[1]].name, -1]
]
} else {
constraint = [
'pt_pt_distance', dimVal,
[selection[0].name, selection[1].name, -1, -1]
]
}
dimType = 'd'
}
@ -93,7 +95,7 @@ export async function drawDimension() {
point.layers.enable(2)
this.dimGroup.add(line).add(point)
const onMove = this._onMoveDimension(point, line)
const onMove = this._onMoveDimension(point, line, true)
point.label = document.createElement('div');
point.label.textContent = dimVal.toFixed(3);
point.label.contentEditable = true;
@ -102,10 +104,10 @@ export async function drawDimension() {
let onEnd, onKey;
let add = await new Promise((res) => {
onEnd = () => {
if (point.userData.dimType == 'd') {
point.userData.offset = hyp2.toArray() // save offset vector from hyp2
} else {
if (point.userData.dimType == 'a') {
point.userData.offset = vecArr[5].toArray()
} else {
point.userData.offset = hyp2.toArray() // save offset vector from hyp2
}
res(true)
}
@ -124,6 +126,17 @@ export async function drawDimension() {
if (add) {
if (line.userData.dimType == 'h') {
constraint[0] = 'h_dist'
constraint[1] = p2.x - p1.x
} else if (line.userData.dimType == 'v') {
constraint[0] = 'v_dist'
constraint[1] = p2.y - p1.y
}
this.constraints.set(++this.c_id, constraint)
selection[0].userData.constraints.push(this.c_id)
@ -181,7 +194,7 @@ export function updateDim(c_id) {
const tagPos = new THREE.Vector2()
let ids
export function _onMoveDimension(point, line) {
export function _onMoveDimension(point, line, initial) {
ids = line.userData.ids
@ -191,10 +204,10 @@ export function _onMoveDimension(point, line) {
let loc;
let update;
if (line.userData.dimType == 'd') {
update = updateDistance
} else {
if (line.userData.dimType == 'a') {
update = updateAngle
} else {
update = updateDistance
}
return (e) => {
@ -203,9 +216,9 @@ export function _onMoveDimension(point, line) {
tagPos.set(loc.x, loc.y)
update(
line.geometry.attributes.position,
point.geometry.attributes.position,
_p1, _p2
line,
point,
_p1, _p2, null, initial
)
sc.render()
}
@ -214,7 +227,7 @@ export function _onMoveDimension(point, line) {
export function setDimLines() {
const restoreLabels = this.labelContainer.childElementCount == 0;
const dims = this.dimGroup.children
let point, dist;
let point, dist
for (let i = 0; i < dims.length; i += 2) {
if (restoreLabels) {
point = dims[i + 1] // point node is at i+1
@ -232,15 +245,17 @@ export function setDimLines() {
let _p2 = this.obj3d.children[this.objIdx.get(ids[1])].geometry.attributes.position.array
let update;
if (dims[i].userData.dimType == 'd') {
update = updateDistance
} else {
if (dims[i].userData.dimType == 'a') {
update = updateAngle
} else {
update = updateDistance
}
update(
dims[i].geometry.attributes.position,
dims[i + 1].geometry.attributes.position,
// dims[i].geometry.attributes.position,
// dims[i + 1].geometry.attributes.position,
dims[i],
dims[i + 1],
_p1,
_p2,
dims[i + 1].userData.offset
@ -262,7 +277,11 @@ let p1eArr, p2eArr, tagPosArr
let dir, linedir, perpOffset
let dp1e, dp2e, dp12
function updateDistance(linegeom, pointgeom, _p1, _p2, offset) {
function updateDistance(line, point, _p1, _p2, offset, initial) {
const linegeom = line.geometry.attributes.position
const pointgeom = point.geometry.attributes.position
if (offset) {
if (_p1.length < _p2.length) { // corner case when p1 is pt and p2 is line
tagPos.set(_p1[0] + offset[0], _p1[1] + offset[1])
@ -271,10 +290,44 @@ function updateDistance(linegeom, pointgeom, _p1, _p2, offset) {
}
}
let phantom = null
if (_p1.length == _p2.length) {
p1.set(_p1[0], _p1[1])
p2.set(_p2[0], _p2[1])
if (initial) {
if (
(tagPos.x - p1.x) * (tagPos.x - p2.x) > 0 &&
(tagPos.y - p1.y) * (tagPos.y - p2.y) < 0
) {
line.userData.dimType = 'v'
point.userData.dimType = 'v'
// point.label.textContent = Math.abs(p1.y - p2.y).toFixed(3);
point.label.textContent = (p2.y - p1.y).toFixed(3);
} else if (
(tagPos.x - p1.x) * (tagPos.x - p2.x) < 0 &&
(tagPos.y - p1.y) * (tagPos.y - p2.y) > 0
) {
line.userData.dimType = 'h'
point.userData.dimType = 'h'
// point.label.textContent = Math.abs(p1.x - p2.x).toFixed(3);
point.label.textContent = (p2.x - p1.x).toFixed(3);
} else {
line.userData.dimType = 'd'
point.userData.dimType = 'd'
point.label.textContent = dimVal.toFixed(3);
}
}
switch (line.userData.dimType) {
case 'v':
phantom = [_p1[0] + 1, _p1[1]]
break;
case 'h':
phantom = [_p1[0], _p1[1] + 1]
break;
default:
dir = p2.clone().sub(p1).normalize()
hyp2 = tagPos.clone().sub(p2) // note that this value is used to calculate tag-p2 offset
proj = dir.multiplyScalar(hyp2.dot(dir))
@ -289,11 +342,20 @@ function updateDistance(linegeom, pointgeom, _p1, _p2, offset) {
dp1e = p1e.distanceToSquared(tagPos)
dp2e = p2e.distanceToSquared(tagPos)
dp12 = p1e.distanceToSquared(p2e)
linegeom.array.set(p1.toArray(), 0)
} else {
if (_p1.length > _p2.length) { // when p1 is line, p2 is point
break;
}
}
if (_p1.length != _p2.length || phantom) {
if (phantom) {
p1.set(_p1[0], _p1[1])
p1x.set(...phantom)
p2.set(_p2[0], _p2[1])
} else if (_p1.length > _p2.length) { // when p1 is line, p2 is point
p1.set(_p1[0], _p1[1])
p1x.set(_p1[3], _p1[4])
p2.set(_p2[0], _p2[1])
@ -431,7 +493,7 @@ function updateAngle(linegeom, pointgeom, _l1, _l2, offset) {
tA1 = unreflex(a[2] - (a[0] + shift))
tA2 = unreflex(a[2] - (a[0] + dA + shift))
if (dA * tA1 < 0) {
if (dA * tA1 < 0) { // if dA and tA1 are not the same sign
a1 = a[0] + tA1 + shift
deltaAngle = dA - tA1
} else if (dA * tA2 > 0) {
@ -506,9 +568,9 @@ const getAngle = (Obj3dLines) => {
export function onDimMoveEnd(point) {
if (point.userData.dimType == 'd') {
point.userData.offset = hyp2.toArray() // save offset vector from hyp2
} else {
if (point.userData.dimType == 'a') {
point.userData.offset = vecArr[5].toArray()
} else {
point.userData.offset = hyp2.toArray() // save offset vector from hyp2
}
}

View File

@ -47,6 +47,35 @@ export const NavBar = () => {
forceUpdate()
}
// const mirror = (plane) => {
// if (sc.selected.length != 2 || ) {
// alert('please first select two bodies for boolean operation')
// return
// }
// const [m1, m2] = sc.selected
// const mesh = sc.boolOp(m1, m2, code)
// sc.obj3d.add(mesh)
// dispatch({
// type: 'set-entry-visibility', obj: {
// [m1.name]: false,
// [m2.name]: false,
// [mesh.name]: true,
// }
// })
// dispatch({
// type: 'rx-boolean', mesh, deps: [m1.name, m2.name]
// })
// sc.render()
// forceUpdate()
// }
const addSketch = () => {
const sketch = sc.addSketch()
if (!sketch) {

View File

@ -11,7 +11,7 @@ export const Tree = () => {
const fileHandle = useSelector(state => state.ui.fileHandle)
return <div className='sideNav flex flex-col bg-gray-800'>
<div className='w-16 text-gray-50 h-9 text-lg mx-1 border-0 flex items-center focus:outline-none bg-transparent'>
<div className='w-full text-gray-50 h-9 text-lg mx-1 border-0 flex items-center focus:outline-none bg-transparent'>
{fileHandle ? fileHandle.name.replace(/\.[^/.]+$/, "") : 'untitled'}
</div>
{treeEntries.allIds.map((entId, idx) => (

View File

@ -7,8 +7,8 @@ const _vec3 = new THREE.Vector3()
const raycaster = new THREE.Raycaster();
raycaster.params.Line.threshold = 0.1;
raycaster.params.Points.threshold = 0.1;
raycaster.params.Line.threshold = 1;
raycaster.params.Points.threshold = 1;
const color = {

View File

@ -38,6 +38,10 @@ 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
- dimension to origin vs ordinate dimensioninging
- increased design payload handling
-unable cancel out of new sketches //fixed seemingly
-unable to delete arc // fixed seemingly

View File

@ -397,6 +397,35 @@ static inline Slvs_Constraint Slvs_MakeConstraint(Slvs_hConstraint h,
return r;
}
static inline Slvs_Constraint Slvs_MakeConstraint_Alt(Slvs_hConstraint h,
Slvs_hGroup group,
int type,
Slvs_hEntity wrkpl,
double valA,
Slvs_hEntity ptA,
Slvs_hEntity ptB,
Slvs_hEntity entityA,
Slvs_hEntity entityB,
int other, int other2
)
{
Slvs_Constraint r;
memset(&r, 0, sizeof(r));
r.h = h;
r.group = group;
r.type = type;
r.wrkpl = wrkpl;
r.valA = valA;
r.ptA = ptA;
r.ptB = ptB;
r.entityA = entityA;
r.entityB = entityB;
r.other = other;
r.other2 = other2;
return r;
}
#ifdef __cplusplus
}
#endif

View File

@ -3,7 +3,7 @@
* initial guesses for their positions, and then constrain them. The solver
* calculates their new positions, in order to satisfy the constraints.
*
* Copyright 2008-2013 Jonathan Westhues.
* Copyright -2008-2013 Jonathan Westhues.
*---------------------------------------------------------------------------*/
#ifdef WIN32
#include <windows.h>
@ -43,9 +43,9 @@ int solver(int nPts, float *p_ptr, int nConst, float *c_ptr, int nLinks, float *
/* First, we create our workplane. Its origin corresponds to the origin
* of our base frame (x y z) = (0 0 0) */
sys.param[sys.params++] = Slvs_MakeParam(1, g, 0.0);
sys.param[sys.params++] = Slvs_MakeParam(2, g, 0.0);
sys.param[sys.params++] = Slvs_MakeParam(3, g, 0.0);
sys.entity[sys.entities++] = Slvs_MakePoint3d(101, g, 1, 2, 3);
sys.param[sys.params++] = Slvs_MakeParam(2, g, 1.0);
sys.param[sys.params++] = Slvs_MakeParam(3, g, -1.0);
sys.entity[sys.entities++] = Slvs_MakePoint3d(-101, g, 1, 1, 1);
/* and it is parallel to the xy plane, so it has basis vectors (1 0 0)
* and (0 1 0). */
Slvs_MakeQuaternion(1, 0, 0,
@ -54,9 +54,9 @@ int solver(int nPts, float *p_ptr, int nConst, float *c_ptr, int nLinks, float *
sys.param[sys.params++] = Slvs_MakeParam(5, g, qx);
sys.param[sys.params++] = Slvs_MakeParam(6, g, qy);
sys.param[sys.params++] = Slvs_MakeParam(7, g, qz);
sys.entity[sys.entities++] = Slvs_MakeNormal3d(102, g, 4, 5, 6, 7);
sys.entity[sys.entities++] = Slvs_MakeNormal3d(-102, g, 4, 5, 6, 7);
sys.entity[sys.entities++] = Slvs_MakeWorkplane(200, g, 101, 102);
sys.entity[sys.entities++] = Slvs_MakeWorkplane(-200, g, -101, -102);
/* Now create a second group. We'll solve group 2, while leaving group 1
* constant; so the workplane that we've created will be locked down,
@ -65,9 +65,15 @@ int solver(int nPts, float *p_ptr, int nConst, float *c_ptr, int nLinks, float *
/* These points are represented by their coordinates (u v) within the
* workplane, so they need only two parameters each. */
sys.entity[sys.entities++] = Slvs_MakePoint2d(-103, g, -200, 1, 1);
sys.entity[sys.entities++] = Slvs_MakePoint2d(-104, g, -200, 1, 3);
sys.entity[sys.entities++] = Slvs_MakePoint2d(-105, g, -200, 3, 1);
sys.entity[sys.entities++] = Slvs_MakeLineSegment(-106, g,
-200, -103, -104); //y-axis
sys.entity[sys.entities++] = Slvs_MakeLineSegment(-107, g,
-200, -103, -105); //x-axis
Slvs_hParam ph = 11;
Slvs_hParam vh = 301, vh_s = 301;
Slvs_hParam lh = 400, lh_s = 400;
float *buf_pt_start = p_ptr;
int p_start = sys.params;
@ -81,7 +87,7 @@ int solver(int nPts, float *p_ptr, int nConst, float *c_ptr, int nLinks, float *
sys.param[sys.params++] = Slvs_MakeParam(ph++, g, (float)*p_ptr++);
sys.param[sys.params++] = Slvs_MakeParam(ph++, g, (float)*p_ptr++);
sys.entity[sys.entities++] = Slvs_MakePoint2d(i, g, 200, ph - 1, ph - 2);
sys.entity[sys.entities++] = Slvs_MakePoint2d(i, g, -200, ph - 1, ph - 2);
p_ptr += 1;
}
@ -92,10 +98,10 @@ int solver(int nPts, float *p_ptr, int nConst, float *c_ptr, int nLinks, float *
{
case 0:
sys.entity[sys.entities++] = Slvs_MakeLineSegment((int)*(l_ptr + 2), g,
200, (int)*l_ptr, (int)*(l_ptr + 1));
-200, (int)*l_ptr, (int)*(l_ptr + 1));
break;
case 1:
sys.entity[sys.entities++] = Slvs_MakeArcOfCircle((int)*(l_ptr + 3), g, 200, 102,
sys.entity[sys.entities++] = Slvs_MakeArcOfCircle((int)*(l_ptr + 3), g, -200, -102,
(int)*(l_ptr + 2), (int)*(l_ptr), (int)*(l_ptr + 1));
break;
default:
@ -109,19 +115,30 @@ int solver(int nPts, float *p_ptr, int nConst, float *c_ptr, int nLinks, float *
sys.constraint[sys.constraints++] = Slvs_MakeConstraint(
c_pre++, 2,
SLVS_C_POINTS_COINCIDENT,
200,
-200,
-1,
101, geomStartIdx, -1, -1);
-101, geomStartIdx, -1, -1);
for (int c_id=c_pre; c_id < c_pre + nConst; c_id++, c_ptr += 6)
for (int c_id = c_pre; c_id < c_pre + nConst; c_id++, c_ptr += 8)
{
sys.constraint[sys.constraints++] = Slvs_MakeConstraint(
if ((int)*c_ptr >= 34)
{
sys.constraint[sys.constraints++] = Slvs_MakeConstraint_Alt(
c_id, g,
30 + 100000,
-200,
*(c_ptr + 1),
(int)*(c_ptr + 2), (int)*(c_ptr + 3), (int)*c_ptr == 34 ? -106: -107, (int)*(c_ptr + 5), (int)*(c_ptr + 6), (int)*(c_ptr + 7));
}
else
{
sys.constraint[sys.constraints++] = Slvs_MakeConstraint_Alt(
c_id, g,
(int)*c_ptr + 100000,
200,
-200,
*(c_ptr + 1),
(int)*(c_ptr + 2), (int)*(c_ptr + 3), (int)*(c_ptr + 4), (int)*(c_ptr + 5));
(int)*(c_ptr + 2), (int)*(c_ptr + 3), (int)*(c_ptr + 4), (int)*(c_ptr + 5), (int)*(c_ptr + 6), (int)*(c_ptr + 7));
}
}
/* And solve. */
@ -174,7 +191,6 @@ int main(int argc, char *argv[])
sys.failed = CheckMalloc(500 * sizeof(sys.failed[0]));
sys.faileds = 500;
// printf("hello\n");
return 0;
}