Biggest distance between different points based on x-values and y-values? - javascript

I got a bunch of nodes which are stored in an array arr.
Each node has a x and y value which repesents the position on the screen.
Now, i created the middle element of arr and save it in middle.
Now, my goal is, to find out the distance between middle and all other nodes and also find out the one with the maximum distance. For the distance I use the Pythagorean theorem a^2 + b^2 = c^2, that means sqrt(a^2 + b^2) = c or in my case sqrt(x^2 + y^2) = distance between 2 nodes.
For example to create the distance between (10,10) and (20,30) I create the difference of the x-scale and the y-scale, that means x = 20-10 = 10 and y = 30-10 = 20. The result is, that the distance between those nodes is sqrt( 10^2 + 20^2) = 22,3. In my code, I check with the if-loop, which x-value and y-value is bigger to avoid negative values. But something I made is wrong. Maybe someone can help?
var middle = arr[Math.floor(arr.length / 2)];
var arrayForDistance = [];
var distance = [];
for(i = 0; i != arr[middle] & i< arr.length; i++ ) {
if(arr[i].x > arr[middle].x) {
var newX = arr[i].x - arr[middle].x;
var newY = arr[i].y - arr[middle].y;
}
else if ( arr[i].x < arr[middle].x)
{
var newX = arr[middle].x - arr[i].x;
var newY = arr[middle].y - arr[i].y;
}}
distance = sqrt( newX^2 + newY^2)
arrayForDistance.push(distance[i]);
}
var maxDistance = Math.max.apply(null, arrayForDistance)

First of all you dont need to worry about negatives since you are squareing them, they will cancel out.
secondly your for loop is wrong it should be
var middle = arr[Math.floor(arr.length / 2)];
var arrayForDistance = [];
var distance ;
for(i = 0; i< arr.length; i++ ) {
if (i != Math.floor(arr.length / 2)){
var newX = arr[i].x - arr[middle].x;
var newY = arr[i].y - arr[middle].y;
distance = sqrt( newX^2 + newY^2)
arrayForDistance.push(distance);
}
}
var maxDistance = Math.max.apply(null, arrayForDistance)

Related

How to format an array of coordinates to a different reference point

