diff --git a/bin/shp2json b/bin/shp2json index facc848..16756bc 100755 --- a/bin/shp2json +++ b/bin/shp2json @@ -2,7 +2,8 @@ var fs = require("fs"), commander = require("commander"), - shapefile = require("../"); + shapefile = require("../"), + proj4 = require('proj4'); commander .version(require("../package.json").version) @@ -26,10 +27,18 @@ else if (commander.args.length !== 1) { var out = (commander.out === "-" ? process.stdout : fs.createWriteStream(commander.out)).on("error", handleEpipe); +// My addition to read prj file, turn it into a function that I will apply to all coordinates +var shpFilename = commander.args[0], + prjFilename = shpFilename.substring(0, shpFilename.length - 4) + ".prj", + prjStr = fs.readFileSync(prjFilename).toString(), + prj = proj4(prjStr), + xform = prj.inverse.bind(prj); +// end for now, but `xform` will be passed around + shapefile.open( commander.args[0] === "-" ? process.stdin : commander.args[0], commander.geometry || commander.ignoreProperties ? null : undefined, - {encoding: commander.encoding}) + {encoding: commander.encoding, xform: xform}) .then(commander.newlineDelimited ? (commander.geometry ? writeNewlineDelimitedGeometries : writeNewlineDelimitedFeatures) : (commander.geometry ? writeGeometryCollection : writeFeatureCollection)) diff --git a/index.js b/index.js index c9739ec..15f06ef 100644 --- a/index.js +++ b/index.js @@ -26,7 +26,7 @@ export function open(shp, dbf, options) { return Promise.all([shp, dbf]).then(function(sources) { var shp = sources[0], dbf = sources[1], encoding = "windows-1252"; if (options && options.encoding != null) encoding = options.encoding; - return shapefile(shp, dbf, dbf && new TextDecoder(encoding)); + return shapefile(shp, dbf, dbf && new TextDecoder(encoding), options ? options.xform : function (x) {x}); }); } diff --git a/package.json b/package.json index 211697e..2689a11 100644 --- a/package.json +++ b/package.json @@ -34,13 +34,14 @@ "array-source": "0.0", "commander": "2", "path-source": "0.1", + "proj4": "2.7.0", "slice-source": "0.4", "stream-source": "0.3", "text-encoding": "^0.6.4" }, "devDependencies": { "package-preamble": "0.1", - "rollup": "0.49", + "rollup": "^0.49.3", "rollup-plugin-node-resolve": "3", "tape": "4", "uglify-js": "3" diff --git a/shapefile/index.js b/shapefile/index.js index b562e72..5436cd0 100644 --- a/shapefile/index.js +++ b/shapefile/index.js @@ -3,9 +3,9 @@ import shp from "../shp/index"; import shapefile_cancel from "./cancel"; import shapefile_read from "./read"; -export default function(shpSource, dbfSource, decoder) { +export default function(shpSource, dbfSource, decoder, xform) { return Promise.all([ - shp(shpSource), + shp(shpSource, xform), dbfSource && dbf(dbfSource, decoder) ]).then(function(sources) { return new Shapefile(sources[0], sources[1]); diff --git a/shp/index.js b/shp/index.js index 8c08f64..1c8be18 100644 --- a/shp/index.js +++ b/shp/index.js @@ -24,21 +24,24 @@ var parsers = { 28: parseMultiPoint // MultiPointM }; -export default function(source) { +export default function(source, xform) { source = slice(source); return source.slice(100).then(function(array) { - return new Shp(source, view(array)); + return new Shp(source, view(array), xform); }); }; -function Shp(source, header) { +function Shp(source, header, xform) { var type = header.getInt32(32, true); if (!(type in parsers)) throw new Error("unsupported shape type: " + type); this._source = source; + this._xform = xform || function (x) { x }; this._type = type; this._index = 0; this._parse = parsers[type]; - this.bbox = [header.getFloat64(36, true), header.getFloat64(44, true), header.getFloat64(52, true), header.getFloat64(60, true)]; + var topLeft = xform([header.getFloat64(36, true), header.getFloat64(44, true)]); + var botRight = xform([header.getFloat64(52, true), header.getFloat64(60, true)]); + this.bbox = [ topLeft[0], topLeft[1], botRight[0], botRight[1] ]; } var prototype = Shp.prototype; diff --git a/shp/multipoint.js b/shp/multipoint.js index 06b8f5c..0051030 100644 --- a/shp/multipoint.js +++ b/shp/multipoint.js @@ -1,5 +1,7 @@ -export default function(record) { +export default function(record, xform) { var i = 40, j, n = record.getInt32(36, true), coordinates = new Array(n); - for (j = 0; j < n; ++j, i += 16) coordinates[j] = [record.getFloat64(i, true), record.getFloat64(i + 8, true)]; + for (j = 0; j < n; ++j, i += 16) { + coordinates[j] = xform([ record.getFloat64(i, true), record.getFloat64(i + 8, true) ]); + } return {type: "MultiPoint", coordinates: coordinates}; }; diff --git a/shp/point.js b/shp/point.js index b11d569..783e652 100644 --- a/shp/point.js +++ b/shp/point.js @@ -1,3 +1,3 @@ -export default function(record) { - return {type: "Point", coordinates: [record.getFloat64(4, true), record.getFloat64(12, true)]}; +export default function(record, xform) { + return {type: "Point", coordinates: xform([ record.getFloat64(4, true), record.getFloat64(12, true) ])}; }; diff --git a/shp/polygon.js b/shp/polygon.js index 3c8e6fb..9dbe16e 100644 --- a/shp/polygon.js +++ b/shp/polygon.js @@ -1,7 +1,8 @@ -export default function(record) { - var i = 44, j, n = record.getInt32(36, true), m = record.getInt32(40, true), parts = new Array(n), points = new Array(m), polygons = [], holes = []; +export default function(record, xform) { + var i = 44, j, n = record.getInt32(36, true), m = record.getInt32(40, true), + parts = new Array(n), points = new Array(m), polygons = [], holes = []; for (j = 0; j < n; ++j, i += 4) parts[j] = record.getInt32(i, true); - for (j = 0; j < m; ++j, i += 16) points[j] = [record.getFloat64(i, true), record.getFloat64(i + 8, true)]; + for (j = 0; j < m; ++j, i += 16) points[j] = xform([ record.getFloat64(i, true), record.getFloat64(i + 8, true) ]); parts.forEach(function(i, j) { var ring = points.slice(i, parts[j + 1]); diff --git a/shp/polyline.js b/shp/polyline.js index f18fd3b..b39b8c3 100644 --- a/shp/polyline.js +++ b/shp/polyline.js @@ -1,7 +1,7 @@ -export default function(record) { +export default function(record, xform) { var i = 44, j, n = record.getInt32(36, true), m = record.getInt32(40, true), parts = new Array(n), points = new Array(m); for (j = 0; j < n; ++j, i += 4) parts[j] = record.getInt32(i, true); - for (j = 0; j < m; ++j, i += 16) points[j] = [record.getFloat64(i, true), record.getFloat64(i + 8, true)]; + for (j = 0; j < m; ++j, i += 16) points[j] = xform([ record.getFloat64(i, true), record.getFloat64(i + 8, true)]); return n === 1 ? {type: "LineString", coordinates: points} : {type: "MultiLineString", coordinates: parts.map(function(i, j) { return points.slice(i, parts[j + 1]); })}; diff --git a/shp/read.js b/shp/read.js index 9a695c2..2035060 100644 --- a/shp/read.js +++ b/shp/read.js @@ -24,7 +24,7 @@ export default function() { function read() { var length = header.getInt32(4, false) * 2 - 4, type = header.getInt32(8, true); return length < 0 || (type && type !== that._type) ? skip() : that._source.slice(length).then(function(chunk) { - return {done: false, value: type ? that._parse(view(concat(array.slice(8), chunk))) : null}; + return {done: false, value: type ? that._parse(view(concat(array.slice(8), chunk)), that._xform) : null}; }); }