@allmaps/render
Version:
Render functions for WebGL and image buffers
356 lines (355 loc) • 14.2 kB
JavaScript
import { triangulateToUnique, interpolatePolygon } from "@allmaps/triangulate";
import { mergeOptions, mixNumbers, mixPoints, mixLineStrings, getPropertyFromQuadrupleCacheOrComputation, getPropertyFromDoubleCacheOrComputation } from "@allmaps/stdlib";
import { WarpedMap } from "./WarpedMap.js";
const DEFAULT_SPECIFIC_TRIANGULATED_WARPED_MAP_OPTIONS = {
distortionMeasures: ["log2sigma", "twoOmega"]
};
class TriangulatedWarpedMap extends WarpedMap {
previousResourceResolution;
resourceResolution;
triangulateErrorCount = 0;
projectedGcpPreviousTriangulation;
projectedGcpTriangulation;
resourceTriangulationCache;
projectedGcpTriangulationCache;
resourceTrianglePoints = [];
projectedGeoPreviousTrianglePoints = [];
projectedGeoTrianglePoints = [];
previousTrianglePointsDistortion = [];
trianglePointsDistortion = [];
projectedGeoPreviousTriangulationAppliableMask = [];
projectedGeoTriangulationAppliableMask = [];
projectedGeoPreviousTriangulationMask = [];
projectedGeoTriangulationMask = [];
/**
* Creates an instance of a TriangulatedWarpedMap.
*
* @param mapId - ID of the map
* @param georeferencedMap - Georeferenced map used to construct the WarpedMap
* @param options - Options
*/
constructor(mapId, georeferencedMap, listOptions, mapOptions) {
super(mapId, georeferencedMap, listOptions, mapOptions);
this.resourceTriangulationCache = /* @__PURE__ */ new Map();
this.projectedGcpTriangulationCache = /* @__PURE__ */ new Map();
this.updateTriangulation();
}
/**
* Get default options
*/
static getDefaultOptions() {
return mergeOptions(
DEFAULT_SPECIFIC_TRIANGULATED_WARPED_MAP_OPTIONS,
super.getDefaultOptions()
);
}
/** Set default options */
setDefaultOptions() {
this.defaultOptions = TriangulatedWarpedMap.getDefaultOptions();
}
/**
* Update the ground control points loaded from a georeferenced map to new ground control points.
*
* @param gcps - the new ground control points
*/
setGcps(gcps) {
super.setGcps(gcps);
this.clearResourceTriangulationCaches();
this.updateTriangulation();
}
/**
* Update the resource mask loaded from a georeferenced map to a new mask.
*
* @param resourceMask - the new mask
*/
setResourceMask(resourceFullMask, resourceAppliableMask, resourceMask) {
super.setResourceMask(resourceFullMask, resourceAppliableMask, resourceMask);
this.updateTriangulation();
}
/**
* Set the distortionMeasure
*
* @param distortionMeasure - the disortion measure
*/
setDistortionMeasure(distortionMeasure) {
super.setDistortionMeasure(distortionMeasure);
this.updateTrianglePointsDistortion();
}
/**
* Set the internal projection
*
* @param projection - the internal projection
*/
setInternalProjection(projection) {
super.setInternalProjection(projection);
this.updateTriangulation();
}
/**
* Set the projection
*
* @param projection - the projection
*/
setProjection(projection) {
super.setProjection(projection);
this.clearProjectedTriangulationCaches();
this.updateTriangulation();
}
/**
* Reset previous transform properties to new ones (when completing an animation).
*/
resetPrevious() {
super.resetPrevious();
this.previousResourceResolution = this.resourceResolution;
this.projectedGcpPreviousTriangulation = this.projectedGcpTriangulation;
this.projectedGeoPreviousTrianglePoints = this.projectedGeoTrianglePoints;
this.previousTrianglePointsDistortion = this.trianglePointsDistortion;
this.projectedGeoPreviousTriangulationAppliableMask = this.projectedGeoTriangulationAppliableMask;
this.projectedGeoPreviousTriangulationMask = this.projectedGeoTriangulationMask;
}
/**
* Mix previous transform properties with new ones (when changing an ongoing animation).
*
* @param t - animation progress
*/
mixPreviousAndNew(t) {
super.mixPreviousAndNew(t);
if (this.projectedGcpPreviousTriangulation && this.projectedGcpTriangulation) {
const projectedGcpPreviousTriangulation = this.projectedGcpPreviousTriangulation;
const projectedGcpTriangulation = this.projectedGcpTriangulation;
this.previousResourceResolution = this.resourceResolution;
this.projectedGcpPreviousTriangulation = {
resourceResolution: projectedGcpPreviousTriangulation.resourceResolution,
gcpUniquePoints: projectedGcpPreviousTriangulation.gcpUniquePoints.map(
(projectedGcp, index) => {
return {
resource: projectedGcp.resource,
geo: mixPoints(
projectedGcpTriangulation.gcpUniquePoints[index].geo,
projectedGcp.geo,
t
),
// Note: Not mixing the distortions Map, only the active distortion
distortions: projectedGcpTriangulation.gcpUniquePoints[index].distortions,
distortion: mixNumbers(
projectedGcpTriangulation.gcpUniquePoints[index].distortion || 0,
projectedGcp.distortion || 0,
t
)
};
}
),
uniquePointIndices: projectedGcpPreviousTriangulation.uniquePointIndices,
uniquePointIndexInterpolatedPolygon: projectedGcpPreviousTriangulation.uniquePointIndexInterpolatedPolygon
};
this.projectedGeoPreviousTrianglePoints = projectedGcpPreviousTriangulation.uniquePointIndices.map(
(i) => projectedGcpPreviousTriangulation.gcpUniquePoints[i].geo
);
this.previousTrianglePointsDistortion = projectedGcpPreviousTriangulation.uniquePointIndices.map(
(i) => projectedGcpPreviousTriangulation.gcpUniquePoints[i].distortion
);
}
this.projectedGeoPreviousTriangulationAppliableMask = mixLineStrings(
this.projectedGeoTriangulationAppliableMask,
this.projectedGeoPreviousTriangulationAppliableMask,
t
);
this.projectedGeoPreviousTriangulationMask = mixLineStrings(
this.projectedGeoTriangulationMask,
this.projectedGeoPreviousTriangulationMask,
t
);
}
/**
* Update the (previous and new) triangulation of the resourceMask. Use cache if available.
*/
updateTriangulation() {
if (!this.resourceTriangulationCache || !this.projectedGcpTriangulationCache) {
return;
}
const resourceResolution = this.options.resourceResolution || this.projectedTransformer.getToGeoTransformationResolution(
this.resourceMaskBbox
);
let refinePrevious = false;
if (resourceResolution && this.previousResourceResolution) {
refinePrevious = this.previousResourceResolution < resourceResolution;
this.resourceResolution = Math.min(
resourceResolution,
this.previousResourceResolution
);
}
if (resourceResolution && !this.previousResourceResolution) {
refinePrevious = true;
this.resourceResolution = resourceResolution;
}
if (!resourceResolution && this.previousResourceResolution) {
this.resourceResolution = this.previousResourceResolution;
} else if (!resourceResolution && !this.previousResourceResolution) {
this.resourceResolution = void 0;
}
this.projectedGcpTriangulation = getPropertyFromQuadrupleCacheOrComputation(
this.projectedGcpTriangulationCache,
this.resourceResolution,
String(this.resourceMask),
this.transformationType,
this.internalProjection.definition,
() => {
const {
uniquePoints,
uniquePointIndexTriangles,
uniquePointIndexInterpolatedPolygon
} = getPropertyFromDoubleCacheOrComputation(
this.resourceTriangulationCache,
this.resourceResolution,
String(this.resourceMask),
() => triangulateToUnique([this.resourceMask], this.resourceResolution, {
steinerPoints: this.gcps.map((gcp) => gcp.resource)
})
);
const resourceResolution2 = this.resourceResolution;
const resourceUniquePoints = uniquePoints;
const gcpUniquePoints = resourceUniquePoints.map(
(resourcePoint) => this.projectedTransformer.transformToGeo(
resourcePoint,
{
distortionMeasures: this.options.distortionMeasures,
referenceScale: this.getReferenceScale()
},
(gcpPartialDistortion) => gcpPartialDistortion
)
);
const uniquePointIndices = uniquePointIndexTriangles.flat();
return {
resourceResolution: resourceResolution2,
gcpUniquePoints,
uniquePointIndices,
uniquePointIndexInterpolatedPolygon
};
}
);
if (!this.projectedGcpPreviousTriangulation) {
this.projectedGcpPreviousTriangulation = this.projectedGcpTriangulation;
}
if (refinePrevious) {
this.previousResourceResolution = this.resourceResolution;
this.projectedGcpPreviousTriangulation = getPropertyFromQuadrupleCacheOrComputation(
this.projectedGcpTriangulationCache,
this.previousResourceResolution,
String(this.resourceMask),
this.previousTransformationType,
this.previousInternalProjection.definition,
() => {
if (!this.projectedGcpTriangulation) {
throw new Error("No projectedGcpTriangulation");
}
const projectedGcpTriangulation = this.projectedGcpTriangulation;
return {
resourceResolution: this.projectedGcpTriangulation.resourceResolution,
gcpUniquePoints: this.projectedGcpTriangulation.gcpUniquePoints.map(
(projectedGcp) => this.projectedPreviousTransformer.transformToGeo(
projectedGcp.resource,
{
distortionMeasures: this.options.distortionMeasures,
referenceScale: this.getReferenceScale()
},
(gcpPartialDistortion) => gcpPartialDistortion
)
),
uniquePointIndices: this.projectedGcpTriangulation.uniquePointIndices,
uniquePointIndexInterpolatedPolygon: projectedGcpTriangulation.uniquePointIndexInterpolatedPolygon
};
},
() => !this.mixed,
() => !this.mixed
);
}
this.updateTrianglePoints();
}
/**
* Derive the (previous and new) resource and projectedGeo points from their corresponding triangulations.
*
* Also derive the (previous and new) triangulation-refined resource and projectedGeo mask
*/
updateTrianglePoints() {
if (!this.projectedGcpPreviousTriangulation || !this.projectedGcpTriangulation) {
return;
}
const projectedGcpPreviousTriangulation = this.projectedGcpPreviousTriangulation;
const projectedGcpTriangulation = this.projectedGcpTriangulation;
this.resourceTrianglePoints = this.projectedGcpTriangulation.uniquePointIndices.map(
(i) => projectedGcpTriangulation.gcpUniquePoints[i].resource
);
this.projectedGeoPreviousTrianglePoints = this.projectedGcpPreviousTriangulation.uniquePointIndices.map(
(i) => projectedGcpPreviousTriangulation.gcpUniquePoints[i].geo
);
this.projectedGeoTrianglePoints = this.projectedGcpTriangulation.uniquePointIndices.map(
(i) => projectedGcpTriangulation.gcpUniquePoints[i].geo
);
this.projectedGeoPreviousTriangulationMask = this.projectedGcpPreviousTriangulation.uniquePointIndexInterpolatedPolygon.map(
(typedRing) => typedRing.map(
(i) => projectedGcpPreviousTriangulation.gcpUniquePoints[i].geo
)
).flat();
this.projectedGeoTriangulationMask = this.projectedGcpTriangulation.uniquePointIndexInterpolatedPolygon.map(
(typedRing) => typedRing.map((i) => projectedGcpTriangulation.gcpUniquePoints[i].geo)
).flat();
this.projectedGeoTriangulationAppliableMask = this.projectedTransformer.transformToGeo(
interpolatePolygon(
[this.resourceAppliableMask],
this.resourceResolution
)[0],
{
isMultiGeometry: true
}
);
if (this.projectedGeoPreviousTriangulationAppliableMask.length == 0) {
this.projectedGeoPreviousTriangulationAppliableMask = this.projectedGeoTriangulationAppliableMask;
}
this.updateTrianglePointsDistortion();
}
/**
* Derive the (previous and new) distortions from their corresponding triangulations.
*/
updateTrianglePointsDistortion() {
if (!this.projectedGcpPreviousTriangulation || !this.projectedGcpTriangulation) {
return;
}
const projectedGcpPreviousTriangulation = this.projectedGcpPreviousTriangulation;
const projectedGcpTriangulation = this.projectedGcpTriangulation;
this.previousTrianglePointsDistortion = projectedGcpPreviousTriangulation.uniquePointIndices.map((i) => {
const distortions = projectedGcpPreviousTriangulation.gcpUniquePoints[i].distortions;
if (!this.previousDistortionMeasure || !distortions) {
return 0;
} else {
return distortions.get(this.previousDistortionMeasure);
}
});
this.trianglePointsDistortion = projectedGcpTriangulation.uniquePointIndices.map((i) => {
const distortions = projectedGcpTriangulation.gcpUniquePoints[i].distortions;
if (!this.distortionMeasure || !distortions) {
return 0;
} else {
return distortions.get(this.distortionMeasure);
}
});
}
updateProjectedTransformerProperties() {
super.updateProjectedTransformerProperties();
this.updateTriangulation();
}
clearProjectedTransformerCaches() {
super.clearProjectedTransformerCaches();
this.clearResourceTriangulationCaches();
}
clearResourceTriangulationCaches() {
this.resourceTriangulationCache = /* @__PURE__ */ new Map();
this.clearProjectedTriangulationCaches();
}
clearProjectedTriangulationCaches() {
this.projectedGcpTriangulationCache = /* @__PURE__ */ new Map();
}
}
export {
DEFAULT_SPECIFIC_TRIANGULATED_WARPED_MAP_OPTIONS,
TriangulatedWarpedMap
};
//# sourceMappingURL=TriangulatedWarpedMap.js.map