I looked around and I couldn't find any info on the topic... probably because I can't iterate my problem accurately into a search engine.
I'm trying to take raw line data from a dxf, sort it into squares, find the center of each square, number the center, and print the result to pdf.
I have a data structure similar to the following:
[
[{x: 50, y:50}, {x:52, y:52}],
[{x: 52, y:52}, {x:54, y:54}],
[{x: 54, y:54}, {x:56, y:56}]...
]
These coordinates are obtained from parsing a dxf using dxf-parser, which returns an array of objects that describe the path of the line. Four of these combine to make a square, which I segment using
function chunkArrayInGroups(arr, size) {
let result = [];
let pos = 0;
while (pos < arr.length) {
result.push(arr.slice(pos, pos + size));
pos += size;
}
return result;
}
((Size = 4))
This behaves as intended for the most part, except these coordinates were created with the origin in the center of the screen. The pdf library I'm using to create the final document does not use the same coordinate system. I believe it starts the origin at the top left of the page. This made all of my negative values ((Anything to the left of the center of the model)) cut off the page.
To remedy this, I iterate through the array and collect '0 - all x and y values' in a new array, which I find the max of to give me my offset. I add this offset to my x values before plugging them into my pdf creator to draw the lines.
I'm not sure what is causing it, but the output is 'Da Vinci Style' as I like to call it, it's rotated 180 degrees and written backwards. I thought adding some value to each cell would fix the negative issue... and it did, but the data is still with respect to a central origin. Is there a way I can redefine this data to work with this library, or is there some other library where I can graph this data and also add text at specific spots as my case dictates. I would like to continue to use this library as I use it for other parts of my program, but I am open to new and more efficient ideas.
I appreciate your time and expertise!
What it's supposed to look like
Source Picture
"Da Vinci'fied" Result
Current Output
Copy of the code:
const PDFDocument = require('pdfkit');
const doc = new PDFDocument({ autoFirstPage: true })
const DxfParser = require('dxf-parser')
let fileText = fs.readFileSync('fulltest.dxf', { encoding: 'utf-8' })
let data = []
let data2 = []
let data3 = []
let shiftx = []
let shifty = []
let factor = 5
var parser = new DxfParser();
let i = 0
doc.pipe(fs.createWriteStream('test.pdf'));
try {
var dxf = parser.parseSync(fileText);
let array = dxf.entities
array.forEach(line => {
if (line.layer === "Modules") {
data.push(line.vertices)
}
if (line.layer === "Buildings") {
data2.push(line.vertices)
}
if (line.layer === "Setbacks") {
data3.push(line.vertices)
}
let segment = line.vertices
segment.forEach(point => {
shiftx.push(0 - point.x)
shifty.push(0 - point.y)
})
})
let shift = biggestNumberInArray(shiftx)
console.log(shift)
data = chunkArrayInGroups(data, 4)
data.forEach(module => {
let midx = []
let midy = []
module.forEach(line => {
let oldx = (line[1].x + shift) * factor
let oldy = (line[1].y + shift) * factor
let newx = (line[0].x + shift) * factor
let newy = (line[0].y + shift) * factor
doc
.moveTo(oldx, oldy)
.lineTo(newx, newy)
.stroke()
midx.push(oldx + (newx - oldx) / 2)
midy.push(oldy + (newy - oldy) / 2)
})
let centerx = (midx[0] + (midx[2] - midx[0]) / 2)
let centery = (midy[0] + (midy[2] - midy[0]) / 2)
let z = (i + 1).toString()
doc
.fontSize(10)
.text(z, centerx-5, centery-5)
i++
})
data2.forEach(line => {
let oldx = (line[0].x + shift) * factor
let oldy = (line[0].y + shift) * factor
let newx = (line[1].x + shift) * factor
let newy = (line[1].y + shift) * factor
doc
.moveTo(oldx, oldy)
.lineTo(newx, newy)
.stroke()
})
data3.forEach(line => {
let oldx = (line[0].x + shift) * factor
let oldy = (line[0].y + shift) * factor
let newx = (line[1].x + shift) * factor
let newy = (line[1].y + shift) * factor
doc
.moveTo(oldx, oldy)
.lineTo(newx, newy)
.stroke('red')
})
doc.end();
} catch (err) {
return console.error(err.stack);
}
function biggestNumberInArray(arr) {
const max = Math.max(...arr);
return max;
}
function chunkArrayInGroups(arr, size) {
let result = [];
let pos = 0;
while (pos < arr.length) {
result.push(arr.slice(pos, pos + size));
pos += size;
}
return result;
}
After sitting outside and staring at the fence for a bit, I revisited my computer and looked at the output again. I rotated it 180 as I did before, and studied it. Then I imagined it flipped over the y axis, like right off my computer. THAT WAS IT! I grabbed some paper and drew out the original coordinates, and the coordinates the pdf library.
input coords ^ >
output coords v >
I realized the only difference in the coordinate systems was that the y axis was inverted! Changing the lines to
let oldx = (line[1].x + shift) * factor
let oldy = (-line[1].y + shift) * factor
let newx = (line[0].x + shift) * factor
let newy = (-line[0].y + shift) * factor
inverted with respect to y and after the shift, printed correctly! Math wins again hahaha

Calculate rectangles angle knowing the outline positions (x/y)

