153 lines
4.7 KiB
JavaScript
153 lines
4.7 KiB
JavaScript
/* Copyright (c) 2016 Jean-Marc VIGLINO,
|
|
released under the CeCILL-B license (French BSD license)
|
|
(http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt).
|
|
|
|
Usefull function to handle geometric operations
|
|
*/
|
|
/*eslint no-constant-condition: ["error", { "checkLoops": false }]*/
|
|
|
|
import ol_geom_MultiLineString from 'ol/geom/MultiLineString.js'
|
|
import ol_geom_Polygon from 'ol/geom/Polygon.js'
|
|
import ol_geom_MultiPolygon from 'ol/geom/MultiPolygon.js'
|
|
import '../render/Cspline.js'
|
|
import { ol_coordinate_splitH } from "./GeomUtils.js";
|
|
|
|
/**
|
|
* Calculate a MultiPolyline to fill a Polygon with a scribble effect that appears hand-made
|
|
* @param {} options
|
|
* @param {Number} options.interval interval beetween lines
|
|
* @param {Number} options.angle hatch angle in radian, default PI/2
|
|
* @return {ol_geom_MultiLineString|null} the resulting MultiLineString geometry or null if none
|
|
*/
|
|
ol_geom_MultiPolygon.prototype.scribbleFill = function (options) {
|
|
var scribbles = [];
|
|
var poly = this.getPolygons();
|
|
var i, p, s;
|
|
for (i=0; p=poly[i]; i++) {
|
|
var mls = p.scribbleFill(options);
|
|
if (mls) scribbles.push(mls);
|
|
}
|
|
if (!scribbles.length) return null;
|
|
// Merge scribbles
|
|
var scribble = scribbles[0];
|
|
var ls;
|
|
for (i = 0; s = scribbles[i]; i++) {
|
|
ls = s.getLineStrings();
|
|
for (var k = 0; k < ls.length; k++) {
|
|
scribble.appendLineString(ls[k]);
|
|
}
|
|
}
|
|
return scribble;
|
|
};
|
|
|
|
/**
|
|
* Calculate a MultiPolyline to fill a Polygon with a scribble effect that appears hand-made
|
|
* @param {} options
|
|
* @param {Number} options.interval interval beetween lines
|
|
* @param {Number} options.angle hatch angle in radian, default PI/2
|
|
* @return {ol_geom_MultiLineString|null} the resulting MultiLineString geometry or null if none
|
|
*/
|
|
ol_geom_Polygon.prototype.scribbleFill = function (options) {
|
|
var step = options.interval;
|
|
var angle = options.angle || Math.PI/2;
|
|
var i, k,l;
|
|
|
|
// Geometry + rotate
|
|
var geom = this.clone();
|
|
geom.rotate(angle, [0,0]);
|
|
var coords = geom.getCoordinates();
|
|
// Merge holes
|
|
var coord = coords[0];
|
|
for (i=1; i<coords.length; i++) {
|
|
// Add a separator
|
|
coord.push([]);
|
|
// Add the hole
|
|
coord = coord.concat(coords[i]);
|
|
}
|
|
// Extent
|
|
var ext = geom.getExtent();
|
|
|
|
// Split polygon with horizontal lines
|
|
var lines = [];
|
|
for (var y = (Math.floor(ext[1]/step)+1)*step; y<ext[3]; y += step) {
|
|
l = ol_coordinate_splitH(coord, y, i);
|
|
lines = lines.concat(l);
|
|
}
|
|
|
|
if (!lines.length) return null;
|
|
// Order lines on segment index
|
|
var mod = coord.length-1;
|
|
var first = lines[0][0].index;
|
|
for (k=0; l=lines[k]; k++) {
|
|
lines[k][0].index = (lines[k][0].index-first+mod) % mod;
|
|
lines[k][1].index = (lines[k][1].index-first+mod) % mod;
|
|
}
|
|
|
|
var scribble = [];
|
|
|
|
while (true) {
|
|
for (k=0; l=lines[k]; k++) {
|
|
if (!l[0].done) break;
|
|
}
|
|
if (!l) break;
|
|
var scrib = [];
|
|
while (l) {
|
|
l[0].done = true;
|
|
scrib.push(l[0].pt);
|
|
scrib.push(l[1].pt);
|
|
var nexty = l[0].pt[1] + step;
|
|
var d0 = Infinity;
|
|
var l2 = null;
|
|
while (lines[k]) {
|
|
if (lines[k][0].pt[1] > nexty) break;
|
|
if (lines[k][0].pt[1] === nexty) {
|
|
var d = Math.min(
|
|
(lines[k][0].index - l[0].index + mod) % mod,
|
|
(l[0].index - lines[k][0].index + mod) % mod
|
|
);
|
|
var d2 = Math.min(
|
|
(l[1].index - l[0].index + mod) % mod,
|
|
(l[0].index - l[1].index + mod) % mod
|
|
);
|
|
if (d<d0 && d<d2) {
|
|
d0 = d;
|
|
if (!lines[k][0].done) l2 = lines[k];
|
|
else l2 = null;
|
|
}
|
|
}
|
|
k++;
|
|
}
|
|
l = l2;
|
|
}
|
|
if (scrib.length) {
|
|
scribble.push(scrib);
|
|
}
|
|
}
|
|
|
|
// Return the scribble as MultiLineString
|
|
if (!scribble.length) return null;
|
|
var mline = new ol_geom_MultiLineString(scribble);
|
|
mline.rotate(-angle,[0,0]);
|
|
return mline.cspline({ pointsPerSeg:8, tension:.9 });
|
|
};
|
|
|
|
/** Calculate a MultiPolyline to fill a geomatry (Polygon or MultiPolygon) with a scribble effect that appears hand-made
|
|
* @param {ol_geom_Geometry} geom the geometry to scribble
|
|
* @param {Object} options
|
|
* @param {Number} options.interval interval beetween lines
|
|
* @param {Number} options.angle hatch angle in radian, default PI/2
|
|
* @return {ol_geom_Geometry} the resulting MultiLineString geometry or initial geometry
|
|
*/
|
|
var ol_geom_scribbleFill = function(geom, options) {
|
|
switch (geom.getType()) {
|
|
case 'Polygon': {
|
|
return ol_geom_Polygon.prototype.scribbleFill.call(geom, options)
|
|
}
|
|
case 'MultiPolygon': {
|
|
return ol_geom_MultiPolygon.prototype.scribbleFill.call(geom, options)
|
|
}
|
|
default: return geom
|
|
}
|
|
}
|
|
|
|
export default ol_geom_scribbleFill |