Skip to content

Commit 7e7cd7e

Browse files
authored
Merge pull request #4725 from AnalyticalGraphicsInc/rectangle-texture
Fix RectangleGeometry texture rotation
2 parents 571dca3 + 42f8932 commit 7e7cd7e

File tree

6 files changed

+176
-85
lines changed

6 files changed

+176
-85
lines changed

Apps/Sandcastle/gallery/Rectangle.html

+17-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
var greenRectangle = viewer.entities.add({
4343
name : 'Green translucent, rotated, and extruded rectangle at height with outline',
4444
rectangle : {
45-
coordinates : Cesium.Rectangle.fromDegrees(-100.0, 30.0, -90.0, 40.0),
45+
coordinates : Cesium.Rectangle.fromDegrees(-110.0, 30.0, -100.0, 40.0),
4646
material : Cesium.Color.GREEN.withAlpha(0.5),
4747
rotation : Cesium.Math.toRadians(45),
4848
extrudedHeight : 300000.0,
@@ -52,6 +52,22 @@
5252
}
5353
});
5454

55+
var rotation = Cesium.Math.toRadians(30);
56+
57+
function getRotationValue() {
58+
rotation += 0.005;
59+
return rotation;
60+
}
61+
viewer.entities.add({
62+
name: 'Rotating rectangle with rotating texture coordinate',
63+
rectangle: {
64+
coordinates: Cesium.Rectangle.fromDegrees(-92.0, 30.0, -76.0, 40.0),
65+
material: '../images/Cesium_Logo_Color.jpg',
66+
rotation: new Cesium.CallbackProperty(getRotationValue, false),
67+
stRotation: new Cesium.CallbackProperty(getRotationValue, false)
68+
}
69+
});
70+
5571
viewer.zoomTo(viewer.entities);
5672
//Sandcastle_End
5773
Sandcastle.finishedLoading();

Apps/Sandcastle/gallery/Rectangle.jpg

2.8 KB
Loading

CHANGES.md

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Change Log
55