I got an matrix of ones and zeros like this (& I hope you can get the rectangle of ones):
And I'd like to calculate the rectangles rotation angle.
So what I'm starting with: I now all of the positions (x/y-coordinates) of the rectangles outline (symbolized with ' ' (spaces) in the image above) and got them in an array like this:
var outline_positions = [[120,22],[122,22],...,[94,119],[93,119]]
So now my question: How is it possible to calculate the rectangles rotation-angle to the X-axis, knowing that the long side of the rectangle at angle 0° is parallel to the X-asis?
Because I got now idea how to start this code is all that I got so far:
var positions = [[120,22],[122,22],[120,22],[121,22],[122,22],[119,23],[125,23],[119,24],[127,24],[118,25],[129,25],[118,26],[131,26],[117,27],[132,27],[117,28],[134,28],[117,29],[137,29],[116,30],[139,30],[115,31],[141,31],[115,32],[142,32],[114,33],[142,33],[113,34],[142,34],[113,35],[142,35],[112,36],[141,36],[111,37],[140,37],[111,38],[140,38],[110,39],[139,39],[109,40],[139,40],[109,41],[138,41],[108,42],[138,42],[108,43],[137,43],[106,44],[137,44],[106,45],[136,45],[105,46],[136,46],[105,47],[135,47],[104,48],[135,48],[103,49],[134,49],[103,50],[134,50],[103,51],[133,51],[102,52],[132,52],[101,53],[132,53],[100,54],[131,54],[100,55],[131,55],[99,56],[130,56],[98,57],[129,57],[97,58],[128,58],[97,59],[128,59],[96,60],[127,60],[95,61],[127,61],[95,62],[126,62],[94,63],[126,63],[94,64],[125,64],[93,65],[124,65],[92,66],[124,66],[92,67],[124,67],[91,68],[123,68],[91,69],[122,69],[90,70],[121,70],[89,71],[121,71],[89,72],[120,72],[88,73],[120,73],[87,74],[119,74],[87,75],[118,75],[86,76],[118,76],[86,77],[116,77],[85,78],[116,78],[85,79],[116,79],[83,80],[115,80],[83,81],[115,81],[82,82],[115,82],[81,83],[114,83],[81,84],[113,84],[80,85],[113,85],[80,86],[112,86],[79,87],[112,87],[78,88],[112,88],[78,89],[111,89],[78,90],[110,90],[77,91],[110,91],[76,92],[109,92],[76,93],[109,93],[75,94],[108,94],[74,95],[107,95],[74,96],[107,96],[73,97],[106,97],[73,98],[105,98],[72,99],[105,99],[72,100],[104,100],[71,101],[104,101],[70,102],[103,102],[70,103],[103,103],[69,104],[102,104],[70,105],[102,105],[72,106],[101,106],[73,107],[101,107],[75,108],[100,108],[76,109],[100,109],[77,110],[99,110],[80,111],[98,111],[81,112],[98,112],[83,113],[97,113],[84,114],[96,114],[86,115],[96,115],[88,116],[96,116],[90,117],[95,117],[91,118],[94,118],[93,119],[94,119],[94,119],[93,119]]
Array.prototype.calculate_rotation = function() {
var array=this
var max_x = array.filter(e => e[0] === Math.max(... array.map(e => e[0])))[0];
var min_x = array.filter(e => e[0] === Math.min(... array.map(e => e[0])))[0]
return max_x[1]-min_x[1]
}
console.log(positions.calculate_rotation());
One approach could be as follows:
function calculate_rotation(arr){
var N = arr.length;
if(!N) return;
var xmin = arr[0][0];
var ymin = arr[0][1];
var A = arr[0];
var P = arr[0];
for(var i = 0; i < N; ++i){
var x = arr[i][0];
var y = arr[i][1];
if(x < xmin || (x == xmin && y < A[1])){
xmin = x;
A = [x, y];
}
if(y < ymin || (y == ymin && x > P[0])){
ymin = y;
P = [x, y];
}
}
return Math.atan2(P[1] - A[1], P[0] - A[0])*180/Math.PI;
}
The idea is to identify the left-most (A) and bottom-most (P) points. The rotation angle is then calculated with respect to the point A. Alternatively, one could do a second pass through the array, identify all points which are on the line segment connecting A and P and do a linear fit in order to obtain the slope.

Draw "Squiggly" line along a curve in javascript

