Skip to content

Commit

Permalink
refactoring"
Browse files Browse the repository at this point in the history
  • Loading branch information
mbloch committed Nov 19, 2024
1 parent c189361 commit c3640a7
Show file tree
Hide file tree
Showing 15 changed files with 133 additions and 126 deletions.
2 changes: 1 addition & 1 deletion src/cli/mapshaper-options.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export function getOptionParser() {
describe: 'aspect ratio as a number or range (e.g. 2 0.8,1.6 ,2)'
},
offsetOpt = {
describe: 'padding as distance or pct of h/w (single value or list)',
describe: 'offset distance or pct of h/w (single value or l,b,r,t list)',
type: 'distance'
};

Expand Down
2 changes: 1 addition & 1 deletion src/commands/mapshaper-affine.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import utils from '../utils/mapshaper-utils';
import cmd from '../mapshaper-cmd';
import { absArcId } from '../paths/mapshaper-arc-utils';
import { Bounds } from '../geom/mapshaper-bounds';
import { calcFrameData } from '../furniture/mapshaper-frame-data';
import { calcFrameData } from '../furniture/mapshaper-frame-utils';

// Apply rotation, scale and/or shift to some or all of the features in a dataset
//
Expand Down
2 changes: 1 addition & 1 deletion src/commands/mapshaper-frame.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getFrameSize } from '../furniture/mapshaper-frame-data';
import { getFrameSize } from '../furniture/mapshaper-frame-utils';
import { DataTable } from '../datatable/mapshaper-data-table';
import { message, stop } from '../utils/mapshaper-logging';
import { probablyDecimalDegreeBounds } from '../geom/mapshaper-latlon';
Expand Down
2 changes: 1 addition & 1 deletion src/commands/mapshaper-scalebar.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getMapFrameMetersPerPixel, findFrameDataset } from '../furniture/mapshaper-frame-data';
import { getMapFrameMetersPerPixel, findFrameDataset } from '../furniture/mapshaper-frame-utils';
import { addFurnitureLayer } from '../furniture/mapshaper-furniture-cmd';
import cmd from '../mapshaper-cmd';
import utils from '../utils/mapshaper-utils';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import { Bounds } from '../geom/mapshaper-bounds';
import { getDatasetCRS, getScaleFactorAtXY} from '../crs/mapshaper-projections';
import { getDatasetBounds } from '../dataset/mapshaper-dataset-utils';
import { getFurnitureLayerType, getFurnitureLayerData } from '../furniture/mapshaper-furniture';
import utils from '../utils/mapshaper-utils';
import { error } from '../utils/mapshaper-logging';
import { layerIsRectangle, getLayerBounds } from '../dataset/mapshaper-layer-utils';
import { transformPoints } from '../dataset/mapshaper-dataset-utils';
import utils from '../utils/mapshaper-utils';
/*
{
width: size[0],
Expand All @@ -13,18 +14,30 @@ import { layerIsRectangle, getLayerBounds } from '../dataset/mapshaper-layer-uti
type: 'frame'
}
*/


export function getFrameData(dataset, exportOpts) {
var frameLyr = findFrameLayerInDataset(dataset);
var frameData;
var data;
if (frameLyr) {
frameData = getFrameLayerData(frameLyr, dataset.arcs);
data = getFrameLayerData(frameLyr, dataset.arcs);
} else {
frameData = calcFrameData(dataset, exportOpts);
data = calcFrameData(dataset, exportOpts);
}
frameData.crs = getDatasetCRS(dataset);
return frameData;
data.invert_y = !!exportOpts.invert_y;
data.crs = getDatasetCRS(dataset);
return data;
}

export function fitDatasetToFrame(dataset, frame) {
var bounds = new Bounds(frame.bbox);
var bounds2 = frame.bbox2 ? new Bounds(frame.bbox2) : new Bounds(0, 0, frame.width, frame.height);
bounds.fillOut(bounds2.width() / bounds2.height());
var fwd = bounds.getTransform(bounds2, frame.invert_y);
transformPoints(dataset, function(x, y) {
return fwd.transform(x, y);
});
}

