Skip to content

Commit 09963a5

Browse files
committed
v0.2.2 updates the Visvalingam weighting function
1 parent 4d6a8ba commit 09963a5

5 files changed

Lines changed: 120 additions & 193 deletions

File tree

mapshaper.js

Lines changed: 62 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -3303,9 +3303,9 @@ MapShaper.getOptionParser = function() {
33033303

33043304
// Work-in-progress (no .describe(), so hidden from -h)
33053305
parser.command('tracing');
3306-
/*
33073306
parser.command("flatten")
33083307
.option("target", targetOpt);
3308+
/*
33093309
33103310
parser.command("divide")
33113311
.option("name", nameOpt)
@@ -5497,71 +5497,6 @@ Visvalingam.getArcCalculator = function(metric2D, metric3D, scale) {
54975497
Visvalingam.standardMetric = triangleArea;
54985498
Visvalingam.standardMetric3D = triangleArea3D;
54995499

5500-
// Replacement for original "Modified Visvalingam"
5501-
// Underweight polyline vertices with acute angles in proportion to 1 - cosine
5502-
//
5503-
Visvalingam.weightedMetric = function(ax, ay, bx, by, cx, cy) {
5504-
var area = triangleArea(ax, ay, bx, by, cx, cy);
5505-
return area * Visvalingam.weight(ax, ay, bx, by, cx, cy);
5506-
};
5507-
5508-
Visvalingam.weightedMetric3D = function(ax, ay, az, bx, by, bz, cx, cy, cz) {
5509-
var area = triangleArea3D(ax, ay, az, bx, by, bz, cx, cy, cz),
5510-
cos = cosine3D(ax, ay, az, bx, by, bz, cx, cy, cz),
5511-
weight = cos > 0 ? 1 - cos : 1;
5512-
return area * weight;
5513-
};
5514-
5515-
// deg. weight
5516-
// 180 1
5517-
// 90 1
5518-
// 60
5519-
// 45
5520-
// 0 0
5521-
//
5522-
Visvalingam.weightA = function(cos) {
5523-
return cos > 0 ? 1 - cos : 1;
5524-
};
5525-
5526-
// deg. weight
5527-
// 180 1
5528-
// 90 1
5529-
// 60
5530-
// 45
5531-
// 0 0
5532-
//
5533-
Visvalingam.weightB = function(cos) {
5534-
return cos > 0 ? 1 - cos * cos : 1;
5535-
};
5536-
5537-
Visvalingam.weightC = function(cos) {
5538-
return 0.5 - cos * 0.5;
5539-
};
5540-
5541-
// deg. weight
5542-
// 180 2
5543-
// 90 1
5544-
// 0 0
5545-
//
5546-
Visvalingam.weightD = function(cos) {
5547-
return 1 + -cos;
5548-
};
5549-
5550-
// deg. weight
5551-
// 180 1.5
5552-
// 90 1
5553-
// 0 0.5
5554-
//
5555-
Visvalingam.weightE = function(cos) {
5556-
return -cos * 0.5 + 1;
5557-
};
5558-
5559-
Visvalingam.weightF = function(cos) {
5560-
return -cos * 0.7 + 1;
5561-
};
5562-
5563-
Visvalingam.weight = Visvalingam.weightF;
5564-
55655500
Visvalingam.weightedMetric = function(ax, ay, bx, by, cx, cy) {
55665501
var area = triangleArea(ax, ay, bx, by, cx, cy),
55675502
cos = cosine(ax, ay, bx, by, cx, cy);
@@ -5574,23 +5509,34 @@ Visvalingam.weightedMetric3D = function(ax, ay, az, bx, by, bz, cx, cy, cz) {
55745509
return Visvalingam.weight(cos) * area;
55755510
};
55765511

5577-
// The original "modified Visvalingam" function used a step function to
5512+
// Functions for weighting triangle area
5513+
5514+
// The original Flash-based Mapshaper (ca. 2006) used a step function to
55785515
// underweight more acute triangles.
5579-
/*
5580-
Visvalingam.weightedMetric_v1 = function(ax, ay, bx, by, cx, cy) {
5581-
var area = triangleArea(ax, ay, bx, by, cx, cy),
5582-
angle = innerAngle(ax, ay, bx, by, cx, cy),
5583-
weight = angle < 0.5 ? 0.1 : angle < 1 ? 0.3 : 1;
5584-
return area * weight;
5516+
Visvalingam.weight_v1 = function(cos) {
5517+
var angle = Math.acos(cos),
5518+
weight = 1;
5519+
if (angle < 0.5) {
5520+
weight = 0.1;
5521+
} else if (angle < 1) {
5522+
weight = 0.3;
5523+
}
5524+
return weight;
55855525
};
55865526

5587-
Visvalingam.weightedMetric3D_v1 = function(ax, ay, az, bx, by, bz, cx, cy, cz) {
5588-
var area = triangleArea3D(ax, ay, az, bx, by, bz, cx, cy, cz),
5589-
angle = innerAngle3D(ax, ay, az, bx, by, bz, cx, cy, cz),
5590-
weight = angle < 0.5 ? 0.1 : angle < 1 ? 0.3 : 1;
5591-
return area * weight;
5527+
// v2 weighting: underweight polyline vertices at acute angles in proportion to 1 - cosine
5528+
Visvalingam.weight_v2 = function(cos) {
5529+
return cos > 0 ? 1 - cos : 1;
5530+
};
5531+
5532+
// v3 weighting: weight by inverse cosine
5533+
// Standard weighting favors 90-deg angles; this curve peaks at 120 deg.
5534+
Visvalingam.weight_v3 = function(cos) {
5535+
var k = 0.7;
5536+
return -cos * k + 1;
55925537
};
5593-
*/
5538+
5539+
Visvalingam.weight = Visvalingam.weight_v3;
55945540

55955541

55965542

@@ -7988,7 +7934,6 @@ function PathImporter(reservedPoints, opts) {
79887934
*/
79897935

79907936
// Import coordinates from an array with coordinates in format: [x, y, x, y, ...]
7991-
// (for Shapefile import -- consider moving out of here)
79927937
//
79937938
this.importPathFromFlatArray = function(arr, type) {
79947939
var len = arr.length,
@@ -10429,7 +10374,6 @@ MapShaper.importShp = function(src, opts) {
1042910374
var importer = new PathImporter(pathPoints, opts);
1043010375

1043110376
// TODO: test cases: null shape; non-null shape with no valid parts
10432-
1043310377
reader.forEachShape(function(shp) {
1043410378
importer.startShape();
1043510379
if (shp.isNull) return;
@@ -12754,16 +12698,37 @@ MapShaper.appendHolestoRings = function(cw, ccw) {
1275412698

1275512699

1275612700

12757-
// Remove overlapping polygon shapes
12701+
// Flatten overlapping polygon shapes
1275812702
// (Unfinished)
12759-
/*
12760-
api.flattenLayer = function(lyr, arcs, opts) {
12761-
// MapShaper.divideArcs([lyr], arcs);
12762-
var shapes = MapShaper.flattenShapes(lyr.shapes, arcs);
12763-
var lyr2 = Utils.defaults({shapes: shapes, data: null}, lyr);
12764-
return lyr2;
12703+
api.flattenLayer = function(lyr, dataset, opts) {
12704+
var nodes = MapShaper.divideArcs(dataset);
12705+
var flatten = MapShaper.getPolygonFlattener(nodes);
12706+
var lyr2 = {data: null};
12707+
lyr2.shapes = lyr.shapes.map(flatten);
12708+
// TODO: copy data over
12709+
return Utils.defaults(lyr2, lyr);
12710+
};
12711+
12712+
MapShaper.getPolygonFlattener = function(nodes) {
12713+
var flags = new Uint8Array(nodes.arcs.size());
12714+
var divide = MapShaper.getHoleDivider(nodes, flags);
12715+
var flatten = MapShaper.getRingIntersector(nodes, 'flatten', flags);
12716+
12717+
return function(shp) {
12718+
if (!shp) return null;
12719+
var cw = [],
12720+
ccw = [];
12721+
12722+
divide(shp, cw, ccw);
12723+
cw = flatten(cw);
12724+
ccw.forEach(MapShaper.reversePath);
12725+
ccw = flatten(ccw);
12726+
ccw.forEach(MapShaper.reversePath);
12727+
12728+
var shp2 = MapShaper.appendHolestoRings(cw, ccw);
12729+
return shp2 && shp2.length > 0 ? shp2 : null;
12730+
};
1276512731
};
12766-
*/
1276712732

1276812733

1276912734

@@ -13247,8 +13212,8 @@ api.runCommand = function(cmd, dataset, cb) {
1324713212
} else if (name == 'filter') {
1324813213
MapShaper.applyCommand(api.filterFeatures, targetLayers, arcs, opts.expression);
1324913214

13250-
//} else if (name == 'flatten') {
13251-
// newLayers = MapShaper.applyCommand(api.flattenLayer, targetLayers, arcs, opts);
13215+
} else if (name == 'flatten') {
13216+
newLayers = MapShaper.applyCommand(api.flattenLayer, targetLayers, dataset, opts);
1325213217

1325313218
} else if (name == 'info') {
1325413219
api.printInfo(dataset);
@@ -13622,6 +13587,11 @@ Utils.extend(api.internal, {
1362213587
api.T = T;
1362313588
C.VERBOSE = false;
1362413589

13625-
module.exports = api;
13590+
if (typeof define === "function" && define.amd) {
13591+
define("mapshaper", api);
13592+
} else if (typeof module === "object" && module.exports) {
13593+
module.exports = api;
13594+
}
13595+
this.mapshaper = api;
1362613596

1362713597
})();

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "mapshaper",
3-
"version": "0.2.1",
3+
"version": "0.2.2",
44
"description": "A tool for editing vector datasets for mapping and GIS.",
55
"keywords": ["shapefile","topojson","geojson","cartography","simplification","topology","gis"],
66
"author": "Matthew Bloch <masiyou@gmail.com>",

test/visvalingam-test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,4 @@ describe("mapshaper-visvalingam.js", function() {
6969
v.weightedMetric(0, 0, 1, 8, 2, 0));
7070
})
7171
})
72-
})
72+
})

www/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
<div id="page-wrapper">
1616
<div class="g-page-header">
17-
<div class="g-mapshaper-logo">map<span class="g-logo-highlight">shaper</span> <span class="mshp-version">v. 0.2.0</span></div>
17+
<div class="g-mapshaper-logo">map<span class="g-logo-highlight">shaper</span> <span class="mshp-version">v. 0.2.2</span></div>
1818

1919
<div id="g-simplify-control-wrapper"><div id="g-simplify-control"><span class="g-label">Simplify</span>
2020
<div class="g-slider">

0 commit comments

Comments
 (0)