Skip to content

Commit

Permalink
Merge pull request #602 from OpenGeoscience/close-lines
Browse files Browse the repository at this point in the history
Add closed flag to line features
  • Loading branch information
manthey authored Aug 5, 2016
2 parents daf9c26 + f30050e commit ccef540
Show file tree
Hide file tree
Showing 8 changed files with 347 additions and 48 deletions.
18 changes: 12 additions & 6 deletions examples/picking/main.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
/* globals utils */

// Run after the DOM loads
$(function () {
'use strict';

var query = utils.getQuery();

// Create a map object with the OpenStreetMaps base layer.
var map = geo.map({
node: '#map',
Expand Down Expand Up @@ -62,9 +66,10 @@ $(function () {
vglLayer.createFeature('line', {selectionAPI: true})
.data([window.randomPath(1000, 0.1, -88, 30), window.randomPath(500, 0.05, -110, 40)])
.style({
'strokeColor': function (d, i, e, j) { return (j % 2) ? color(0) : color(1); },
'strokeWidth': 5,
'strokeOpacity': function (d, i, e) { return e.clicked ? 1 : 0.5; }
strokeColor: function (d, i, e, j) { return (j % 2) ? color(0) : color(1); },
strokeWidth: 5,
strokeOpacity: function (d, i, e) { return e.clicked ? 1 : 0.5; },
closed: query.closed === 'true'
})
.geoOn(geo.event.feature.mouseover, handleMouseOver)
.geoOn(geo.event.feature.mouseout, handleMouseOut)
Expand All @@ -74,9 +79,10 @@ $(function () {
svgLayer.createFeature('line', {selectionAPI: true})
.data([window.randomPath(1000, 0.1, -108, 30), window.randomPath(500, 0.05, -88, 40)])
.style({
'strokeColor': function (d, i, l, j) { return (j % 2) ? color(2) : color(3); },
'strokeWidth': 5,
'strokeOpacity': function (d, i, e) { return e.clicked ? 1 : 0.5; }
strokeColor: function (d, i, l, j) { return (j % 2) ? color(2) : color(3); },
strokeWidth: 5,
strokeOpacity: function (d, i, e) { return e.clicked ? 1 : 0.5; },
closed: query.closed === 'true'
})
.geoOn(geo.event.feature.mouseover, handleMouseOver)
.geoOn(geo.event.feature.mouseout, handleMouseOut)
Expand Down
9 changes: 6 additions & 3 deletions src/d3/lineFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,7 @@ var d3_lineFeature = function (arg) {
s_style = m_this.style(),
m_renderer = m_this.renderer(),
pos_func = m_this.position(),
line = d3.svg.line()
.x(function (d) { return m_this.featureGcsToDisplay(d).x; })
.y(function (d) { return m_this.featureGcsToDisplay(d).y; });
line;

s_update.call(m_this);
s_style.fill = function () { return false; };
Expand All @@ -86,6 +84,11 @@ var d3_lineFeature = function (arg) {
}
}

line = d3.svg.line()
.x(function (d) { return m_this.featureGcsToDisplay(d).x; })
.y(function (d) { return m_this.featureGcsToDisplay(d).y; })
.interpolate(m_this.style.get('closed')(item, idx) && ln.length > 2 ?
'linear-closed' : 'linear');
// item is an object representing a single line
// m_this.line()(item) is an array of coordinates
m_style = {
Expand Down
46 changes: 35 additions & 11 deletions src/gl/lineFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,11 @@ var gl_lineFeature = function (arg) {

function createGLLines() {
var data = m_this.data(),
i, j, k, v,
i, j, k, v, lidx,
numSegments = 0, len,
lineItem, lineItemData,
vert = [{}, {}], vertTemp,
pos, posIdx3,
pos, posIdx3, firstpos, firstPosIdx3,
position = [],
posFunc = m_this.position(),
strkWidthFunc = m_this.style.get('strokeWidth'),
Expand All @@ -141,7 +141,8 @@ var gl_lineFeature = function (arg) {
posBuf, nextBuf, prevBuf, offsetBuf, indicesBuf,
strokeWidthBuf, strokeColorBuf, strokeOpacityBuf,
dest, dest3,
geom = m_mapper.geometryData();
geom = m_mapper.geometryData(),
closedFunc = m_this.style.get('closed'), closed = [];

for (i = 0; i < data.length; i += 1) {
lineItem = m_this.line()(data[i], i);
Expand All @@ -151,6 +152,19 @@ var gl_lineFeature = function (arg) {
position.push(pos.x);
position.push(pos.y);
position.push(pos.z || 0.0);
if (!j) {
firstpos = pos;
}
}
if (lineItem.length > 2 && closedFunc(data[i], i)) {
/* line is closed */
if (pos.x !== firstpos.x || pos.y !== firstpos.y ||
pos.z !== firstpos.z) {
numSegments += 1;
closed[i] = 2; /* first and last points are distinct */
} else {
closed[i] = 1; /* first point is repeated as last point */
}
}
}

Expand All @@ -174,21 +188,30 @@ var gl_lineFeature = function (arg) {

for (i = posIdx3 = dest = dest3 = 0; i < data.length; i += 1) {
lineItem = m_this.line()(data[i], i);
for (j = 0; j < lineItem.length; j += 1, posIdx3 += 3) {
lineItemData = lineItem[j];
firstPosIdx3 = posIdx3;
for (j = 0; j < lineItem.length + (closed[i] === 2 ? 1 : 0); j += 1, posIdx3 += 3) {
lidx = j;
if (j === lineItem.length) {
lidx = 0;
posIdx3 -= 3;
}
lineItemData = lineItem[lidx];
/* swap entries in vert so that vert[0] is the first vertex, and
* vert[1] will be reused for the second vertex */
if (j) {
vertTemp = vert[0];
vert[0] = vert[1];
vert[1] = vertTemp;
}
vert[1].pos = posIdx3;
vert[1].prev = posIdx3 - (j ? 3 : 0);
vert[1].next = posIdx3 + (j + 1 < lineItem.length ? 3 : 0);
vert[1].strokeWidth = strkWidthFunc(lineItemData, j, lineItem, i);
vert[1].strokeColor = strkColorFunc(lineItemData, j, lineItem, i);
vert[1].strokeOpacity = strkOpacityFunc(lineItemData, j, lineItem, i);
vert[1].pos = j === lidx ? posIdx3 : firstPosIdx3;
vert[1].prev = lidx ? posIdx3 - 3 : (closed[i] ?
firstPosIdx3 + (lineItem.length - 3 + closed[i]) * 3 : posIdx3);
vert[1].next = j + 1 < lineItem.length ? posIdx3 + 3 : (closed[i] ?
(j !== lidx ? firstPosIdx3 + 3 : firstPosIdx3 + 6 - closed[i] * 3) :
posIdx3);
vert[1].strokeWidth = strkWidthFunc(lineItemData, lidx, lineItem, i);
vert[1].strokeColor = strkColorFunc(lineItemData, lidx, lineItem, i);
vert[1].strokeOpacity = strkOpacityFunc(lineItemData, lidx, lineItem, i);
if (j) {
for (k = 0; k < order.length; k += 1, dest += 1, dest3 += 3) {
v = vert[order[k][0]];
Expand Down Expand Up @@ -384,6 +407,7 @@ var gl_lineFeature = function (arg) {
////////////////////////////////////////////////////////////////////////////
this._exit = function () {
m_this.renderer().contextRenderer().removeActor(m_actor);
m_actor = null;
s_exit();
};

Expand Down
41 changes: 28 additions & 13 deletions src/lineFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,12 @@ var lineFeature = function (arg) {
/**
* Returns an array of datum indices that contain the given point.
* This is a slow implementation with runtime order of the number of
* vertices.
* vertices. A point is considered on a line segment if it is close to the
* line or either end point. Closeness is based on the maximum width of the
* line segement, and is ceil(maxwidth / 2) + 2 pixels. This means that
* corner extensions due to mitering may be outside of the selection area and
* that variable width lines will have a greater selection region than their
* visual size at the narrow end.
*/
////////////////////////////////////////////////////////////////////////////
this.pointSearch = function (p) {
Expand Down Expand Up @@ -118,7 +123,8 @@ var lineFeature = function (arg) {

// for each line
data.forEach(function (d, index) {
var last = null;
var closed = m_this.style.get('closed')(d, index),
last, lastr, first;

try {
line(d, index).forEach(function (current, j) {
Expand All @@ -127,19 +133,25 @@ var lineFeature = function (arg) {
var p = pos(current, j, d, index);
var s = m_this.featureGcsToDisplay(p);
var r = Math.ceil(width(p, j, d, index) / 2) + 2;
r = r * r;

if (last) {
var r2 = lastr > r ? lastr * lastr : r * r;
// test the line segment s -> last
if (lineDist2(pt, s, last) <= r) {

if (lineDist2(pt, s, last) <= r2) {
// short circuit the loop here
throw 'found';
}
}

last = s;
lastr = r;
if (!first && closed) {
first = {s: s, r: r};
}
});
if (closed && lineDist2(pt, last, first.s) <= first.r) {
throw 'found';
}
} catch (err) {
if (err !== 'found') {
throw err;
Expand All @@ -150,7 +162,7 @@ var lineFeature = function (arg) {
});

return {
data: found,
found: found,
index: indices
};
};
Expand All @@ -168,7 +180,7 @@ var lineFeature = function (arg) {
opts = opts || {};
opts.partial = opts.partial || false;
if (opts.partial) {
throw 'Unimplemented query method.';
throw new Error('Unimplemented query method.');
}

m_this.data().forEach(function (d, i) {
Expand Down Expand Up @@ -197,18 +209,20 @@ var lineFeature = function (arg) {
*/
////////////////////////////////////////////////////////////////////////////
this._init = function (arg) {
arg = arg || {};
s_init.call(m_this, arg);

var defaultStyle = $.extend(
{},
{
'strokeWidth': 1.0,
strokeWidth: 1.0,
// Default to gold color for lines
'strokeColor': { r: 1.0, g: 0.8431372549, b: 0.0 },
'strokeStyle': 'solid',
'strokeOpacity': 1.0,
'line': function (d) { return d; },
'position': function (d) { return d; }
strokeColor: { r: 1.0, g: 0.8431372549, b: 0.0 },
strokeStyle: 'solid',
strokeOpacity: 1.0,
closed: false,
line: function (d) { return d; },
position: function (d) { return d; }
},
arg.style === undefined ? {} : arg.style
);
Expand Down Expand Up @@ -240,6 +254,7 @@ var lineFeature = function (arg) {
lineFeature.create = function (layer, spec) {
'use strict';

spec = spec || {};
spec.type = 'line';
return feature.create(layer, spec);
};
Expand Down
2 changes: 1 addition & 1 deletion src/pointFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ var pointFeature = function (arg) {
});

return {
data: found,
found: found,
index: ifound
};
};
Expand Down
18 changes: 5 additions & 13 deletions src/polygonFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -247,24 +247,15 @@ var polygonFeature = function (arg) {
* @param {object} item: the polygon.
* @param {number} itemIndex: the index of the polygon
* @param {Array} loop: the inner or outer loop.
* @param {function} posFunc: a function that gets the coordinates of a
* vertex. Used to compare the first and last vertices of the polygon.
* If they do not match exactly, the first vertex is added at the end to
* close the polyline.
* @returns {Array} the loop with the data necessary to send to the position
* function for each vertex.
*/
this._getLoopData = function (item, itemIndex, loop, posFunc) {
var line = [], i, startpos, endpos;
this._getLoopData = function (item, itemIndex, loop) {
var line = [], i;

for (i = 0; i < loop.length; i += 1) {
line.push([loop[i], i, item, itemIndex]);
}
startpos = posFunc(loop[0], 0, item, itemIndex);
endpos = posFunc(loop[loop.length - 1], loop.length - 1, item, itemIndex);
if (startpos.x !== endpos.x || startpos.y !== endpos.y || startpos.z !== endpos.z) {
line.push([loop[0], 0, item, itemIndex]);
}
return line;
};

Expand All @@ -291,6 +282,7 @@ var polygonFeature = function (arg) {
}
var polyStyle = m_this.style();
m_lineFeature.style({
closed: true,
strokeWidth: polyStyle.strokeWidth,
strokeStyle: polyStyle.strokeStyle,
strokeColor: polyStyle.strokeColor,
Expand All @@ -306,10 +298,10 @@ var polygonFeature = function (arg) {
for (i = 0; i < data.length; i += 1) {
polygon = m_this.polygon()(data[i], i);
loop = polygon.outer || (polygon instanceof Array ? polygon : []);
lineData.push(m_this._getLoopData(data[i], i, loop, posFunc));
lineData.push(m_this._getLoopData(data[i], i, loop));
if (polygon.inner) {
polygon.inner.forEach(function (loop) {
lineData.push(m_this._getLoopData(data[i], i, loop, posFunc));
lineData.push(m_this._getLoopData(data[i], i, loop));
});
}
}
Expand Down
Loading

0 comments on commit ccef540

Please sign in to comment.