Calculating the subsegments of a line, using logarithmic scaling - javascript

I want to calculate the length of the subsegments of a line having a length of totalLineLength, where the subsegments are proportional to the log of the events given.
A visual representation: |---|-----|---------| a line composed of subsegments.
I want the sum of the calculated subsegments to be equal to totalLineLength, and Success must be printed. Log(x+1) must be used too (because it gives always positive results for positive arguments and scales 1 too).
Using linear scaling, I'm doing this, and it works.
var totalLineLength = 20;
var eventTotal;
var calcSubSegment = function(x) {
return totalLineLength * x / eventTotal;
}
var events = [0.1, 1, 22];
eventTotal = events.reduce((a, b) => a + b, 0);
var subSegments = events.map(calcSubSegment);
var segmentLength = subSegments.reduce((a, b) => a + b);
if (segmentLength != totalLineLength) {
console.log("Error:", segmentLength);
} else {
console.log("Success");
}
Using log(x+1) (calcSubSegment is updated), it doesn't work.
var totalLineLength = 20;
var eventTotal;
var calcSubSegment = function(x) {
return totalLineLength * Math.log(x+1) / Math.log(eventTotal+1);
}
var events = [0.1, 1, 22];
eventTotal = events.reduce((a, b) => a + b, 0);
var subSegments = events.map(calcSubSegment);
var segmentLength = subSegments.reduce((a, b) => a + b, 0);
if (segmentLength != totalLineLength) {
console.log("Error:", segmentLength);
} else {
console.log("Success");
}
What's wrong with my code? I suppose the eventTotal calculation, but I'm not sure how to proceed.
How should I use logarithmic scaling? I'd also like a mathematical explanation.

If I understand your task correctly, the simplest solution is first map all events using your log(x+1) functions and then just use linear split you've already implemented. Something like this:
function linearSplit(events, totalLineLength) {
var eventTotal;
var calcSubSegment = function(x) {
return totalLineLength * x / eventTotal;
}
eventTotal = events.reduce((a, b) => a + b, 0);
var subSegments = events.map(calcSubSegment);
return subSegments;
}
function logSplit(events, totalLineLength) {
var logEvents = events.map(function(x) { return Math.log(x+1); } );
return linearSplit(logEvents, totalLineLength);
}
function testSplit(events, totalLineLength, fnSplit, splitName) {
var subSegments = fnSplit(events, totalLineLength);
var segmentLength = subSegments.reduce((a, b) => a + b, 0);
console.log(splitName + ":\n" + events + " =>\n" + subSegments);
if (Math.abs(segmentLength - totalLineLength) > 0.001) {
console.log(splitName + " Error:", segmentLength);
} else {
console.log(splitName + " Success");
}
}
var totalLineLength = 20;
var events = [0.1, 1, 22];
testSplit(events, totalLineLength, linearSplit, "linearSplit");
testSplit(events, totalLineLength, logSplit, "logSplit");
The idea is that the only splitting that
Has parts proportionally to some coefficients
Makes sum of all parts equal to the whole
at the same time is the linear splitting. So if you want to scale coefficients in any way, you should scale them before passing to the linear splitting logic. Otherwise the sum of parts will not equal the whole (in case of any non-linear scaling) as it happens in your code.
P.S. It is not very good idea to compare floating point values by ==. You should use some tolerance for calculation/rounding errors.

Important rule while dealing with logarithms: log(a)+log(b) = log(a*b). Hence for the calculation of the total length, we need to the find the product of the individual numbers instead of their sum.
What you are doing is showing that log(a)+log(b) != log(a+b), so try multiplying the numbers instead of adding them.
Use an error margin as described in SergGr's answer, because of the way floating point operations work.
var totalLineLength = 20;
var eventTotal;
var calcSubSegment = function(x) {
return totalLineLength * Math.log(x+1) / Math.log(eventTotal);
}
var events = [0.1, 1, 22];
eventTotal = events.reduce((a, b) => a * (b+1), 1);
var subSegments = events.map(calcSubSegment);
var segmentLength = subSegments.reduce((a, b) => a + b, 0);
if (segmentLength != totalLineLength) {
console.log("Error:", segmentLength);
} else {
console.log("Success", subSegments);
}

