25
25
26
26
/**
27
27
* @author dcollins
28
- * @version $Id: SurfacePolygon.java 3430 2015-10-01 04:27:40Z dcollins $
28
+ * @version $Id: SurfacePolygon.java 3436 2015-10-28 17:43:24Z tgaskins $
29
29
*/
30
30
@ SuppressWarnings ("unchecked" )
31
31
public class SurfacePolygon extends AbstractSurfaceShape implements Exportable
@@ -297,8 +297,8 @@ protected void doDrawGeographic(DrawContext dc, SurfaceTileDrawContext sdc)
297
297
298
298
if (shapeData == null )
299
299
{
300
- double edgeIntervalsPerDegree = this .computeEdgeIntervalsPerDegree (sdc );
301
- List <List <Vertex >> contours = this .assembleContours (edgeIntervalsPerDegree );
300
+ Angle degreesPerInterval = Angle . fromDegrees ( 1.0 / this .computeEdgeIntervalsPerDegree (sdc ) );
301
+ List <List <Vertex >> contours = this .assembleContours (degreesPerInterval );
302
302
shapeData = this .tessellateContours (contours );
303
303
304
304
if (shapeData == null )
@@ -349,7 +349,8 @@ protected void applyInteriorState(DrawContext dc, SurfaceTileDrawContext sdc, Sh
349
349
{
350
350
GL2 gl = dc .getGL ().getGL2 (); // GL initialization checks for GL2 compatibility.
351
351
OGLUtil .applyBlending (gl , true );
352
- OGLUtil .applyColor (gl , attributes .getInteriorMaterial ().getDiffuse (), attributes .getInteriorOpacity (), true );
352
+ OGLUtil .applyColor (gl , attributes .getInteriorMaterial ().getDiffuse (), attributes .getInteriorOpacity (),
353
+ true );
353
354
354
355
if (this .explicitTexture .bind (dc ))
355
356
{
@@ -365,7 +366,7 @@ protected void applyInteriorState(DrawContext dc, SurfaceTileDrawContext sdc, Sh
365
366
}
366
367
}
367
368
368
- protected List <List <Vertex >> assembleContours (double edgeIntervalsPerDegree )
369
+ protected List <List <Vertex >> assembleContours (Angle maxEdgeLength )
369
370
{
370
371
List <List <Vertex >> result = new ArrayList <List <Vertex >>();
371
372
@@ -391,21 +392,21 @@ protected List<List<Vertex>> assembleContours(double edgeIntervalsPerDegree)
391
392
392
393
// Interpolate the contour vertices according to this polygon's path type and number of edge intervals.
393
394
this .closeContour (contour );
394
- List < Vertex > interpolated = this .interpolateContour (contour , edgeIntervalsPerDegree );
395
+ this .subdivideContour (contour , maxEdgeLength );
395
396
396
397
// Modify the contour vertices to compensate for the spherical nature of geographic coordinates.
397
- String pole = LatLon .locationsContainPole (interpolated );
398
+ String pole = LatLon .locationsContainPole (contour );
398
399
if (pole != null )
399
400
{
400
- result .add (this .clipWithPole (interpolated , pole ));
401
+ result .add (this .clipWithPole (contour , pole , maxEdgeLength ));
401
402
}
402
- else if (LatLon .locationsCrossDateLine (interpolated ))
403
+ else if (LatLon .locationsCrossDateLine (contour ))
403
404
{
404
- result .addAll (this .clipWithDateline (interpolated ));
405
+ result .addAll (this .clipWithDateline (contour ));
405
406
}
406
407
else
407
408
{
408
- result .add (interpolated );
409
+ result .add (contour );
409
410
}
410
411
}
411
412
@@ -420,39 +421,45 @@ protected void closeContour(List<Vertex> contour)
420
421
}
421
422
}
422
423
423
- protected List < Vertex > interpolateContour (List <Vertex > contour , double edgeIntervalsPerDegree )
424
+ protected void subdivideContour (List <Vertex > contour , Angle maxEdgeLength )
424
425
{
425
- List <Vertex > result = new ArrayList <Vertex >();
426
- Vertex prev = null ;
426
+ List <Vertex > original = new ArrayList <Vertex >(contour .size ());
427
+ original .addAll (contour );
428
+ contour .clear ();
427
429
428
- for (Vertex cur : contour )
430
+ for (int i = 0 ; i < original . size () - 1 ; i ++ )
429
431
{
430
- if (prev != null )
431
- {
432
- Angle pathLength = LatLon .pathDistance (this .pathType , prev , cur );
433
- double edgeIntervals = WWMath .clamp (edgeIntervalsPerDegree * pathLength .degrees ,
434
- this .minEdgeIntervals , this .maxEdgeIntervals );
435
- int numEdgeIntervals = (int ) Math .ceil (edgeIntervals );
432
+ Vertex begin = original .get (i );
433
+ Vertex end = original .get (i + 1 );
434
+ contour .add (begin );
435
+ this .subdivideEdge (begin , end , maxEdgeLength , contour );
436
+ }
436
437
437
- for (int j = 1 ; j <= numEdgeIntervals ; j ++)
438
- {
439
- double amount = j / (double ) (numEdgeIntervals + 1 );
440
- LatLon location = LatLon .interpolate (this .pathType , amount , prev , cur );
441
- Vertex vertex = new Vertex (location );
442
- vertex .u = prev .u * (1 - amount ) + cur .u * amount ;
443
- vertex .v = prev .v * (1 - amount ) + cur .v * amount ;
444
- result .add (vertex );
445
- }
446
- }
438
+ Vertex last = original .get (original .size () - 1 );
439
+ contour .add (last );
440
+ }
447
441
448
- result .add (cur );
449
- prev = cur ;
450
- }
442
+ protected void subdivideEdge (Vertex begin , Vertex end , Angle maxEdgeLength , List <Vertex > result )
443
+ {
444
+ Vertex center = new Vertex (LatLon .interpolate (this .pathType , 0.5 , begin , end ));
445
+ center .u = 0.5 * (begin .u + end .u );
446
+ center .v = 0.5 * (begin .v + end .v );
447
+ center .edgeFlag = begin .edgeFlag || end .edgeFlag ;
451
448
452
- return result ;
449
+ Angle edgeLength = LatLon .linearDistance (begin , end );
450
+ if (edgeLength .compareTo (maxEdgeLength ) > 0 )
451
+ {
452
+ this .subdivideEdge (begin , center , maxEdgeLength , result );
453
+ result .add (center );
454
+ this .subdivideEdge (center , end , maxEdgeLength , result );
455
+ }
456
+ else
457
+ {
458
+ result .add (center );
459
+ }
453
460
}
454
461
455
- protected List <Vertex > clipWithPole (List <Vertex > contour , String pole )
462
+ protected List <Vertex > clipWithPole (List <Vertex > contour , String pole , Angle maxEdgeLength )
456
463
{
457
464
List <Vertex > newVertices = new ArrayList <Vertex >();
458
465
@@ -481,12 +488,30 @@ protected List<Vertex> clipWithPole(List<Vertex> contour, String pole)
481
488
// | |
482
489
// 1 | v 4
483
490
// --->---- ------>
484
- Vertex one = new Vertex (lat , thisSideLon , 0 , 0 );
485
- Vertex two = new Vertex (poleLat , thisSideLon , 0 , 0 );
486
- Vertex three = new Vertex (poleLat , otherSideLon , 0 , 0 );
487
- Vertex four = new Vertex (lat , otherSideLon , 0 , 0 );
488
- one .edgeFlag = two .edgeFlag = three .edgeFlag = four .edgeFlag = false ;
489
- newVertices .addAll (Arrays .asList (one , two , three , four ));
491
+ Vertex in = new Vertex (lat , thisSideLon , 0 , 0 );
492
+ Vertex inPole = new Vertex (poleLat , thisSideLon , 0 , 0 );
493
+ Vertex centerPole = new Vertex (poleLat , Angle .ZERO , 0 , 0 );
494
+ Vertex outPole = new Vertex (poleLat , otherSideLon , 0 , 0 );
495
+ Vertex out = new Vertex (lat , otherSideLon , 0 , 0 );
496
+ in .edgeFlag = inPole .edgeFlag = centerPole .edgeFlag = outPole .edgeFlag = out .edgeFlag = false ;
497
+
498
+ double vertexDistance = LatLon .linearDistance (vertex , in ).degrees ;
499
+ double nextVertexDistance = LatLon .linearDistance (nextVertex , out ).degrees ;
500
+ double a = vertexDistance / (vertexDistance + nextVertexDistance );
501
+ in .u = out .u = WWMath .mix (a , vertex .u , nextVertex .u );
502
+ in .v = out .v = WWMath .mix (a , vertex .v , nextVertex .v );
503
+
504
+ double [] uv = this .uvWeightedAverage (contour , centerPole );
505
+ inPole .u = outPole .u = centerPole .u = uv [0 ];
506
+ inPole .v = outPole .v = centerPole .v = uv [1 ];
507
+
508
+ newVertices .add (in );
509
+ newVertices .add (inPole );
510
+ this .subdivideEdge (inPole , centerPole , maxEdgeLength , newVertices );
511
+ newVertices .add (centerPole );
512
+ this .subdivideEdge (centerPole , outPole , maxEdgeLength , newVertices );
513
+ newVertices .add (outPole );
514
+ newVertices .add (out );
490
515
}
491
516
}
492
517
vertex = nextVertex ;
@@ -496,6 +521,29 @@ protected List<Vertex> clipWithPole(List<Vertex> contour, String pole)
496
521
return newVertices ;
497
522
}
498
523
524
+ protected double [] uvWeightedAverage (List <Vertex > contour , Vertex vertex )
525
+ {
526
+ double [] weight = new double [contour .size ()];
527
+ double sumOfWeights = 0 ;
528
+ for (int i = 0 ; i < contour .size (); i ++)
529
+ {
530
+ double distance = LatLon .greatCircleDistance (contour .get (i ), vertex ).degrees ;
531
+ weight [i ] = 1 / distance ;
532
+ sumOfWeights += weight [i ];
533
+ }
534
+
535
+ double u = 0 ;
536
+ double v = 0 ;
537
+ for (int i = 0 ; i < contour .size (); i ++)
538
+ {
539
+ double factor = weight [i ] / sumOfWeights ;
540
+ u += contour .get (i ).u * factor ;
541
+ v += contour .get (i ).v * factor ;
542
+ }
543
+
544
+ return new double [] {u , v };
545
+ }
546
+
499
547
protected List <List <Vertex >> clipWithDateline (List <Vertex > contour )
500
548
{
501
549
List <Vertex > result = new ArrayList <Vertex >();
0 commit comments