bruce-cesium 6.9.2 → 6.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -36557,7 +36557,7 @@
36557
36557
  }
36558
36558
 
36559
36559
  (function (EntityRenderEnginePolygon) {
36560
- function Render(params) {
36560
+ async function Render(params) {
36561
36561
  var _a, _b;
36562
36562
  const entity = params.entity;
36563
36563
  const pRings = BModels.Entity.GetValue({
@@ -36568,9 +36568,26 @@
36568
36568
  return null;
36569
36569
  }
36570
36570
  const style = params.style;
36571
+ const fillType = style.fillType || BModels.Style.EPolygonFillType.Color;
36571
36572
  const fillColorTrace = style.fillColor ? BModels.Calculator.TraceGetColor(style.fillColor, entity, params.tags) : { value: null, effective: null };
36572
36573
  const bFillColor = fillColorTrace.value;
36573
36574
  const cFillColor = bFillColor ? ColorToCColor(bFillColor) : Cesium.Color.fromCssColorString("rgba(139, 195, 74, 0.8)");
36575
+ let textureDataUri = null;
36576
+ let textureTraceEffective = null;
36577
+ if (fillType === BModels.Style.EPolygonFillType.Texture) {
36578
+ const resolved = await resolveTexturedFill({
36579
+ api: params.api,
36580
+ style,
36581
+ entity,
36582
+ tags: params.tags
36583
+ });
36584
+ textureDataUri = resolved.dataUri;
36585
+ textureTraceEffective = resolved.effective;
36586
+ }
36587
+ const hasFill = fillType === BModels.Style.EPolygonFillType.Texture ? Boolean(textureDataUri) : cFillColor.alpha > 0;
36588
+ const fillMaterial = textureDataUri
36589
+ ? new Cesium.ImageMaterialProperty({ image: textureDataUri, transparent: true })
36590
+ : cFillColor;
36574
36591
  const lineColorTrace = style.lineColor ? BModels.Calculator.TraceGetColor(style.lineColor, entity, params.tags) : { value: null, effective: null };
36575
36592
  const bLineColor = lineColorTrace.value;
36576
36593
  const cLineColor = bLineColor ? ColorToCColor(bLineColor) : Cesium.Color.fromCssColorString("rgba(80, 80, 80, 0.8)");
@@ -36589,7 +36606,7 @@
36589
36606
  }
36590
36607
  // If both outline and fill is not available then don't render anything.
36591
36608
  if ((width <= 0 || cLineColor.alpha <= 0) &&
36592
- cFillColor.alpha <= 0) {
36609
+ !hasFill) {
36593
36610
  return null;
36594
36611
  }
36595
36612
  let heightRef = getHeightRef$3(style);
@@ -36644,7 +36661,7 @@
36644
36661
  id: BModels.ObjectUtils.UId(15),
36645
36662
  polygon: {
36646
36663
  hierarchy: new Cesium.PolygonHierarchy(posses, holePosses.map(x => new Cesium.PolygonHierarchy(x))),
36647
- material: cFillColor,
36664
+ material: fillMaterial,
36648
36665
  extrudedHeight: extrusion.value,
36649
36666
  extrudedHeightReference: extrusion.exHeightRef,
36650
36667
  shadows: Cesium.ShadowMode.ENABLED,
@@ -36709,15 +36726,21 @@
36709
36726
  cEntity.polygon.distanceDisplayCondition = new Cesium.ConstantProperty(exports.EntityRenderEngine.GetDisplayCondition(params.minDistance, params.maxDistance, width <= 0 || !cLineColor || units == "m" ? size : null, true));
36710
36727
  cEntity.polygon.shadows = new Cesium.ConstantProperty(Cesium.ShadowMode.ENABLED);
36711
36728
  cEntity.polygon.classificationType = new Cesium.ConstantProperty(classification);
36712
- // We'll use "SetDefaultColor" to updating the internal reference and to allow for an animation.
36713
- // WARNING: polygon does not support animation (yet?).
36714
- exports.CesiumEntityStyler.SetDefaultColor({
36715
- color: cFillColor,
36716
- entity: cEntity,
36717
- viewer: params.viewer,
36718
- override: true,
36719
- requestRender: false
36720
- });
36729
+ // TODO: animate the texture!
36730
+ if (textureDataUri) {
36731
+ cEntity.polygon.material = fillMaterial;
36732
+ }
36733
+ else {
36734
+ // We'll use "SetDefaultColor" to updating the internal reference and to allow for an animation.
36735
+ // WARNING: polygon does not support animation (yet?).
36736
+ exports.CesiumEntityStyler.SetDefaultColor({
36737
+ color: cFillColor,
36738
+ entity: cEntity,
36739
+ viewer: params.viewer,
36740
+ override: true,
36741
+ requestRender: false
36742
+ });
36743
+ }
36721
36744
  cEntity.show = true;
36722
36745
  }
36723
36746
  if (hasOutline) {
@@ -36865,6 +36888,7 @@
36865
36888
  }
36866
36889
  cEntity.styleEffective = exports.StyleEffective.Combine([
36867
36890
  { key: "color", effective: fillColorTrace.effective },
36891
+ { key: "texture", effective: textureTraceEffective },
36868
36892
  { key: "lineColor", effective: lineColorTrace.effective },
36869
36893
  { key: "lineWidth", effective: lineWidthTrace.effective }
36870
36894
  ]);
@@ -36916,11 +36940,12 @@
36916
36940
  }
36917
36941
  }
36918
36942
  const pStyle = (_b = style === null || style === void 0 ? void 0 : style.polygonStyle) !== null && _b !== void 0 ? _b : {};
36919
- const cEntity = Render({
36943
+ const cEntity = await Render({
36920
36944
  entity: entity,
36921
36945
  style: pStyle,
36922
36946
  tags: tags,
36923
36947
  viewer: params.viewer,
36948
+ api,
36924
36949
  maxDistance: zoomItem.MaxZoom,
36925
36950
  minDistance: zoomItem.MinZoom,
36926
36951
  // Temporarily disabling re-using graphics for polygons as they have some bugs, and
@@ -37038,6 +37063,95 @@
37038
37063
  }
37039
37064
  return style;
37040
37065
  }
37066
+ // Cache of tinted texture data URIs, keyed by resolved url + color mask, so repeated renders of the
37067
+ // same polygon (or multiple polygons sharing a texture) don't refetch/reprocess the same image.
37068
+ const _textureCache = new BModels.LRUCache(50);
37069
+ /**
37070
+ * Returns if a resolved texture value looks like a URL rather than a client file ID.
37071
+ * @param value
37072
+ */
37073
+ function looksLikeTextureUrl(value) {
37074
+ return /^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(value) || value.startsWith("//") || value.startsWith("data:");
37075
+ }
37076
+ /**
37077
+ * Resolves a polygon style's texture field and if a color ask is needed it tints the resulting image.
37078
+ * @param params
37079
+ */
37080
+ async function resolveTexturedFill(params) {
37081
+ const { api, style, entity, tags } = params;
37082
+ const textureTrace = style.texture ? BModels.Calculator.TraceGetString(style.texture, entity, tags) : { value: null, effective: null };
37083
+ const raw = textureTrace.value;
37084
+ if (!raw || typeof raw != "string" || !api) {
37085
+ return { dataUri: null, effective: textureTrace.effective };
37086
+ }
37087
+ let url = raw;
37088
+ if (!looksLikeTextureUrl(raw)) {
37089
+ await api.Loading;
37090
+ url = BModels.ClientFile.GetUrl({
37091
+ api,
37092
+ fileId: raw,
37093
+ viaCdn: true
37094
+ });
37095
+ }
37096
+ const mask = style.textureColorMask;
37097
+ const cacheKey = "texture-" + url + "-" + (mask ? mask.type + "-" + mask.minColor + "-" + mask.maxColor : "none");
37098
+ let prom = _textureCache.Get(cacheKey);
37099
+ if (!prom) {
37100
+ prom = buildTintedTextureDataUri(url, mask).catch(() => null);
37101
+ _textureCache.Set(cacheKey, prom);
37102
+ }
37103
+ return { dataUri: await prom, effective: textureTrace.effective };
37104
+ }
37105
+ /**
37106
+ * Fetches an image and, if a color mask is provided, remaps its (assumed grayscale) pixel values
37107
+ * into a gradient between the mask's minColor/maxColor, preserving source alpha.
37108
+ * @param url
37109
+ * @param mask
37110
+ */
37111
+ async function buildTintedTextureDataUri(url, mask) {
37112
+ const response = await fetch(url);
37113
+ const blob = await response.blob();
37114
+ const objectUrl = URL.createObjectURL(blob);
37115
+ let image;
37116
+ try {
37117
+ image = await loadImage(objectUrl);
37118
+ }
37119
+ finally {
37120
+ URL.revokeObjectURL(objectUrl);
37121
+ }
37122
+ const canvas = document.createElement("canvas");
37123
+ canvas.width = image.width;
37124
+ canvas.height = image.height;
37125
+ const context = canvas.getContext("2d");
37126
+ context.drawImage(image, 0, 0);
37127
+ if (mask && mask.type === BModels.Style.ETextureColorMaskType.BlackWhite) {
37128
+ const minColor = BModels.Color.ColorFromStr(mask.minColor) || { red: 0, green: 0, blue: 0, alpha: 1 };
37129
+ const maxColor = BModels.Color.ColorFromStr(mask.maxColor) || { red: 255, green: 255, blue: 255, alpha: 1 };
37130
+ const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
37131
+ const data = imageData.data;
37132
+ for (let i = 0; i < data.length; i += 4) {
37133
+ // The texture is rendered black-to-white server-side, so any channel carries the value.
37134
+ const t = data[i] / 255;
37135
+ data[i] = Math.round(minColor.red + (maxColor.red - minColor.red) * t);
37136
+ data[i + 1] = Math.round(minColor.green + (maxColor.green - minColor.green) * t);
37137
+ data[i + 2] = Math.round(minColor.blue + (maxColor.blue - minColor.blue) * t);
37138
+ // Preserve source transparency (eg unrasterized pixels) blended with the mask's own alpha.
37139
+ const srcAlpha = data[i + 3] / 255;
37140
+ const maskAlpha = minColor.alpha + (maxColor.alpha - minColor.alpha) * t;
37141
+ data[i + 3] = Math.round(srcAlpha * maskAlpha * 255);
37142
+ }
37143
+ context.putImageData(imageData, 0, 0);
37144
+ }
37145
+ return canvas.toDataURL("image/png");
37146
+ }
37147
+ function loadImage(src) {
37148
+ return new Promise((res, rej) => {
37149
+ const image = new Image();
37150
+ image.onload = () => res(image);
37151
+ image.onerror = (e) => rej(e);
37152
+ image.src = src;
37153
+ });
37154
+ }
37041
37155
  /**
37042
37156
  * Compares two color materials.
37043
37157
  * Returns if they are equal.
@@ -38323,7 +38437,7 @@
38323
38437
  StyleUtils.ApplyTypeStyle = ApplyTypeStyle;
38324
38438
  })(exports.StyleUtils || (exports.StyleUtils = {}));
38325
38439
 
38326
- const VERSION = "6.9.2";
38440
+ const VERSION = "6.9.3";
38327
38441
  /**
38328
38442
  * Updates the environment instance used by bruce-cesium to one specified.
38329
38443
  * This can be used to ensure that the instance a parent is referencing is shared between bruce-cesium, bruce-models, and the parent app.