Skip to content

Commit 1ff7e0a

Browse files
committed
Fixed SurfaceText rotation.
- Modified the SurfaceText class by first, removing the offset calculation in the drawText() method. We want the text to be drawn normally without any offsets added at this point. Then, we modified the applyDrawTransform() method by moving the text to the center, applying the rotation, moving the text back to the offset position. A new private method called getRotatedTextDimensions() was added. This method calculates the pixel-dimensions of the rotated text. Changed the cumputeSector() method to take the rotated-text dimensions into account when calculating the bounding-sector. - Changed the SurfaceTextUsage class by changing the code to add a lot of SurfaceText objects. We iterate over all of the different position-offsets as well as incrementing the angle by 30-degrees so that we can see the text rotation together with the bounding-box. The position of the surface-text is drawn with a red-dot for debugging purposes (we use a placemark for this).
1 parent 6a7b4a4 commit 1ff7e0a

File tree

2 files changed

+119
-29
lines changed

2 files changed

+119
-29
lines changed

src/gov/nasa/worldwind/render/SurfaceText.java

Lines changed: 81 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -420,13 +420,6 @@ protected void drawGeographic(DrawContext dc, SurfaceTileDrawContext sdc)
420420
protected void drawText(DrawContext dc)
421421
{
422422
TextRenderer tr = this.getTextRenderer(dc);
423-
424-
Point2D point = this.getOffset().computeOffset(this.textBounds.getWidth(), this.textBounds.getHeight(), null,
425-
null);
426-
427-
int x = (int) point.getX();
428-
int y = (int) point.getY();
429-
430423
try
431424
{
432425
tr.begin3DRendering();
@@ -435,9 +428,9 @@ protected void drawText(DrawContext dc)
435428
CharSequence text = this.getText();
436429

437430
tr.setColor(bgColor);
438-
tr.draw(text, x + 1, y - 1);
431+
tr.draw(text, 1, -1);
439432
tr.setColor(this.getColor());
440-
tr.draw(text, x, y);
433+
tr.draw(text, 0, 0);
441434
}
442435
finally
443436
{
@@ -487,9 +480,24 @@ protected void applyDrawTransform(DrawContext dc, SurfaceTileDrawContext sdc)
487480

488481
// Apply the scaling factor to draw the text at the correct geographic size
489482
gl.glScaled(this.scale, this.scale, 1d);
490-
491-
// Apply rotation angle
483+
484+
double widthInPixels = this.textBounds.getWidth();
485+
double heightInPixels = this.textBounds.getHeight();
486+
487+
Point2D textDimensions = getRotatedTextDimensions();
488+
double rotatedPixelHeight = textDimensions.getY();
489+
double rotatedPixelWidth = textDimensions.getX();
490+
491+
Point2D textOffset = getOffset().computeOffset(rotatedPixelWidth, rotatedPixelHeight, null, null);
492+
493+
// Move to offset position.
494+
gl.glTranslated(rotatedPixelWidth / 2.0 + textOffset.getX(), rotatedPixelHeight / 2.0 + textOffset.getY(), 0);
495+
496+
// Apply rotation angle on from center.
492497
gl.glRotated(-this.heading.degrees, 0, 0, 1);
498+
499+
// Move to center.
500+
gl.glTranslated(-widthInPixels / 2.0, -heightInPixels / 2.0, 0);
493501
}
494502

495503
/**
@@ -552,6 +560,54 @@ protected Color computeBackgroundColor(Color color)
552560
else
553561
return new Color(1, 1, 1, 0.7f);
554562
}
563+
564+
private Point2D getRotatedTextDimensions()
565+
{
566+
double widthInPixels = this.textBounds.getWidth();
567+
double heightInPixels = this.textBounds.getHeight();
568+
569+
Angle rotation = Angle.normalizedLongitude(this.heading);
570+
double ct = Math.cos(rotation.radians);
571+
double st = Math.sin(rotation.radians);
572+
573+
double hct = heightInPixels * ct;
574+
double wct = widthInPixels * ct;
575+
double hst = heightInPixels * st;
576+
double wst = widthInPixels * st;
577+
578+
if (rotation.degrees > 0)
579+
{
580+
if (rotation.degrees < 90)
581+
{
582+
// 0 < theta < 90
583+
heightInPixels = hct + wst;
584+
widthInPixels = wct + hst;
585+
}
586+
else
587+
{
588+
// 90 <= theta <= 180
589+
heightInPixels = wst - hct;
590+
widthInPixels = hst - wct;
591+
}
592+
}
593+
else
594+
{
595+
if (rotation.degrees > -90 )
596+
{
597+
// -90 < theta <= 0
598+
heightInPixels = hct - wst;
599+
widthInPixels = wct - hst;
600+
}
601+
else
602+
{
603+
// -180 <= theta <= -90
604+
heightInPixels = -(hct + wst);
605+
widthInPixels = -(wct + hst);
606+
}
607+
}
608+
609+
return new Point2D.Double(widthInPixels, heightInPixels);
610+
}
555611

556612
/**
557613
* Compute the sector covered by this surface text.
@@ -565,30 +621,32 @@ protected Sector[] computeSector(DrawContext dc)
565621
// Compute text extent depending on distance from eye
566622
Globe globe = dc.getGlobe();
567623

568-
double widthInPixels = this.textBounds.getWidth();
569-
double heightInPixels = this.textBounds.getHeight();
570-
571-
double heightInMeters = this.textSizeInMeters;
624+
Point2D textDimensions = getRotatedTextDimensions();
625+
double heightInPixels = textDimensions.getY();
626+
double widthInPixels = textDimensions.getX();
627+
628+
double heightFactor = heightInPixels / this.textBounds.getHeight();
629+
double heightInMeters = heightFactor * this.textSizeInMeters;
572630
double widthInMeters = heightInMeters * (widthInPixels / heightInPixels);
573-
631+
574632
double radius = globe.getRadius();
575633
double heightInRadians = heightInMeters / radius;
576634
double widthInRadians = widthInMeters / radius;
577635

578-
// Compute the offset from the reference position. Convert pixels to meters based on the geographic size
579-
// of the text.
580-
Point2D point = this.getOffset().computeOffset(widthInPixels, heightInPixels, null, null);
636+
// Compute the offset from the reference position.
637+
// Convert pixels to meters based on the geographic size of the text.
638+
Point2D textOffset = getOffset().computeOffset(widthInPixels, heightInPixels, null, null);
581639

582640
double metersPerPixel = heightInMeters / heightInPixels;
583641

584-
double dxRadians = (point.getX() * metersPerPixel) / radius;
585-
double dyRadians = (point.getY() * metersPerPixel) / radius;
586-
642+
double dxRadians = (textOffset.getX() * metersPerPixel) / radius;
643+
double dyRadians = (textOffset.getY() * metersPerPixel) / radius;
644+
587645
double minLat = this.location.latitude.addRadians(dyRadians).degrees;
588646
double maxLat = this.location.latitude.addRadians(dyRadians + heightInRadians).degrees;
589647
double minLon = this.location.longitude.addRadians(dxRadians).degrees;
590648
double maxLon = this.location.longitude.addRadians(dxRadians + widthInRadians).degrees;
591-
649+
592650
this.drawLocation = LatLon.fromDegrees(minLat, minLon);
593651

594652
if (maxLon > 180) {

src/gov/nasa/worldwindx/examples/SurfaceTextUsage.java

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,14 @@
77
package gov.nasa.worldwindx.examples;
88

99
import gov.nasa.worldwind.Configuration;
10+
import gov.nasa.worldwind.WorldWind;
1011
import gov.nasa.worldwind.avlist.AVKey;
1112
import gov.nasa.worldwind.geom.Angle;
1213
import gov.nasa.worldwind.geom.Position;
1314
import gov.nasa.worldwind.layers.RenderableLayer;
15+
import gov.nasa.worldwind.render.Offset;
16+
import gov.nasa.worldwind.render.PointPlacemark;
17+
import gov.nasa.worldwind.render.PointPlacemarkAttributes;
1418
import gov.nasa.worldwind.render.SurfaceText;
1519

1620
/**
@@ -21,27 +25,55 @@
2125
*/
2226
public class SurfaceTextUsage extends ApplicationTemplate
2327
{
28+
private static Position center = Position.fromDegrees(38.9345, -120.1670, 50000);
29+
2430
public static class AppFrame extends ApplicationTemplate.AppFrame
2531
{
2632
public AppFrame()
2733
{
2834
super(true, true, false);
2935

3036
RenderableLayer layer = new RenderableLayer();
37+
38+
int j = 0;
39+
for (double x = -1.0; x <= 0.0; x += 0.5, j++)
40+
{
41+
for (double y = -1.0; y <= 0.0; y += 0.5, j++)
42+
{
43+
for (int i = 0; i <= 12; i++)
44+
{
45+
double latitude = center.latitude.degrees + ((j - 4) / 5.0);
46+
double longitude = center.longitude.degrees + ((i - 6) / 5.0);
47+
Position position = Position.fromDegrees(latitude, longitude, 0);
48+
49+
SurfaceText surfaceText = new SurfaceText("Test Label Description", position);
50+
surfaceText.setDrawBoundingSectors(true);
51+
surfaceText.setHeading(Angle.fromDegrees(i * 30));
52+
surfaceText.setOffset(Offset.fromFraction(x, y));
53+
layer.addRenderable(surfaceText);
3154

32-
SurfaceText surfaceText = new SurfaceText("Desolation Wilderness", Position.fromDegrees(38.9345, -120.1670, 0));
33-
surfaceText.setHeading(Angle.fromDegrees(30));
34-
layer.addRenderable(surfaceText);
55+
PointPlacemark placemark = new PointPlacemark(position);
56+
placemark.setAltitudeMode(WorldWind.CLAMP_TO_GROUND);
57+
PointPlacemarkAttributes attrs = new PointPlacemarkAttributes();
58+
attrs.setLabelColor("ffffffff");
59+
attrs.setLineColor("ff0000ff");
60+
attrs.setUsePointAsDefaultImage(true);
61+
attrs.setScale(5d);
62+
placemark.setAttributes(attrs);
63+
layer.addRenderable(placemark);
64+
}
65+
}
66+
}
3567

3668
this.getWwd().getModel().getLayers().add(layer);
3769
}
3870
}
3971

4072
public static void main(String[] args)
4173
{
42-
Configuration.setValue(AVKey.INITIAL_LATITUDE, 38.9345);
43-
Configuration.setValue(AVKey.INITIAL_LONGITUDE, -120.1670);
44-
Configuration.setValue(AVKey.INITIAL_ALTITUDE, 50000);
74+
Configuration.setValue(AVKey.INITIAL_LATITUDE, center.latitude.degrees);
75+
Configuration.setValue(AVKey.INITIAL_LONGITUDE, center.longitude.degrees);
76+
Configuration.setValue(AVKey.INITIAL_ALTITUDE, center.elevation);
4577

4678
ApplicationTemplate.start("WorldWind Surface Text", AppFrame.class);
4779
}

0 commit comments

Comments
 (0)