d3.select('body').selectAppend('div.tooltip.tooltip-hidden') console.clear() var s = 150 var edges = makeEdge(54, [0, 0]) var step = 0 var edgeUUID = 1 var squares = d3.range(10, s, 3) .map(d => { return {s: d} }) .sort(d3.ascendingKey(d => d.s)) .reverse() var c = d3.conventions({sel: d3.select('.graph').html('')}) var {width, height} = c var g = c.svg.append('g').translate([width/2, height/2]) render() if (window.timer) window.timer.stop() window.timer = d3.interval(() => { if (step > 20) window.timer.stop() d3.range(1).forEach(() => { addNext() render() }) }, 100) function addNext(){ console.log('STEP', ++step) var next = squares.filter(d => !d.included)[0] if (!next) return window.timer.stop() next.included = true var s = next.s var validEdgesStart = [] // d3.shuffle(edges).forEach(e0 => { edges.forEach(e0 => { var nextEdges = makeEdge(s, [e0.x, e0.y], e0) intersections = [] nextEdges.forEach(e1 => { // todo exit early edges.forEach(e2 => { intersections.push(intersects(e1, e2)) }) }) if (intersections.every(d => !d.crosses)){ validEdgesStart.push({nextEdges, intersections}) } }) var {nextEdges, intersections} = validEdgesStart[1] intersections.filter(d => d.overlap).forEach(d => { d.e0.remove = true d.e1.remove = true edges = edges.concat(d.newSegments) }) edges = edges .concat(nextEdges) .filter(d => !d.remove) edges.forEach(d => { if (!d.uuid) d.uuid = edgeUUID++ }) } function render(){ g.selectAll('.edge').remove() g.appendMany('path.all-edge', edges) .at({ d: d => ['M', d.x, d.y, d.type, d.l].join(' '), stroke: '#000', }) .st({strokeWidth: 1}) var edgeSel = g.appendMany('path.edge', edges) .at({ d: d => ['M', d.x, d.y, d.type, d.l].join(' '), stroke: '#000', }) .on('mouseover', d => edgeSel.classed('active', e => e.l == d.l) ) .call(d3.attachTooltip) } function intersects(e0, e1){ if (e0.type == e1.type){ // todo gather edges var newSegments = [] if (e0.type == 'h'){ if (e0.y != e1.y) return {} var y = e0.y var [min0, max0] = _.sortBy([e0.x, e0.x + e0.l]) var [min1, max1] = _.sortBy([e1.x, e1.x + e1.l]) if (max0 <= min1 || max1 <= min0) return {} // check min overlap var l = Math.abs(min1 - min0) if (min0 < min1 && min1 < max0){ newSegments.push({ x: e0.l > 0 ? min0 : min1, y, l: e0.l > 0 ? l : -l, type: 'h' }) } else if (min1 < min0 && min0 < max1){ newSegments.push({ x: e1.l > 0 ? min1 : min0, y, l: e1.l > 0 ? l : -l, type: 'h' }) } // check max overlap var l = Math.abs(max1 - max0) if (min0 < max1 && max1 < max0){ newSegments.push({ x: e0.l > 0 ? max1 : max0, y, l: e0.l > 0 ? l : -l, type: 'h' }) } else if (min1 < max0 && max0 < max1){ newSegments.push({ x: e1.l > 0 ? max0 : max1, y, l: e1.l > 0 ? l : -l, type: 'h' }) } } else{ if (e0.x != e1.x) return {} var x = e0.x var [min0, max0] = _.sortBy([e0.y, e0.y + e0.l]) var [min1, max1] = _.sortBy([e1.y, e1.y + e1.l]) if (max0 <= min1 || max1 <= min0) return {} var isLogging = e0.l == -145 && e0.y == 0 && e0.x == 54 && false // check min overlap var l = Math.abs(min1 - min0) if (min0 < min1 && min1 < max0){ if (isLogging) console.log('overlap found') newSegments.push({ x, y: e0.l > 0 ? min0 : min1, l: e0.l > 0 ? l : -l, type: 'v' }) } else if (min1 < min0 && min0 < max1){ newSegments.push({ x: x, y: e1.l > 0 ? min1 : min0, l: e1.l > 0 ? l : -l, type: 'v' }) } if (isLogging){ console.log('ERROR') console.log(min0, max0) console.log(min1, max1) console.table([e0, e1]) console.log(l) console.table(newSegments) } // check max overlap var l = Math.abs(max1 - max0) if (min0 < max1 && max1 < max0){ newSegments.push({ x, y: e0.l > 0 ? max1 : max0, l: e0.l > 0 ? l : -l, type: 'v' }) } else if (min1 < max0 && max0 < max1){ newSegments.push({ x, y: e1.l > 0 ? max0 : max1, l: e1.l > 0 ? l : -l, type: 'v' }) } } return {overlap: true, newSegments, e0, e1} } else{ var h = e0.type == 'h' ? e0 : e1 var v = e0.type == 'v' ? e0 : e1 var [xMin, xMax] = _.sortBy([h.x, h.x + h.l]) var xInt = xMin < v.x && v.x < xMax var [yMin, yMax] = _.sortBy([v.y, v.y + v.l]) var yInt = yMin < h.y && h.y < yMax var uuidStr = e0.uuid + '-' + e1.uuid if (uuidStr.includes(93) && uuidStr.includes(439) && uuidStr == '439-93'){ console.log('intersection not detected ', uuidStr) console.log(yInt, xInt) console.log(yMin, h.y, yMax) } return {crosses: xInt && yInt} } } // console.log(intersects( // {x: 0, y: 170, l: 110, type: "h"}, // {x: 45, y: 90, l: 85, type: "v"} // )) function makeEdge(l, [x, y], e = {}){ if (e.l < 0) y = y - l if (e.type == 'h' && e.l < 0) x = x - l if (e.type == 'v' && e.l > 0) x = x - l return [ {x: x + 0, y: y + 0, l: l, type: 'v', uuid: edgeUUID++}, {x: x + 0, y: y + l, l: l, type: 'h', uuid: edgeUUID++}, {x: x + l, y: y + l, l: -l, type: 'v', uuid: edgeUUID++}, {x: x + l, y: y + 0, l: -l, type: 'h', uuid: edgeUUID++}, ] }