caluclate segment length in screen-space/in-pixels

This commit is contained in:
Kurt Hutten Irev-Dev
2024-04-01 21:32:59 +11:00
parent b9e544d410
commit 149130d264
5 changed files with 108 additions and 13 deletions

View File

@ -30,10 +30,15 @@ export function createGridHelper({
}
export const orthoScale = (cam: OrthographicCamera | PerspectiveCamera) =>
0.55 / cam.zoom
(0.55 * 760) / cam.zoom / window.innerHeight
export const perspScale = (cam: PerspectiveCamera, group: Group | Mesh) =>
(group.position.distanceTo(cam.position) * cam.fov) / 4000
(group.position.distanceTo(cam.position) * cam.fov * 760) /
4000 /
window.innerHeight
export const getPxLength = (scale: number, length: number) =>
(length * 10.458256051295065) / scale
export function isQuaternionVertical(q: Quaternion) {
const v = new Vector3(0, 0, 1).applyQuaternion(q)

View File

@ -36,7 +36,11 @@ import {
Y_AXIS,
YZ_PLANE,
} from './sceneInfra'
import { isQuaternionVertical, quaternionFromUpNForward } from './helpers'
import {
getPxLength,
isQuaternionVertical,
quaternionFromUpNForward,
} from './helpers'
import {
CallExpression,
getTangentialArcToInfo,
@ -97,6 +101,7 @@ export const TANGENTIAL_ARC_TO__SEGMENT_DASH =
'tangential-arc-to-segment-body-dashed'
export const TANGENTIAL_ARC_TO_SEGMENT = 'tangential-arc-to-segment'
export const TANGENTIAL_ARC_TO_SEGMENT_BODY = 'tangential-arc-to-segment-body'
export const MIN_SEGMENT_LENGTH = 60 // in pixels
// This singleton Class is responsible for all of the things the user sees and interacts with.
// That mostly mean sketch elements.
@ -856,8 +861,6 @@ export class SceneEntities {
group.userData.prevSegment = prevSegment
const arrowGroup = group.getObjectByName(ARROWHEAD) as Group
arrowGroup.position.set(to[0], to[1], 0)
const previousPoint =
prevSegment?.type === 'TangentialArcTo'
? getTangentPointFromPreviousArc(
@ -874,13 +877,21 @@ export class SceneEntities {
obtuse: true,
})
const arrowheadAngle =
arcInfo.endAngle + (Math.PI / 2) * (arcInfo.ccw ? 1 : -1)
arrowGroup.quaternion.setFromUnitVectors(
new Vector3(0, 1, 0),
new Vector3(Math.cos(arrowheadAngle), Math.sin(arrowheadAngle), 0)
)
arrowGroup.scale.set(scale, scale, scale)
const pxLength = getPxLength(scale, arcInfo.arcLength)
const shouldHide = pxLength < MIN_SEGMENT_LENGTH
if (arrowGroup) {
arrowGroup.position.set(to[0], to[1], 0)
const arrowheadAngle =
arcInfo.endAngle + (Math.PI / 2) * (arcInfo.ccw ? 1 : -1)
arrowGroup.quaternion.setFromUnitVectors(
new Vector3(0, 1, 0),
new Vector3(Math.cos(arrowheadAngle), Math.sin(arrowheadAngle), 0)
)
arrowGroup.scale.set(scale, scale, scale)
arrowGroup.visible = !shouldHide
}
const tangentialArcToSegmentBody = group.children.find(
(child) => child.userData.type === TANGENTIAL_ARC_TO_SEGMENT_BODY
@ -931,6 +942,13 @@ export class SceneEntities {
shape.lineTo(0, 0.08 * scale) // The width of the line
const arrowGroup = group.getObjectByName(ARROWHEAD) as Group
const length = Math.sqrt(
Math.pow(to[0] - from[0], 2) + Math.pow(to[1] - from[1], 2)
)
const pxLength = getPxLength(scale, length)
const shouldHide = pxLength < MIN_SEGMENT_LENGTH
if (arrowGroup) {
arrowGroup.position.set(to[0], to[1], 0)
@ -942,6 +960,7 @@ export class SceneEntities {
.normalize()
arrowGroup.quaternion.setFromUnitVectors(new Vector3(0, 1, 0), dir)
arrowGroup.scale.set(scale, scale, scale)
arrowGroup.visible = !shouldHide
}
const extraSegmentGroup = group.getObjectByName(EXTRA_SEGMENT_HANDLE)
@ -955,7 +974,7 @@ export class SceneEntities {
0
)
extraSegmentGroup.scale.set(scale, scale, scale)
group.add(extraSegmentGroup)
extraSegmentGroup.visible = !shouldHide
}
const straightSegmentBody = group.children.find(

View File

@ -251,6 +251,7 @@ export function getTangentialArcToInfo({
startAngle: number
endAngle: number
ccw: boolean
arcLength: number
} {
const result = get_tangential_arc_to_info(
arcStartPoint[0],
@ -268,6 +269,7 @@ export function getTangentialArcToInfo({
startAngle: result.start_angle,
endAngle: result.end_angle,
ccw: result.ccw > 0,
arcLength: result.arc_length,
}
}

View File

@ -576,6 +576,8 @@ pub struct TangentialArcInfoOutput {
pub end_angle: f64,
/// If the arc is counter-clockwise.
pub ccw: i32,
/// The length of the arc.
pub arc_length: f64,
}
// tanPreviousPoint and arcStartPoint make up a straight segment leading into the arc (of which the arc should be tangential). The arc should start at arcStartPoint and end at, arcEndPoint
@ -626,6 +628,17 @@ pub fn get_tangential_arc_to_info(input: TangentialArcInfoInput) -> TangentialAr
let end_angle = (input.arc_end_point[1] - center[1]).atan2(input.arc_end_point[0] - center[0]);
let ccw = is_points_ccw(&[input.arc_start_point, arc_mid_point, input.arc_end_point]);
let arc_mid_angle = (arc_mid_point[1] - center[1]).atan2(arc_mid_point[0] - center[0]);
let start_to_mid_arc_length = radius
* delta(Angle::from_radians(start_angle), Angle::from_radians(arc_mid_angle))
.radians()
.abs();
let mid_to_end_arc_length = radius
* delta(Angle::from_radians(arc_mid_angle), Angle::from_radians(end_angle))
.radians()
.abs();
let arc_length = start_to_mid_arc_length + mid_to_end_arc_length;
TangentialArcInfoOutput {
center,
radius,
@ -633,6 +646,7 @@ pub fn get_tangential_arc_to_info(input: TangentialArcInfoInput) -> TangentialAr
start_angle,
end_angle,
ccw,
arc_length,
}
}
@ -758,6 +772,58 @@ mod get_tangential_arc_to_info_tests {
assert_relative_eq!(result.end_angle, -PI / 2.0);
assert_eq!(result.ccw, 1);
}
#[test]
fn test_arc_length_obtuse_cw() {
let result = get_tangential_arc_to_info(TangentialArcInfoInput {
tan_previous_point: [-1.0, -1.0],
arc_start_point: [-1.0, 0.0],
arc_end_point: [0.0, -1.0],
obtuse: true,
});
let circumference = 2.0 * PI * result.radius;
let expected_length = circumference * 3.0 / 4.0; // 3 quarters of a circle circle
assert_relative_eq!(result.arc_length, expected_length);
}
#[test]
fn test_arc_length_acute_cw() {
let result = get_tangential_arc_to_info(TangentialArcInfoInput {
tan_previous_point: [-1.0, -1.0],
arc_start_point: [-1.0, 0.0],
arc_end_point: [0.0, 1.0],
obtuse: true,
});
let circumference = 2.0 * PI * result.radius;
let expected_length = circumference / 4.0; // 1 quarters of a circle circle
assert_relative_eq!(result.arc_length, expected_length);
}
#[test]
fn test_arc_length_obtuse_ccw() {
let result = get_tangential_arc_to_info(TangentialArcInfoInput {
tan_previous_point: [1.0, -1.0],
arc_start_point: [1.0, 0.0],
arc_end_point: [0.0, -1.0],
obtuse: true,
});
let circumference = 2.0 * PI * result.radius;
let expected_length = circumference * 3.0 / 4.0; // 1 quarters of a circle circle
assert_relative_eq!(result.arc_length, expected_length);
}
#[test]
fn test_arc_length_acute_ccw() {
let result = get_tangential_arc_to_info(TangentialArcInfoInput {
tan_previous_point: [1.0, -1.0],
arc_start_point: [1.0, 0.0],
arc_end_point: [0.0, 1.0],
obtuse: true,
});
let circumference = 2.0 * PI * result.radius;
let expected_length = circumference / 4.0; // 1 quarters of a circle circle
assert_relative_eq!(result.arc_length, expected_length);
}
}
pub fn get_tangent_point_from_previous_arc(

View File

@ -333,6 +333,8 @@ pub struct TangentialArcInfoOutputWasm {
pub end_angle: f64,
/// Flag to determine if the arc is counter clockwise.
pub ccw: i32,
/// The length of the arc.
pub arc_length: f64,
}
#[wasm_bindgen]
@ -362,6 +364,7 @@ pub fn get_tangential_arc_to_info(
start_angle: result.start_angle,
end_angle: result.end_angle,
ccw: result.ccw,
arc_length: result.arc_length,
}
}