This is a bit complicated to describe, so please bear with me.
I'm using the HTML5 canvas to extend a diagramming tool (Diagramo). It implements multiple types of line, straight, jagged (right angle) and curved (cubic or quadratic). These lines can be solid, dotted or dashed.
The new feature I am implementing is a "squiggly" line, where instead of following a constant path, the line zigzags back and forth across the desired target path in smooth arcs.
Below is an example of this that is correct. This works in most cases, however, in certain edge cases it does not.
The implementation is to take the curve, use the quadratic or cubic functions to estimate equidistance points along the line, and draw squiggles along these straight lines by placing control points on either side of the straight line (alternating) and drawing multiple cubic curves.
The issues occur when the line is relatively short, and doubles back on itself close to the origin. An example is below, this happens on longer lines too - the critical point is that there is a very small sharp curve immediately after the origin. In this situation the algorithm picks the first point after the sharp curve, in some cases immediately next to the origin, and considers that the first segment.
Each squiggle has a minimum/maximum pixel length of 8px/14px (which I can change, but much below that and it becomes too sharp, and above becomes too wavy) the code tries to find the right sized squiggle for the line segment to fit with the minimum empty space, which is then filled by a straight line.
I'm hoping there is a solution to this that can account for sharply curved lines, if I know all points along a line can I choose control points that alternate either side of the line, perpendicular too it?
Would one option be to consider a point i and the points i-1 and i+1 and use that to determine the orientation of the line, and thus pick control points?
Code follows below
//fragment is either Cubic or Quadratic curve.
paint(fragment){
var length = fragment.getLength();
var points = Util.equidistancePoints(fragment, length < 100 ? (length < 50 ? 3: 5): 11);
points.splice(0, 1); //remove origin as that is the initial point of the delegate.
//points.splice(0, 1);
delegate.paint(context, points);
}
/**
*
* #param {QuadCurve} or {CubicCurbe} curve
* #param {Number} m the number of points
* #return [Point] a set of equidistance points along the polyline of points
* #author Zack
* #href http://math.stackexchange.com/questions/321293/find-coordinates-of-equidistant-points-in-bezier-curve
*/
equidistancePoints: function(curve, m){
var points = curve.getPoints(0.001);
// Get fractional arclengths along polyline
var n = points.length;
var s = 1.0/(n-1);
var dd = [];
var cc = [];
var QQ = [];
function findIndex(dd, d){
var i = 0;
for (var j = 0 ; j < dd.length ; j++){
if (d > dd[j]) {
i = j;
}
else{
return i;
}
}
return i;
};
dd.push(0);
cc.push(0);
for (var i = 0; i < n; i++){
if(i >0) {
cc.push(Util.distance(points[i], points[i - 1]));
}
}
for (var i = 1 ; i < n ; i++) {
dd.push(dd[i-1] + cc[i]);
}
for (var i = 1 ; i < n ; i++) {
dd[i] = dd[i]/dd[n-1];
}
var step = 1.0/(m-1);
for (var r = 0 ; r < m ; r++){
var d = parseFloat(r)*step;
var i = findIndex(dd, d);
var u = (d - dd[i]) / (dd[i+1] - dd[i]);
var t = (i + u)*s;
QQ[r] = curve.getPoint(t);
}
return QQ;
}
SquigglyLineDelegate.prototype = {
constructor: SquigglyLineDelegate,
paint: function(context, points){
var squiggles = 0;
var STEP = 0.1;
var useStart = false;
var bestSquiggles = -1;
var bestA = 0;
var distance = Util.distance(points[0], this.start);
for(var a = SquigglyLineDelegate.MIN_SQUIGGLE_LENGTH; a < SquigglyLineDelegate.MAX_SQUIGGLE_LENGTH; a += STEP){
squiggles = distance / a;
var diff = Math.abs(Math.floor(squiggles) - squiggles);
if(diff < bestSquiggles || bestSquiggles == -1){
bestA = a;
bestSquiggles = diff;
}
}
squiggles = distance / bestA;
for(var i = 0; i < points.length; i++){
context.beginPath();
var point = points[i];
for(var s = 0; s < squiggles-1; s++){
var start = Util.point_on_segment(this.start, point, s * bestA);
var end = Util.point_on_segment(this.start, point, (s + 1) * bestA);
var mid = Util.point_on_segment(this.start, point, (s + 0.5) * bestA);
end.style.lineWidth = 1;
var line1 = new Line(Util.point_on_segment(mid, end, -this.squiggleWidth), Util.point_on_segment(mid, end, this.squiggleWidth));
var mid1 = Util.getMiddle(line1.startPoint, line1.endPoint);
line1.transform(Matrix.translationMatrix(-mid1.x, -mid1.y));
line1.transform(Matrix.rotationMatrix(radians = 90 * (Math.PI/180)));
line1.transform(Matrix.translationMatrix(mid1.x, mid1.y));
var control1 = useStart ? line1.startPoint : line1.endPoint;
var curve = new QuadCurve(start, control1, end);
curve.style = null;
curve.paint(context);
useStart = !useStart;
}
this.start = point;
context.lineTo(point.x, point.y);
context.stroke();
}
}
}

