@@ -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) {
54975497Visvalingam . standardMetric = triangleArea ;
54985498Visvalingam . 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-
55655500Visvalingam . 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, {
1362213587api . T = T ;
1362313588C . 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} ) ( ) ;
0 commit comments