Skip to content

Commit ef2829f

Browse files
authored
Merge pull request #1439 from OpenGeoscience/patterned-polygons
feat: Add a patterns to polygons
2 parents f2f1ad9 + 81a0890 commit ef2829f

11 files changed

+407
-43
lines changed

src/markerFeature.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ var pointFeature = require('./pointFeature');
1818
*
1919
* @typedef {geo.feature.styleSpec} geo.markerFeature.styleSpec
2020
* @extends geo.feature.styleSpec
21-
* @property {number|Function} [radius=5] Radius of each marker in pixels.
21+
* @property {number|Function} [radius=6.25] Radius of each marker in pixels.
2222
* This includes the stroke width if `strokeOffset` is -1, excludes it if
2323
* `strokeOffset` is 1, and includes half the stroke width if `strokeOffset`
2424
* is 0. Note that is `radiusIncludesStroke` is `false`, this never

src/polygonFeature.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,45 @@ var transform = require('./transform');
1515
* style options.
1616
*/
1717

18+
/**
19+
* Style specification for a polygon pattern.
20+
*
21+
* @typedef {geo.polygonPattern} geo.polygonPattern
22+
* @property {geo.geoColor} [fillColor] RGBA fill color. Default is polygon
23+
* strokeColor and strokeOpacity.
24+
* @property {geo.geoColor} [strokeColor] RGBA stroke color. Default is
25+
* polygon fillColor and fillOpacity.
26+
* @property {number} [strokeWidth=1.25] The weight of the pattern marker's
27+
* stroke in pixels. Set this or A on strokeFill to zero to not have a
28+
* stroke.
29+
* @property {number} [strokeOffset=-1] The position of the stroke compared to
30+
* the pattern radius. This can only be -1, 0, or 1 (the sign of the value
31+
* is used).
32+
* @property {boolean} [radiusIncludesStroke=true] If truthy or undefined, the
33+
* `radius` includes the `strokeWidth` based on the `strokeOffset`. If
34+
* defined and falsy, the radius does not include the `strokeWidth`.
35+
* @property {number} [symbol=0] One of the predefined symbol numbers. This is
36+
* one of `geo.markerFeature.symbols`.
37+
* @property {number|number[]} [symbolValue=0] A value the affects the
38+
* appearance of the symbol. Some symbols can take an array of numbers.
39+
* @property {number} [rotation=0] The rotation of the symbol in clockwise
40+
* radians.
41+
* @property {geo.markerFeature.scaleMode} [scaleWithZoom='none'] This
42+
* determines if the fill, stroke, or both scale with zoom. If set, the
43+
* values for radius and strokeWidth are the values at zoom-level zero.
44+
* @property {boolean} [rotateWithMap=false] If truthy, rotate symbols with the
45+
* map. If falsy, symbol orientation is absolute.
46+
* @property {number} [radius=6.25] Radius of each marker in pixels. This
47+
* includes the stroke width if `strokeOffset` is -1, excludes it if
48+
* `strokeOffset` is 1, and includes half the stroke width if `strokeOffset`
49+
* is 0. Note that is `radiusIncludesStroke` is `false`, this never
50+
* includes the stroke width.
51+
* @property {number} [spacing=20] Spacing in pixels between pattern symbols;
52+
* scaled if either radius or strokeWidth is scaled. If positive, patterns
53+
* are on a square grid. If negative, patterns are on a triangular grid.
54+
* @property {number[]} [origin=[0, 0]] Origin of the pattern.
55+
*/
56+
1857
/**
1958
* Style specification for a polygon feature.
2059
*
@@ -35,6 +74,9 @@ var transform = require('./transform');
3574
* function, this is passed an array of items, each of which has a vertices
3675
* property that is a single continuous array in map gcs coordinates. It
3776
* defaults to the first polygon's first vertex's position.
77+
* @property {geo.polygonPattern|Function} [pattern] Pattern to apply to each
78+
* polygon. Each polygon can be distinct, but the pattern is uniform across
79+
* any one polygon.
3880
*/
3981