Reading MNIST dataset with javascript/node.js

I'm trying to decode the dataset from this source: http://yann.lecun.com/exdb/mnist/
There is a description of the "very simple" IDX file type in the bottom, but I cannot figure it out.
What I'm trying to achieve is something like:
var imagesFileBuffer = fs.readFileSync(__dirname + '/train-images-idx3-ubyte');
var labelFileBuffer = fs.readFileSync(__dirname + '/train-labels-idx1-ubyte');
var pixelValues = {};
Do magic
pixelValues are now like:
// {
// "0": [0,0,200,190,79,0... for all 784 pixels ... ],
// "4": [0,0,200,190,79,0... for all 784 pixels ... ],
etc for all image entries in the dataset. I've tried to figure out the structure of the binary files, but failed.
I realized there would be duplicate keys in my structure of the pixelValues object, so I made an array of objects of it instaed. The following code will create the structure I'm after:
var dataFileBuffer = fs.readFileSync(__dirname + '/train-images-idx3-ubyte');
var labelFileBuffer = fs.readFileSync(__dirname + '/train-labels-idx1-ubyte');
var pixelValues = [];
// It would be nice with a checker instead of a hard coded 60000 limit here
for (var image = 0; image <= 59999; image++) {
var pixels = [];
for (var x = 0; x <= 27; x++) {
for (var y = 0; y <= 27; y++) {
pixels.push(dataFileBuffer[(image * 28 * 28) + (x + (y * 28)) + 15]);
}
}
var imageData = {};
imageData[JSON.stringify(labelFileBuffer[image + 8])] = pixels;
pixelValues.push(imageData);
}
The structure of pixelValues is now something like this:
[
{5: [28,0,0,0,0,0,0,0,0,0...]},
{0: [0,0,0,0,0,0,0,0,0,0...]},
...
]
There are 28x28=784 pixel values, all varying from 0 to 255.
To render the pixels, use my for loops like I did above, rendering the first pixel in the upper left corner, then working towards the right.
Just a small improvement:
for (var image = 0; image <= 59999; image++) {
with 60000 there is an "entry" with null's at the very end of your pixelValues.
EDIT:
I got a little obsessed with details because I wanted to convert the MNIST dataset back to real and separate image files. So I have found more mistakes in your code.
it is definitely +16 because you have to skip the 16 Bytes of header data. This little mistake is reflected in your answer where the first pixel value of the first digit (with is a 5) is '28'. Which is actually the value that tells how many columns the image has - not the first pixel of the image.
Your nested for loops has to be turned inside-out to get you the right pixel order - asuming you will "rebuild" your image from the upper left corner down to the lower right corner. With your code the image will be flipped along the axis that goes from the upper left to the lower right corner.
So your code should be:
var dataFileBuffer = fs.readFileSync(__dirname + '/train-images-idx3-ubyte');
var labelFileBuffer = fs.readFileSync(__dirname + '/train-labels-idx1-ubyte');
var pixelValues = [];
// It would be nice with a checker instead of a hard coded 60000 limit here
for (var image = 0; image <= 59999; image++) {
var pixels = [];
for (var y = 0; y <= 27; y++) {
for (var x = 0; x <= 27; x++) {
pixels.push(dataFileBuffer[(image * 28 * 28) + (x + (y * 28)) + 16]);
}
}
var imageData = {};
imageData[JSON.stringify(labelFileBuffer[image + 8])] = pixels;
pixelValues.push(imageData);
}
Those little details wouldn't be an issue if you stay consistent and use those extracted data to -for example- train neural networks, because you will do the same with the testing dataset. But if you want to take that MNIST trained neural network and try to verify it with real life hand written digits, you will get bad results because the real images are not flipped.
Hopefully this helps someone out, I have added the ability to save the images to a png. Please note you will need to have an images directory
var fs = require('fs');
const {createCanvas} = require('canvas');
function readMNIST(start, end)
{
var dataFileBuffer = fs.readFileSync(__dirname + '\\test_images_10k.idx3-ubyte');
var labelFileBuffer = fs.readFileSync(__dirname + '\\test_labels_10k.idx1-ubyte');
var pixelValues = [];
for (var image = start; image < end; image++)
{
var pixels = [];
for (var y = 0; y <= 27; y++)
{
for (var x = 0; x <= 27; x++)
{
pixels.push(dataFileBuffer[(image * 28 * 28) + (x + (y * 28)) + 16]);
}
}
var imageData = {};
imageData["index"] = image;
imageData["label"] = labelFileBuffer[image + 8];
imageData["pixels"] = pixels;
pixelValues.push(imageData);
}
return pixelValues;
}
function saveMNIST(start, end)
{
const canvas = createCanvas(28, 28);
const ctx = canvas.getContext('2d');
var pixelValues = readMNIST(start, end);
pixelValues.forEach(function(image)
{
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var y = 0; y <= 27; y++)
{
for (var x = 0; x <= 27; x++)
{
var pixel = image.pixels[x + (y * 28)];
var colour = 255 - pixel;
ctx.fillStyle = `rgb(${colour}, ${colour}, ${colour})`;
ctx.fillRect(x, y, 1, 1);
}
}
const buffer = canvas.toBuffer('image/png')
fs.writeFileSync(__dirname + `\\images\\image${image.index}-${image.label}.png`, buffer)
})
}
saveMNIST(0, 5);

