@@ -15,8 +15,8 @@ import (
1515const goldenCell = "../../../testdata/US4MD81M.000"
1616
1717func TestBandForScale (t * testing.T ) {
18- if BandForScale (12_000 ).ZoomRange () != (ZoomRange {14 , 16 }) {
19- t .Error ("12k should be harbor [14 ,16]" )
18+ if BandForScale (12_000 ).ZoomRange () != (ZoomRange {13 , 16 }) {
19+ t .Error ("12k should be harbor [13 ,16]" )
2020 }
2121 if BandForScale (3_000_000 ) != BandOverview {
2222 t .Error ("3M should be overview" )
@@ -343,41 +343,40 @@ func TestSoundingGrouping(t *testing.T) {
343343}
344344
345345func TestSectorLights (t * testing.T ) {
346- // expandSector: a sector -> 2 short legs (sleg 0) + 2 full-length legs
347- // (sleg 1) + OUTLW underlay + coloured arc (both sleg -1, always shown).
348- anchor := mustLatLon ( 38.97 , - 76.49 )
349- strokes := expandSector ( anchor , sp ( 0 , 90 , "LITRD" ), 14 )
350- if len (strokes ) != 6 {
351- t .Fatalf ("sector strokes = %d, want 6 " , len (strokes ))
352- }
353- if ! strokes [0 ].dashed || strokes [0 ].colorToken != "CHBLK" || strokes [0 ].sleg != 0 {
346+ // tessellateFigure drives each constructed figure element off the rule's params.
347+ // A leg with a nominal range emits the short ( sleg 0) + extended full-length
348+ // (sleg 1) variants, both dashed in the rule's colour, for the client's toggle.
349+ leg := tessellateFigure ( legPrim ( 90 , 8 ), 14 )
350+ if len (leg ) != 2 {
351+ t .Fatalf ("leg strokes = %d, want 2 (short + full) " , len (leg ))
352+ }
353+ if ! leg [0 ].dashed || leg [0 ].colorToken != "CHBLK" || leg [0 ].sleg != 0 {
354354 t .Error ("stroke 0 should be the dashed CHBLK short leg (sleg 0)" )
355355 }
356- if ! strokes [2 ].dashed || strokes [2 ].colorToken != "CHBLK" || strokes [2 ].sleg != 1 {
357- t .Error ("stroke 2 should be the dashed CHBLK full-length leg (sleg 1)" )
358- }
359- if strokes [4 ].colorToken != "OUTLW" || strokes [4 ].widthPx != 4 || strokes [4 ].sleg != - 1 {
360- t .Error ("stroke 4 should be the 4px OUTLW arc underlay (sleg -1)" )
356+ if leg [1 ].sleg != 1 {
357+ t .Error ("stroke 1 should be the full-length leg (sleg 1)" )
361358 }
362- if strokes [5 ].colorToken != "LITRD" || strokes [5 ].widthPx != 2 || strokes [5 ].dashed || strokes [5 ].sleg != - 1 {
363- t .Error ("stroke 5 should be the 2px solid LITRD arc (sleg -1)" )
364- }
365- // A light with a VALNMR nominal range emits full legs (sleg 1) longer than
366- // the 25 mm short legs (sleg 0) — the toggle's whole point.
367- spR := sp (0 , 90 , "LITRD" )
368- spR .RadiusNM = 8
369- withR := expandSector (anchor , spR , 14 )
370359 legLen := func (s sectorStroke ) float64 {
371360 return absf (s .points [1 ].Lat - s .points [0 ].Lat ) + absf (s .points [1 ].Lon - s .points [0 ].Lon )
372361 }
373- if legLen (withR [2 ]) <= legLen (withR [0 ]) {
374- t .Errorf ("full leg (%.6f) should be longer than short leg (%.6f)" , legLen (withR [2 ]), legLen (withR [0 ]))
362+ if legLen (leg [1 ]) <= legLen (leg [0 ]) {
363+ t .Errorf ("full leg (%.6f) should be longer than short leg (%.6f)" , legLen (leg [1 ]), legLen (leg [0 ]))
364+ }
365+ // A leg with no nominal range is a single always-shown stroke (sleg -1).
366+ plain := tessellateFigure (legPrim (90 , 0 ), 14 )
367+ if len (plain ) != 1 || plain [0 ].sleg != - 1 {
368+ t .Errorf ("plain leg = %+v, want 1 stroke sleg -1" , plain )
375369 }
376- // Screen-fixed: lat span ~halves per zoom level.
377- r14 := expandSector (anchor , sp (0 , 0 , "LITYW" ), 14 ) // ring
378- r15 := expandSector (anchor , sp (0 , 0 , "LITYW" ), 15 )
379- span := func (s []sectorStroke ) float64 { return absf (s [len (s )- 1 ].points [0 ].Lat - anchor .Lat ) }
380- if ratio := span (r14 ) / span (r15 ); ratio < 1.9 || ratio > 2.1 {
370+ // An arc/ring is one stroke in the rule's colour (white light → yellow LITYW),
371+ // always shown (sleg -1). Screen-fixed: the radius ~halves per zoom level.
372+ arc14 := tessellateFigure (arcPrim (26 , 0 , 360 , "LITYW" ), 14 )
373+ if len (arc14 ) != 1 || arc14 [0 ].colorToken != "LITYW" || arc14 [0 ].sleg != - 1 {
374+ t .Fatalf ("arc = %+v, want 1 LITYW stroke sleg -1" , arc14 )
375+ }
376+ arc15 := tessellateFigure (arcPrim (26 , 0 , 360 , "LITYW" ), 15 )
377+ anchor := mustLatLon (38.97 , - 76.49 )
378+ span := func (s []sectorStroke ) float64 { return absf (s [0 ].points [0 ].Lat - anchor .Lat ) }
379+ if ratio := span (arc14 ) / span (arc15 ); ratio < 1.9 || ratio > 2.1 {
381380 t .Errorf ("ring radius ratio z14/z15 = %.3f, want ~2" , ratio )
382381 }
383382}
@@ -388,8 +387,8 @@ func TestSectorLights(t *testing.T) {
388387// suppressed only where a finer prim sits on it. zMax is set > natMax to simulate
389388// the overzoomed coarse prim and drive the branch directly.
390389func TestUpSuppressionPointOverlap (t * testing.T ) {
391- coastal := BandCoastal .ZoomRange () // {10,12 }
392- harbor := BandHarbor .ZoomRange () // {14 ,16}
390+ coastal := BandCoastal .ZoomRange () // {9,11 }
391+ harbor := BandHarbor .ZoomRange () // {13 ,16}
393392 base := geo.LatLon {Lat : 38.97 , Lon : - 76.49 }
394393 mk := func (b * Baker , ll geo.LatLon , layer string , zr ZoomRange , zMax uint32 ) {
395394 r := routed {layer : layer , kind : mvt .GeomPoint , npoint : normPt (ll ),
@@ -419,8 +418,22 @@ func TestUpSuppressionPointOverlap(t *testing.T) {
419418}
420419
421420func mustLatLon (lat , lon float64 ) geo.LatLon { return geo.LatLon {Lat : lat , Lon : lon } }
422- func sp (start , end float64 , color string ) portrayal.SectorParams {
423- return portrayal.SectorParams {StartAngleDeg : start , EndAngleDeg : end , ColorToken : color }
421+
422+ // legPrim / arcPrim build a one-element sector figure (as the rule emits) at a
423+ // fixed anchor: a dashed CHBLK leg at the given bearing (fullNM>0 enables the
424+ // extended variant), or a coloured arc/ring.
425+ func legPrim (bearingDeg , fullNM float64 ) * sectorPrim {
426+ return & sectorPrim {fig : portrayal.AugmentedFigure {
427+ Anchor : mustLatLon (38.97 , - 76.49 ), Ray : true , BearingDeg : bearingDeg ,
428+ LengthMM : 25 , ColorToken : "CHBLK" , WidthMM : 0.32 , Dash : portrayal .DashDashed ,
429+ FullLengthNM : fullNM ,
430+ }}
431+ }
432+ func arcPrim (radiusMM , startDeg , sweepDeg float64 , color string ) * sectorPrim {
433+ return & sectorPrim {fig : portrayal.AugmentedFigure {
434+ Anchor : mustLatLon (38.97 , - 76.49 ), RadiusMM : radiusMM ,
435+ StartDeg : startDeg , SweepDeg : sweepDeg , ColorToken : color , WidthMM : 0.64 ,
436+ }}
424437}
425438
426439func absf (x float64 ) float64 {
0 commit comments