export function getFrameLayerData(lyr, arcs) {
var bounds = getLayerBounds(lyr, arcs);
Expand All @@ -42,25 +55,25 @@ export function getFrameLayerData(lyr, arcs) {


export function calcFrameData(dataset, opts) {
var bounds;
var outputBbox = opts.svg_bbox || opts.output_bbox || null;
if (outputBbox) {
bounds = new Bounds(outputBbox);
var inputBounds, outputBounds;
if (opts.svg_bbox) {
inputBounds = new Bounds(opts.svg_bbox);
opts = Object.assign({margin: 0}, opts); // prevent default pixel margin around content
} else {
bounds = getDatasetBounds(dataset);
inputBounds = getDatasetBounds(dataset);
}
var outputBounds = calcOutputSizeInPixels(bounds, opts);
// side effect: inputBounds may be expanded to add margins
outputBounds = calcOutputBounds(inputBounds, opts);
return {
bbox: bounds.toArray(),
bbox: inputBounds.toArray(),
bbox2: outputBounds.toArray(),
width: Math.round(outputBounds.width()),
height: Math.round(outputBounds.height()) || 1,
type: 'frame'
};
}

// Used by mapshaper-frame and mapshaper-pixel-transform. TODO: refactor
// Used by mapshaper-frame TODO: refactor
export function getFrameSize(bounds, opts) {
var aspectRatio = bounds.width() / bounds.height();
var height, width;
Expand Down Expand Up @@ -129,9 +142,9 @@ export function getMapFrameMetersPerPixel(data) {


// bounds: Bounds object containing bounds of content in geographic coordinates
// returns Bounds object containing bounds of pixel output
// returns Bounds object containing output bounds
// side effect: bounds param is modified to match the output frame
export function calcOutputSizeInPixels(bounds, opts) {
export function calcOutputBounds(bounds, opts) {
var padX = 0,
padY = 0,
offX = 0,
Expand All @@ -144,65 +157,59 @@ export function calcOutputSizeInPixels(bounds, opts) {
// TODO: add option to tweak alignment of content when both width and height are given
wx = 0.5, // how padding is distributed horizontally (0: left aligned, 0.5: centered, 1: right aligned)
wy = 0.5, // vertical padding distribution
widthPx, heightPx, size, kx, ky;
width2, height2, size2, kx, ky;

if (opts.fit_bbox) {
// scale + shift content to fit within a bbox
offX = opts.fit_bbox[0];
offY = opts.fit_bbox[1];
widthPx = opts.fit_bbox[2] - offX;
heightPx = opts.fit_bbox[3] - offY;
if (width / height > widthPx / heightPx) {
// data is wider than fit box...
// scale the data to fit widthwise
heightPx = 0;
} else {
widthPx = 0; // fit the data to the height
}
width2 = opts.fit_bbox[2] - offX;
height2 = opts.fit_bbox[3] - offY;
marginX = marginY = 0; // TODO: support margins

} else if (opts.svg_scale > 0) {
// alternative to using a fixed width (e.g. when generating multiple files
// at a consistent geographic scale)
widthPx = width / opts.svg_scale + marginX;
heightPx = 0;
width2 = width / opts.svg_scale + marginX;
height2 = 0;
} else if (+opts.pixels) {
size = getFrameSize(bounds, opts);
widthPx = size[0];
heightPx = size[1];
size2 = getFrameSize(bounds, opts);
width2 = size2[0];
height2 = size2[1];
} else {
heightPx = opts.height || 0;
widthPx = opts.width || (heightPx > 0 ? 0 : 800); // 800 is default width
height2 = opts.height || 0;
width2 = opts.width || (height2 > 0 ? 0 : 800); // 800 is default width
}

if (heightPx > 0) {
if (height2 > 0) {
// vertical meters per pixel to fit height param
ky = (height || width || 1) / (heightPx - marginY);
ky = (height || width || 1) / (height2 - marginY);
}
if (widthPx > 0) {
if (width2 > 0) {
// horizontal meters per pixel to fit width param
kx = (width || height || 1) / (widthPx - marginX);
kx = (width || height || 1) / (width2 - marginX);
}

if (!widthPx) { // heightPx and ky are defined, set width to match
if (!width2) { // height2 and ky are defined, set width to match
kx = ky;
widthPx = width > 0 ? marginX + width / kx : heightPx; // export square graphic if content has 0 width (reconsider this?)
} else if (!heightPx) { // widthPx and kx are set, set height to match
width2 = width > 0 ? marginX + width / kx : height2; // export square graphic if content has 0 width (reconsider this?)
} else if (!height2) { // width2 and kx are set, set height to match
ky = kx;
heightPx = height > 0 ? marginY + height / ky : widthPx;
height2 = height > 0 ? marginY + height / ky : width2;
// limit height if max_height is defined
if (opts.max_height > 0 && heightPx > opts.max_height) {
ky = kx * heightPx / opts.max_height;
heightPx = opts.max_height;
if (opts.max_height > 0 && height2 > opts.max_height) {
ky = kx * height2 / opts.max_height;
height2 = opts.max_height;
}
}

// add padding, if needed
if (kx > ky) { // content is wide -- need to pad vertically
ky = kx;
padY = ky * (heightPx - marginY) - height;
padY = ky * (height2 - marginY) - height;
} else if (ky > kx) { // content is tall -- need to pad horizontally
kx = ky;
padX = kx * (widthPx - marginX) - width;
padX = kx * (width2 - marginX) - width;
}

bounds.padBounds(
Expand All @@ -211,14 +218,14 @@ export function calcOutputSizeInPixels(bounds, opts) {
margins[2] * kx + padX * (1 - wx),
margins[3] * ky + padY * (1 - wy));

if (!(widthPx > 0 && heightPx > 0)) {
if (!(width2 > 0 && height2 > 0)) {
error("Missing valid height and width parameters");
}
if (!(kx === ky && kx > 0)) {
error("Missing valid margin parameters");
}

return new Bounds(offX, offY, widthPx + offX, heightPx + offY);
return new Bounds(offX, offY, width2 + offX, height2 + offY);
}

export function parseMarginOption(opt) {
Expand All @@ -229,6 +236,6 @@ export function parseMarginOption(opt) {
if (margins.length == 3) margins.push(margins[2]);
return margins.map(function(str) {
var px = parseFloat(str);
return isNaN(px) ? 1 : px; // 1 is default
return isNaN(px) ? 0 : px; // 0 is default
});
}
18 changes: 0 additions & 18 deletions src/furniture/mapshaper-pixel-transform.mjs

This file was deleted.

4 changes: 2 additions & 2 deletions src/geom/mapshaper-units.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ export function convertIntervalPair(opt, crs) {
convertIntervalParam(opt[1], crs)];
}

// Accepts a single value or a list of four values. List order is l,b,t,r
// Accepts a single value or a list of four values. List order is l,b,r,t
export function convertFourSides(opt, crs, bounds) {
var arr = opt.includes(',') ? opt.split(',') : opt.split(' ');
if (arr.length == 1) {
Expand All @@ -171,7 +171,7 @@ export function convertFourSides(opt, crs, bounds) {
tmp = parseFloat(param) / 100 || 0;
return tmp * (i == 1 || i == 3 ? bounds.height() : bounds.width());
}
return convertIntervalParam(opt, crs);
return convertIntervalParam(param, crs);
});
}

Expand Down
8 changes: 4 additions & 4 deletions src/gui/gui-map.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ export function MshpMap(gui) {
function calcFullBounds() {
var b;
if (isPreviewView()) {
b = new Bounds(getFrameData().bbox);
b = new Bounds(getFrameLayerData().bbox);
} else {
b = getContentLayerBounds();
}
Expand Down Expand Up @@ -383,10 +383,10 @@ export function MshpMap(gui) {

// Preview view: symbols are scaled based on display size of frame layer
function isPreviewView() {
return !isTableView() && !!getFrameData();
return !isTableView() && !!getFrameLayerData();
}

function getFrameData() {
function getFrameLayerData() {
var lyr = findFrameLayer();
return lyr && internal.getFrameLayerData(lyr, lyr.gui.displayArcs) || null;
}
Expand Down Expand Up @@ -507,7 +507,7 @@ export function MshpMap(gui) {
}
if (layersMayHaveChanged) {
// kludge to handle layer visibility toggling
_ext.setFrameData(isPreviewView() ? getFrameData() : null);
_ext.setFrameData(isPreviewView() ? getFrameLayerData() : null);
updateFullBounds();
updateLayerStyles(contentLayers);
updateLayerStackOrder(model.getLayers());// update menu_order property of all layers
Expand Down
7 changes: 3 additions & 4 deletions src/mapshaper-internal.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ import * as FileReader from './io/mapshaper-file-reader';
import * as FileTypes from './io/mapshaper-file-types';
import * as FilterGeom from './commands/mapshaper-filter-geom';
import * as Frame from './commands/mapshaper-frame';
import * as FrameData from './furniture/mapshaper-frame-data';
import * as FrameUtils from './furniture/mapshaper-frame-utils';
import * as Furniture from './furniture/mapshaper-furniture';
import * as Geodesic from './geom/mapshaper-geodesic';
import * as GeojsonExport from './geojson/geojson-export';
Expand Down Expand Up @@ -140,7 +140,6 @@ import * as PathfinderUtils from './paths/mapshaper-pathfinder-utils';
import * as PathImport from './paths/mapshaper-path-import';
import * as PathRepair from './paths/mapshaper-path-repair-utils';
import * as PathUtils from './paths/mapshaper-path-utils';
import * as PixelTransform from './furniture/mapshaper-pixel-transform';
import * as PointPolygonJoin from './join/mapshaper-point-polygon-join';
import * as Points from './commands/mapshaper-points';
import * as PointUtils from './points/mapshaper-point-utils';
Expand Down Expand Up @@ -225,7 +224,7 @@ Object.assign(internal,
FileTypes,
FilterGeom,
Frame,
FrameData,
FrameUtils,
Furniture,
Geodesic,
GeojsonExport,
Expand Down Expand Up @@ -260,7 +259,7 @@ Object.assign(internal,
PathImport,
PathRepair,
PathUtils,
PixelTransform,
// PixelTransform,
PointPolygonJoin,
Points,
PointToGrid,
Expand Down
10 changes: 5 additions & 5 deletions src/svg/mapshaper-svg.mjs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { exportDatasetAsGeoJSON } from '../geojson/geojson-export';
import { getFurnitureLayerData, layerHasFurniture, renderFurnitureLayer } from '../furniture/mapshaper-furniture';
import { getFrameData } from '../furniture/mapshaper-frame-data';
import { getFrameData, fitDatasetToFrame } from '../furniture/mapshaper-frame-utils';
import { setCoordinatePrecision } from '../geom/mapshaper-rounding';
import { getScalebarLayer } from '../commands/mapshaper-scalebar';
import { fitDatasetToFrame } from '../furniture/mapshaper-pixel-transform';
import { copyDataset } from '../dataset/mapshaper-dataset-utils';
import utils from '../utils/mapshaper-utils';
import { message, error, stop } from '../utils/mapshaper-logging';
Expand Down Expand Up @@ -35,10 +34,11 @@ export function exportSVG(dataset, opts) {
dataset = copyDataset(dataset); // Modify a copy of the dataset
}

// invert_y setting for screen coordinates and geojson polygon generation
utils.extend(opts, {invert_y: true});
// use invert_y: 0 setting for screen coordinates and geojson polygon generation
// use 1px default margin so typical strokes don't get cut off on the sides
opts = Object.assign({invert_y: true, margin: "1"}, opts);
frame = getFrameData(dataset, opts);
fitDatasetToFrame(dataset, frame, opts);
fitDatasetToFrame(dataset, frame);
setCoordinatePrecision(dataset, opts.precision || 0.0001);

// error if one or more svg_data fields are not present in any layers
Expand Down
10 changes: 7 additions & 3 deletions src/topojson/topojson-export.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { exportIds } from '../geojson/geojson-export';
import { exportProperties } from '../geojson/geojson-export';
import { dissolveArcs } from '../paths/mapshaper-arc-dissolve';
import { setCoordinatePrecision } from '../geom/mapshaper-rounding';
import { transformDatasetToPixels } from '../furniture/mapshaper-pixel-transform';
import { getFrameData, fitDatasetToFrame } from '../furniture/mapshaper-frame-utils';
import { getFormattedStringify } from '../geojson/mapshaper-stringify';
import { copyDatasetForExport, datasetHasPaths, splitDataset, getDatasetBounds } from '../dataset/mapshaper-dataset-utils';
import { getOutputFileBase } from '../utils/mapshaper-filename-utils';
Expand All @@ -36,10 +36,14 @@ export function exportTopoJSON(dataset, opts) {
}

if (opts.width > 0 || opts.height > 0) {
// these options create a TopoJSON with pixel coordinates, including
// origin (0,0) in the top left corner of the viewport, generally for
// direct conversion to SVG (many online examples using d3 are like this)
//
opts = utils.defaults({invert_y: true}, opts);
transformDatasetToPixels(dataset, opts);
fitDatasetToFrame(dataset, getFrameData(dataset, opts));
} else if (opts.fit_bbox) {
transformDatasetToPixels(dataset, {fit_bbox: opts.fit_bbox});
fitDatasetToFrame(dataset, getFrameData(dataset, {fit_bbox: opts.fit_bbox}));
}

if (opts.precision && opts.no_quantization) {
Expand Down
Loading

0 comments on commit c3640a7

Please sign in to comment.