I am trying to plot coordinates around a square

I am trying to plot coordinates around a square programatically here it is hard coded to show what i am after.
http://jsfiddle.net/zwkny/
// amount of chairs
var aoc = 4;
// table width
var tw = 200;
// table height
var th = 200;
// chair width height
var cwh = 60 / 2;
var space = tw * 4 / aoc;
var left = [-30,100,-30,-160];
var top = [-160,-30,100,-30];
// straing point
var sp = 12;
for(var i=0; i<aoc; i++){
var x = cwh + space * i / aoc;
console.log(x);
//var y = space / 2 - cwh * i;
$("#center").append("<div class='chair' style='left:"+left[i]+"px;top:"+top[i]+"px;'>"+i+"</div>");
}
Maths is definately not my strong point just thought i would post up here see if anyone can help point me in the right direction i keep going and update if i get it???
I need it this way to represent people the small circles standing around the large square but there will be random amounts of people and they all need to be at equal distances.
I posted the same post about a circle object yesterday and now i am on squares i just cant get my head around the maths, any help.
Sore that this has been voted down just thought i would update with a post putting all these together
http://devsforrest.com/116/plot-positions-around-shapes-with-javascript
Hope it helps someone else
var x,y;
// amount of chairs
var totalChairs = 12;
// square size
var squareSize = 200;
var chairSize = 20;
for(var i=0; i<totalChairs; i++){
var angle = 2*Math.PI * i/totalChairs;
if (angle > Math.PI/4 && angle <= Math.PI* 3/4){
x = (squareSize/2) / Math.tan(angle);
y = -squareSize/2;
} else if (angle > Math.PI* 3/4 && angle <= Math.PI* 5/4){
x = -squareSize/2;
y = (squareSize/2) * Math.tan(angle);
} else if (angle > Math.PI* 5/4 && angle <= Math.PI* 7/4){
x = -(squareSize/2) / Math.tan(angle);
y = -squareSize/2 + squareSize;
} else {
x = -squareSize/2 + squareSize;
y = -(squareSize/2) * Math.tan(angle);
}
x -= chairSize/2;
y -= chairSize/2;
$("#center").append("<div class='chair' style='left:"+x+"px;top:"+y+"px;'></div>");
}
Demo

Categories