caluclate segment length in screen-space/in-pixels
This commit is contained in:
@ -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)
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user