diff --git a/src/clientSideScene/helpers.ts b/src/clientSideScene/helpers.ts index 4a2e2f027..40cad6eed 100644 --- a/src/clientSideScene/helpers.ts +++ b/src/clientSideScene/helpers.ts @@ -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) diff --git a/src/clientSideScene/sceneEntities.ts b/src/clientSideScene/sceneEntities.ts index 877051d62..db6da3bd5 100644 --- a/src/clientSideScene/sceneEntities.ts +++ b/src/clientSideScene/sceneEntities.ts @@ -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( diff --git a/src/lang/wasm.ts b/src/lang/wasm.ts index 4385ebe06..b2d2628f6 100644 --- a/src/lang/wasm.ts +++ b/src/lang/wasm.ts @@ -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, } } diff --git a/src/wasm-lib/kcl/src/std/utils.rs b/src/wasm-lib/kcl/src/std/utils.rs index 55dec5127..b766ee4fb 100644 --- a/src/wasm-lib/kcl/src/std/utils.rs +++ b/src/wasm-lib/kcl/src/std/utils.rs @@ -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( diff --git a/src/wasm-lib/src/wasm.rs b/src/wasm-lib/src/wasm.rs index e115f6ca1..7fb68aee8 100644 --- a/src/wasm-lib/src/wasm.rs +++ b/src/wasm-lib/src/wasm.rs @@ -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, } }