4082
/**

src/util/common.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1506,6 +1506,27 @@ var util = {
15061506
return d;
15071507
},
15081508

1509+
/**
1510+
* Pack an array of three numbers and one boolean into a single float. Each
1511+
* numerical value is either undefined or on the scale of [0, 1] and is
1512+
* mapped to an integer range of [0, 250].
1513+
*
1514+
* @param {number|number[]} value A single value or an array of up to four
1515+
* values where the first three values are numbers and the last is a
1516+
* boolean.
1517+
* @returns {number} A packed number.
1518+
*/
1519+
packFloats: function (value) {
1520+
if (!value.length) {
1521+
return value === undefined ? 0 : Math.floor(Math.abs(value) * 250) + 1;
1522+
}
1523+
return (
1524+
(value[0] === undefined ? 0 : Math.floor(Math.abs(value[0]) * 250) + 1) +
1525+
(value[1] === undefined ? 0 : Math.floor(Math.abs(value[1]) * 250) + 1) * 252 +
1526+
(value[2] === undefined ? 0 : Math.floor(Math.abs(value[2]) * 250) + 1) * 252 * 252
1527+
) * (value[3] ? -1 : 1);
1528+
},
1529+
15091530
///////////////////////////////////////////////////////////////////////////
15101531
/*
15111532
* Utility member properties.

src/webgl/markerFeature.js

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -74,27 +74,6 @@ var webgl_markerFeature = function (arg) {
7474
return shader;
7575
}
7676

77-
/**
78-
* Pack an array of three numbers and one boolean into a single float. Each
79-
* numerical value is either undefined or on the scale of [0, 1] and is
80-
* mapped to an integer range of [0, 250].
81-
*
82-
* @param {number|number[]} value A single value or an array of up to four
83-
* values where the first three values are numbers and the last is a
84-
* boolean.
85-
* @returns {number} A packed number.
86-
*/
87-
function packFloats(value) {
88-
if (!value.length) {
89-
return value === undefined ? 0 : Math.floor(Math.abs(value) * 250) + 1;
90-
}
91-
return (
92-
(value[0] === undefined ? 0 : Math.floor(Math.abs(value[0]) * 250) + 1) +
93-
(value[1] === undefined ? 0 : Math.floor(Math.abs(value[1]) * 250) + 1) * 252 +
94-
(value[2] === undefined ? 0 : Math.floor(Math.abs(value[2]) * 250) + 1) * 252 * 252
95-
) * (value[3] ? -1 : 1);
96-
}
97-
9877
/**
9978
* Create and style the data needed to render the markers.
10079
*
@@ -195,7 +174,7 @@ var webgl_markerFeature = function (arg) {
195174
((Math.sign(styleVal.radiusIncludesStroke !== undefined && styleVal.radiusIncludesStroke ? styleVal.strokeOffset : 1) + 1) * 16) +
196175
styleVal.symbol * 64);
197176
if (styleVal.symbolValue && styleVal.symbol >= markerFeature.symbols.arrow && styleVal.symbol < markerFeature.symbols.arrow + markerFeature.symbols.arrowMax) {
198-
styleVal.symbolValue = packFloats(styleVal.symbolValue);
177+
styleVal.symbolValue = util.packFloats(styleVal.symbolValue);
199178
}
200179
for (j = 0; j < vpf; j += 1, ivpf += 1, ivpf3 += 3) {
201180
if (!onlyStyle) {

src/webgl/markerFeatureFS.glsl

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -256,14 +256,42 @@ vec2 rotationalSymmetry(vec2 pos, int repetitions) {
256256
return vec2(cos(ang), sin(ang)) * length(pos);
257257
}
258258

259-
void markerFeatureFragment(vec2 pos) {
259+
float markerFeatureFragment(vec3 posAndSpacing) {
260+
vec2 pos = posAndSpacing.xy;
261+
float spacing = posAndSpacing.z;
262+
// square lattice
263+
if (spacing > 0.0) {
264+
pos.x = mod(pos.x + spacing * 0.5, spacing) - spacing * 0.5;
265+
pos.y = mod(pos.y + spacing * 0.5, spacing) - spacing * 0.5;
266+
}
267+
// triangular lattice
268+
if (spacing < 0.0) {
269+
spacing = spacing * -1.0;
270+
float cz = (2.0 * pos.y) / (sqrt(3.0) * spacing);
271+
float cx = pos.x / spacing - 0.5 * cz;
272+
float cy = -cx - cz;
273+
float rx = floor(cx + 0.5);
274+
float ry = floor(cy + 0.5);
275+
float rz = floor(cz + 0.5);
276+
float dx = abs(rx - cx);
277+
float dy = abs(ry - cy);
278+
float dz = abs(rz - cz);
279+
if (dx > dy && dx > dz) {
280+
rx = -ry - rz;
281+
} else if (dy > dz) {
282+
ry = -rx - rz;
283+
} else {
284+
rz = -rx - ry;
285+
}
286+
vec2 center = vec2(spacing * (rx + 0.5 * rz), (sqrt(3.0) * spacing * 0.5) * rz);
287+
pos = pos - center;
288+
}
260289
// rad is a value in pixels from the edge of the symbol where negative is
261290
// inside the shape
262291
float rad = length(pos.xy) - radiusVar;
263292
// never allow points outside of the main radius
264293
if (rad > 0.0) {
265-
discard;
266-
return;
294+
return 0.0;
267295
}
268296
// apply clockwise rotation
269297
if (rotationVar != 0.0) {
@@ -309,8 +337,7 @@ void markerFeatureFragment(vec2 pos) {
309337
}
310338

311339
if (rad >= 0.0) {
312-
discard;
313-
return;
340+
return 0.0;
314341
}
315342
// If there is no stroke, the fill region should transition to nothing
316343
if (strokeColorVar.a == 0.0 || strokeWidthVar <= 0.0) {
@@ -326,13 +353,19 @@ void markerFeatureFragment(vec2 pos) {
326353
} else {
327354
fillColor = fillColorVar;
328355
}
356+
float alpha = 1.0;
329357
if (rad <= endStep) {
330358
float step = smoothstep(endStep - antialiasDist, endStep, rad);
331359
vec4 color = mix(fillColor, strokeColor, step);
332360
float step2 = smoothstep(-antialiasDist, 0.0, rad);
333361
gl_FragColor = mix(color, vec4(color.rgb, 0.0), step2);
362+
if (color.a > 0.0)
363+
alpha = gl_FragColor.a / color.a;
334364
} else {
335365
float step = smoothstep(-antialiasDist, 0.0, rad);
336366
gl_FragColor = mix(strokeColor, vec4(strokeColor.rgb, 0.0), step);
367+
if (strokeColor.a > 0.0)
368+
alpha = gl_FragColor.a / strokeColor.a;
337369
}
370+
return alpha;
338371
}

src/webgl/markerFeaturePoly.frag

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@ varying vec2 unitVar; // distinct for square/triangle
77
void main() {
88
if (fillColorVar.a == 0.0 && strokeColorVar.a == 0.0)
99
discard;
10-
markerFeatureFragment(unitVar);
10+
if (markerFeatureFragment(vec3(unitVar, 0.0)) == 0.0)
11+
discard;
1112
}

src/webgl/markerFeatureSprite.frag

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ void main(void) {
1010
discard;
1111
// for sprites, convert the position to [-radius,radius],[-radius,radius]
1212
vec2 pos = (gl_PointCoord.xy - 0.5) * 2.0 * radiusVar;
13-
markerFeatureFragment(pos);
13+
if (markerFeatureFragment(vec3(pos, 0.0)) == 0.0)
14+
discard;
1415
}

0 commit comments

Comments
 (0)