-
Notifications
You must be signed in to change notification settings - Fork 3.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added Ellipsoid surface area #8986
Changes from 2 commits
a1fd2ef
7c7a1d1
8dfcf3a
5255bb6
7ba009b
4e730ef
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -8,10 +8,12 @@ | |||||
|
||||||
##### Additions :tada: | ||||||
|
||||||
- Added `Ellipsoid.surfaceArea` for computing the surface area under given rectangle. | ||||||
- Added support for PolylineVolume in CZML [#8841](https://github.com/CesiumGS/cesium/pull/8841) | ||||||
|
||||||
##### Fixes :wrench: | ||||||
|
||||||
- Fixed `Ellipsoid.geodeticSurfaceNormal` dividing by zero when given origin as input. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
- Fixed error with `WallGeoemtry` when there were adjacent positions with very close values [#8952](https://github.com/CesiumGS/cesium/pull/8952) | ||||||
- Fixed artifact for skinned model when log depth is enabled. [#6447](https://github.com/CesiumGS/cesium/issues/6447) | ||||||
- Fixed a bug where certain rhumb arc polylines would lead to a crash. [#8787](https://github.com/CesiumGS/cesium/pull/8787) | ||||||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -362,6 +362,11 @@ Ellipsoid.prototype.geodeticSurfaceNormalCartographic = function ( | |||||
* @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if none was provided. | ||||||
*/ | ||||||
Ellipsoid.prototype.geodeticSurfaceNormal = function (cartesian, result) { | ||||||
if ( | ||||||
Cartesian3.equalsEpsilon(cartesian, Cartesian3.ZERO, CesiumMath.EPSILON14) | ||||||
) { | ||||||
return undefined; | ||||||
} | ||||||
if (!defined(result)) { | ||||||
result = new Cartesian3(); | ||||||
} | ||||||
|
@@ -688,4 +693,112 @@ Ellipsoid.prototype.getSurfaceNormalIntersectionWithZAxis = function ( | |||||
|
||||||
return result; | ||||||
}; | ||||||
|
||||||
var abscissas = [ | ||||||
0.14887433898163, | ||||||
0.43339539412925, | ||||||
0.67940956829902, | ||||||
0.86506336668898, | ||||||
0.97390652851717, | ||||||
0.0, | ||||||
]; | ||||||
var weights = [ | ||||||
0.29552422471475, | ||||||
0.26926671930999, | ||||||
0.21908636251598, | ||||||
0.14945134915058, | ||||||
0.066671344308684, | ||||||
0.0, | ||||||
]; | ||||||
|
||||||
/** | ||||||
* Compute the 10th order Gauss-Legendre Quadrature of the given definite integral. | ||||||
* | ||||||
* @param {Number} a The lower bound for the integration. | ||||||
* @param {Number} b The upper bound for the integration. | ||||||
* @param {Ellipsoid~RealValuedScalarFunction} func The function to integrate. | ||||||
* @returns {Number} The value of the integral of the given function over the given domain. | ||||||
* | ||||||
* @private | ||||||
*/ | ||||||
function gaussLegendreQuadrature(a, b, func) { | ||||||
//>>includeStart('debug', pragmas.debug); | ||||||
Check.typeOf.number("a", a); | ||||||
Check.typeOf.number("b", b); | ||||||
Check.typeOf.func("func", func); | ||||||
//>>includeEnd('debug'); | ||||||
|
||||||
// The range is half of the normal range since the five weights add to one (ten weights add to two). | ||||||
// The values of the abscissas are multiplied by two to account for this. | ||||||
var xMean = 0.5 * (b + a); | ||||||
var xRange = 0.5 * (b - a); | ||||||
|
||||||
var sum = 0.0; | ||||||
for (var i = 0; i < 5; i++) { | ||||||
var dx = xRange * abscissas[i]; | ||||||
sum += weights[i] * (func(xMean + dx) + func(xMean - dx)); | ||||||
} | ||||||
|
||||||
// Scale the sum to the range of x. | ||||||
sum *= xRange; | ||||||
return sum; | ||||||
} | ||||||
|
||||||
/** | ||||||
* A real valued scalar function. | ||||||
* @callback Ellipsoid~RealValuedScalarFunction | ||||||
* | ||||||
* @param {Number} x The value used to evaluate the function. | ||||||
* @returns {Number} The value of the function at x. | ||||||
* | ||||||
* @private | ||||||
*/ | ||||||
|
||||||
/** | ||||||
* Computes an approximation of the surface area of a given section of the surface of an ellipsoid using | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
* Gauss-Legendre 10th order quadrature. | ||||||
* | ||||||
* @param {Rectangle} rectangle The rectangle to find the surface area of. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
* @returns {Number} The approximate area of the section on the surface of this ellipsoid. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
*/ | ||||||
Ellipsoid.prototype.surfaceArea = function (rectangle) { | ||||||
//>>includeStart('debug', pragmas.debug); | ||||||
Check.typeOf.object("rectangle", rectangle); | ||||||
//>>includeEnd('debug'); | ||||||
var minLongitude = rectangle.west; | ||||||
var maxLongitude = rectangle.east; | ||||||
var minLatitude = rectangle.south; | ||||||
var maxLatitude = rectangle.north; | ||||||
|
||||||
while (maxLongitude < minLongitude) { | ||||||
maxLongitude += CesiumMath.TWO_PI; | ||||||
} | ||||||
|
||||||
var radiiSquared = this._radiiSquared; | ||||||
var a2 = radiiSquared.x; | ||||||
var b2 = radiiSquared.y; | ||||||
var c2 = radiiSquared.z; | ||||||
var a2b2 = a2 * b2; | ||||||
return gaussLegendreQuadrature(minLatitude, maxLatitude, function (lat) { | ||||||
// phi represents the angle measured from the north pole | ||||||
// sin(phi) = sin(pi / 2 - lat) = cos(lat), cos(phi) is similar | ||||||
var sinPhi = Math.cos(lat); | ||||||
var cosPhi = Math.sin(lat); | ||||||
return ( | ||||||
Math.cos(lat) * | ||||||
gaussLegendreQuadrature(minLongitude, maxLongitude, function (lon) { | ||||||
var cosTheta = Math.cos(lon); | ||||||
var sinTheta = Math.sin(lon); | ||||||
return Math.sqrt( | ||||||
a2b2 * cosPhi * cosPhi + | ||||||
c2 * | ||||||
(b2 * cosTheta * cosTheta + a2 * sinTheta * sinTheta) * | ||||||
sinPhi * | ||||||
sinPhi | ||||||
); | ||||||
}) | ||||||
); | ||||||
}); | ||||||
}; | ||||||
|
||||||
export default Ellipsoid; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ import { Cartographic } from "../../Source/Cesium.js"; | |
import { Ellipsoid } from "../../Source/Cesium.js"; | ||
import { Math as CesiumMath } from "../../Source/Cesium.js"; | ||
import createPackableSpecs from "../createPackableSpecs.js"; | ||
import { Rectangle } from "../../Source/Cesium.js"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just to keep things tidy, move this |
||
|
||
describe("Core/Ellipsoid", function () { | ||
var radii = new Cartesian3(1.0, 2.0, 3.0); | ||
|
@@ -137,6 +138,12 @@ describe("Core/Ellipsoid", function () { | |
); | ||
}); | ||
|
||
it("geodeticSurfaceNormal returns undefined when given the origin", function () { | ||
var ellipsoid = Ellipsoid.WGS84; | ||
var returnedResult = ellipsoid.geodeticSurfaceNormal(Cartesian3.ZERO); | ||
expect(returnedResult).toBeUndefined(); | ||
}); | ||
|
||
it("geodeticSurfaceNormal works with a result parameter", function () { | ||
var ellipsoid = Ellipsoid.WGS84; | ||
var result = new Cartesian3(); | ||
|
@@ -708,6 +715,53 @@ describe("Core/Ellipsoid", function () { | |
expect(ellipsoid._squaredXOverSquaredZ).toEqual(squaredXOverSquaredZ); | ||
}); | ||
|
||
it("surfaceArea throws without rectangle", function () { | ||
expect(function () { | ||
return Ellipsoid.WGS84.surfaceArea(undefined); | ||
}).toThrowDeveloperError(); | ||
}); | ||
|
||
it("computes surfaceArea", function () { | ||
// area of an oblate spheroid | ||
var ellipsoid = new Ellipsoid(4, 4, 3); | ||
var a2 = ellipsoid.radiiSquared.x; | ||
var c2 = ellipsoid.radiiSquared.z; | ||
var e = Math.sqrt(1.0 - c2 / a2); | ||
var area = | ||
CesiumMath.TWO_PI * a2 + | ||
CesiumMath.PI * (c2 / e) * Math.log((1.0 + e) / (1.0 - e)); | ||
expect( | ||
ellipsoid.surfaceArea( | ||
new Rectangle( | ||
-CesiumMath.PI, | ||
-CesiumMath.PI_OVER_TWO, | ||
CesiumMath.PI, | ||
CesiumMath.PI_OVER_TWO | ||
) | ||
) | ||
).toEqualEpsilon(area, CesiumMath.EPSILON3); | ||
|
||
// area of a prolate spheroid | ||
ellipsoid = new Ellipsoid(3, 3, 4); | ||
a2 = ellipsoid.radiiSquared.x; | ||
c2 = ellipsoid.radiiSquared.z; | ||
e = Math.sqrt(1.0 - a2 / c2); | ||
var a = ellipsoid.radii.x; | ||
var c = ellipsoid.radii.z; | ||
area = | ||
CesiumMath.TWO_PI * a2 + CesiumMath.TWO_PI * ((a * c) / e) * Math.asin(e); | ||
expect( | ||
ellipsoid.surfaceArea( | ||
new Rectangle( | ||
-CesiumMath.PI, | ||
-CesiumMath.PI_OVER_TWO, | ||
CesiumMath.PI, | ||
CesiumMath.PI_OVER_TWO | ||
) | ||
) | ||
).toEqualEpsilon(area, CesiumMath.EPSILON3); | ||
}); | ||
|
||
createPackableSpecs(Ellipsoid, Ellipsoid.WGS84, [ | ||
Ellipsoid.WGS84.radii.x, | ||
Ellipsoid.WGS84.radii.y, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.