Interp almost-complete brute-force interpolation
This commit is contained in:
@@ -166,7 +166,7 @@
|
|||||||
<label title="Number of iterations done at the end">
|
<label title="Number of iterations done at the end">
|
||||||
Full: Iterations
|
Full: Iterations
|
||||||
<output id="fullIterationsSliderOutput">20</output><br/>
|
<output id="fullIterationsSliderOutput">20</output><br/>
|
||||||
<input type="range" min="1" max="100" value="20" step="1" oninput="d3.select('#fullIterationsSliderOutput').text(value); FULL_ITERATIONS=value;">
|
<input type="range" min="0" max="100" value="20" step="1" oninput="d3.select('#fullIterationsSliderOutput').text(value); FULL_ITERATIONS=value;">
|
||||||
</label>
|
</label>
|
||||||
<br/>
|
<br/>
|
||||||
<label title="Full NeighbourSize">
|
<label title="Full NeighbourSize">
|
||||||
|
|||||||
@@ -297,16 +297,21 @@ function startHybridSimulation() {
|
|||||||
simulation.stop();
|
simulation.stop();
|
||||||
p1 = performance.now();
|
p1 = performance.now();
|
||||||
|
|
||||||
hybridSimulation = d3.hybridSimulation(nodes);
|
configuration = {
|
||||||
|
iteration: ITERATIONS,
|
||||||
hybridSimulation
|
neighbourSize: NEIGHBOUR_SIZE,
|
||||||
.multiplier(MULTIPLIER)
|
sampleSize: SAMPLE_SIZE,
|
||||||
.sampleIterations(ITERATIONS)
|
distanceRange: SELECTED_DISTANCE * MULTIPLIER,
|
||||||
.pivots(PIVOTS)
|
fullIterations: FULL_ITERATIONS,
|
||||||
.numPivots(NUM_PIVOTS)
|
fullNeighbourSize: FULL_NEIGHBOUR_SIZE,
|
||||||
.fullIterations(FULL_ITERATIONS)
|
fullSampleSize: FULL_SAMPLE_SIZE,
|
||||||
.neighbourSize(NEIGHBOUR_SIZE)
|
fullDistanceRange: FULL_SELECTED_DISTANCE * MULTIPLIER,
|
||||||
|
distanceFn: function (s, t) {return distanceFunction(s, t, props, norm) * MULTIPLIER;},
|
||||||
|
pivots: PIVOTS,
|
||||||
|
numPivots: NUM_PIVOTS
|
||||||
|
};
|
||||||
.sampleSize(SAMPLE_SIZE);
|
.sampleSize(SAMPLE_SIZE);
|
||||||
|
hybridSimulation = d3.hybridSimulation(nodes, configuration);
|
||||||
|
|
||||||
let sample = hybridSimulation.sample();
|
let sample = hybridSimulation.sample();
|
||||||
let remainder = hybridSimulation.remainder();
|
let remainder = hybridSimulation.remainder();
|
||||||
|
|||||||
@@ -16,34 +16,34 @@ export default function (nodes, config) {
|
|||||||
FullneighbourSize = config.hasOwnProperty("fullNeighbourSize") ? config.fullNeighbourSize : 6,
|
FullneighbourSize = config.hasOwnProperty("fullNeighbourSize") ? config.fullNeighbourSize : 6,
|
||||||
FullsampleSize = config.hasOwnProperty("fullSampleSize") ? config.fullSampleSize : 3,
|
FullsampleSize = config.hasOwnProperty("fullSampleSize") ? config.fullSampleSize : 3,
|
||||||
FulldistanceRange = config.hasOwnProperty("fullDistanceRange") ? config.fullDistanceRange : 10,
|
FulldistanceRange = config.hasOwnProperty("fullDistanceRange") ? config.fullDistanceRange : 10,
|
||||||
distanceFn = config.hasOwnProperty("distanceFn") ? config.distance : constant(300),
|
distanceFn = config.hasOwnProperty("distanceFn") ? config.distanceFn : constant(300),
|
||||||
PIVOTS = config.hasOwnProperty("pivots") ? config.pivots : false,
|
PIVOTS = config.hasOwnProperty("pivots") ? config.pivots : false,
|
||||||
NUMPIVOTS = config.hasOwnProperty("numPivots") ? config.numPivots : 3,
|
NUMPIVOTS = config.hasOwnProperty("numPivots") ? config.numPivots : 3,
|
||||||
event = d3.dispatch("sampleTick", "fullTick", "startFull", "end");
|
event = d3.dispatch("sampleTick", "fullTick", "startFull", "end");
|
||||||
|
|
||||||
var sets = sampleFromNodes(nodes, nodes.length, Math.sqrt(nodes.length));
|
var sets = sampleFromNodes(nodes, Math.sqrt(nodes.length));
|
||||||
var sample = sets.sample;
|
var sample = sets.sample;
|
||||||
var remainder = sets.remainder;
|
var remainder = sets.remainder;
|
||||||
var interpSubset = sampleFromNodes(sample, sample.length, Math.sqrt(sample.length)).sample;
|
var sampleSubset = sampleFromNodes(sample, Math.sqrt(sample.length)).sample;
|
||||||
|
|
||||||
var sampleSimulation = d3.forceSimulation(sample)
|
var sampleSimulation = d3.forceSimulation(sample)
|
||||||
.stop()
|
.stop()
|
||||||
.alphaDecay(1 - Math.pow(0.001, 1 / SAMPLE_ITERATIONS));
|
.alphaDecay(1 - Math.pow(0.001, 1 / SAMPLE_ITERATIONS))
|
||||||
|
|
||||||
sampleSimulation
|
|
||||||
.on("tick", function () {
|
.on("tick", function () {
|
||||||
event.call("sampleTick", sampleSimulation);
|
event.call("sampleTick", sampleSimulation);
|
||||||
})
|
})
|
||||||
.on("end", ended)
|
.on("end", ended);
|
||||||
.force("neighbourSampling", neighbourSamplingDistance()
|
|
||||||
|
sampleSimulation.force("forces", neighbourSamplingDistance()
|
||||||
.neighbourSize(neighbourSize)
|
.neighbourSize(neighbourSize)
|
||||||
.sampleSize(sampleSize)
|
.sampleSize(sampleSize)
|
||||||
.distanceRange(distanceRange)
|
.distanceRange(distanceRange)
|
||||||
.distance(distanceFn)
|
.distance(distanceFn)
|
||||||
)
|
);
|
||||||
.alpha(1).restart();
|
sampleSimulation.alpha(1).restart();
|
||||||
|
|
||||||
function ended() {
|
function ended() {
|
||||||
|
event.call("startFull");
|
||||||
console.log("Ended sample simulation");
|
console.log("Ended sample simulation");
|
||||||
/*
|
/*
|
||||||
if (PIVOTS) {
|
if (PIVOTS) {
|
||||||
@@ -52,12 +52,16 @@ export default function (nodes, config) {
|
|||||||
interpolation(sample, remainder, interpSubset, distance);
|
interpolation(sample, remainder, interpSubset, distance);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if (FULL_ITERATIONS==0) return;
|
event.call("fullTick");
|
||||||
|
alert('About to Full run');
|
||||||
|
if (FULL_ITERATIONS==0) {
|
||||||
|
event.call("end");
|
||||||
|
return;
|
||||||
|
}
|
||||||
fullSimulation = d3.forceSimulation()
|
fullSimulation = d3.forceSimulation()
|
||||||
.stop()
|
.stop()
|
||||||
.alphaDecay(1 - Math.pow(0.001, 1 / FULL_ITERATIONS));
|
.alphaDecay(1 - Math.pow(0.001, 1 / FULL_ITERATIONS));
|
||||||
|
|
||||||
event.call("startFull", fullSimulation);
|
|
||||||
|
|
||||||
fullSimulation
|
fullSimulation
|
||||||
.force("neighbourSampling", neighbourSamplingDistance()
|
.force("neighbourSampling", neighbourSamplingDistance()
|
||||||
@@ -139,8 +143,9 @@ export default function (nodes, config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function sampleFromNodes(nodes, max, size) {
|
function sampleFromNodes(nodes, size) {
|
||||||
var randElements = [];
|
let randElements = [],
|
||||||
|
max = nodes.length;
|
||||||
|
|
||||||
for (var i = 0; i < size; ++i) {
|
for (var i = 0; i < size; ++i) {
|
||||||
var rand = nodes[Math.floor((Math.random() * max))];
|
var rand = nodes[Math.floor((Math.random() * max))];
|
||||||
|
|||||||
@@ -1,60 +1,45 @@
|
|||||||
export default function(sampleSet, remainderSet, interpSubset, distanceFunction) {
|
export default function(sampleSet, remainderSet, sampleSubset, distanceFn) {
|
||||||
var distance = distanceFunction;
|
var distance = distanceFunction;
|
||||||
// var distance = calculateEuclideanDistance;
|
// var distance = calculateEuclideanDistance;
|
||||||
|
|
||||||
// console.log("Brute-force");
|
// console.log("Brute-force");
|
||||||
|
for (let node of remainderSet) {
|
||||||
|
let nearestSample = undefined,
|
||||||
|
minDist = undefined,
|
||||||
|
sampleSubsetDistanceCache = [];
|
||||||
|
|
||||||
for (var i = 0; i < remainderSet.length; i++) {
|
for (let sample of sampleSet) {
|
||||||
var node = remainderSet[i],
|
let dist = distanceFn(node, sample);
|
||||||
minNode = sampleSet[0],
|
if (nearestSample === undefined || dist < minDist) {
|
||||||
minDist = 0,
|
minDist = dist;
|
||||||
sampleCache = [];
|
nearestSample = sample;
|
||||||
|
}
|
||||||
|
|
||||||
minDist = distance(node, minNode, props, norm);
|
let index = sampleSubset.indexOf(sample);
|
||||||
|
if (index !== -1) {
|
||||||
for (var j = 1, sample; j < sampleSet.length; j++) {
|
sampleSubsetDistanceCache[index] = dist;
|
||||||
sample = sampleSet[j];
|
|
||||||
if ((sample !== node) && (distance(node, sample, props, norm) < minDist)) {
|
|
||||||
minDist = distance(node, sample, props, norm);
|
|
||||||
minNode = sample;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// console.log()
|
placeNearToNearestNeighbour(node, nearestSample, minDist, sampleSubset, sampleSubsetDistanceCache);
|
||||||
|
|
||||||
for (var k = 0; k < interpSubset.length; k++) {
|
|
||||||
sampleCache[k] = distance(node, interpSubset[k], props, norm);
|
|
||||||
}
|
|
||||||
var radius = distance(node, minNode, props, norm);
|
|
||||||
placeNearToNearestNeighbour(node, minNode, interpSubset, sampleCache, radius);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function placeNearToNearestNeighbour(node, minNode, sample, sampleCache, radius) {
|
function placeNearToNearestNeighbour(node, minNode, radius, samples, realDistances) {
|
||||||
var
|
let
|
||||||
dist0 = 0.0,
|
dist0 = sumDistError(pointOnCircle(minNode.x, minNode.y, 0, radius), samples, realDistances),
|
||||||
dist90 = 0.0,
|
dist90 = sumDistError(pointOnCircle(minNode.x, minNode.y, 90, radius), samples, realDistances),
|
||||||
dist180 = 0.0,
|
dist180 = sumDistError(pointOnCircle(minNode.x, minNode.y, 180, radius), samples, realDistances),
|
||||||
dist270 = 0.0,
|
dist270 = sumDistError(pointOnCircle(minNode.x, minNode.y, 270, radius), samples, realDistances),
|
||||||
lowBound = 0.0,
|
lowBound = 0.0,
|
||||||
highBound = 0.0;
|
highBound = 0.0;
|
||||||
|
|
||||||
dist0 = sumDistToSample(node, centerPoint(0, radius, minNode.x, minNode.y), sample, sampleCache);
|
|
||||||
dist90 = sumDistToSample(node, centerPoint(90, radius, minNode.x, minNode.y), sample, sampleCache);
|
|
||||||
dist180 = sumDistToSample(node, centerPoint(180, radius, minNode.x, minNode.y), sample, sampleCache);
|
|
||||||
dist270 = sumDistToSample(node, centerPoint(270, radius, minNode.x, minNode.y), sample, sampleCache);
|
|
||||||
|
|
||||||
// console.log(dist0, dist90, dist180, dist270);
|
|
||||||
|
|
||||||
// Determine the closest quadrant
|
// Determine the closest quadrant
|
||||||
|
|
||||||
if (dist0 == dist180) {
|
if (dist0 == dist180) {
|
||||||
if (dist90 > dist270)
|
if (dist90 > dist270)
|
||||||
lowBound = highBound = 270;
|
lowBound = highBound = 270;
|
||||||
else
|
else
|
||||||
lowBound = highBound = 90;
|
lowBound = highBound = 90;
|
||||||
|
|
||||||
} else if (dist90 == dist270) {
|
} else if (dist90 == dist270) {
|
||||||
if (dist0 > dist180)
|
if (dist0 > dist180)
|
||||||
lowBound = highBound = 180;
|
lowBound = highBound = 180;
|
||||||
@@ -78,8 +63,11 @@ function placeNearToNearestNeighbour(node, minNode, sample, sampleCache, radius)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let angle = binarySearch(lowBound, highBound, minNode.x, minNode.y, radius, node, sample, realDistances);
|
let angle = binarySearchMin(lowBound, highBound,
|
||||||
let newPoint = centerPoint(angle, radius, minNode.x, minNode.y);
|
function(angle){
|
||||||
|
return sumDistError(pointOnCircle(minNode.x, minNode.y, angle, radius), samples, realDistances);
|
||||||
|
});
|
||||||
|
let newPoint = pointOnCircle(minNode.x, minNode.y, angle, radius);
|
||||||
|
|
||||||
// console.log(newPoint);
|
// console.log(newPoint);
|
||||||
node.x = newPoint.x;
|
node.x = newPoint.x;
|
||||||
@@ -110,17 +98,13 @@ function toRadians(degrees) {
|
|||||||
return degrees * (Math.PI / 180);
|
return degrees * (Math.PI / 180);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sumDistToSample(node, point, sample, sampleCache) {
|
function sumDistError(currentPos, samples, realDistances) {
|
||||||
var total = 0.0;
|
let total = 0.0;
|
||||||
// console.log(total, sample);
|
for (let i = 0; i < samples.length; i++) {
|
||||||
|
let sample = samples[i];
|
||||||
for (var i = 0; i < sample.length; i++) {
|
let lowDDistance = Math.hypot(sample.x - currentPos.x, sample.y - currentPos.y);
|
||||||
var s = sample[i];
|
total += Math.abs(lowDDistance - realDistances[i]);
|
||||||
var realDist = Math.hypot(s.x - point.x, s.y - point.y);
|
|
||||||
var desDist = sampleCache[i];
|
|
||||||
total += Math.abs(realDist - desDist);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,32 +149,26 @@ function sumForcesToSample(node, sample, sampleCache) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function binarySearchMin(lb, hb, fn) {
|
||||||
function binarySearch(lb, hb, x, y, r, node, sample, sampleCache) {
|
|
||||||
while (lb <= hb) {
|
while (lb <= hb) {
|
||||||
var mid = Math.round((lb + hb) / 2);
|
if(lb === hb) return lb;
|
||||||
|
if(hb-lb == 1) {
|
||||||
|
if (fn(lb) >= fn(hb)) return hb;
|
||||||
|
else return lb;
|
||||||
|
}
|
||||||
|
|
||||||
if ((mid === lb) || (mid === hb)) {
|
let range = hb-lb;
|
||||||
if (sumDistToSample(node, centerPoint(lb, r, x, y), sample, sampleCache) >=
|
let valLowerHalf = fn(lb + range/4);
|
||||||
sumDistToSample(node, centerPoint(hb, r, x, y), sample, sampleCache)) {
|
let valHigherHalf = fn(lb + range*3/4);
|
||||||
return hb;
|
|
||||||
} else {
|
|
||||||
return lb;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
var distMidLeft = sumDistToSample(node, centerPoint(mid + 1, r, x, y), sample, sampleCache);
|
|
||||||
var distMidRight = sumDistToSample(node, centerPoint(mid - 1, r, x, y), sample, sampleCache);
|
|
||||||
var distMid = sumDistToSample(node, centerPoint(mid, r, x, y), sample, sampleCache);
|
|
||||||
|
|
||||||
if (distMid > distMidLeft) {
|
if (valLowerHalf > valHigherHalf)
|
||||||
lb = mid + 1;
|
lb = Math.floor((lb + hb) / 2);
|
||||||
} else if (distMid > distMidRight) {
|
else if (valLowerHalf < valHigherHalf)
|
||||||
hb = mid - 1;
|
hb = Math.ceil((lb + hb) / 2);
|
||||||
} else {
|
else {
|
||||||
return mid;
|
lb += Math.floor(range/4);
|
||||||
}
|
hb -= Math.ceil(range/4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user