diff --git a/src/c3nav/editor/static/editor/js/editor.js b/src/c3nav/editor/static/editor/js/editor.js index cd69262e..312ab026 100644 --- a/src/c3nav/editor/static/editor/js/editor.js +++ b/src/c3nav/editor/static/editor/js/editor.js @@ -185,6 +185,8 @@ editor = { // Clear snap indicators when unloading editor._clear_snap_indicators(); + + editor._destroy_staircase_editing(); }, _fill_level_control: function (level_control, level_list, geometryURLs) { var levels = level_list.find('a'); @@ -1365,7 +1367,7 @@ editor = { } else if (mapitem_type) { // creating a new geometry, already drawn but form was rejected options = editor._get_mapitem_type_style(mapitem_type); - if (mapitem_type === 'area') { + if (mapitem_type === 'area' || mapitem_type === 'staircase') { options.fillOpacity = 0.5; } } @@ -1385,7 +1387,7 @@ editor = { } else if (form.is('[data-new]')) { // create new geometry options = editor._get_mapitem_type_style(mapitem_type); - if (mapitem_type === 'area') { + if (mapitem_type === 'area' || mapitem_type === 'staircase') { options.fillOpacity = 0.5; } form.addClass('creation-lock'); @@ -1434,6 +1436,10 @@ editor = { } startGeomEditing(selected_geomtype); } + + if (mapitem_type === 'staircase') { + editor._setup_staircase_editing() + } } }, _cancel_editing: function () { @@ -1886,6 +1892,127 @@ editor = { if (editor._snap_indicator) { editor._snap_indicator.clearLayers(); } + }, + + _setup_staircase_editing: function() { + editor._staircase_steps_count = 10 + editor._staircase_layer = L.layerGroup().addTo(editor.map); + $('#stairway-steps').on('input', function() { + editor._staircase_steps_count = parseInt($(this).val()) || 10; + editor._update_staircase_preview(); + }); + + editor.map.on('editable:editing', editor._update_staircase_preview); + }, + + _destroy_staircase_editing: function() { + if (editor._staircase_layer !== null) { + editor.map.removeLayer(editor._staircase_layer) + editor._staircase_layer = null + } + editor.map.off('editable:editing', editor._update_staircase_preview) + if (editor._current_editing_shape !== null) { + editor._current_editing_shape.editor.cancelDrawing() + editor._current_editing_shape.remove() + editor._current_editing_shape = null + } + }, + + _transform_point_for_staircase: function(p, p0, cos_a, sin_a) { + return { + x: + (p.x - p0.x) * cos_a + (p.y - p0.y) * sin_a + p0.x, + y: - (p.x - p0.x) * sin_a + (p.y - p0.y) * cos_a + p0.y, + } + }, + + _transform_for_staircase: function(xs, ys, num_stairs) { + let base_length = Math.sqrt((xs[1]-xs[0])**2 + (ys[1]-ys[0])**2) + let cos_a = (xs[1] - xs[0]) / base_length + let sin_a = (ys[1] - ys[0]) / base_length + let p0 = { x: xs[0], y: ys[0] } + + xs = points.map(p => editor._transform_point_for_staircase(p, p0, cos_a, sin_a).x) + ys = points.map(p => editor._transform_point_for_staircase(p, p0, cos_a, sin_a).y) + n = xs.length + + if (Math.abs(Math.max(...ys) - ys[0]) > Math.abs(Math.min(...ys) - ys[0])) { + height = Math.max(...ys) - ys[0] + } else { + height = Math.min(...ys) - ys[0] + } + //console.log(xs, ys, base_length, height) + + lines = [{p1: { x: xs[0], y: ys[0] }, p2: { x: xs[1], y: ys[1] }}] + for (i = 1; i < num_stairs; ++i) { + // intersect line y=y0+height/num_stairs*i with all transformed (xs,ys) + y = ys[0] + height/num_stairs*i + inters_xs = [] + for (j = 0; j < n; ++j) { + y1 = ys[j] + y2 = ys[(j+1)%n] + x1 = xs[j] + x2 = xs[(j+1)%n] + if ((y1 > y && y2 > y) || (y1 < y && y2 < y)) { + //console.log("disconnected", y, j, x1,y1, x2,y2, xs, ys) + continue + } + + if (Math.abs(x2 - x1) < 0.0001) { + // vertical line, m would be infinity + inters_xs.push(x1) + continue + } + + m = (y2 - y1) / (x2 - x1) + q = y2 - m * x2 + //console.log("connected", y, j, x1,y1, x2,y2, m, q, xs, ys) + inters_xs.push((y - q) / m) + } + + //console.log("inters_xs", inters_xs) + if (inters_xs.length < 2) { + continue + } + + min_xs = Math.min(...inters_xs) + max_xs = Math.max(...inters_xs) + lines.push({p1: {x: min_xs-2, y: y}, p2: {x: max_xs+2, y: y}}) + } + + //console.log("untransformed lines", lines) + lines = lines.map(l => ({ + p1: editor._transform_point_for_staircase(l.p1, p0, cos_a, -sin_a), + p2: editor._transform_point_for_staircase(l.p2, p0, cos_a, -sin_a), + })) + + //console.log(lines) + return lines + }, + + _update_staircase_preview: function(e = null) { + if (editor._current_editing_shape === null) { + return + } + points = editor._current_editing_shape._parts[0] || [] + editor._staircase_layer.clearLayers() + //console.log(points) + if (points.length < 3) { + return + } + + xs = points.map(p => p.x) + ys = points.map(p => p.y) + lines = editor._transform_for_staircase(xs, ys, editor._staircase_steps_count) + + lines.forEach(l => { + L.polyline( + [ + editor.map.layerPointToLatLng([l.p1.x, l.p1.y]), + editor.map.layerPointToLatLng([l.p2.x, l.p2.y]), + ], + {color: "red"} + ).addTo(editor._staircase_layer); + }) } }; diff --git a/src/c3nav/editor/templates/editor/create_staircase.html b/src/c3nav/editor/templates/editor/create_staircase.html new file mode 100644 index 00000000..b17e0754 --- /dev/null +++ b/src/c3nav/editor/templates/editor/create_staircase.html @@ -0,0 +1,40 @@ +{% load bootstrap3 %} +{% load i18n %} + +{% include 'editor/fragment_levels.html' %} + +