Skip to content

Commit

Permalink
Merge pull request #9676 from CesiumGS/polyline-color-bug
Browse files Browse the repository at this point in the history
Fix polyline color issue involving duplicate positions
  • Loading branch information
lilleyse authored Jul 19, 2021
2 parents fe8fec2 + 332aff5 commit 9081c2c
Show file tree
Hide file tree
Showing 5 changed files with 648 additions and 41 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
- Fixed the ability to set a material's image to `undefined` and `Material.DefaultImageId`. [#9644](https://github.com/CesiumGS/cesium/pull/9644)
- Fixed the calculation of `OrientedBoundingBox.distancedSquaredTo` such that they handle `halfAxes` with magnitudes near zero. [#9670](https://github.com/CesiumGS/cesium/pull/9670)
- Fixed render crash when creating a `polylineVolume` with very close points. [#9669](https://github.com/CesiumGS/cesium/pull/9669)
- Fixed a bug in `PolylineGeometry` that incorrectly shifted colors when duplicate positions were removed. [#9676](https://github.com/CesiumGS/cesium/pull/9676)

### 1.83 - 2021-07-01

Expand Down
27 changes: 26 additions & 1 deletion Source/Core/PolylineGeometry.js
Original file line number Diff line number Diff line change
Expand Up @@ -309,10 +309,35 @@ PolylineGeometry.createGeometry = function (polylineGeometry) {
var j;
var k;

var removedIndices = [];
var positions = arrayRemoveDuplicates(
polylineGeometry._positions,
Cartesian3.equalsEpsilon
Cartesian3.equalsEpsilon,
false,
removedIndices
);

if (defined(colors) && removedIndices.length > 0) {
var removedArrayIndex = 0;
var nextRemovedIndex = removedIndices[0];
colors = colors.filter(function (color, index) {
var remove = false;
if (colorsPerVertex) {
remove =
index === nextRemovedIndex || (index === 0 && nextRemovedIndex === 1);
} else {
remove = index + 1 === nextRemovedIndex;
}

if (remove) {
removedArrayIndex++;
nextRemovedIndex = removedIndices[removedArrayIndex];
return false;
}
return true;
});
}

var positionsLength = positions.length;

// A width of a pixel or less is not a valid geometry, but in order to support external data
Expand Down
98 changes: 62 additions & 36 deletions Source/Core/arrayRemoveDuplicates.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ var removeDuplicatesEpsilon = CesiumMath.EPSILON10;
*
* @param {Array.<*>} [values] The array of values.
* @param {Function} equalsEpsilon Function to compare values with an epsilon. Boolean equalsEpsilon(left, right, epsilon).
* @param {Boolean} [wrapAround=false] Compare the last value in the array against the first value.
* @param {Boolean} [wrapAround=false] Compare the last value in the array against the first value. If they are equal, the last value is removed.
* @param {Array.<Number>} [removedIndices=undefined] Store the indices that correspond to the duplicate items removed from the array, if there were any.
* @returns {Array.<*>|undefined} A new array of values with no adjacent duplicate values or the input array if no duplicates were found.
*
* @example
Expand All @@ -33,9 +34,25 @@ var removeDuplicatesEpsilon = CesiumMath.EPSILON10;
* new Cesium.Cartesian3(1.0, 1.0, 1.0)];
* var nonDuplicatevalues = Cesium.PolylinePipeline.removeDuplicates(values, Cartesian3.equalsEpsilon, true);
*
* @example
* // Returns [(1.0, 1.0, 1.0), (2.0, 2.0, 2.0), (3.0, 3.0, 3.0)]
* // removedIndices will be equal to [1, 3, 5]
* var values = [
* new Cesium.Cartesian3(1.0, 1.0, 1.0),
* new Cesium.Cartesian3(1.0, 1.0, 1.0),
* new Cesium.Cartesian3(2.0, 2.0, 2.0),
* new Cesium.Cartesian3(2.0, 2.0, 2.0),
* new Cesium.Cartesian3(3.0, 3.0, 3.0),
* new Cesium.Cartesian3(1.0, 1.0, 1.0)];
* var nonDuplicatevalues = Cesium.PolylinePipeline.removeDuplicates(values, Cartesian3.equalsEpsilon, true);
* @private
*/
function arrayRemoveDuplicates(values, equalsEpsilon, wrapAround) {
function arrayRemoveDuplicates(
values,
equalsEpsilon,
wrapAround,
removedIndices
) {
//>>includeStart('debug', pragmas.debug);
Check.defined("equalsEpsilon", equalsEpsilon);
//>>includeEnd('debug');
Expand All @@ -45,60 +62,69 @@ function arrayRemoveDuplicates(values, equalsEpsilon, wrapAround) {
}

wrapAround = defaultValue(wrapAround, false);
var storeRemovedIndices = defined(removedIndices);

var length = values.length;
if (length < 2) {
return values;
}

var i;
var v0;
var v0 = values[0];
var v1;

for (i = 1; i < length; ++i) {
v0 = values[i - 1];
v1 = values[i];
if (equalsEpsilon(v0, v1, removeDuplicatesEpsilon)) {
break;
}
}
// We only want to create a new array if there are duplicates in the array.
// As such, cleanedValues is undefined until it encounters the first duplicate, if it exists.
var cleanedValues;
var lastCleanIndex = 0;

if (i === length) {
if (
wrapAround &&
equalsEpsilon(
values[0],
values[values.length - 1],
removeDuplicatesEpsilon
)
) {
return values.slice(1);
}
return values;
}
// removedIndexLCI keeps track of where lastCleanIndex would be if it were sorted into the removedIndices array.
// In case of arrays such as [A, B, C, ..., A, A, A], removedIndices will not be sorted properly without this.
var removedIndexLCI = -1;

var cleanedvalues = values.slice(0, i);
for (; i < length; ++i) {
// v0 is set by either the previous loop, or the previous clean point.
for (i = 1; i < length; ++i) {
v1 = values[i];
if (!equalsEpsilon(v0, v1, removeDuplicatesEpsilon)) {
cleanedvalues.push(v1);
if (equalsEpsilon(v0, v1, removeDuplicatesEpsilon)) {
if (!defined(cleanedValues)) {
cleanedValues = values.slice(0, i);
lastCleanIndex = i - 1;
removedIndexLCI = 0;
}
if (storeRemovedIndices) {
removedIndices.push(i);
}
} else {
if (defined(cleanedValues)) {
cleanedValues.push(v1);
lastCleanIndex = i;
if (storeRemovedIndices) {
removedIndexLCI = removedIndices.length;
}
}
v0 = v1;
}
}

if (
wrapAround &&
cleanedvalues.length > 1 &&
equalsEpsilon(
cleanedvalues[0],
cleanedvalues[cleanedvalues.length - 1],
removeDuplicatesEpsilon
)
equalsEpsilon(values[0], values[length - 1], removeDuplicatesEpsilon)
) {
cleanedvalues.shift();
if (storeRemovedIndices) {
if (defined(cleanedValues)) {
removedIndices.splice(removedIndexLCI, 0, lastCleanIndex);
} else {
removedIndices.push(length - 1);
}
}

if (defined(cleanedValues)) {
cleanedValues.length -= 1;
} else {
cleanedValues = values.slice(0, -1);
}
}

return cleanedvalues;
return defined(cleanedValues) ? cleanedValues : values;
}

export default arrayRemoveDuplicates;
Loading

0 comments on commit 9081c2c

Please sign in to comment.