From 62e0ef2eb466f1f62dd03f5d88ac8a95d8f0d141 Mon Sep 17 00:00:00 2001 From: deyihu Date: Mon, 1 Jan 2024 12:18:39 +0800 Subject: [PATCH 1/3] fix Gemetry getContainerExtent is error when markerWidth is 0 --- src/core/util/marker.js | 27 +++++++ src/geometry/Geometry.js | 13 +++- .../symbolizers/ImageMarkerSymbolizer.js | 1 + .../geometry/symbolizers/Symbolizer.js | 7 +- .../symbolizers/TextMarkerSymbolizer.js | 1 + .../symbolizers/VectorMarkerSymbolizer.js | 1 + test/geometry/MarkerSpec.js | 74 +++++++++++++++++++ 7 files changed, 122 insertions(+), 2 deletions(-) diff --git a/src/core/util/marker.js b/src/core/util/marker.js index b1a29560af..889dce6eab 100644 --- a/src/core/util/marker.js +++ b/src/core/util/marker.js @@ -136,6 +136,10 @@ const SIZE = []; export function getVectorMarkerFixedExtent(out, symbol, size) { // const padding = getVectorPadding(symbol) * 2; size = size || calVectorMarkerSize(SIZE, symbol); + if (size && (size[0] === 0 || size[1] === 0)) { + setEmptyFixedExent(out); + return out; + } // if (padding) { // size = size.map(d => d - padding); // } @@ -185,6 +189,11 @@ export function calVectorMarkerSize(out, symbol) { const padding = getVectorPadding(symbol); const width = getValueOrDefault(symbol['markerWidth'], DEFAULT_MARKER_SYMBOLS.markerWidth); const height = getValueOrDefault(symbol['markerHeight'], DEFAULT_MARKER_SYMBOLS.markerHeight); + if (width === 0 || height === 0) { + out[0] = 0; + out[1] = 0; + return out; + } const lineWidth = getValueOrDefault(symbol['markerLineWidth'], DEFAULT_MARKER_SYMBOLS.markerLineWidth), shadow = 2 * ((symbol['shadowBlur'] || 0) + Math.max(Math.abs(symbol['shadowOffsetX'] || 0) + Math.abs(symbol['shadowOffsetY'] || 0))), // add some tolerance for shadowOffsetX/Y w = Math.round(width + lineWidth + shadow + padding * 2), @@ -217,6 +226,10 @@ export function getImageMarkerFixedExtent(out, symbol, resources) { height = symbol['markerHeight'] || (img ? img.height : 0); TEMP_SIZE.width = width; TEMP_SIZE.height = height; + if (symbol['markerWidth'] === 0 || symbol['markerHeight'] === 0) { + setEmptyFixedExent(out); + return out; + } const alignPoint = getAlignPoint(TEMP_SIZE, symbol['markerHorizontalAlignment'] || 'middle', symbol['markerVerticalAlignment'] || 'top'); return getFixedExtent(out, symbol['markerDx'] || 0, symbol['markerDy'] || 0, getMarkerRotation(symbol), alignPoint, width, height); @@ -225,6 +238,10 @@ export function getImageMarkerFixedExtent(out, symbol, resources) { export function getTextMarkerFixedExtent(out, symbol, textDesc) { const size = textDesc['size']; + if (size && (size.width === 0 || size.height === 0)) { + setEmptyFixedExent(out); + return out; + } const alignPoint = getAlignPoint(size, symbol['textHorizontalAlignment'], symbol['textVerticalAlignment']); // if (symbol['textHaloRadius']) { // const r = symbol['textHaloRadius']; @@ -316,3 +333,13 @@ export const DYNAMIC_SYMBOL_PROPS = [ export const SIZE_SYMBOL_PROPS = [ 'textName', 'markerType', 'markerFile', 'textHaloRadius', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY', 'textWrapWidth' ]; + +export function setEmptyFixedExent(extent) { + if (!extent) { + return; + } + extent.xmin = Infinity; + extent.ymin = Infinity; + extent.xmax = -Infinity; + extent.ymax = -Infinity; +} diff --git a/src/geometry/Geometry.js b/src/geometry/Geometry.js index 3f2eba08a6..4e1d025e10 100644 --- a/src/geometry/Geometry.js +++ b/src/geometry/Geometry.js @@ -31,6 +31,14 @@ const TEMP_POINT0 = new Point(0, 0); const TEMP_EXTENT = new PointExtent(); const TEMP_PROPERTIES = {}; +function validteExtent(extent) { + if (!extent) { + return false; + } + const { xmin, ymin, xmax, ymax } = extent; + return (xmax - xmin > 0 && ymax - ymin > 0); +} + /** * @property {Object} options - geometry options * @property {Boolean} [options.id=null] - id of the geometry @@ -452,7 +460,10 @@ class Geometry extends JSONAble(Eventable(Handlerable(Class))) { extent._combine(groundExtent); } if (extent) { - extent._add(this._getFixedExtent()); + const fixedExtent = this._getFixedExtent(); + if (validteExtent(fixedExtent)) { + extent._add(fixedExtent); + } } const smoothness = this.options['smoothness']; if (smoothness) { diff --git a/src/renderer/geometry/symbolizers/ImageMarkerSymbolizer.js b/src/renderer/geometry/symbolizers/ImageMarkerSymbolizer.js index bc80b8002a..b83c25a960 100644 --- a/src/renderer/geometry/symbolizers/ImageMarkerSymbolizer.js +++ b/src/renderer/geometry/symbolizers/ImageMarkerSymbolizer.js @@ -24,6 +24,7 @@ export default class ImageMarkerSymbolizer extends PointSymbolizer { symbolize(ctx, resources) { const style = this.style; if (!this.painter.isHitTesting() && (style['markerWidth'] === 0 || style['markerHeight'] === 0 || style['markerOpacity'] === 0)) { + this._resetBBOX(ctx); return; } const cookedPoints = this._getRenderContainerPoints(); diff --git a/src/renderer/geometry/symbolizers/Symbolizer.js b/src/renderer/geometry/symbolizers/Symbolizer.js index 4a54714bc6..772f71cc5b 100644 --- a/src/renderer/geometry/symbolizers/Symbolizer.js +++ b/src/renderer/geometry/symbolizers/Symbolizer.js @@ -1,6 +1,6 @@ import { COLOR_PROPERTIES } from '../../../core/Constants'; import { isString } from '../../../core/util'; -import { bufferBBOX, getDefaultBBOX, setBBOX } from '../../../core/util/bbox'; +import { bufferBBOX, getDefaultBBOX, resetBBOX, setBBOX } from '../../../core/util/bbox'; /** * @classdesc @@ -21,6 +21,11 @@ class Symbolizer { } return this; } + _resetBBOX(ctx) { + if (!ctx.isHitTesting) { + resetBBOX(this.bbox); + } + } _bufferBBOX(ctx, bufferSize = 0) { if (!ctx.isHitTesting) { diff --git a/src/renderer/geometry/symbolizers/TextMarkerSymbolizer.js b/src/renderer/geometry/symbolizers/TextMarkerSymbolizer.js index cd9080a81d..8974a9eb24 100644 --- a/src/renderer/geometry/symbolizers/TextMarkerSymbolizer.js +++ b/src/renderer/geometry/symbolizers/TextMarkerSymbolizer.js @@ -36,6 +36,7 @@ export default class TextMarkerSymbolizer extends PointSymbolizer { if (!this.painter.isHitTesting() && (this.style['textSize'] === 0 || !this.style['textOpacity'] && (!this.style['textHaloRadius'] || !this.style['textHaloOpacity']) || this.style['textWrapWidth'] === 0)) { + this._resetBBOX(ctx); return; } const cookedPoints = this._getRenderContainerPoints(); diff --git a/src/renderer/geometry/symbolizers/VectorMarkerSymbolizer.js b/src/renderer/geometry/symbolizers/VectorMarkerSymbolizer.js index 4bc8c98006..b73af719a2 100644 --- a/src/renderer/geometry/symbolizers/VectorMarkerSymbolizer.js +++ b/src/renderer/geometry/symbolizers/VectorMarkerSymbolizer.js @@ -38,6 +38,7 @@ export default class VectorMarkerSymbolizer extends PointSymbolizer { const style = this.style; if (!this.painter.isHitTesting() && (style['markerWidth'] === 0 || style['markerHeight'] === 0 || (style['polygonOpacity'] === 0 && style['lineOpacity'] === 0))) { + this._resetBBOX(ctx); return; } const cookedPoints = this._getRenderContainerPoints(); diff --git a/test/geometry/MarkerSpec.js b/test/geometry/MarkerSpec.js index 982368fb60..3d51f56f6c 100644 --- a/test/geometry/MarkerSpec.js +++ b/test/geometry/MarkerSpec.js @@ -909,4 +909,78 @@ describe('Geometry.Marker', function () { }); done(); }); + + it('#2175 marker ContainerExtent/RenderBBOX when markerWidth/markerHeight/textSize =0', function (done) { + const imageSymbol = { + markerWidth: 10, + markerHeight: 10, + 'markerFile': 'resources/tile.png', + }; + + const pathSymbol = { + 'markerType': 'path', + 'markerPath': [{ + 'path': 'M8 23l0 0 0 0 0 0 0 0 0 0c-4,-5 -8,-10 -8,-14 0,-5 4,-9 8,-9l0 0 0 0c4,0 8,4 8,9 0,4 -4,9 -8,14z M3,9 a5,5 0,1,0,0,-0.9Z', + 'fill': '#DE3333' + }], + 'markerPathWidth': 16, + 'markerPathHeight': 23, + 'markerWidth': 8, + 'markerHeight': 20, + }; + + const vectorSymbol = { + markerType: 'ellipse', + markerWidth: 10, + markerHeight: 10 + }; + + const textSymbol = { + textSize: 12, + textName: 'hello' + }; + + const symbols = [imageSymbol, pathSymbol, vectorSymbol, textSymbol]; + + let idx = 0; + + function test() { + layer.clear(); + if (idx < symbols.length) { + const symbol = symbols[idx]; + const isText = symbol.textSize !== undefined; + const point = new maptalks.Marker(map.getCenter(), { + symbol: symbol + }) + point.addTo(layer); + setTimeout(() => { + const extent = point.getContainerExtent(); + expect(extent.getWidth()).not.to.be.eql(0); + expect(extent.getHeight()).not.to.be.eql(0); + const bbox = point._getPainter().getRenderBBOX(); + expect(bbox[0]).not.to.be.eql(Infinity); + if (isText) { + symbol.textSize = 0; + point.setSymbol(symbol) + } else { + symbol.markerWidth = 0; + point.setSymbol(symbol) + } + + setTimeout(() => { + const extent = point.getContainerExtent(); + expect(extent.getWidth()).to.be.eql(0); + expect(extent.getHeight()).to.be.eql(0); + const bbox = point._getPainter().getRenderBBOX(); + expect(bbox).to.be.eql(null); + idx++; + test(); + }, 50); + }, 50); + } else { + done(); + } + } + test(); + }); }); From 09f77a89bdffcfa1fb2a861101f52605a615ffb0 Mon Sep 17 00:00:00 2001 From: deyihu Date: Mon, 1 Jan 2024 20:06:56 +0800 Subject: [PATCH 2/3] fix typo --- src/geometry/Geometry.js | 4 ++-- src/renderer/geometry/symbolizers/ImageMarkerSymbolizer.js | 1 - src/renderer/geometry/symbolizers/Symbolizer.js | 7 +------ src/renderer/geometry/symbolizers/TextMarkerSymbolizer.js | 1 - .../geometry/symbolizers/VectorMarkerSymbolizer.js | 1 - test/geometry/MarkerSpec.js | 7 ++----- 6 files changed, 5 insertions(+), 16 deletions(-) diff --git a/src/geometry/Geometry.js b/src/geometry/Geometry.js index 4e1d025e10..ac97aa44a2 100644 --- a/src/geometry/Geometry.js +++ b/src/geometry/Geometry.js @@ -31,7 +31,7 @@ const TEMP_POINT0 = new Point(0, 0); const TEMP_EXTENT = new PointExtent(); const TEMP_PROPERTIES = {}; -function validteExtent(extent) { +function validateExtent(extent) { if (!extent) { return false; } @@ -461,7 +461,7 @@ class Geometry extends JSONAble(Eventable(Handlerable(Class))) { } if (extent) { const fixedExtent = this._getFixedExtent(); - if (validteExtent(fixedExtent)) { + if (validateExtent(fixedExtent)) { extent._add(fixedExtent); } } diff --git a/src/renderer/geometry/symbolizers/ImageMarkerSymbolizer.js b/src/renderer/geometry/symbolizers/ImageMarkerSymbolizer.js index b83c25a960..bc80b8002a 100644 --- a/src/renderer/geometry/symbolizers/ImageMarkerSymbolizer.js +++ b/src/renderer/geometry/symbolizers/ImageMarkerSymbolizer.js @@ -24,7 +24,6 @@ export default class ImageMarkerSymbolizer extends PointSymbolizer { symbolize(ctx, resources) { const style = this.style; if (!this.painter.isHitTesting() && (style['markerWidth'] === 0 || style['markerHeight'] === 0 || style['markerOpacity'] === 0)) { - this._resetBBOX(ctx); return; } const cookedPoints = this._getRenderContainerPoints(); diff --git a/src/renderer/geometry/symbolizers/Symbolizer.js b/src/renderer/geometry/symbolizers/Symbolizer.js index 772f71cc5b..4a54714bc6 100644 --- a/src/renderer/geometry/symbolizers/Symbolizer.js +++ b/src/renderer/geometry/symbolizers/Symbolizer.js @@ -1,6 +1,6 @@ import { COLOR_PROPERTIES } from '../../../core/Constants'; import { isString } from '../../../core/util'; -import { bufferBBOX, getDefaultBBOX, resetBBOX, setBBOX } from '../../../core/util/bbox'; +import { bufferBBOX, getDefaultBBOX, setBBOX } from '../../../core/util/bbox'; /** * @classdesc @@ -21,11 +21,6 @@ class Symbolizer { } return this; } - _resetBBOX(ctx) { - if (!ctx.isHitTesting) { - resetBBOX(this.bbox); - } - } _bufferBBOX(ctx, bufferSize = 0) { if (!ctx.isHitTesting) { diff --git a/src/renderer/geometry/symbolizers/TextMarkerSymbolizer.js b/src/renderer/geometry/symbolizers/TextMarkerSymbolizer.js index 8974a9eb24..cd9080a81d 100644 --- a/src/renderer/geometry/symbolizers/TextMarkerSymbolizer.js +++ b/src/renderer/geometry/symbolizers/TextMarkerSymbolizer.js @@ -36,7 +36,6 @@ export default class TextMarkerSymbolizer extends PointSymbolizer { if (!this.painter.isHitTesting() && (this.style['textSize'] === 0 || !this.style['textOpacity'] && (!this.style['textHaloRadius'] || !this.style['textHaloOpacity']) || this.style['textWrapWidth'] === 0)) { - this._resetBBOX(ctx); return; } const cookedPoints = this._getRenderContainerPoints(); diff --git a/src/renderer/geometry/symbolizers/VectorMarkerSymbolizer.js b/src/renderer/geometry/symbolizers/VectorMarkerSymbolizer.js index b73af719a2..4bc8c98006 100644 --- a/src/renderer/geometry/symbolizers/VectorMarkerSymbolizer.js +++ b/src/renderer/geometry/symbolizers/VectorMarkerSymbolizer.js @@ -38,7 +38,6 @@ export default class VectorMarkerSymbolizer extends PointSymbolizer { const style = this.style; if (!this.painter.isHitTesting() && (style['markerWidth'] === 0 || style['markerHeight'] === 0 || (style['polygonOpacity'] === 0 && style['lineOpacity'] === 0))) { - this._resetBBOX(ctx); return; } const cookedPoints = this._getRenderContainerPoints(); diff --git a/test/geometry/MarkerSpec.js b/test/geometry/MarkerSpec.js index 3d51f56f6c..80401b3737 100644 --- a/test/geometry/MarkerSpec.js +++ b/test/geometry/MarkerSpec.js @@ -910,7 +910,7 @@ describe('Geometry.Marker', function () { done(); }); - it('#2175 marker ContainerExtent/RenderBBOX when markerWidth/markerHeight/textSize =0', function (done) { + it('#2175 marker ContainerExtent when markerWidth/markerHeight/textSize =0', function (done) { const imageSymbol = { markerWidth: 10, markerHeight: 10, @@ -957,8 +957,7 @@ describe('Geometry.Marker', function () { const extent = point.getContainerExtent(); expect(extent.getWidth()).not.to.be.eql(0); expect(extent.getHeight()).not.to.be.eql(0); - const bbox = point._getPainter().getRenderBBOX(); - expect(bbox[0]).not.to.be.eql(Infinity); + if (isText) { symbol.textSize = 0; point.setSymbol(symbol) @@ -971,8 +970,6 @@ describe('Geometry.Marker', function () { const extent = point.getContainerExtent(); expect(extent.getWidth()).to.be.eql(0); expect(extent.getHeight()).to.be.eql(0); - const bbox = point._getPainter().getRenderBBOX(); - expect(bbox).to.be.eql(null); idx++; test(); }, 50); From 25846b1777c36340c449d1e880fbd9cab4808189 Mon Sep 17 00:00:00 2001 From: deyihu Date: Mon, 1 Jan 2024 20:19:21 +0800 Subject: [PATCH 3/3] updates --- src/core/util/marker.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/util/marker.js b/src/core/util/marker.js index 889dce6eab..8d6de9ad83 100644 --- a/src/core/util/marker.js +++ b/src/core/util/marker.js @@ -137,7 +137,7 @@ export function getVectorMarkerFixedExtent(out, symbol, size) { // const padding = getVectorPadding(symbol) * 2; size = size || calVectorMarkerSize(SIZE, symbol); if (size && (size[0] === 0 || size[1] === 0)) { - setEmptyFixedExent(out); + emptyExtent(out); return out; } // if (padding) { @@ -227,7 +227,7 @@ export function getImageMarkerFixedExtent(out, symbol, resources) { TEMP_SIZE.width = width; TEMP_SIZE.height = height; if (symbol['markerWidth'] === 0 || symbol['markerHeight'] === 0) { - setEmptyFixedExent(out); + emptyExtent(out); return out; } const alignPoint = getAlignPoint(TEMP_SIZE, symbol['markerHorizontalAlignment'] || 'middle', symbol['markerVerticalAlignment'] || 'top'); @@ -239,7 +239,7 @@ export function getImageMarkerFixedExtent(out, symbol, resources) { export function getTextMarkerFixedExtent(out, symbol, textDesc) { const size = textDesc['size']; if (size && (size.width === 0 || size.height === 0)) { - setEmptyFixedExent(out); + emptyExtent(out); return out; } const alignPoint = getAlignPoint(size, symbol['textHorizontalAlignment'], symbol['textVerticalAlignment']); @@ -334,7 +334,7 @@ export const SIZE_SYMBOL_PROPS = [ 'textName', 'markerType', 'markerFile', 'textHaloRadius', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY', 'textWrapWidth' ]; -export function setEmptyFixedExent(extent) { +export function emptyExtent(extent) { if (!extent) { return; }