mapshaper 0.6.32 → 0.6.34
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.
- package/mapshaper.js +76 -19
- package/package.json +1 -1
- package/www/mapshaper-gui.js +17 -10
- package/www/mapshaper.js +76 -19
package/mapshaper.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
(function () {
|
|
2
2
|
|
|
3
|
-
var VERSION = "0.6.
|
|
3
|
+
var VERSION = "0.6.34";
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
var utils = /*#__PURE__*/Object.freeze({
|
|
@@ -11665,8 +11665,16 @@
|
|
|
11665
11665
|
}
|
|
11666
11666
|
cands.forEach(function(cand) {
|
|
11667
11667
|
var p = getTestPoint(cand.ids);
|
|
11668
|
-
var isEnclosed = b.containsPoint(p[0], p[1]) &&
|
|
11669
|
-
|
|
11668
|
+
var isEnclosed = b.containsPoint(p[0], p[1]) &&
|
|
11669
|
+
// added a bounds-in-bounds test to handle a case where the test point
|
|
11670
|
+
// fell along the shared boundary of two rings, but the rings did no overlap
|
|
11671
|
+
// (this gave a false positive for the enclosure test)
|
|
11672
|
+
// (for speed, the midpoint of an arc is used as the test point; this
|
|
11673
|
+
// works well in the typical case where rings to not share an edge.
|
|
11674
|
+
// Finding an internal test point would be better, we just need a fast
|
|
11675
|
+
// function to find internal points)
|
|
11676
|
+
b.contains(cand.bounds) &&
|
|
11677
|
+
(index ? index.pointInPolygon(p[0], p[1]) : geom.testPointInRing(p[0], p[1], pathIds, arcs));
|
|
11670
11678
|
if (isEnclosed) {
|
|
11671
11679
|
paths.push(cand.ids);
|
|
11672
11680
|
}
|
|
@@ -11674,6 +11682,7 @@
|
|
|
11674
11682
|
return paths.length > 0 ? paths : null;
|
|
11675
11683
|
};
|
|
11676
11684
|
|
|
11685
|
+
// return array of indexed paths within a given shape
|
|
11677
11686
|
this.findPathsInsideShape = function(shape) {
|
|
11678
11687
|
var paths = []; // list of enclosed paths
|
|
11679
11688
|
shape.forEach(function(ids) {
|
|
@@ -12075,7 +12084,6 @@
|
|
|
12075
12084
|
yy = coords.yy,
|
|
12076
12085
|
ids = nodes.getConnectedArcs(fromArcId),
|
|
12077
12086
|
toArcId = fromArcId; // initialize to fromArcId -- an error condition
|
|
12078
|
-
|
|
12079
12087
|
if (filter) {
|
|
12080
12088
|
ids = ids.filter(filter);
|
|
12081
12089
|
}
|
|
@@ -12104,14 +12112,12 @@
|
|
|
12104
12112
|
continue;
|
|
12105
12113
|
}
|
|
12106
12114
|
icand = arcs.indexOfVertex(candId, -2);
|
|
12107
|
-
|
|
12108
12115
|
if (toArcId == fromArcId) {
|
|
12109
12116
|
// first valid candidate
|
|
12110
12117
|
ito = icand;
|
|
12111
12118
|
toArcId = candId;
|
|
12112
12119
|
continue;
|
|
12113
12120
|
}
|
|
12114
|
-
|
|
12115
12121
|
code = chooseRighthandPath(fromX, fromY, nodeX, nodeY, xx[ito], yy[ito], xx[icand], yy[icand]);
|
|
12116
12122
|
if (code == 2) {
|
|
12117
12123
|
ito = icand;
|
|
@@ -12119,6 +12125,7 @@
|
|
|
12119
12125
|
}
|
|
12120
12126
|
}
|
|
12121
12127
|
|
|
12128
|
+
|
|
12122
12129
|
if (toArcId == fromArcId) {
|
|
12123
12130
|
// This shouldn't occur, assuming that other arcs are present
|
|
12124
12131
|
error("Pathfinder error");
|
|
@@ -12183,6 +12190,9 @@
|
|
|
12183
12190
|
chooseRighthandVector: chooseRighthandVector
|
|
12184
12191
|
});
|
|
12185
12192
|
|
|
12193
|
+
var FWD_USED = 0x8;
|
|
12194
|
+
var REV_USED = 0x80;
|
|
12195
|
+
|
|
12186
12196
|
function setBits(bits, arcBits, mask) {
|
|
12187
12197
|
return (bits & ~mask) | (arcBits & mask);
|
|
12188
12198
|
}
|
|
@@ -12210,6 +12220,16 @@
|
|
|
12210
12220
|
return bits & 7;
|
|
12211
12221
|
}
|
|
12212
12222
|
|
|
12223
|
+
function markPathsAsUsed(paths, routesArr) {
|
|
12224
|
+
forEachArcId(paths, function(arcId) {
|
|
12225
|
+
if (arcId < 0) {
|
|
12226
|
+
routesArr[~arcId] |= REV_USED;
|
|
12227
|
+
} else {
|
|
12228
|
+
routesArr[arcId] |= FWD_USED;
|
|
12229
|
+
}
|
|
12230
|
+
});
|
|
12231
|
+
}
|
|
12232
|
+
|
|
12213
12233
|
// Open arc pathways in a single shape or array of shapes
|
|
12214
12234
|
//
|
|
12215
12235
|
function openArcRoutes(paths, arcColl, routesArr, fwd, rev, dissolve, orBits) {
|
|
@@ -12400,6 +12420,7 @@
|
|
|
12400
12420
|
andBits: andBits,
|
|
12401
12421
|
setRouteBits: setRouteBits,
|
|
12402
12422
|
getRouteBits: getRouteBits,
|
|
12423
|
+
markPathsAsUsed: markPathsAsUsed,
|
|
12403
12424
|
openArcRoutes: openArcRoutes,
|
|
12404
12425
|
closeArcRoutes: closeArcRoutes,
|
|
12405
12426
|
getPathFinder: getPathFinder,
|
|
@@ -18192,6 +18213,7 @@
|
|
|
18192
18213
|
dy: 'measure',
|
|
18193
18214
|
fill: 'color',
|
|
18194
18215
|
'fill-pattern': 'pattern',
|
|
18216
|
+
'fill-effect': null, // todo: validate effect names
|
|
18195
18217
|
'font-family': null,
|
|
18196
18218
|
'font-size': null,
|
|
18197
18219
|
'font-style': null,
|
|
@@ -18240,7 +18262,7 @@
|
|
|
18240
18262
|
var commonProperties = 'css,class,opacity,stroke,stroke-width,stroke-dasharray,stroke-opacity,fill-opacity,vector-effect'.split(',');
|
|
18241
18263
|
|
|
18242
18264
|
var propertiesBySymbolType = {
|
|
18243
|
-
polygon: utils.arrayToIndex(commonProperties.concat('fill', 'fill-pattern')),
|
|
18265
|
+
polygon: utils.arrayToIndex(commonProperties.concat('fill', 'fill-pattern', 'fill-effect')),
|
|
18244
18266
|
polyline: utils.arrayToIndex(commonProperties.concat('stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit')),
|
|
18245
18267
|
point: utils.arrayToIndex(commonProperties.concat('fill', 'r')),
|
|
18246
18268
|
label: utils.arrayToIndex(commonProperties.concat(
|
|
@@ -19125,6 +19147,9 @@
|
|
|
19125
19147
|
if (obj.tag == 'path' && obj.properties['fill-pattern']) {
|
|
19126
19148
|
convertFillPattern(obj.properties, defs);
|
|
19127
19149
|
}
|
|
19150
|
+
if (obj.tag == 'path' && obj.properties['fill-effect'] == 'sphere') {
|
|
19151
|
+
convertSphereEffect(obj.properties, defs);
|
|
19152
|
+
}
|
|
19128
19153
|
if (obj.tag == 'image') {
|
|
19129
19154
|
if (/\.svg/.test(obj.properties.href || '')) {
|
|
19130
19155
|
convertSvgImage(obj, defs);
|
|
@@ -19135,6 +19160,25 @@
|
|
|
19135
19160
|
}
|
|
19136
19161
|
}
|
|
19137
19162
|
|
|
19163
|
+
function convertSphereEffect(obj, defs) {
|
|
19164
|
+
var id = 'mapshaper_sphere_effect';
|
|
19165
|
+
var href = `url(#${ id })`;
|
|
19166
|
+
var svg =
|
|
19167
|
+
`<radialGradient id="${id}" cx="0.5" cy="0.5" r=".56" fx="0.4" fy="0.35">
|
|
19168
|
+
<stop offset=".35" stop-opacity="0"/>
|
|
19169
|
+
<stop offset=".65" stop-opacity="0.1" />
|
|
19170
|
+
<stop offset=".85" stop-opacity="0.45" />
|
|
19171
|
+
<stop offset=".95" stop-opacity="1" />
|
|
19172
|
+
</radialGradient>` ;
|
|
19173
|
+
if (!utils.find(defs, function(o) { return o.id == id; })) {
|
|
19174
|
+
defs.push({svg, id, href});
|
|
19175
|
+
}
|
|
19176
|
+
obj.fill = href;
|
|
19177
|
+
if ('opacity' in obj === false && 'fill-opacity' in obj === false) {
|
|
19178
|
+
obj['fill-opacity'] = 0.35;
|
|
19179
|
+
}
|
|
19180
|
+
}
|
|
19181
|
+
|
|
19138
19182
|
function convertSvgImage(obj, defs) {
|
|
19139
19183
|
// Same-origin policy prevents embedding images in the web UI
|
|
19140
19184
|
var href = obj.properties.href;
|
|
@@ -23896,7 +23940,9 @@ ${svg}
|
|
|
23896
23940
|
.option('polygon', {
|
|
23897
23941
|
describe: 'create a polygon to match the outline of the graticule',
|
|
23898
23942
|
type: 'flag'
|
|
23899
|
-
})
|
|
23943
|
+
})
|
|
23944
|
+
.option('name', nameOpt);
|
|
23945
|
+
|
|
23900
23946
|
|
|
23901
23947
|
parser.command('grid')
|
|
23902
23948
|
.describe('create a grid of square or hexagonal polygons')
|
|
@@ -24426,6 +24472,9 @@ ${svg}
|
|
|
24426
24472
|
.option('fill-pattern', {
|
|
24427
24473
|
describe: 'pattern fill, ex: "hatches 2px grey 2px blue"'
|
|
24428
24474
|
})
|
|
24475
|
+
.option('fill-effect', {
|
|
24476
|
+
describe: 'use "sphere" on a circle for a 3d globe effect'
|
|
24477
|
+
})
|
|
24429
24478
|
.option('fill-opacity', {
|
|
24430
24479
|
describe: 'fill opacity'
|
|
24431
24480
|
})
|
|
@@ -33401,7 +33450,7 @@ ${svg}
|
|
|
33401
33450
|
var clipArcTouches = 0;
|
|
33402
33451
|
var clipArcUses = 0;
|
|
33403
33452
|
var usedClipArcs = [];
|
|
33404
|
-
var
|
|
33453
|
+
var findPath = getPathFinder(nodes, useRoute, routeIsActive);
|
|
33405
33454
|
var dissolvePolygon = getPolygonDissolver(nodes);
|
|
33406
33455
|
|
|
33407
33456
|
// The following cleanup step is a performance bottleneck (it often takes longer than
|
|
@@ -33434,12 +33483,16 @@ ${svg}
|
|
|
33434
33483
|
return null;
|
|
33435
33484
|
});
|
|
33436
33485
|
|
|
33486
|
+
markPathsAsUsed(clippedShapes, routeFlags); // to help us find unused paths later
|
|
33487
|
+
|
|
33488
|
+
|
|
33437
33489
|
// add clip/erase polygons that are fully contained in a target polygon
|
|
33438
33490
|
// need to index only non-intersecting clip shapes
|
|
33439
33491
|
// (Intersecting shapes have one or more arcs that have been scanned)
|
|
33440
33492
|
|
|
33441
33493
|
// first, find shapes that do not intersect the target layer
|
|
33442
33494
|
// (these could be inside or outside the target polygons)
|
|
33495
|
+
|
|
33443
33496
|
var undividedClipShapes = findUndividedClipShapes(clipShapes);
|
|
33444
33497
|
|
|
33445
33498
|
closeArcRoutes(clipShapes, arcs, routeFlags, true, true); // not needed?
|
|
@@ -33468,7 +33521,7 @@ ${svg}
|
|
|
33468
33521
|
for (var i=0, n=ids.length; i<n; i++) {
|
|
33469
33522
|
clipArcTouches = 0;
|
|
33470
33523
|
clipArcUses = 0;
|
|
33471
|
-
path =
|
|
33524
|
+
path = findPath(ids[i]);
|
|
33472
33525
|
if (path) {
|
|
33473
33526
|
// if ring doesn't touch/intersect a clip/erase polygon, check if it is contained
|
|
33474
33527
|
// if (clipArcTouches === 0) {
|
|
@@ -33487,6 +33540,7 @@ ${svg}
|
|
|
33487
33540
|
}
|
|
33488
33541
|
});
|
|
33489
33542
|
|
|
33543
|
+
|
|
33490
33544
|
// Clear pathways of current target shape to hidden/closed
|
|
33491
33545
|
closeArcRoutes(shape, arcs, routeFlags, true, true, true);
|
|
33492
33546
|
// Also clear pathways of any clip arcs that were used
|
|
@@ -33557,8 +33611,9 @@ ${svg}
|
|
|
33557
33611
|
return usable;
|
|
33558
33612
|
}
|
|
33559
33613
|
|
|
33560
|
-
|
|
33561
|
-
//
|
|
33614
|
+
|
|
33615
|
+
// Filter a collection of shapes to exclude paths that incorporate parts of
|
|
33616
|
+
// clip/erase polygons and paths that are hidden (e.g. internal boundaries)
|
|
33562
33617
|
function findUndividedClipShapes(clipShapes) {
|
|
33563
33618
|
return clipShapes.map(function(shape) {
|
|
33564
33619
|
var usableParts = [];
|
|
@@ -33582,12 +33637,12 @@ ${svg}
|
|
|
33582
33637
|
});
|
|
33583
33638
|
}
|
|
33584
33639
|
|
|
33585
|
-
|
|
33586
|
-
// (not testing open/closed or visible/hidden)
|
|
33640
|
+
|
|
33587
33641
|
function arcIsUnused(id, flags) {
|
|
33588
33642
|
var abs = absArcId(id),
|
|
33589
33643
|
flag = flags[abs];
|
|
33590
|
-
return (flag &
|
|
33644
|
+
return (flag & 0x88) === 0;
|
|
33645
|
+
// return id < 0 ? (flag & 0x80) === 0 : (flag & 0x8) === 0;
|
|
33591
33646
|
}
|
|
33592
33647
|
|
|
33593
33648
|
function arcIsVisible(id, flags) {
|
|
@@ -33610,7 +33665,7 @@ ${svg}
|
|
|
33610
33665
|
enclosedPaths.forEach(function(ids) {
|
|
33611
33666
|
var path;
|
|
33612
33667
|
for (var j=0; j<ids.length; j++) {
|
|
33613
|
-
path =
|
|
33668
|
+
path = findPath(ids[j]);
|
|
33614
33669
|
if (path) {
|
|
33615
33670
|
dissolvedPaths.push(path);
|
|
33616
33671
|
}
|
|
@@ -37902,7 +37957,8 @@ ${svg}
|
|
|
37902
37957
|
return {
|
|
37903
37958
|
gnom: 60,
|
|
37904
37959
|
laea: 179,
|
|
37905
|
-
ortho: 89.9, //
|
|
37960
|
+
//ortho: 89.9, // projection errors betwen lat +/-35 to 55
|
|
37961
|
+
ortho: 89.85, // TODO: investigate
|
|
37906
37962
|
stere: 142,
|
|
37907
37963
|
sterea: 142,
|
|
37908
37964
|
ups: 10.5 // TODO: should be 6.5 deg at north pole
|
|
@@ -38281,7 +38337,7 @@ ${svg}
|
|
|
38281
38337
|
});
|
|
38282
38338
|
|
|
38283
38339
|
cmd.graticule = function(dataset, opts) {
|
|
38284
|
-
var name = opts.polygon
|
|
38340
|
+
var name = opts.name || opts.polygon && 'polygon' || 'graticule';
|
|
38285
38341
|
var graticule, destInfo;
|
|
38286
38342
|
if (dataset && !isLatLngDataset(dataset)) {
|
|
38287
38343
|
// project graticule to match dataset
|
|
@@ -38347,7 +38403,7 @@ ${svg}
|
|
|
38347
38403
|
//
|
|
38348
38404
|
function createGraticule(P, outlined, opts) {
|
|
38349
38405
|
var interval = opts.interval || 10;
|
|
38350
|
-
if (![5,10,15,30,45].includes(interval)) stop('Invalid interval:', interval);
|
|
38406
|
+
if (![5,10,15,20,30,45].includes(interval)) stop('Invalid interval:', interval);
|
|
38351
38407
|
P.lam0 * 180 / Math.PI;
|
|
38352
38408
|
var precision = interval > 10 ? 1 : 0.5; // degrees between each vertex
|
|
38353
38409
|
var xstep = interval;
|
|
@@ -40935,6 +40991,7 @@ ${svg}
|
|
|
40935
40991
|
}
|
|
40936
40992
|
commandStr = runGlobalExpression(opts.expression, targets);
|
|
40937
40993
|
if (commandStr) {
|
|
40994
|
+
message(`command: [${commandStr}]`);
|
|
40938
40995
|
commands = parseCommands(commandStr);
|
|
40939
40996
|
runParsedCommands(commands, job, cb);
|
|
40940
40997
|
} else {
|
package/package.json
CHANGED
package/www/mapshaper-gui.js
CHANGED
|
@@ -4038,8 +4038,11 @@
|
|
|
4038
4038
|
}
|
|
4039
4039
|
|
|
4040
4040
|
function updateMenuBtn() {
|
|
4041
|
-
var
|
|
4042
|
-
|
|
4041
|
+
var lyrName = model.getActiveLayer().layer.name || '';
|
|
4042
|
+
var menuTitle = lyrName || '[unnamed layer]';
|
|
4043
|
+
var pageTitle = lyrName || 'mapshaper';
|
|
4044
|
+
btn.classed('active', 'true').findChild('.layer-name').html(menuTitle + " ▼");
|
|
4045
|
+
window.document.title = pageTitle;
|
|
4043
4046
|
}
|
|
4044
4047
|
|
|
4045
4048
|
function render() {
|
|
@@ -10172,12 +10175,12 @@
|
|
|
10172
10175
|
return action == 'hover' && _overlayCanv.visible();
|
|
10173
10176
|
}
|
|
10174
10177
|
|
|
10175
|
-
function drawCanvasLayer(
|
|
10176
|
-
if (!
|
|
10177
|
-
if (
|
|
10178
|
-
drawOutlineLayerToCanvas(
|
|
10178
|
+
function drawCanvasLayer(lyr, canv) {
|
|
10179
|
+
if (!lyr) return;
|
|
10180
|
+
if (lyr.style.type == 'outline') {
|
|
10181
|
+
drawOutlineLayerToCanvas(lyr, canv, ext);
|
|
10179
10182
|
} else {
|
|
10180
|
-
drawStyledLayerToCanvas(
|
|
10183
|
+
drawStyledLayerToCanvas(lyr, canv, ext);
|
|
10181
10184
|
}
|
|
10182
10185
|
}
|
|
10183
10186
|
|
|
@@ -11039,7 +11042,9 @@
|
|
|
11039
11042
|
} else {
|
|
11040
11043
|
_overlayLyr = null;
|
|
11041
11044
|
}
|
|
11042
|
-
|
|
11045
|
+
// 'hover' bypasses style creation in drawLayers2()... sometimes we need that
|
|
11046
|
+
// drawLayers('hover');
|
|
11047
|
+
drawLayers();
|
|
11043
11048
|
}
|
|
11044
11049
|
|
|
11045
11050
|
function getDisplayOptions() {
|
|
@@ -11054,12 +11059,14 @@
|
|
|
11054
11059
|
return flags.simplify_method || flags.simplify || flags.proj ||
|
|
11055
11060
|
flags.arc_count || flags.repair || flags.clip || flags.erase ||
|
|
11056
11061
|
flags.slice || flags.affine || flags.rectangle || flags.buffer ||
|
|
11057
|
-
flags.union || flags.mosaic || flags.snap || flags.clean || false;
|
|
11062
|
+
flags.union || flags.mosaic || flags.snap || flags.clean || flags.drop || false;
|
|
11058
11063
|
}
|
|
11059
11064
|
|
|
11060
11065
|
// Test if an update allows hover popup to stay open
|
|
11061
11066
|
function popupCanStayOpen(flags) {
|
|
11062
|
-
//
|
|
11067
|
+
// keeping popup open after -drop geometry causes problems...
|
|
11068
|
+
// // if (arcsMayHaveChanged(flags)) return false;
|
|
11069
|
+
if (arcsMayHaveChanged(flags)) return false;
|
|
11063
11070
|
if (flags.points || flags.proj) return false;
|
|
11064
11071
|
if (!flags.same_table) return false;
|
|
11065
11072
|
return true;
|
package/www/mapshaper.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
(function () {
|
|
2
2
|
|
|
3
|
-
var VERSION = "0.6.
|
|
3
|
+
var VERSION = "0.6.34";
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
var utils = /*#__PURE__*/Object.freeze({
|
|
@@ -11665,8 +11665,16 @@
|
|
|
11665
11665
|
}
|
|
11666
11666
|
cands.forEach(function(cand) {
|
|
11667
11667
|
var p = getTestPoint(cand.ids);
|
|
11668
|
-
var isEnclosed = b.containsPoint(p[0], p[1]) &&
|
|
11669
|
-
|
|
11668
|
+
var isEnclosed = b.containsPoint(p[0], p[1]) &&
|
|
11669
|
+
// added a bounds-in-bounds test to handle a case where the test point
|
|
11670
|
+
// fell along the shared boundary of two rings, but the rings did no overlap
|
|
11671
|
+
// (this gave a false positive for the enclosure test)
|
|
11672
|
+
// (for speed, the midpoint of an arc is used as the test point; this
|
|
11673
|
+
// works well in the typical case where rings to not share an edge.
|
|
11674
|
+
// Finding an internal test point would be better, we just need a fast
|
|
11675
|
+
// function to find internal points)
|
|
11676
|
+
b.contains(cand.bounds) &&
|
|
11677
|
+
(index ? index.pointInPolygon(p[0], p[1]) : geom.testPointInRing(p[0], p[1], pathIds, arcs));
|
|
11670
11678
|
if (isEnclosed) {
|
|
11671
11679
|
paths.push(cand.ids);
|
|
11672
11680
|
}
|
|
@@ -11674,6 +11682,7 @@
|
|
|
11674
11682
|
return paths.length > 0 ? paths : null;
|
|
11675
11683
|
};
|
|
11676
11684
|
|
|
11685
|
+
// return array of indexed paths within a given shape
|
|
11677
11686
|
this.findPathsInsideShape = function(shape) {
|
|
11678
11687
|
var paths = []; // list of enclosed paths
|
|
11679
11688
|
shape.forEach(function(ids) {
|
|
@@ -12075,7 +12084,6 @@
|
|
|
12075
12084
|
yy = coords.yy,
|
|
12076
12085
|
ids = nodes.getConnectedArcs(fromArcId),
|
|
12077
12086
|
toArcId = fromArcId; // initialize to fromArcId -- an error condition
|
|
12078
|
-
|
|
12079
12087
|
if (filter) {
|
|
12080
12088
|
ids = ids.filter(filter);
|
|
12081
12089
|
}
|
|
@@ -12104,14 +12112,12 @@
|
|
|
12104
12112
|
continue;
|
|
12105
12113
|
}
|
|
12106
12114
|
icand = arcs.indexOfVertex(candId, -2);
|
|
12107
|
-
|
|
12108
12115
|
if (toArcId == fromArcId) {
|
|
12109
12116
|
// first valid candidate
|
|
12110
12117
|
ito = icand;
|
|
12111
12118
|
toArcId = candId;
|
|
12112
12119
|
continue;
|
|
12113
12120
|
}
|
|
12114
|
-
|
|
12115
12121
|
code = chooseRighthandPath(fromX, fromY, nodeX, nodeY, xx[ito], yy[ito], xx[icand], yy[icand]);
|
|
12116
12122
|
if (code == 2) {
|
|
12117
12123
|
ito = icand;
|
|
@@ -12119,6 +12125,7 @@
|
|
|
12119
12125
|
}
|
|
12120
12126
|
}
|
|
12121
12127
|
|
|
12128
|
+
|
|
12122
12129
|
if (toArcId == fromArcId) {
|
|
12123
12130
|
// This shouldn't occur, assuming that other arcs are present
|
|
12124
12131
|
error("Pathfinder error");
|
|
@@ -12183,6 +12190,9 @@
|
|
|
12183
12190
|
chooseRighthandVector: chooseRighthandVector
|
|
12184
12191
|
});
|
|
12185
12192
|
|
|
12193
|
+
var FWD_USED = 0x8;
|
|
12194
|
+
var REV_USED = 0x80;
|
|
12195
|
+
|
|
12186
12196
|
function setBits(bits, arcBits, mask) {
|
|
12187
12197
|
return (bits & ~mask) | (arcBits & mask);
|
|
12188
12198
|
}
|
|
@@ -12210,6 +12220,16 @@
|
|
|
12210
12220
|
return bits & 7;
|
|
12211
12221
|
}
|
|
12212
12222
|
|
|
12223
|
+
function markPathsAsUsed(paths, routesArr) {
|
|
12224
|
+
forEachArcId(paths, function(arcId) {
|
|
12225
|
+
if (arcId < 0) {
|
|
12226
|
+
routesArr[~arcId] |= REV_USED;
|
|
12227
|
+
} else {
|
|
12228
|
+
routesArr[arcId] |= FWD_USED;
|
|
12229
|
+
}
|
|
12230
|
+
});
|
|
12231
|
+
}
|
|
12232
|
+
|
|
12213
12233
|
// Open arc pathways in a single shape or array of shapes
|
|
12214
12234
|
//
|
|
12215
12235
|
function openArcRoutes(paths, arcColl, routesArr, fwd, rev, dissolve, orBits) {
|
|
@@ -12400,6 +12420,7 @@
|
|
|
12400
12420
|
andBits: andBits,
|
|
12401
12421
|
setRouteBits: setRouteBits,
|
|
12402
12422
|
getRouteBits: getRouteBits,
|
|
12423
|
+
markPathsAsUsed: markPathsAsUsed,
|
|
12403
12424
|
openArcRoutes: openArcRoutes,
|
|
12404
12425
|
closeArcRoutes: closeArcRoutes,
|
|
12405
12426
|
getPathFinder: getPathFinder,
|
|
@@ -18192,6 +18213,7 @@
|
|
|
18192
18213
|
dy: 'measure',
|
|
18193
18214
|
fill: 'color',
|
|
18194
18215
|
'fill-pattern': 'pattern',
|
|
18216
|
+
'fill-effect': null, // todo: validate effect names
|
|
18195
18217
|
'font-family': null,
|
|
18196
18218
|
'font-size': null,
|
|
18197
18219
|
'font-style': null,
|
|
@@ -18240,7 +18262,7 @@
|
|
|
18240
18262
|
var commonProperties = 'css,class,opacity,stroke,stroke-width,stroke-dasharray,stroke-opacity,fill-opacity,vector-effect'.split(',');
|
|
18241
18263
|
|
|
18242
18264
|
var propertiesBySymbolType = {
|
|
18243
|
-
polygon: utils.arrayToIndex(commonProperties.concat('fill', 'fill-pattern')),
|
|
18265
|
+
polygon: utils.arrayToIndex(commonProperties.concat('fill', 'fill-pattern', 'fill-effect')),
|
|
18244
18266
|
polyline: utils.arrayToIndex(commonProperties.concat('stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit')),
|
|
18245
18267
|
point: utils.arrayToIndex(commonProperties.concat('fill', 'r')),
|
|
18246
18268
|
label: utils.arrayToIndex(commonProperties.concat(
|
|
@@ -19125,6 +19147,9 @@
|
|
|
19125
19147
|
if (obj.tag == 'path' && obj.properties['fill-pattern']) {
|
|
19126
19148
|
convertFillPattern(obj.properties, defs);
|
|
19127
19149
|
}
|
|
19150
|
+
if (obj.tag == 'path' && obj.properties['fill-effect'] == 'sphere') {
|
|
19151
|
+
convertSphereEffect(obj.properties, defs);
|
|
19152
|
+
}
|
|
19128
19153
|
if (obj.tag == 'image') {
|
|
19129
19154
|
if (/\.svg/.test(obj.properties.href || '')) {
|
|
19130
19155
|
convertSvgImage(obj, defs);
|
|
@@ -19135,6 +19160,25 @@
|
|
|
19135
19160
|
}
|
|
19136
19161
|
}
|
|
19137
19162
|
|
|
19163
|
+
function convertSphereEffect(obj, defs) {
|
|
19164
|
+
var id = 'mapshaper_sphere_effect';
|
|
19165
|
+
var href = `url(#${ id })`;
|
|
19166
|
+
var svg =
|
|
19167
|
+
`<radialGradient id="${id}" cx="0.5" cy="0.5" r=".56" fx="0.4" fy="0.35">
|
|
19168
|
+
<stop offset=".35" stop-opacity="0"/>
|
|
19169
|
+
<stop offset=".65" stop-opacity="0.1" />
|
|
19170
|
+
<stop offset=".85" stop-opacity="0.45" />
|
|
19171
|
+
<stop offset=".95" stop-opacity="1" />
|
|
19172
|
+
</radialGradient>` ;
|
|
19173
|
+
if (!utils.find(defs, function(o) { return o.id == id; })) {
|
|
19174
|
+
defs.push({svg, id, href});
|
|
19175
|
+
}
|
|
19176
|
+
obj.fill = href;
|
|
19177
|
+
if ('opacity' in obj === false && 'fill-opacity' in obj === false) {
|
|
19178
|
+
obj['fill-opacity'] = 0.35;
|
|
19179
|
+
}
|
|
19180
|
+
}
|
|
19181
|
+
|
|
19138
19182
|
function convertSvgImage(obj, defs) {
|
|
19139
19183
|
// Same-origin policy prevents embedding images in the web UI
|
|
19140
19184
|
var href = obj.properties.href;
|
|
@@ -23896,7 +23940,9 @@ ${svg}
|
|
|
23896
23940
|
.option('polygon', {
|
|
23897
23941
|
describe: 'create a polygon to match the outline of the graticule',
|
|
23898
23942
|
type: 'flag'
|
|
23899
|
-
})
|
|
23943
|
+
})
|
|
23944
|
+
.option('name', nameOpt);
|
|
23945
|
+
|
|
23900
23946
|
|
|
23901
23947
|
parser.command('grid')
|
|
23902
23948
|
.describe('create a grid of square or hexagonal polygons')
|
|
@@ -24426,6 +24472,9 @@ ${svg}
|
|
|
24426
24472
|
.option('fill-pattern', {
|
|
24427
24473
|
describe: 'pattern fill, ex: "hatches 2px grey 2px blue"'
|
|
24428
24474
|
})
|
|
24475
|
+
.option('fill-effect', {
|
|
24476
|
+
describe: 'use "sphere" on a circle for a 3d globe effect'
|
|
24477
|
+
})
|
|
24429
24478
|
.option('fill-opacity', {
|
|
24430
24479
|
describe: 'fill opacity'
|
|
24431
24480
|
})
|
|
@@ -33401,7 +33450,7 @@ ${svg}
|
|
|
33401
33450
|
var clipArcTouches = 0;
|
|
33402
33451
|
var clipArcUses = 0;
|
|
33403
33452
|
var usedClipArcs = [];
|
|
33404
|
-
var
|
|
33453
|
+
var findPath = getPathFinder(nodes, useRoute, routeIsActive);
|
|
33405
33454
|
var dissolvePolygon = getPolygonDissolver(nodes);
|
|
33406
33455
|
|
|
33407
33456
|
// The following cleanup step is a performance bottleneck (it often takes longer than
|
|
@@ -33434,12 +33483,16 @@ ${svg}
|
|
|
33434
33483
|
return null;
|
|
33435
33484
|
});
|
|
33436
33485
|
|
|
33486
|
+
markPathsAsUsed(clippedShapes, routeFlags); // to help us find unused paths later
|
|
33487
|
+
|
|
33488
|
+
|
|
33437
33489
|
// add clip/erase polygons that are fully contained in a target polygon
|
|
33438
33490
|
// need to index only non-intersecting clip shapes
|
|
33439
33491
|
// (Intersecting shapes have one or more arcs that have been scanned)
|
|
33440
33492
|
|
|
33441
33493
|
// first, find shapes that do not intersect the target layer
|
|
33442
33494
|
// (these could be inside or outside the target polygons)
|
|
33495
|
+
|
|
33443
33496
|
var undividedClipShapes = findUndividedClipShapes(clipShapes);
|
|
33444
33497
|
|
|
33445
33498
|
closeArcRoutes(clipShapes, arcs, routeFlags, true, true); // not needed?
|
|
@@ -33468,7 +33521,7 @@ ${svg}
|
|
|
33468
33521
|
for (var i=0, n=ids.length; i<n; i++) {
|
|
33469
33522
|
clipArcTouches = 0;
|
|
33470
33523
|
clipArcUses = 0;
|
|
33471
|
-
path =
|
|
33524
|
+
path = findPath(ids[i]);
|
|
33472
33525
|
if (path) {
|
|
33473
33526
|
// if ring doesn't touch/intersect a clip/erase polygon, check if it is contained
|
|
33474
33527
|
// if (clipArcTouches === 0) {
|
|
@@ -33487,6 +33540,7 @@ ${svg}
|
|
|
33487
33540
|
}
|
|
33488
33541
|
});
|
|
33489
33542
|
|
|
33543
|
+
|
|
33490
33544
|
// Clear pathways of current target shape to hidden/closed
|
|
33491
33545
|
closeArcRoutes(shape, arcs, routeFlags, true, true, true);
|
|
33492
33546
|
// Also clear pathways of any clip arcs that were used
|
|
@@ -33557,8 +33611,9 @@ ${svg}
|
|
|
33557
33611
|
return usable;
|
|
33558
33612
|
}
|
|
33559
33613
|
|
|
33560
|
-
|
|
33561
|
-
//
|
|
33614
|
+
|
|
33615
|
+
// Filter a collection of shapes to exclude paths that incorporate parts of
|
|
33616
|
+
// clip/erase polygons and paths that are hidden (e.g. internal boundaries)
|
|
33562
33617
|
function findUndividedClipShapes(clipShapes) {
|
|
33563
33618
|
return clipShapes.map(function(shape) {
|
|
33564
33619
|
var usableParts = [];
|
|
@@ -33582,12 +33637,12 @@ ${svg}
|
|
|
33582
33637
|
});
|
|
33583
33638
|
}
|
|
33584
33639
|
|
|
33585
|
-
|
|
33586
|
-
// (not testing open/closed or visible/hidden)
|
|
33640
|
+
|
|
33587
33641
|
function arcIsUnused(id, flags) {
|
|
33588
33642
|
var abs = absArcId(id),
|
|
33589
33643
|
flag = flags[abs];
|
|
33590
|
-
return (flag &
|
|
33644
|
+
return (flag & 0x88) === 0;
|
|
33645
|
+
// return id < 0 ? (flag & 0x80) === 0 : (flag & 0x8) === 0;
|
|
33591
33646
|
}
|
|
33592
33647
|
|
|
33593
33648
|
function arcIsVisible(id, flags) {
|
|
@@ -33610,7 +33665,7 @@ ${svg}
|
|
|
33610
33665
|
enclosedPaths.forEach(function(ids) {
|
|
33611
33666
|
var path;
|
|
33612
33667
|
for (var j=0; j<ids.length; j++) {
|
|
33613
|
-
path =
|
|
33668
|
+
path = findPath(ids[j]);
|
|
33614
33669
|
if (path) {
|
|
33615
33670
|
dissolvedPaths.push(path);
|
|
33616
33671
|
}
|
|
@@ -37902,7 +37957,8 @@ ${svg}
|
|
|
37902
37957
|
return {
|
|
37903
37958
|
gnom: 60,
|
|
37904
37959
|
laea: 179,
|
|
37905
|
-
ortho: 89.9, //
|
|
37960
|
+
//ortho: 89.9, // projection errors betwen lat +/-35 to 55
|
|
37961
|
+
ortho: 89.85, // TODO: investigate
|
|
37906
37962
|
stere: 142,
|
|
37907
37963
|
sterea: 142,
|
|
37908
37964
|
ups: 10.5 // TODO: should be 6.5 deg at north pole
|
|
@@ -38281,7 +38337,7 @@ ${svg}
|
|
|
38281
38337
|
});
|
|
38282
38338
|
|
|
38283
38339
|
cmd.graticule = function(dataset, opts) {
|
|
38284
|
-
var name = opts.polygon
|
|
38340
|
+
var name = opts.name || opts.polygon && 'polygon' || 'graticule';
|
|
38285
38341
|
var graticule, destInfo;
|
|
38286
38342
|
if (dataset && !isLatLngDataset(dataset)) {
|
|
38287
38343
|
// project graticule to match dataset
|
|
@@ -38347,7 +38403,7 @@ ${svg}
|
|
|
38347
38403
|
//
|
|
38348
38404
|
function createGraticule(P, outlined, opts) {
|
|
38349
38405
|
var interval = opts.interval || 10;
|
|
38350
|
-
if (![5,10,15,30,45].includes(interval)) stop('Invalid interval:', interval);
|
|
38406
|
+
if (![5,10,15,20,30,45].includes(interval)) stop('Invalid interval:', interval);
|
|
38351
38407
|
P.lam0 * 180 / Math.PI;
|
|
38352
38408
|
var precision = interval > 10 ? 1 : 0.5; // degrees between each vertex
|
|
38353
38409
|
var xstep = interval;
|
|
@@ -40935,6 +40991,7 @@ ${svg}
|
|
|
40935
40991
|
}
|
|
40936
40992
|
commandStr = runGlobalExpression(opts.expression, targets);
|
|
40937
40993
|
if (commandStr) {
|
|
40994
|
+
message(`command: [${commandStr}]`);
|
|
40938
40995
|
commands = parseCommands(commandStr);
|
|
40939
40996
|
runParsedCommands(commands, job, cb);
|
|
40940
40997
|
} else {
|