77using System . Diagnostics ;
88using System . Drawing ;
99using System . Linq ;
10+ using System . Windows . Forms ;
1011
1112namespace RateController . RateMap
1213{
@@ -72,7 +73,7 @@ public void Build()
7273 var bounds = ComputeBounds ( ) ;
7374 var grid = BuildGrid ( bounds ) ;
7475
75- grid = SmoothGrid ( grid , passes : 2 ) ;
76+ grid = SmoothGrid ( grid , passes : 1 ) ;
7677
7778 var contours = GenerateContours ( grid , bounds ) ;
7879
@@ -142,6 +143,7 @@ private void ApplySimulatedElevations()
142143 Readings = simulatedReadings ;
143144 ShowReadings ( ) ;
144145 }
146+
145147 private double [ , ] BuildGrid ( ( double minLat , double maxLat , double minLon , double maxLon ) b )
146148 {
147149 gridRows = ( int ) ( MetersBetweenLat ( b . minLat , b . maxLat ) / GridResolutionMeters ) + 1 ;
@@ -212,7 +214,6 @@ private void DrawContours(List<ContourLine> contours)
212214 . Select ( ratio => contour . Points [ ( int ) ( contour . Points . Count * ratio ) ] )
213215 . ToList ( ) ;
214216
215- bool labelPlaced = false ;
216217 foreach ( var labelPos in candidates )
217218 {
218219 bool tooClose = allPlacedLabels . Any ( p =>
@@ -221,10 +222,9 @@ private void DrawContours(List<ContourLine> contours)
221222 if ( ! tooClose )
222223 {
223224 _labelOverlay . Markers . Add (
224- new TextMarker ( labelPos , $ " { group . Key : 0 } m" ) ) ;
225+ new TextMarker ( labelPos , group . Key ) ) ;
225226 allPlacedLabels . Add ( labelPos ) ;
226227 labelCountThisLevel ++ ;
227- labelPlaced = true ;
228228 break ; // Successfully placed, move to next contour
229229 }
230230 }
@@ -233,6 +233,7 @@ private void DrawContours(List<ContourLine> contours)
233233 }
234234 }
235235 }
236+
236237 private List < ContourLine > GenerateContours (
237238 double [ , ] grid ,
238239 ( double minLat , double maxLat , double minLon , double maxLon ) b )
@@ -242,7 +243,10 @@ private List<ContourLine> GenerateContours(
242243 double minElev = Readings . Min ( r => r . Elevation ) ;
243244 double maxElev = Readings . Max ( r => r . Elevation ) ;
244245
245- for ( double level = minElev ; level <= maxElev ; level += ContourInterval )
246+ double start = Math . Floor ( minElev / ContourInterval ) * ContourInterval ;
247+ double end = Math . Ceiling ( maxElev / ContourInterval ) * ContourInterval ;
248+
249+ for ( double level = start ; level <= end + 1e-9 ; level += ContourInterval )
246250 {
247251 var lines = MarchingSquares ( grid , b , level ) ;
248252
@@ -309,7 +313,8 @@ private double Haversine(double lat1, double lon1, double lat2, double lon2)
309313 private double InterpolateElevation ( double lat , double lon )
310314 {
311315 var nearest = Readings
312- . Select ( r => new {
316+ . Select ( r => new
317+ {
313318 Reading = r ,
314319 Dist = Haversine ( lat , lon , r . Latitude , r . Longitude )
315320 } )
@@ -330,7 +335,6 @@ private double InterpolateElevation(double lat, double lon)
330335 return valueSum / weightSum ;
331336 }
332337
333-
334338 private List < List < PointLatLng > > MarchingSquares (
335339 double [ , ] grid ,
336340 ( double minLat , double maxLat , double minLon , double maxLon ) b ,
@@ -391,7 +395,6 @@ private double MetersBetweenLat(double lat1, double lat2)
391395 private double MetersBetweenLon ( double lon1 , double lon2 , double lat )
392396 => Haversine ( lat , lon1 , lat , lon2 ) ;
393397
394-
395398 private double PolylineLengthMeters ( List < PointLatLng > line )
396399 {
397400 double length = 0 ;
@@ -413,7 +416,7 @@ private void ShowReadings()
413416 {
414417 if ( reading . Elevation > 280 ) count ++ ;
415418 }
416- Debug . Print ( "total: " + Readings . Count . ToString ( ) + ", above 280: " + count . ToString ( ) ) ;
419+ Debug . Print ( "total: " + Readings . Count . ToString ( ) + ", above 280: " + count . ToString ( ) ) ;
417420 }
418421
419422 private double [ , ] SmoothGrid ( double [ , ] grid , int passes = 2 )
@@ -538,30 +541,73 @@ private struct Segment
538541
539542 public class TextMarker : GMapMarker
540543 {
541- private readonly Brush _brush = Brushes . Black ;
542- private readonly Font _font = new Font ( "Segoe UI" , 12 , FontStyle . Bold ) ;
543- private readonly Pen _outline = new Pen ( Color . White , 3 ) ;
544+ private static readonly Font TextFont =
545+ new Font ( "Segoe UI" , 11 , FontStyle . Bold ) ;
546+
547+ // Fully opaque tooltip-style yellow
548+ private static readonly Brush BgBrush =
549+ new SolidBrush ( Color . FromArgb ( 255 , 255 , 255 , 200 ) ) ;
550+
551+ private static readonly Brush TextBrush =
552+ new SolidBrush ( Color . Black ) ;
553+
554+ private static readonly Pen BorderPen =
555+ new Pen ( Color . FromArgb ( 255 , 160 , 160 , 120 ) , 1 ) ;
556+
557+ // Minimal padding
558+ private const int PadX = 3 ;
559+ private const int PadY = 1 ;
560+
561+ public double ElevationMeters { get ; }
544562
545- public TextMarker ( PointLatLng pos , string text ) : base ( pos )
563+ public TextMarker ( PointLatLng position , double elevationMeters )
564+ : base ( position )
546565 {
547- Text = text ;
566+ ElevationMeters = elevationMeters ;
548567 }
549568
550- public string Text { get ; set ; }
569+ private string GetDisplayText ( )
570+ {
571+ if ( Props . UseMetric )
572+ {
573+ return $ "{ ElevationMeters : F1} m";
574+ }
575+ else
576+ {
577+ double feet = ElevationMeters * 3.28084 ;
578+ return $ "{ Math . Round ( feet ) : 0} ft";
579+ }
580+ }
551581
552582 public override void OnRender ( Graphics g )
553583 {
554- if ( string . IsNullOrEmpty ( Text ) )
584+ string text = GetDisplayText ( ) ;
585+ if ( string . IsNullOrEmpty ( text ) )
555586 return ;
556587
557- SizeF size = g . MeasureString ( Text , _font ) ;
588+ // Prevent yellow washout in GMap.NET
589+ var oldMode = g . CompositingMode ;
590+ g . CompositingMode = System . Drawing . Drawing2D . CompositingMode . SourceCopy ;
591+
592+ SizeF textSize = g . MeasureString ( text , TextFont ) ;
593+
594+ float w = textSize . Width + PadX * 2 ;
595+ float h = textSize . Height + PadY * 2 ;
596+
597+ float x = LocalPosition . X - w / 2 ;
598+ float y = LocalPosition . Y - h / 2 ;
599+
600+ RectangleF rect = new RectangleF ( x , y , w , h ) ;
601+
602+ // Background
603+ g . FillRectangle ( BgBrush , rect ) ;
558604
559- // Center text
560- float x = LocalPosition . X - size . Width / 2 ;
561- float y = LocalPosition . Y - size . Height / 2 ;
605+ // Restore normal blending
606+ g . CompositingMode = oldMode ;
562607
563- // Outline for readability
564- g . DrawString ( Text , _font , _brush , x , y ) ;
608+ // Border + text
609+ g . DrawRectangle ( BorderPen , rect . X , rect . Y , rect . Width , rect . Height ) ;
610+ g . DrawString ( text , TextFont , TextBrush , rect . X + PadX , rect . Y + PadY ) ;
565611 }
566612 }
567613}
0 commit comments