66
* Added the ability to blend a `Model` with a color/translucency. Added `color`, `colorBlendMode`, and `colorBlendAmount` properties to `Model`, `ModelGraphics`, and CZML. Added `ColorBlendMode` enum. [#4547](https://github.com/AnalyticalGraphicsInc/cesium/pull/4547)
77
* Fixed tooltips for gallery thumbnails in Sandcastle [#4702](https://github.com/AnalyticalGraphicsInc/cesium/pull/4702)
8+
* Fixed texture rotation for `RectangleGeometry` [#2737](https://github.com/AnalyticalGraphicsInc/cesium/issues/2737)
89

910
### 1.28 - 2016-12-01
1011

Source/Core/RectangleGeometry.js

+9-12
Original file line numberDiff line numberDiff line change
@@ -752,9 +752,9 @@ define([
752752
return result;
753753
};
754754

755-
var textureMatrixScratch = new Matrix2();
756755
var tangentRotationMatrixScratch = new Matrix3();
757756
var nwScratch = new Cartographic();
757+
var stNwScratch = new Cartographic();
758758
var quaternionScratch = new Quaternion();
759759
var centerScratch = new Cartographic();
760760
/**
@@ -776,30 +776,27 @@ define([
776776
var surfaceHeight = rectangleGeometry._surfaceHeight;
777777
var extrude = rectangleGeometry._extrude;
778778
var extrudedHeight = rectangleGeometry._extrudedHeight;
779+
var rotation = rectangleGeometry._rotation;
779780
var stRotation = rectangleGeometry._stRotation;
780781
var vertexFormat = rectangleGeometry._vertexFormat;
781782

782-
var options = RectangleGeometryLibrary.computeOptions(rectangleGeometry, rectangle, nwScratch);
783+
var options = RectangleGeometryLibrary.computeOptions(rectangleGeometry, rectangle, nwScratch, stNwScratch);
783784

784-
var textureMatrix = textureMatrixScratch;
785785
var tangentRotationMatrix = tangentRotationMatrixScratch;
786-
if (defined(stRotation)) {
787-
// negate angle for a counter-clockwise rotation
788-
Matrix2.fromRotation(-stRotation, textureMatrix);
786+
if (stRotation !== 0 || rotation !== 0) {
789787
var center = Rectangle.center(rectangle, centerScratch);
790-
var axis = ellipsoid.cartographicToCartesian(center, v1Scratch);
791-
Cartesian3.normalize(axis, axis);
788+
var axis = ellipsoid.geodeticSurfaceNormalCartographic(center, v1Scratch);
792789
Quaternion.fromAxisAngle(axis, -stRotation, quaternionScratch);
793790
Matrix3.fromQuaternion(quaternionScratch, tangentRotationMatrix);
794791
} else {
795-
Matrix2.clone(Matrix2.IDENTITY, textureMatrix);
796792
Matrix3.clone(Matrix3.IDENTITY, tangentRotationMatrix);
797793
}
798794

799-
options.lonScalar = 1.0 / rectangle.width;
800-
options.latScalar = 1.0 / rectangle.height;
795+
options.lonScalar = 1.0 / rectangleGeometry._rectangle.width;
796+
options.latScalar = 1.0 / rectangleGeometry._rectangle.height;
801797
options.vertexFormat = vertexFormat;
802-
options.textureMatrix = textureMatrix;
798+
options.rotation = rotation;
799+
options.stRotation = stRotation;
803800
options.tangentRotationMatrix = tangentRotationMatrix;
804801
options.size = options.width * options.height;
805802

Source/Core/RectangleGeometryLibrary.js

+127-72
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
/*global define*/
22
define([
3-
'./Cartesian3',
4-
'./Cartographic',
5-
'./defined',
6-
'./DeveloperError',
7-
'./GeographicProjection',
8-
'./Math',
9-
'./Matrix2',
10-
'./Rectangle'
11-
], function(
12-
Cartesian3,
13-
Cartographic,
14-
defined,
15-
DeveloperError,
16-
GeographicProjection,
17-
CesiumMath,
18-
Matrix2,
19-
Rectangle) {
3+
'./Cartesian3',
4+
'./Cartographic',
5+
'./defined',
6+
'./DeveloperError',
7+
'./GeographicProjection',
8+
'./Math',
9+
'./Matrix2',
10+
'./Rectangle'
11+
], function(
12+
Cartesian3,
13+
Cartographic,
14+
defined,
15+
DeveloperError,
16+
GeographicProjection,
17+
CesiumMath,
18+
Matrix2,
19+
Rectangle) {
2020
'use strict';
2121

2222
var cos = Math.cos;
@@ -55,10 +55,17 @@ define([
5555
position.z = kZ / gamma;
5656

5757
if (defined(options.vertexFormat) && options.vertexFormat.st) {
58-
st.x = (stLongitude - rectangle.west) * options.lonScalar;
59-
st.y = (stLatitude - rectangle.south) * options.latScalar;
60-
61-
Matrix2.multiplyByVector(options.textureMatrix, st, st);
58+
var stNwCorner = options.stNwCorner;
59+
if (defined(stNwCorner)) {
60+
stLatitude = stNwCorner.latitude - options.stGranYCos * row + col * options.stGranXSin;
61+
stLongitude = stNwCorner.longitude + row * options.stGranYSin + col * options.stGranXCos;
62+
63+
st.x = (stLongitude - options.stWest) * options.lonScalar;
64+
st.y = (stLatitude - options.stSouth) * options.latScalar;
65+
} else {
66+
st.x = (stLongitude - rectangle.west) * options.lonScalar;
67+
st.y = (stLatitude - rectangle.south) * options.latScalar;
68+
}
6269
}
6370
};
6471

@@ -67,14 +74,65 @@ define([
6774
var centerScratch = new Cartographic();
6875
var centerCartesian = new Cartesian3();
6976
var proj = new GeographicProjection();
77+
78+
function getRotationOptions(nwCorner, rotation, granularityX, granularityY, center, width, height) {
79+
var cosRotation = Math.cos(rotation);
80+
var granYCos = granularityY * cosRotation;
81+
var granXCos = granularityX * cosRotation;
82+
83+
var sinRotation = Math.sin(rotation);
84+
var granYSin = granularityY * sinRotation;
85+
var granXSin = granularityX * sinRotation;
86+
87+
nwCartesian = proj.project(nwCorner, nwCartesian);
88+
89+
nwCartesian = Cartesian3.subtract(nwCartesian, centerCartesian, nwCartesian);
90+
var rotationMatrix = Matrix2.fromRotation(rotation, rotationMatrixScratch);
91+
nwCartesian = Matrix2.multiplyByVector(rotationMatrix, nwCartesian, nwCartesian);
92+
nwCartesian = Cartesian3.add(nwCartesian, centerCartesian, nwCartesian);
93+
nwCorner = proj.unproject(nwCartesian, nwCorner);
94+
95+
width -= 1;
96+
height -= 1;
97+
98+
var latitude = nwCorner.latitude;
99+
var latitude0 = latitude + width * granXSin;
100+
var latitude1 = latitude - granYCos * height;
101+
var latitude2 = latitude - granYCos * height + width * granXSin;
102+
103+
var north = Math.max(latitude, latitude0, latitude1, latitude2);
104+
var south = Math.min(latitude, latitude0, latitude1, latitude2);
105+
106+
var longitude = nwCorner.longitude;
107+
var longitude0 = longitude + width * granXCos;
108+
var longitude1 = longitude + height * granYSin;
109+
var longitude2 = longitude + height * granYSin + width * granXCos;
110+
111+
var east = Math.max(longitude, longitude0, longitude1, longitude2);
112+
var west = Math.min(longitude, longitude0, longitude1, longitude2);
113+
114+
return {
115+
north: north,
116+
south: south,
117+
east: east,
118+
west: west,
119+
granYCos : granYCos,
120+
granYSin : granYSin,
121+
granXCos : granXCos,
122+
granXSin : granXSin,
123+
nwCorner : nwCorner
124+
};
125+
}
126+
70127
/**
71128
* @private
72129
*/
73-
RectangleGeometryLibrary.computeOptions = function(geometry, rectangle, nwCorner) {
130+
RectangleGeometryLibrary.computeOptions = function(geometry, rectangle, nwCorner, stNwCorner) {
74131
var granularity = geometry._granularity;
75132
var ellipsoid = geometry._ellipsoid;
76133
var surfaceHeight = geometry._surfaceHeight;
77134
var rotation = geometry._rotation;
135+
var stRotation = geometry._stRotation;
78136
var extrudedHeight = geometry._extrudedHeight;
79137
var east = rectangle.east;
80138
var west = rectangle.west;
@@ -103,76 +161,73 @@ define([
103161

104162
nwCorner = Rectangle.northwest(rectangle, nwCorner);
105163
var center = Rectangle.center(rectangle, centerScratch);
106-
107-
var granYCos = granularityY;
108-
var granXCos = granularityX;
109-
var granYSin = 0.0;
110-
var granXSin = 0.0;
111-
112-
if (defined(rotation) && rotation !== 0) {
113-
var cosRotation = Math.cos(rotation);
114-
granYCos *= cosRotation;
115-
granXCos *= cosRotation;
116-
117-
var sinRotation = Math.sin(rotation);
118-
granYSin = granularityY * sinRotation;
119-
granXSin = granularityX * sinRotation;
120-
164+
if (rotation !== 0 || stRotation !== 0) {
121165
if (center.longitude < nwCorner.longitude) {
122166
center.longitude += CesiumMath.TWO_PI;
123167
}
124-
125-
nwCartesian = proj.project(nwCorner, nwCartesian);
126168
centerCartesian = proj.project(center, centerCartesian);
169+
}
127170

128-
nwCartesian = Cartesian3.subtract(nwCartesian, centerCartesian, nwCartesian);
129-
var rotationMatrix = Matrix2.fromRotation(rotation, rotationMatrixScratch);
130-
nwCartesian = Matrix2.multiplyByVector(rotationMatrix, nwCartesian, nwCartesian);
131-
nwCartesian = Cartesian3.add(nwCartesian, centerCartesian, nwCartesian);
132-
nwCorner = proj.unproject(nwCartesian, nwCorner);
133-
134-
var latitude = nwCorner.latitude;
135-
var latitude0 = latitude + (width - 1) * granXSin;
136-
var latitude1 = latitude - granYCos * (height - 1);
137-
var latitude2 = latitude - granYCos * (height - 1) + (width - 1) * granXSin;
138-
139-
north = Math.max(latitude, latitude0, latitude1, latitude2);
140-
south = Math.min(latitude, latitude0, latitude1, latitude2);
171+
var granYCos = granularityY;
172+
var granXCos = granularityX;
173+
var granYSin = 0.0;
174+
var granXSin = 0.0;
141175

142-
var longitude = nwCorner.longitude;
143-
var longitude0 = longitude + (width - 1) * granXCos;
144-
var longitude1 = longitude + (height - 1) * granYSin;
145-
var longitude2 = longitude + (height - 1) * granYSin + (width - 1) * granXCos;
176+
var options = {
177+
granYCos : granYCos,
178+
granYSin : granYSin,
179+
granXCos : granXCos,
180+
granXSin : granXSin,
181+
ellipsoid : ellipsoid,
182+
surfaceHeight : surfaceHeight,
183+
extrudedHeight : extrudedHeight,
184+
nwCorner : nwCorner,
185+
rectangle : rectangle,
186+
width: width,
187+
height: height
188+
};
146189

147-
east = Math.max(longitude, longitude0, longitude1, longitude2);
148-
west = Math.min(longitude, longitude0, longitude1, longitude2);
190+
if (rotation !== 0) {
191+
var rotationOptions = getRotationOptions(nwCorner, rotation, granularityX, granularityY, center, width, height);
192+
north = rotationOptions.north;
193+
south = rotationOptions.south;
194+
east = rotationOptions.east;
195+
west = rotationOptions.west;
149196

150197
//>>includeStart('debug', pragmas.debug);
151198
if (north < -CesiumMath.PI_OVER_TWO || north > CesiumMath.PI_OVER_TWO ||
152-
south < -CesiumMath.PI_OVER_TWO || south > CesiumMath.PI_OVER_TWO) {
199+
south < -CesiumMath.PI_OVER_TWO || south > CesiumMath.PI_OVER_TWO) {
153200
throw new DeveloperError('Rotated rectangle is invalid. It crosses over either the north or south pole.');
154201
}
155202
//>>includeEnd('debug')
156203

204+
options.granYCos = rotationOptions.granYCos;
205+
options.granYSin = rotationOptions.granYSin;
206+
options.granXCos = rotationOptions.granXCos;
207+
options.granXSin = rotationOptions.granXSin;
208+
157209
rectangle.north = north;
158210
rectangle.south = south;
159211
rectangle.east = east;
160212
rectangle.west = west;
161213
}
162214

163-
return {
164-
granYCos : granYCos,
165-
granYSin : granYSin,
166-
granXCos : granXCos,
167-
granXSin : granXSin,
168-
ellipsoid : ellipsoid,
169-
width : width,
170-
height : height,
171-
surfaceHeight : surfaceHeight,
172-
extrudedHeight : extrudedHeight,
173-
nwCorner: nwCorner,
174-
rectangle: rectangle
175-
};
215+
if (stRotation !== 0) {
216+
rotation = rotation - stRotation;
217+
stNwCorner = Rectangle.northwest(rectangle, stNwCorner);
218+
219+
var stRotationOptions = getRotationOptions(stNwCorner, rotation, granularityX, granularityY, center, width, height);
220+
221+
options.stGranYCos = stRotationOptions.granYCos;
222+
options.stGranXCos = stRotationOptions.granXCos;
223+
options.stGranYSin = stRotationOptions.granYSin;
224+
options.stGranXSin = stRotationOptions.granXSin;
225+
options.stNwCorner = stNwCorner;
226+
options.stWest = stRotationOptions.west;
227+
options.stSouth = stRotationOptions.south;
228+
}
229+
230+
return options;
176231
};
177232

178233
return RectangleGeometryLibrary;

Specs/Core/RectangleGeometrySpec.js

+22
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,28 @@ defineSuite([
145145
expect(st[length - 1]).toEqualEpsilon(0.0, CesiumMath.EPSILON14);
146146
});
147147

148+
it('compute texture coordinate rotation with rectangle rotation', function() {
149+
var rectangle = new Rectangle(-1, -1, 1, 1);
150+
var angle = CesiumMath.toRadians(30);
151+
var m = RectangleGeometry.createGeometry(new RectangleGeometry({
152+
vertexFormat : VertexFormat.POSITION_AND_ST,
153+
rectangle : rectangle,
154+
rotation: angle,
155+
stRotation : angle,
156+
granularity : 1.0
157+
}));
158+
var st = m.attributes.st.values;
159+
160+
expect(st[0]).toEqual(0.0); //top left corner
161+
expect(st[1]).toEqual(1.0);
162+
expect(st[4]).toEqual(1.0); //top right corner
163+
expect(st[5]).toEqual(1.0);
164+
expect(st[12]).toEqual(0.0); //bottom left corner
165+
expect(st[13]).toEqual(0.0);
166+
expect(st[16]).toEqual(1.0); //bottom right corner
167+
expect(st[17]).toEqual(0.0);
168+
});
169+
148170
it('throws without rectangle', function() {
149171
expect(function() {
150172
return new RectangleGeometry({});

0 commit comments

Comments
 (0)