Related

Is it possible to make offset/shift in d3.js scales?

I want to make an "overflow" scale that will reset value and continue count from zero if it overflows limit
For example, I want to draw a chart but change the original 0 point place. The first column represents a normal scale, and in the second column I shifted the scale
5 2
4 1
3 0
2 5
1 4
0 3
I think I can alter input data and convert first half of values to negative so the domain will look like this [-2: 3]. But I would prefer not to alter input data values and just have a parameter in scale that can do this for me.
UPD:
I've tried to use more than 2 domain/range values - didn't give me the results that I want, so I wrote a custom interpolation function.
I doubt that only I need something like this and probably d3.js provide something similar. If you know a function like this in standard d3.js distribution please point me to it.
const svg = d3.select("svg").attr('height', 200);
myinterpolate = function(a, b) {
var a = a;
var b = b;
var shift = 100;
var max_value = Math.max(a, b)
var min_value = Math.min(a, b)
return function(t) {
let result = a * (1 - t) + b * t + shift;
if (result < min_value) {
result = result + max_value
} else if (result > max_value) {
result = result % max_value
}
return result
}
;
}
const myScale = d3.scaleLinear().domain([0, 10]).range([200, 0]).interpolate(myinterpolate);
const axis = d3.axisLeft(myScale).tickValues(d3.range(10)).tickFormat(d=>~~d)(svg.append("g").attr("transform", "translate(50,0)"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg><svg>
You said "I would prefer not to alter input data values and just have a parameter in scale that can do this for me", but that's a very specific and highly unusual use case, so there is none.
What you could easily do is creating a piecewise scale with more than 2 domain/range values:
const svg = d3.select("svg");
const myScale = d3.scaleLinear()
.domain([0, 3, 4, 6])
.range([75, 6, 144, 98]);
const axis = d3.axisLeft(myScale).tickValues(d3.range(7)).tickFormat(d => ~~d)(svg.append("g").attr("transform", "translate(50,0)"))
path {
stroke: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg></svg>
This simply answers your question as it is. Mind you that it raises several other questions: where are you drawing the values between 3 and 4? What's the meaning of the area between 6 and 0?
A custom interpolation function worked for me.
My code snippet uses a hardcoded value for the shift, but it can be rewritten to use shift value as a parameter.
const svg = d3.select("svg").attr('height', 200);
myinterpolate = function(a, b) {
var a = a;
var b = b;
var shift = 100;
var max_value = Math.max(a, b)
var min_value = Math.min(a, b)
return function(t) {
let result = a * (1 - t) + b * t + shift;
if (result < min_value) {
result = result + max_value
} else if (result > max_value) {
result = result % max_value
}
return result
}
;
}
const myScale = d3.scaleLinear().domain([0, 10]).range([200, 0]).interpolate(myinterpolate);
const axis = d3.axisLeft(myScale).tickValues(d3.range(10)).tickFormat(d=>~~d)(svg.append("g").attr("transform", "translate(50,0)"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg><svg>

Math operations from string using Javascript

I am trying to find a simple way to perform a set of javascript math operations without using eval() function. Example: 1+2x3x400+32/2+3 and it must follow the PEMDAS math principle. This is what I have, but it doesn't work exactly it should.
function mdas(equation) {
let operations = ["*", "/", "+", "-"];
for (let outerCount = 0; outerCount < operations.length; outerCount++) {
for (let innerCount = 0; innerCount < equation.length; ) {
if (equation[innerCount] == operations[outerCount]) {
let operationResult = runOperation(equation[innerCount - 1], operations[outerCount], equation[innerCount + 1]);
var leftSideOfEquation = equation.substr(0, equation.indexOf(innerCount - 1));
var rightSideOfEquation = equation.substr(equation.indexOf(innerCount), equation.length);
var rightSideOfEquation = rightSideOfEquation.replace(rightSideOfEquation[0],String(operationResult));
equation = leftSideOfEquation + rightSideOfEquation;
innerCount = 0;
}
else {
innerCount++;
}
}
}
return "Here is it: " + equation; //result of the equation
}
If you don't want to use a complete library like mathjs - and you don't want to tackle creating your own script which would involve: lexical analysis, tokenization, syntax analysis, recursive tree parsing, compiling and output...
the simplest banal suggestion: Function
const calc = s => Function(`return(${s})`)();
console.log( calc("1+2*3*400+32/2+3") ); // 2420
console.log( calc("-3*-2") ); // 6
console.log( calc("-3 * + 1") ); // -3
console.log( calc("-3 + -1") ); // -4
console.log( calc("2 * (3 + 1)") ); // 8
My take at a custom MDAS
Here I created a Regex to retrieve operands and operators, accounting for negative values: /(-?[\d.]+)([*\/+-])?/g.
Firstly we need to remove any whitespace from our string using str.replace(/ /g , "")
Using JavaScript's String.prototype.matchAll() we can get a 2D array with all the matches as [[fullMatch, operand, operator], [.. ] we can than further flatten it using Array.prototype.flat()
Having that flattened array, we can now filter it using Array.prototype.filter() to remove the fullMatch -es returned by the regular expression and remove the last undefined value.
Define a calc Object with the needed operation functions
Iterate over the MDAS groups */ and than +- as regular expressions /\/*/ and /+-/
Consume finally the array of matches until only one array key is left
let str = "-1+2 * 3*+400+-32 /2+3.1"; // 2386.1
str = str.replace(/ +/g, ""); // Remove all spaces!
// Get operands and operators as array.
// Remove full matches and undefined values.
const m = [...str.matchAll(/(-?[\d.]+)([*\/+-])?/g)].flat().filter((x, i) => x && i % 3);
const calc = {
"*": (a, b) => a * b,
"/": (a, b) => a / b,
"+": (a, b) => a + b,
"-": (a, b) => a - b,
};
// Iterate by MDAS groups order (first */ and than +-)
[/[*\/]/, /[+-]/].forEach(expr => {
for (let i = 0; i < m.length; i += 2) {
let [a, x, b] = [m[i], m[i + 1], m[i + 2]];
x = expr.exec(x);
if (!x) continue;
m[i] = calc[x.input](parseFloat(a), parseFloat(b)); // calculate and insert
m.splice(i + 1, 2); // remove operator and operand
i -= 2; // rewind loop
}
});
// Get the last standing result
console.log(m[0]); // 2386.1
It's a little hacky, but you can try something like this:
var eqs = [
'1+2*3*4+1+1+3',
'1+2*3*400+32/2+3',
'-5+2',
'3*-2',
];
for(var eq in eqs) { console.log(mdas(eqs[eq])); }
function mdas(equation) {
console.log(equation);
var failsafe = 100;
var num = '(((?<=[*+-])-|^-)?[0-9.]+)';
var reg = new RegExp(num + '([*/])' + num);
while(m = reg.exec(equation)) {
var n = (m[3] == "*") ? m[1]*m[4] : m[1]/m[4];
equation = equation.replace(m[0], n);
if(failsafe--<0) { return 'failsafe'; }
}
var reg = new RegExp(num + '([+-])' + num);
while(m = reg.exec(equation)) {
var n = (m[3] == "+") ? 1*m[1] + 1*m[4] : m[1]-m[4];
equation = equation.replace(m[0], n);
if(failsafe--<0) { return 'failsafe'; }
}
return equation;
}

Javascript K Closest Points to Origin in Linear Time?

Is it problem to solve this problem in linear time O(N)? The only way I see to solve it is with sort() which give me O(NlogN) time.
Problem:
We have a list of points on the plane. Find the K closest points to the origin (0, 0).
(Here, the distance between two points on a plane is the Euclidean distance.)
You may return the answer in any order. The answer is guaranteed to be unique (except for the order that it is in.)
My solution:
/*
d = sqrt ( (x-0)^2 + (y-0)^2 )
*/
var kClosest = function(points, K) {
points.sort((a,b) => {
const d1 = Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2));
const d2 = Math.sqrt(Math.pow(b[0], 2) + Math.pow(b[1], 2));
return d1-d2;
});
return points.splice(0, K);
};
There is a way, using count sort instead.
Suppousing that the maximum X and Y coordinates are fairly limited, you can skip using Math.sqrt altogether. You will end up with a distances array of integer values representing the square of each point's distance to the center.
Then, you loop from 0 to the maximum possible distance through this array and print every point you find, until you have found K points.
Here's my implementation (you might be able to make it prettier 😄):
points = [[-1, 9], [2, 2], [10, 15], [3, 4], [7,5]]
var kClosest = function(points, K) {
const MAX_X = 100
const MAX_Y = 100
const MAX_DISTANCE = MAX_X**2 + MAX_Y**2
let distancesSquared = new Array(MAX_DISTANCE).fill(null).map(() => [])
for(let point of points) {
const distanceSquared = point[0]**2 + point[1]**2
distancesSquared[distanceSquared].push(point)
}
const result = []
let pointsLeft = Math.min(points.length, K) // Make sure K isn't greater than the amount of points
for(let crtDistance = 0; crtDistance <= MAX_DISTANCE; ++crtDistance) {
while(distancesSquared[crtDistance].length > 0 && pointsLeft > 0) {
result.push(distancesSquared[crtDistance].pop())
--pointsLeft
}
if(pointsLeft === 0) { // Tiny optimisation
break
}
}
return result
};
kClosest(points, 3)

How to calculate coefficients of polynomial expansion in javascript

Suppose I have the following factors:
(1+3x)(1+x)(1+2x)
Expanded to a polynomial, it looks like:
1 + 6x + 11x^2 + 6x^3
The coefficients of this polynomial would be
c0 = 1
c1 = 6
c2 = 11
c3 = 6
I'm trying to figure out how to calculate these rapidly (for any set of factors). The ideal output would be an array of the coefficients, like
var coeff = [c0,c1,c2,c3];
What I'm trying to do is find a way to quickly go from the factors to the array of coefficients. Any suggestions on how to rapidly handle this in javascript? And for the sake of clarity, I'm trying to figure out how to do this for any set of n factors, not just this particular scenario.
You could use the factors as vector and use a cross product for the result.
function multiply(a1, a2) {
var result = [];
a1.forEach(function (a, i) {
a2.forEach(function (b, j) {
result[i + j] = (result[i + j] || 0) + a * b;
});
});
return result;
}
var data = [[1, 3], [1, 1], [1, 2]], // (1+3x)(1+x)(1+2x)
result = data.reduce(multiply);
console.log(result); // [1, 6, 11, 6] = 1x^0 + 6x^1 + 11x^2 + 6x^3
Well I found a method to do what you want from start to finish even without the need for any treatment in the original factors. Although I had to use a Math library. I found there is at least a library that does what you want: Nerdamer
As you can see from the code below the coeficients are correctly calculated from the factors you gave.
var factors = '(1+3x)(1+x)(1+2x)';
console.log('original factors: ' + factors);
var y = nerdamer('expand(' + factors + ')');
var polynomialform = y.toString();
console.log('polynomial form: ' + polynomialform);
var coef = polynomialform.split('+').map(v=>v.trim()).map(v=>v.split('x')[0]).map(v=>v.replace(/^\*+|\*+$/g, ''));
console.log('coeficients: ' + coef);
<script src="http://nerdamer.com/js/nerdamer.core.js"></script>
Notice that coefs var is an array.
Obviously, by the way I otained the coeficients, the operation may fail in different factor cases. This has to be adapted for minus characters and edge cases. You can create some kind of loop and put failed calculations in an array to check for edge cases to adapt the code for the full dataset. I can improve the answer if you provide a larger test dataset.
Hope it helps you.
Here's my take based on the fact that when you multiply (1+ax) by (1+b_1*x+b_2*x^2+...+b_nx^n), in the resulting polynomial (of degree n+1), the first term's coefficient will be one and its last term's coefficient will be a*b_n.
I think it is a bit simpler than the accepted answer, but still quadratic in time. To make this more efficient, you will need more advanced techniques.
function multOne(a, b) {
var n = b.length;
var r = [1]; //The first term is always 1
r[n] = a * b[n - 1]; //The last term is always a*b_n-1
for (var i = 1; i < n; i++)
r[i] = b[i] + a * b[i - 1];
return r;
}
function solve(c) {
var result = [1, c[0]]; //use result as an accumulator
for (var j = 1; j < c.length; j++)
result = multOne(c[j], result);
return result;
}
console.log(solve([3, 1, 2])); //You don't need to pass 1s either. Just pass the varying coefficients
I needed something similar (to calculate permutations via exponential generating functions) so I wrote a version that works when some terms missing, by using objects as the base instead. I also needed it not not calculate anything over a certain power, so that's also an option
/**
* Calculates the result of multiplying many polynomials together
* #example
* polynomials = [{0: 1, 1: 10, 2:1}, {0: 0, 1: 5, 2: 0, 3: 0.5}]
* limit = 4;
* polynomialMultiplication(polynomials, limit);
* #param {Array.<Object.<number,number>>} polynomials an array of polynomials,
* each expressed as an array of term coefficients
* #param {number} limit the maximum term to calculate
* #returns the resultant polynomial from multiplying all polynomials together
*/
function polynomialMultiplication(polynomials, limit) {
const length = limit ?? polynomials.reduce((sum, poly) => sum += Math.max(...Object.keys(poly)), 0)
// make an object to hold the result in
// which is prepopulated by zeros
const template = { ...Array.from({
length
}).fill(0)
};
return polynomials.reduce((memo, poly, polyIndex) => {
const tempCopy = { ...template};
if (polyIndex === 0) return { ...poly };
for (let termIndex = 0; termIndex < length && termIndex <= Math.max(...Object.keys(poly)); termIndex++) {
for (let memoIndex = 0;
(memoIndex + termIndex) <= length && memoIndex <= Math.max(...Object.keys(memo)); memoIndex++) {
const addition = (memo[memoIndex] ?? 0) * (poly[termIndex] ?? 0);
const copyIndex = memoIndex + termIndex;
tempCopy[copyIndex] = (tempCopy[copyIndex] ?? 0) + addition;
}
}
return tempCopy;
}, template)
}
console.log('(1+3x)(1+x)(1+2x)');
const polynomials = [{
0: 1,
1: 3
}, {
0: 1,
1: 1
}, {
0: 1,
1: 2
}];
console.log(polynomialMultiplication(polynomials));
const morePolynomials = [{
0: 1,
1: 0,
2: 5
}, {
0: 0,
1: 6
}, {
0: 1,
1: 2,
2: 0
}];
console.log('(1+5x^2)(6x)(1+2x) up to x^2')
console.log(polynomialMultiplication(morePolynomials, 2));

Check if given three line segments represented by coordinates of 4 element array can form a triangle

I need to check if given three line segments form a triangle. A line segment can be expressed as an array of 4 integers giving the end-points coordinates in the form [ x1, y1, x2, y2 ].
So I need to write a function that is given as input three line segments K, L and M and will return 1 if they form a triangle, 0 otherwise.
If the input parameters are outside the range of the algorithm supports I need to return -1.
Examples :
function trigTest(K, L, M)
var K=[2,3,6,9], L=[8,1,6,9], M=[8,1,2,3], X=[1,7,6,9]
trigTest(K, L, M) // -> 1
trigTest(L, K, M) // -> 1
trigTest(M, K, L) // -> 1
trigTest(L, L, M) // -> 0
trigTest(X, L, M) // -> 0
I actually have a solution but it's pretty cumbersome and I don't think it is the right way. First I calculate the distance of every line segment and then I use triangle inequalities to check if they can actually form a triangles base on their lengths.
function distance(line){
var x1 = line[0],
y1 = line[1],
x2 = line[2],
y2 = line[3];
return Math.sqrt(Math.pow((x2-x1),2) + Math.pow(y2-y1),2)
}
function trigTest(K,L,M){
var distanceK = distance(K), distanceL = distance(L), distanceM = distance(M);
if((distanceK + distanceL) > distanceM && (distanceK + distanceM) > distanceL && distanceL + distanceM > distanceK){
// algorithm here
}else{
return 0;
}
}
Update
Thanks to #antoniskamamis and #trincot I have made a similar solution if someone wants to stick with arrays instead of working with strings. Big shout out to them.
function trigTest(K, L, M) {
var points = [];
var k = dots(K), l = dots(L), m = dots(M);
if(ifDotsOnSameLineAreEqual(k) || ifDotsOnSameLineAreEqual(l) || ifDotsOnSameLineAreEqual(m)){
return false;
}else{
return points.concat(k,l,m).every(function(point, index, array){
return array.filter(function(i){ return ifTwoDotsAreEqual(i,point)}).length == 2;
})
}
}
function dots(line) {
var x1 = line[0],
y1 = line[1],
x2 = line[2],
y2 = line[3];
return [[x1,y1],[x2, y2]];
}
function ifTwoDotsAreEqual(x,y){
return x[0] == y[0] && x[1] == y[1];
}
function ifDotsOnSameLineAreEqual(line){
return ifTwoDotsAreEqual(line[0],line[1]);
}
you could use this approach
function trigTest(a,b,c){
var parts = [];
Array.prototype.slice.call(arguments).forEach(function(item){
parts.push(item.slice(0,2).join("|"));
parts.push(item.slice(2).join("|"));
})
return parts.every(function(item, index, array){
return array.filter( function(x){ return x == item}).length == 2;
})
}
What it does is:
runs through the list of arguments
Array.prototype.slice.call(arguments).forEach
seperates the arrays into points first two, last two as strings parts.push(item.slice(0,2).join(""));parts.push(item.slice(2).join(""));
given the array of points it checks that each point is present two times parts.every(function(item, index, array){ return array.filter( function(x){ return x == item}).length == 2; })
Using a 'one liner'
function trigTest(a,b,c){
var slice = Array.prototype.slice;
return slice.call(arguments).reduce(function(previous, current){
previous.push(current.slice(0,2).join("|"));
previous.push(current.slice(2).join("|"));
return previous;
}, [])
.every(function(item, index, array){
return array.filter( function(x){ return x == item; }).length == 2;
})
}
Checking for zero length lines
if we know that the inputs are not validated to be lines before we have to add a check if any of the given lines has start and end points the same (is a 0 length line or a point)
in this case our code will have to be like this
function trigTest(a,b,c){
var slice = Array.prototype.slice;
if(slice.call(arguments).some(isPoint)){
return false;
};
return slice.call(arguments).reduce(function(previous, current){
previous.push(current.slice(0,2).join("|"));
previous.push(current.slice(2).join("|"));
return previous;
}, [])
.every(function(item, index, array){
return array.filter( function(x){ return x == item; }).length == 2;
})
}
function isPoint(value){
return value[0] == value[2] && value[1] == value[3];
}
Based on your examples, the key criteria is that you have exactly two copies of three x,y coordinates, so rather than deal with this from a geometric or trigonometric standpoint, you may have an easier time dealing with this based on basic set-theory: to have a triangle formed from three points A, B, C, your line segments must follow the pattern [Ax, Ay, Bx, By], [Bx, By, Cx, Cy], [Cx, Cy, Ax, Ay].
These segments are not required to be in that order, such as [Bx, By, Ax, Ay] is also valid for the first term.
To check for a valid triangle, count repeated coordinates first to verify two repeats of three unique coordinates (this will also eliminate repeated line segments), then verify that each line segment is non-zero in length (not [Ax, Ay, Ax, Ay]). Those two checks will handle the first two requirements.
I don't know the boundary limits, so I cannot advise on how to test whether it is outside the bounds of the algorithm, but I suspect that will require checking the actual coordinate range, which is integer arithmetic.
This approach should be usable in any javascript engine, although your specific choice of javascript engine will determine the best way to implement it.
var getRandom = () => 1+ Math.floor( Math.random() * 3 ) ;
// get random line
var getLine = () =>
{
do
var l = {
'a' : {
'x' : getRandom(),
'y' : getRandom()
},
'b' : {
'x' : getRandom(),
'y' : getRandom()
}
};
// repeat until startPoint differ from endPoint
while ( l.a.x == l.b.x & l.a.y == l.b.y )
return l;
};
var match = (K, L, M) => {
// Tirangle consist of three points
// three lines -> six points
var p1 = K.a.x + "," + K.a.y,
p2 = K.b.x + "," + K.b.y,
p3 = L.a.x + "," + L.a.y,
p4 = L.b.x + "," + L.b.y,
p5 = M.a.x + "," + M.a.y,
p6 = M.b.x + "," + M.b.y;
// count frequency
var freq = {};
freq[p1] = freq[p1] + 1 || 1;
freq[p2] = freq[p2] + 1 || 1;
freq[p3] = freq[p3] + 1 || 1;
freq[p4] = freq[p4] + 1 || 1;
freq[p5] = freq[p5] + 1 || 1;
freq[p6] = freq[p6] + 1 || 1;
// result Array
var result = Array();
for ( point in freq ){
// if the point is common for two lines add to result array
freq[point] == 2 ? result.push( point ) : false;
}
return result;
}
var test = () => {
// Three random lines
var K = getLine(), L = getLine(), M = getLine();
// Test if three lines has three common points
if ( match(K, L, M).length == 3 ) {
printSvg(K,L,M);
return 1
} else {
return 0
}
}
// run when document ready
var app = () => {
// div#box needed to print svg with triangles
const box = document.getElementById('box');
// test random lines, repeat
for (x =0; x <= 1000; x++) {
t = test ();
}
}
// fire app() when document ready
document.onreadystatechange = ()=> document.readyState == "complete" ? app() : false;
// format legend html
var printWsp = (L) => "("+ L.a.x + ","+ L.a.y+") ("+L.b.x+","+L.b.y+")";
// append svg to div#box
var printSvg = (K, L, M) => {
var legend = '<div class="legend">K ' + printWsp(K) +"<br>L " + printWsp(L) +"<br>M "+ printWsp(M) + "</div>";
var svgStr = "<svg height='250' width='250'>";
svgStr += "<line x1="+K.a.x*60 +" y1="+K.a.y*60 +" x2="+K.b.x*60 +" y2="+K.b.y*60 +" style='stroke:rgb(255,0,0);stroke-width:2' />";
svgStr += "<line x1="+L.a.x*60 +" y1="+L.a.y*60 +" x2="+L.b.x*60 +" y2="+L.b.y*60 +" style='stroke:rgb(0,255,0);stroke-width:2' />";
svgStr += "<line x1="+M.a.x*60 +" y1="+M.a.y*60 +" x2="+M.b.x*60 +" y2="+M.b.y*60 +" style='stroke:rgb(255,0,255);stroke-width:2' />";
svgStr += "</svg> ";
box.insertAdjacentHTML('beforeend', legend);
box.insertAdjacentHTML('beforeend', svgStr);
}

Categories