@@ -305,9 +305,13 @@ export function buildVisibleLineOfSightSegments(
305305 if ( ! endpoints || points . length === 0 ) return [ ] ;
306306
307307 const lastDistance = points . at ( - 1 ) ?. distance ?? 0 ;
308+ const profilePoints =
309+ adjustment === "curvature-adjusted"
310+ ? densifyProfilePointsForCurvature ( points , lastDistance )
311+ : points ;
308312 const output : ( LineOfSightChartPoint | null ) [ ] = [ ] ;
309313 const first = classifyPoint (
310- points [ 0 ] ! ,
314+ profilePoints [ 0 ] ! ,
311315 lastDistance ,
312316 endpoints ,
313317 adjustment ,
@@ -317,16 +321,16 @@ export function buildVisibleLineOfSightSegments(
317321
318322 appendLineOfSightPoint ( output , first . visible ? first . linePoint : null ) ;
319323
320- for ( let index = 1 ; index < points . length ; index ++ ) {
324+ for ( let index = 1 ; index < profilePoints . length ; index ++ ) {
321325 const previous = classifyPoint (
322- points [ index - 1 ] ! ,
326+ profilePoints [ index - 1 ] ! ,
323327 lastDistance ,
324328 endpoints ,
325329 adjustment ,
326330 unitScales ,
327331 ) ;
328332 const current = classifyPoint (
329- points [ index ] ! ,
333+ profilePoints [ index ] ! ,
330334 lastDistance ,
331335 endpoints ,
332336 adjustment ,
@@ -351,9 +355,7 @@ export function buildVisibleLineOfSightSegments(
351355 appendLineOfSightPoint ( output , current . visible ? current . linePoint : null ) ;
352356 }
353357
354- return adjustment === "curvature-adjusted"
355- ? densifyLineOfSightPoints ( output , lastDistance , endpoints , unitScales )
356- : output ;
358+ return output ;
357359}
358360
359361type ClassifiedPoint = {
@@ -507,8 +509,12 @@ function buildVisibleFresnelBoundarySegments(
507509 adjustment : LineOfSightAdjustment ,
508510 boundary : FresnelBoundary ,
509511) : LineOfSightChartPoint [ ] [ ] {
512+ const profilePoints =
513+ adjustment === "curvature-adjusted"
514+ ? densifyProfilePointsForCurvature ( points , totalDistance )
515+ : points ;
510516 const first = classifyFresnelBoundaryPoint (
511- points [ 0 ] ! ,
517+ profilePoints [ 0 ] ! ,
512518 endpoints ,
513519 totalDistance ,
514520 frequencyMhz ,
@@ -523,9 +529,9 @@ function buildVisibleFresnelBoundarySegments(
523529 const output : ( LineOfSightChartPoint | null ) [ ] = [ ] ;
524530 appendLineOfSightPoint ( output , first . visible ? first . linePoint : null ) ;
525531
526- for ( let index = 1 ; index < points . length ; index ++ ) {
532+ for ( let index = 1 ; index < profilePoints . length ; index ++ ) {
527533 const previous = classifyFresnelBoundaryPoint (
528- points [ index - 1 ] ! ,
534+ profilePoints [ index - 1 ] ! ,
529535 endpoints ,
530536 totalDistance ,
531537 frequencyMhz ,
@@ -535,7 +541,7 @@ function buildVisibleFresnelBoundarySegments(
535541 boundary ,
536542 ) ;
537543 const current = classifyFresnelBoundaryPoint (
538- points [ index ] ! ,
544+ profilePoints [ index ] ! ,
539545 endpoints ,
540546 totalDistance ,
541547 frequencyMhz ,
@@ -566,19 +572,7 @@ function buildVisibleFresnelBoundarySegments(
566572 appendLineOfSightPoint ( output , current . visible ? current . linePoint : null ) ;
567573 }
568574
569- const segments = splitLineOfSightSegments ( output ) ;
570-
571- return adjustment === "curvature-adjusted"
572- ? densifyFresnelBoundarySegments (
573- segments ,
574- endpoints ,
575- totalDistance ,
576- frequencyMhz ,
577- shellNumber ,
578- unitScales ,
579- boundary ,
580- )
581- : segments ;
575+ return splitLineOfSightSegments ( output ) ;
582576}
583577
584578function classifyFresnelBoundaryPoint (
@@ -640,136 +634,61 @@ function fresnelBoundaryCrossingPoint(
640634 return { x : distance , y : elevation } ;
641635}
642636
643- function densifyLineOfSightPoints (
644- points : ( LineOfSightChartPoint | null ) [ ] ,
645- totalDistance : number ,
646- endpoints : LineOfSightEndpoints ,
647- unitScales : FresnelZoneUnitScales ,
648- ) : ( LineOfSightChartPoint | null ) [ ] {
649- return densifyNullableChartPoints ( points , totalDistance , ( distance ) =>
650- lineOfSightChartPointAt (
651- distance ,
652- totalDistance ,
653- endpoints ,
654- "curvature-adjusted" ,
655- unitScales ,
656- ) ,
657- ) ;
658- }
659-
660- function densifyFresnelBoundarySegments (
661- segments : LineOfSightChartPoint [ ] [ ] ,
662- endpoints : LineOfSightEndpoints ,
663- totalDistance : number ,
664- frequencyMhz : number ,
665- shellNumber : number ,
666- unitScales : FresnelZoneUnitScales ,
667- boundary : FresnelBoundary ,
668- ) : LineOfSightChartPoint [ ] [ ] {
669- return segments . map ( ( segment ) =>
670- densifyChartSegment ( segment , totalDistance , ( distance ) =>
671- fresnelBoundaryChartPointAt (
672- distance ,
673- endpoints ,
674- totalDistance ,
675- frequencyMhz ,
676- shellNumber ,
677- unitScales ,
678- boundary ,
679- ) ,
680- ) ,
681- ) ;
682- }
683-
684- function densifyNullableChartPoints (
685- points : ( LineOfSightChartPoint | null ) [ ] ,
637+ function densifyProfilePointsForCurvature (
638+ points : ProfilePoint [ ] ,
686639 totalDistance : number ,
687- pointAt : ( distance : number ) => LineOfSightChartPoint | null ,
688- ) : ( LineOfSightChartPoint | null ) [ ] {
689- const output : ( LineOfSightChartPoint | null ) [ ] = [ ] ;
690- let previous : LineOfSightChartPoint | null = null ;
691-
692- for ( const point of points ) {
693- if ( point === null ) {
694- appendLineOfSightPoint ( output , null ) ;
695- previous = null ;
696- continue ;
697- }
698-
699- if ( previous ) {
700- appendInteriorSamples (
701- output ,
702- previous . x ,
703- point . x ,
704- totalDistance ,
705- pointAt ,
706- ) ;
707- }
640+ ) : ProfilePoint [ ] {
641+ if ( ! isPositiveFinite ( totalDistance ) || points . length < 2 ) return points ;
708642
709- appendLineOfSightPoint ( output , point ) ;
710- previous = point ;
711- }
643+ const output : ProfilePoint [ ] = [ ] ;
712644
713- return output ;
714- }
715-
716- function densifyChartSegment (
717- segment : LineOfSightChartPoint [ ] ,
718- totalDistance : number ,
719- pointAt : ( distance : number ) => LineOfSightChartPoint | null ,
720- ) : LineOfSightChartPoint [ ] {
721- const output : LineOfSightChartPoint [ ] = [ ] ;
645+ for ( let index = 0 ; index < points . length ; index ++ ) {
646+ const point = points [ index ] ;
647+ if ( ! point ) continue ;
722648
723- for ( const point of segment ) {
724- const previous = output . at ( - 1 ) ?? null ;
649+ output . push ( point ) ;
725650
726- if ( previous ) {
727- appendInteriorSamples (
728- output ,
729- previous . x ,
730- point . x ,
731- totalDistance ,
732- pointAt ,
733- ) ;
734- }
651+ const nextPoint = points [ index + 1 ] ;
652+ if ( ! nextPoint ) continue ;
735653
736- output . push ( point ) ;
654+ appendInteriorProfilePoints ( output , point , nextPoint , totalDistance ) ;
737655 }
738656
739657 return output ;
740658}
741659
742- function appendInteriorSamples (
743- output : ( LineOfSightChartPoint | null ) [ ] ,
744- startDistance : number ,
745- endDistance : number ,
660+ function appendInteriorProfilePoints (
661+ output : ProfilePoint [ ] ,
662+ start : ProfilePoint ,
663+ end : ProfilePoint ,
746664 totalDistance : number ,
747- pointAt : ( distance : number ) => LineOfSightChartPoint | null ,
748665) : void {
749666 if (
750- ! isPositiveFinite ( totalDistance ) ||
751- ! Number . isFinite ( startDistance ) ||
752- ! Number . isFinite ( endDistance ) ||
753- startDistance === endDistance
667+ ! Number . isFinite ( start . distance ) ||
668+ ! Number . isFinite ( end . distance ) ||
669+ ! Number . isFinite ( start . elevation ) ||
670+ ! Number . isFinite ( end . elevation ) ||
671+ start . distance === end . distance
754672 ) {
755673 return ;
756674 }
757675
758- const distanceDelta = endDistance - startDistance ;
676+ const distanceDelta = end . distance - start . distance ;
759677 const sampleStep = totalDistance / curvatureAdjustedSampleCount ;
760678 const sampleCount = Math . max (
761679 1 ,
762680 Math . ceil ( Math . abs ( distanceDelta ) / sampleStep ) ,
763681 ) ;
764682
765683 for ( let sampleIndex = 1 ; sampleIndex < sampleCount ; sampleIndex ++ ) {
766- const distance =
767- startDistance + ( distanceDelta * sampleIndex ) / sampleCount ;
768- const point = pointAt ( distance ) ;
769-
770- if ( point ) {
771- output . push ( point ) ;
772- }
684+ const ratio = sampleIndex / sampleCount ;
685+
686+ output . push ( {
687+ distance : start . distance + distanceDelta * ratio ,
688+ elevation : start . elevation ! + ( end . elevation ! - start . elevation ! ) * ratio ,
689+ x : start . x + ( end . x - start . x ) * ratio ,
690+ y : start . y + ( end . y - start . y ) * ratio ,
691+ } ) ;
773692 }
774693}
775694
@@ -791,41 +710,6 @@ function lineOfSightChartPointAt(
791710 return elevation === null ? null : { x : distance , y : elevation } ;
792711}
793712
794- function fresnelBoundaryChartPointAt (
795- distance : number ,
796- endpoints : LineOfSightEndpoints ,
797- totalDistance : number ,
798- frequencyMhz : number ,
799- shellNumber : number ,
800- unitScales : FresnelZoneUnitScales ,
801- boundary : FresnelBoundary ,
802- ) : LineOfSightChartPoint | null {
803- const radius = fresnelRadiusForChartDistance (
804- distance ,
805- totalDistance ,
806- frequencyMhz ,
807- shellNumber ,
808- unitScales ,
809- ) ;
810- const centerElevation = lineOfSightElevationForAdjustment (
811- distance ,
812- totalDistance ,
813- endpoints ,
814- "curvature-adjusted" ,
815- unitScales ,
816- ) ;
817-
818- if ( radius === null || centerElevation === null ) return null ;
819-
820- return {
821- x : distance ,
822- y :
823- boundary === "upper"
824- ? centerElevation + radius
825- : centerElevation - radius ,
826- } ;
827- }
828-
829713function lineOfSightElevationForAdjustment (
830714 distance : number ,
831715 lastDistance : number ,
0 commit comments