Cytoscape zoom alignment - cytoscape.js

I'm having an issue with my background image maintaining proper alignment with the network image, when using mouse to zoom in or out. Without zoom, the network matches the background. With zoom in however, the background shifts right (out of alignment). The background image stays same width as network, only shifted. Same with zoom out, but to the left.
In order to get zoom to work to this degree, I needed to adjust zoom factor:
cy.on('zoom', function(evt){
var newpct = 135.0 * cy.zoom();
document.getElementById('cy').style.backgroundSize = newpct + '%';
});
The header CSS for image, etc:
#cy {
background-image: url("background6.png");
background-repeat: no-repeat;
background-size: 100%;
width: 100%;
height: 100%;
position: absolute;
top: 0px;
left: 0px;
}
The image is from an 11" x 8.5" MS Publisher file, saved as a PNG
Pan is working well, but an adjustment was needed:
cy.on('pan', function(evt){
var pan = cy.pan();
var x = pan.x - 92;
var y = pan.y - 48;
document.getElementById('cy').style.backgroundPosition = x +'px ' + y + 'px ';
});
Any help is much appreciated

You have to keep your co-ordinates synched, and this has to be done exactly. If you adjust some scale values and translation offsets experimentally or with relative values, you'll probably be off.
For scale, s, and translation, t, applied to your image in CSS, find the constants s0 and t0 such that
s = zoom * s0 and t = { x: pan.x + t0.x, y: pan.y + t0.y }
You can find s0 and t0 by aligning the image at zoom 1 and pan (0, 0).
You can't use percents for anything; you ought to use pixels (or ems if you measure everything in ems).

Thank you so much for your answer. After some more work I learned that the zoom event was afterwards triggering the pan event. So I put the translation (covering both pan and zoom shifts) only in pan event function, like this:
var ax = -120 * cy.zoom();
var ay = -60 * cy.zoom();
var x = pan.x + ax;
var y = pan.y + ay;
document.getElementById('cy').style.backgroundPosition = x +'px ' + y + 'px ';
It is working perfectly now. Thanks again for your support!

Related

QML Canvas clipping - non rectangular possible?

Is it possible to display non rectangular items in an app?
The top right edge of each element is clipped:
I turned off clipping on the canvas element and set the clipping
region of the context. I even allowed for the stroke drawing outside
the path. Here's what I'm using to draw it:
Canvas
{
//id: root
// canvas size
height: parent.height - 8
width: height
anchors.top: parent.top + 4
clip: false
z: index + 1
// handler to override for drawing
onPaint:
{
// get context to draw with
var ctx = getContext("2d")
ctx.reset();
// path that includes 1 pixel margin on all sides
ctx.beginPath()
ctx.moveTo( 8, 0 )
ctx.lineTo( width + 4, 0 )
ctx.lineTo( width - 4, height )
ctx.lineTo( 0, height )
ctx.closePath()
ctx.clip();
// setup the stroke
ctx.lineWidth = 2
ctx.strokeStyle = "white"
ctx.beginPath()
ctx.moveTo( 9, 1 )
ctx.lineTo( 9 + width, 1 )
ctx.lineTo( 1 + width, height - 1 )
ctx.lineTo( 1, height - 1 )
ctx.closePath()
ctx.fillStyle = (roleStatus.toLowerCase().indexOf("success")!==-1) ? "green" : "red"
ctx.fill()
ctx.stroke()
}
}
This will be used on Windows and android.
Thanks
Yes... You can use PaintedItem to paint directly on items using Native Paint tools from C++ like QPainterPath
check out http://doc.qt.io/qt-5/qtquick-customitems-painteditem-example.html
the reason that your canvas is clipping is due to the fact that you are drawing width + 4 which should be (width - 8), but since you move to (8,0) first, then you end up drawing an extra 4 pixels too far. try either moving the item over 4 pixels by doing moveTo(4,0) or make the line shorter by doing just width instead of width + 4
Also check out : anchors.fill: parent which will work better in your case most likely.
The way that I avoid crazy bugs like this is by not ever hard coding width, height, x or y into my application.. instead use percentages such as
(parent.width * 0.25) to get 1/4 of the parent
Here's ONE way you could fix your code...
Canvas
{
//id: root
// canvas size
height: parent.height * 0.95
width: height
anchors.top: parent.top
clip: false
z: index + 1
// handler to override for drawing
onPaint:
{
// get context to draw with
var ctx = getContext("2d")
ctx.reset();
// path that includes 1 pixel margin on all sides
ctx.beginPath()
ctx.moveTo( width * 0.1, 0 )
ctx.lineTo( width * 0.9, 0 )
ctx.lineTo( width * 0.7, height )
ctx.lineTo( 0, height )
ctx.closePath()
ctx.clip();
/* etc etc */
}
}
I was unable to find a way to draw outside the bounds of the item. I was able to achieve the effect I wanted though. I drew the polygon within the bounds of the item and set the 'spacing' property of the ListView to a negative value. This overlaps the drawn items to achieve the desired look:

WebGL-moving the object in the line of sight

I defined my Model-View Matrix defining a function lookAt that represents the eye of the camera, the position of the object that I'm representing and the "up" vector of the camera. How can I move the object in the line of sight of the camera? Any tips? If I define the vector that points to the position of the object and starts at the eye of the camera (so if I define the line of sight) how can I use this to make the object move along this direction?
This is my lookAt function
function lookAt( eye, at, up )
{
if ( !Array.isArray(eye) || eye.length != 3) {
throw "lookAt(): first parameter [eye] must be an a vec3";
}
if ( !Array.isArray(at) || at.length != 3) {
throw "lookAt(): first parameter [at] must be an a vec3";
}
if ( !Array.isArray(up) || up.length != 3) {
throw "lookAt(): first parameter [up] must be an a vec3";
}
if ( equal(eye, at) ) {
return mat4();
}
var v = normalize( subtract(at, eye) ); // view direction vector
var n = normalize( cross(v, up) ); // perpendicular vector
var u = normalize( cross(n, v) ); // "new" up vector
v = negate( v );
var result = mat4(
vec4( n, -dot(n, eye) ),
vec4( u, -dot(u, eye) ),
vec4( v, -dot(v, eye) ),
vec4()
);
return result;
}
Honestly I don't understand you're lookAt function. It's not setting a translation like most look at functions.
Here's a different lookAt function that generates a camera matrix,a matrix that positions the camera in the world. That's in contrast to a lookAt function that generates a view matrix, a matrix that moves everything in the world in front of the camera.
function lookAt(eye, target, up) {
const zAxis = v3.normalize(v3.subtract(eye, target));
const xAxis = v3.normalize(v3.cross(up, zAxis));
const yAxis = v3.normalize(v3.cross(zAxis, xAxis));
return [
...xAxis, 0,
...yAxis, 0,
...zAxis, 0,
...eye, 1,
];
}
Here's an article with some detail about a lookAt matrix.
I find camera matrices more useful can view matrixes because a camera matrix (or a lookAt matrix) and be used to make heads look at other things. Gun turrets look at targets, eyes look at interests, where as a view matrix can pretty much only be used for one thing. You can get one from the other by taking the inverse. But since a scene with turrets, eyes, and heads of characters tracking things might need 50+ lookAt matrices it seems far more useful to generate that kind of matrix and take 1 inverse or a view matrix than to generate 50+ view matrices and have to invert all but 1 of them.
You can move any object relative to the way the camera is facing by taking an axis of the camera matrix and multiplying by some scalar. The xAxis will move left and right perpendicular to the camera, the yAxis up and down perpendicular to the camera, and the zAxis forward/backward in the direction the camera is facing.
The axis of the camera matrix are
+----+----+----+----+
| xx | xy | xz | | xaxis
+----+----+----+----+
| yx | yy | yz | | yaxis
+----+----+----+----+
| zx | zy | zz | | zaxis
+----+----+----+----+
| tx | ty | tz | | translation
+----+----+----+----+
In other words
const camera = lookAt(eye, target, up);
const xaxis = camera.slice(0, 3);
const yaxis = camera.slice(4, 7);
const zaxis = camera.slice(8, 11);
Now you can translate forward or back with
matrix = mult(matrix, zaxis); // moves 1 unit away from camera
Multiply zaxis by the amount you want to move
moveVec = [zaxis[0] * moveAmount, zaxis[1] * moveAmount, zaxis[2] * moveAmount];
matrix = mult(matrix, moveVec); // moves moveAmount units away from camera
Or if you have your translation stored elsewhere just add the zaxis in
// assuming tx, ty, and tz are our translation
tx += zaxis[0] * moveAmount;
ty += zaxis[1] * moveAmount;
tz += zaxis[2] * moveAmount;
const vs = `
uniform mat4 u_worldViewProjection;
attribute vec4 position;
attribute vec2 texcoord;
varying vec4 v_position;
varying vec2 v_texcoord;
void main() {
v_texcoord = texcoord;
gl_Position = u_worldViewProjection * position;
}
`;
const fs = `
precision mediump float;
varying vec2 v_texcoord;
uniform sampler2D u_texture;
void main() {
gl_FragColor = texture2D(u_texture, v_texcoord);
}
`;
"use strict";
const m4 = twgl.m4;
const v3 = twgl.v3;
const gl = document.getElementById("c").getContext("webgl");
// compiles shaders, links program, looks up locations
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
// calls gl.createBuffer, gl.bindBuffer, gl.bufferData for positions, texcoords
const bufferInfo = twgl.primitives.createCubeBufferInfo(gl);
// calls gl.createTexture, gl.bindTexture, gl.texImage2D, gl.texParameteri
const tex = twgl.createTexture(gl, {
min: gl.NEAREST,
mag: gl.NEAREST,
src: [
255, 64, 64, 255,
64, 192, 64, 255,
64, 64, 255, 255,
255, 224, 64, 255,
],
});
const settings = {
xoff: 0,
yoff: 0,
zoff: 0,
};
function render(time) {
time *= 0.001;
twgl.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.CULL_FACE);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
const fov = 45 * Math.PI / 180;
const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
const zNear = 0.01;
const zFar = 100;
const projection = m4.perspective(fov, aspect, zNear, zFar);
const eye = [3, 4, -6];
const target = [0, 0, 0];
const up = [0, 1, 0];
const camera = m4.lookAt(eye, target, up);
const view = m4.inverse(camera);
const viewProjection = m4.multiply(projection, view);
gl.useProgram(programInfo.program);
// calls gl.bindBuffer, gl.enableVertexAttribArray, gl.vertexAttribPointer
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
const t = time * .1;
for (let z = -1; z <= 1; ++z) {
for (let x = -1; x <= 1; ++x) {
const world = m4.identity();
m4.translate(world, v3.mulScalar(camera.slice(0, 3), settings.xoff), world);
m4.translate(world, v3.mulScalar(camera.slice(4, 7), settings.yoff), world);
m4.translate(world, v3.mulScalar(camera.slice(8, 11), settings.zoff), world);
m4.translate(world, [x * 1.4, 0, z * 1.4], world);
m4.rotateY(world, t + z + x, world);
// calls gl.uniformXXX
twgl.setUniforms(programInfo, {
u_texture: tex,
u_worldViewProjection: m4.multiply(viewProjection, world),
});
// calls gl.drawArrays or gl.drawElements
twgl.drawBufferInfo(gl, bufferInfo);
}
}
requestAnimationFrame(render);
}
requestAnimationFrame(render);
setupSlider("#xSlider", "#xoff", "xoff");
setupSlider("#ySlider", "#yoff", "yoff");
setupSlider("#zSlider", "#zoff", "zoff");
function setupSlider(sliderId, labelId, property) {
const slider = document.querySelector(sliderId);
const label = document.querySelector(labelId);
function updateLabel() {
label.textContent = settings[property].toFixed(2);
}
slider.addEventListener('input', e => {
settings[property] = (parseInt(slider.value) / 100 * 2 - 1) * 5;
updateLabel();
});
updateLabel();
slider.value = (settings[property] / 5 * .5 + .5) * 100;
}
body { margin: 0; }
canvas { display: block; width: 100vw; height: 100vh; }
#ui {
position: absolute;
left: 10px;
top: 10px;
z-index: 2;
background: rgba(255, 255, 255, 0.9);
padding: .5em;
}
<script src="https://twgljs.org/dist/3.x/twgl-full.min.js"></script>
<canvas id="c"></canvas>
<div id="ui">
<div><input id="xSlider" type="range" min="0" max="100"/><label>xoff: <span id="xoff"></span></label></div>
<div><input id="ySlider" type="range" min="0" max="100"/><label>yoff: <span id="yoff"></span></label></div>
<div><input id="zSlider" type="range" min="0" max="100"/><label>zoff: <span id="zoff"></span></label></div>
</div>

converting photoshop drop shadow into CSS3 box shadow

If I have a photoshop drop shadow with the following settings
Blend Mode - rgb(0,0,0) /
Opacity - 25% /
Angle - 135 degrees /
Distance 4px /
Spread - 0% /
Size - 4px
How can I set my CSS3 box shadow so it represents my photoshop design?
I wrote an article covering the conversion of Photoshop Drop Shadow properties into a CSS3 box-shadow. If you are using Sass/Compass you can use the photoshop-drop-shadow compass plugin. If you want to do the math yourself, it's not terribly difficult, below is a simple example written in JavaScript. The two tricky parts are converting the angle into X and Y offsets and converting the spread percentage into a spread-radius.
// Assume we have the following values in Photoshop
// Blend Mode: Normal (no other blend mode is supported in CSS)
// Color: 0,0,0
// Opacity: 25%
// Angle: 135deg
// Distance: 4px
// Spread: 0%
// Size: 4px
// Here's some JavaScript that would do the math
function photoshopDropShadow2CSSBoxShadow(color, opacity, angle, distance, spread, size) {
// convert the angle to radians
angle = (180 - angle) * Math.PI / 180;
// the color is just an rgba() color with the opacity.
// for simplicity this function expects color to be an rgb string
// in CSS, opacity is a decimal between 0 and 1 instead of a percentage
color = "rgba(" + color + "," + opacity/100 + ")";
// other calculations
var offsetX = Math.round(Math.cos(angle) * distance) + "px",
offsetY = Math.round(Math.sin(angle) * distance) + "px",
spreadRadius = (size * spread / 100) + "px",
blurRadius = (size - parseInt(spreadRadius, 10)) + "px";
return offsetX + " " + offsetY + " " + blurRadius + " " + spreadRadius + " " + color;
}
// let's try it
// for simplicity drop all of the units
photoshopDropShadow2CSSBoxShadow("0,0,0", 25, 135, 4, 0, 4);
// -> 3px 3px 4px 0px rgba(0,0,0,0.25)
This CSS class is for various web browser collected in one rule without transparency (known support: Firefox 3.5+, Chrome 5+, Safari 5+, Opera 10.6+, IE 9+):
.shadow {
-moz-box-shadow: 4px 4px 4px #000;
-webkit-box-shadow: 4px 4px 4px #000;
box-shadow: 4px 4px 4px #000;
/* For IE 8 */
-ms-filter: "progid:DXImageTransform.Microsoft.Shadow(Strength=4, Direction=135, Color='#000000')";
/* For IE 5.5 - 7 */
filter: progid:DXImageTransform.Microsoft.Shadow(Strength=4, Direction=135, Color='#000000');
}
...and this CSS class is with transparency support:
.shadow {
-webkit-box-shadow:4px 4px 0px rgba(0, 0, 0, 0.25);
-moz-box-shadow:4px 4px 0px rgba(0, 0, 0, 0.25);
box-shadow:4px 4px 0px rgba(0, 0, 0, 0.25);
-webkit-transform:rotate(135deg);
-moz-transform:rotate(135deg);
-o-transform:rotate(135deg);
transform:rotate(135deg);
}
This question may be aged but for those newcomer,
Adobe Photoshop has native support for extract CSS from a layer since version CS6.1.
To do so just: right click on layer you want to export in layer panel and select "copy css" then you can paste it directly on your .css file.
Alternatively you can use http://psd-to-css-shadows.com to get CSS you want.
I had wrote a script that copies layer FX to the clipboard as a CSS string along with standard copying of layer FX. It's a bit raw, but it works.
http://github.com/dfcreative/Photoshopr
I am using a tool called psd to css3, you just need to add values from photoshop and you're done use this link
http://melanieceraso.com/psd-to-css3/#sthash.T9hS7I1j.dpbs
.shadow {
-moz-box-shadow: 3px 3px 4px 0 rgba(0, 0, 0, 0.25);
-webkit-box-shadow: 3px 3px 4px 0 rgba(0, 0, 0, 0.25);
box-shadow: 3px 3px 4px 0 rgba(0, 0, 0, 0.25)
}
Here is a nice tool which requires no coding and creates photoshop css boxes: http://www.layerstyles.org/
The easiest way is to isolate the graphic to one layer, turn off all other layers, then save as a png. This will give you a transparent drop shadow area.
bam

Resizing N # of squares to be as big as possible while still fitting into box of X by Y dimensions. (Thumbnails!)

I have N squares.
I have a Rectangular box.
I want all the squares to fit in the box.
I want the squares to be as large as possible.
How do I calculate the largest size for the squares such that they all fit in the box?
This is for thumbnails in a thumbnail gallery.
int function thumbnailSize(
iItems, // The number of items to fit.
iWidth, // The width of the container.
iHeight, // The height of the container.
iMin // The smallest an item can be.
)
{
// if there are no items we don't care how big they are!
if (iItems = 0) return 0;
// Max size is whichever dimension is smaller, height or width.
iDimension = (iWidth min iHeight);
// Add .49 so that we always round up, even if the square root
// is something like 1.2. If the square root is whole (1, 4, etc..)
// then it won't round up.
iSquare = (round(sqrt(iItems) + 0.49));
// If we arrange our items in a square pattern we have the same
// number of rows and columns, so we can just divide by the number
// iSquare, because iSquare = iRows = iColumns.
iSize = (iDimension / iSquare);
// Don't use a size smaller than the minimum.
iSize = (iSize max iMin);
return iSize;
}
This code currently works OK. The idea behind it is to take the smallest dimension of the rectangular container, pretend the container is a square of that dimension, and then assume we have an equal number of rows and columns, just enough to fit iItems squares inside.
This function works great if the container is mostly squarish. If you have a long rectangle, though, the thumbnails come out smaller than they could be. For instance, if my rectangle is 100 x 300, and I have three thumbnails, it should return 100, but instead returns 33.
Probably not optimal (if it works which I haven't tried), but I think better than you current approach :
w: width of rectangle
h: height of rectangle
n: number of images
a = w*h : area of the rectangle.
ia = a/n max area of an image in the ideal case.
il = sqrt(ia) max length of an image in the ideal case.
nw = round_up(w/il): number of images you need to stack on top of each other.
nh = round_up(h/il): number of images you need to stack next to each other.
l = min(w/nw, w/nh) : length of the images to use.
The solution on https://math.stackexchange.com/a/466248 works perfectly.
An unoptimized javascript implementation:
var getMaxSizeOfSquaresInRect = function(n,w,h)
{
var sw, sh;
var pw = Math.ceil(Math.sqrt(n*w/h));
if (Math.floor(pw*h/w)*pw < n) sw = h/Math.ceil(pw*h/w);
else sw = w/pw;
var ph = Math.ceil(Math.sqrt(n*h/w));
if (Math.floor(ph*w/h)*ph < n) sh = w/Math.ceil(w*ph/h);
else sh = h/ph;
return Math.max(sw,sh);
}
I was looking for a similar solution, but instead of squares I had to fit rectangles in the container. Since a square is also a rectangle, my solution also answers this question.
I combined the answers from Neptilo and mckeed into the fitToContainer() function. Give it the number of rectangles to fit n, the containerWidth and containerHeight and the original itemWidth and itemHeight. In case items have no original width and height, use itemWidth and itemHeight to specify the desired ratio of the items.
For example fitToContainer(10, 1920, 1080, 16, 9) results in {nrows: 4, ncols: 3, itemWidth: 480, itemHeight: 270}, so four columns and 3 rows of 480 x 270 (pixels, or whatever the unit is).
And to fit 10 squares in the same example area of 1920x1080 you could call fitToContainer(10, 1920, 1080, 1, 1) resulting in {nrows: 2, ncols: 5, itemWidth: 384, itemHeight: 384}.
function fitToContainer(n, containerWidth, containerHeight, itemWidth, itemHeight) {
// We're not necessarily dealing with squares but rectangles (itemWidth x itemHeight),
// temporarily compensate the containerWidth to handle as rectangles
containerWidth = containerWidth * itemHeight / itemWidth;
// Compute number of rows and columns, and cell size
var ratio = containerWidth / containerHeight;
var ncols_float = Math.sqrt(n * ratio);
var nrows_float = n / ncols_float;
// Find best option filling the whole height
var nrows1 = Math.ceil(nrows_float);
var ncols1 = Math.ceil(n / nrows1);
while (nrows1 * ratio < ncols1) {
nrows1++;
ncols1 = Math.ceil(n / nrows1);
}
var cell_size1 = containerHeight / nrows1;
// Find best option filling the whole width
var ncols2 = Math.ceil(ncols_float);
var nrows2 = Math.ceil(n / ncols2);
while (ncols2 < nrows2 * ratio) {
ncols2++;
nrows2 = Math.ceil(n / ncols2);
}
var cell_size2 = containerWidth / ncols2;
// Find the best values
var nrows, ncols, cell_size;
if (cell_size1 < cell_size2) {
nrows = nrows2;
ncols = ncols2;
cell_size = cell_size2;
} else {
nrows = nrows1;
ncols = ncols1;
cell_size = cell_size1;
}
// Undo compensation on width, to make squares into desired ratio
itemWidth = cell_size * itemWidth / itemHeight;
itemHeight = cell_size;
return { nrows: nrows, ncols: ncols, itemWidth: itemWidth, itemHeight: itemHeight }
}
The JavaScript implementation form mckeed gave me better results then the other answers I found. The idea to first stretch the rectangle to a square came from Neptilo.
you want something more like
n = number of thumbnails
x = one side of a rect
y = the other side
l = length of a side of a thumbnail
l = sqrt( (x * y) / n )
Here is my final code based off of unknown (google)'s reply:
For the guy who wanted to know what language my first post is in, this is VisualDataflex:
Function ResizeThumbnails Integer iItems Integer iWidth Integer iHeight Returns Integer
Integer iArea iIdealArea iIdealSize iRows iCols iSize
// If there are no items we don't care how big the thumbnails are!
If (iItems = 0) Procedure_Return
// Area of the container.
Move (iWidth * iHeight) to iArea
// Max area of an image in the ideal case (1 image).
Move (iArea / iItems) to iIdealArea
// Max size of an image in the ideal case.
Move (sqrt(iIdealArea)) to iIdealSize
// Number of rows.
Move (round((iHeight / iIdealSize) + 0.50)) to iRows
// Number of cols.
Move (round((iWidth / iIdealSize) + 0.50)) to iCols
// Optimal size of an image.
Move ((iWidth / iCols) min (iHeight / iRows)) to iSize
// Check to make sure it is at least the minimum.
Move (iSize max iMinSize) to iSize
// Return the size
Function_Return iSize
End_Function
This should work. It is solved with an algorithm rather than an equation. The algorithm is as follows:
Span the entire short side of the rectangles with all of the squares
Decrease the number of squares in this span (as a result, increasing the size) until the depth of the squares exceeds the long side of the rectangle
Stop when the span reaches 1, because this is as good as we can get.
Here is the code, written in JavaScript:
function thumbnailSize(items, width, height, min) {
var minSide = Math.min(width, height),
maxSide = Math.max(width, height);
// lets start by spanning the short side of the rectange
// size: the size of the squares
// span: the number of squares spanning the short side of the rectangle
// stack: the number of rows of squares filling the rectangle
// depth: the total depth of stack of squares
var size = 0;
for (var span = items, span > 0, span--) {
var newSize = minSide / span;
var stack = Math.ceil(items / span);
var depth = stack * newSize;
if (depth < maxSide)
size = newSize;
else
break;
}
return Math.max(size, min);
}
In Objective C ... the length of a square side for the given count of items in a containing rectangle.
int count = 8; // number of items in containing rectangle
int width = 90; // width of containing rectangle
int height = 50; // width of container
float sideLength = 0; //side length to use.
float containerArea = width * height;
float maxArea = containerArea/count;
float maxSideLength = sqrtf(maxArea);
float rows = ceilf(height/maxSideLength); //round up
float columns = ceilf(width/maxSideLength); //round up
float minSideLength = MIN((width/columns), (height/rows));
float maxSideLength = MAX((width/columns), (height/rows));
// Use max side length unless this causes overlap
if (((rows * maxSideLength) > height) && (((rows-1) * columns) < count) ||
(((columns * maxSideLength) > width) && (((columns-1) * rows) < count))) {
sideLength = minSideLength;
}
else {
sideLength = maxSideLength;
}
My JavaScript implementation:
var a = Math.floor(Math.sqrt(w * h / n));
return Math.floor(Math.min(w / Math.ceil(w / a), h / Math.ceil(h / a)));
Where w is width of the rectangle, h is height, and n is number of squares you want to squeeze in.
double _getMaxSizeOfSquaresInRect(double numberOfItems, double parentWidth, double parentHeight) {
double sw, sh;
var pw = (numberOfItems * parentWidth / parentHeight).ceil();
if ((pw * parentHeight / parentWidth).floor() * pw < numberOfItems) {
sw = parentHeight / (pw * parentHeight / parentWidth).ceil();
} else {
sw = parentWidth / pw;
}
var ph = (sqrt(numberOfItems * parentHeight / parentWidth)).ceil();
if ((ph * parentWidth / parentHeight).floor() * ph < numberOfItems) {
sh = parentWidth / (parentWidth * ph / parentHeight).ceil();
} else {
sh = parentHeight / ph;
}
return max(sw, sh);
}

Converting Longitude & Latitude to X Y on a map with Calibration points

If i have a jpeg map with size sizeX, sizeY
and some calibration points on the map (X, Y, Lon, Lat)
What would be the algorithm for calculating the corresponding XY point in the map with a given Longitude / Latitude pair?
Here's what worked for me, without so much bs.
int x = (int) ((MAP_WIDTH/360.0) * (180 + lon));
int y = (int) ((MAP_HEIGHT/180.0) * (90 - lat));
The lat,lon coordinates were given to me by Android devices. So they should be in the same standard used by all Google Earth/Map products.
If using the Equidistant Cylindrical Projection type map, here is what you need to do:
Find the Latitude and longitude of your location tutorial here: http://lifehacker.com/267361/how-to-find-latitude-and-longitude
Input that information into the following formulas:
x = (total width of image in px) * (180 + latitude) / 360
y = (total height of image in px) * (90 - longitude) / 180note: when using negative longitude of latitude make sure to add or subtract the negative number i.e. +(-92) or -(-35) which would actually be -92 and +35
You now have your X and Y to plot on your imageMore information can be found about this formula and the map type here: http://www.progonos.com/furuti/MapProj/Dither/CartHow/HowER_W12/howER_W12.html#DeductionEquirectangular
There is plenty of information on the Internet about calculating the distance between two pairings of latitude and longitude. We're using those calculations on our public website and they are not trivial to understand/discuss (so I won't try to cover them here). That said, they are easy to implement.
Once you have a function that returns distance, you should be able to caculate the width and height of the map in terms of distance between the corners.
Then you can calculate the horizontal and vertical distance of your point from the top-left corner.
Now you find out what ratio of the map's width is represented by the distance between the left side and your point, apply that ratio to the pixel width and you have the number of pixels between the left side and your point. Repeat for the y-axis.
(Pixels from left side) = (total width in pixels) * ((geocode distance between left and your point) / (geocode distance between left side and right side))
(Pixels from top) = (total height in pixels) * ((geocode distance between top and your point) / (geocode distance between top and bottom))
EDIT: As you research this further you will note that some solutions will present more accurate results than others due to the fact that you are approximating distance between two points on a spherical surface and mapping that on a flat surface. The accuracy decreases as the distance increases. Best advice to you is to try it out first and see if it meets your needs.
This is fairly straight forward and simple.. let me explain how its possible.
Latitude and Longitude are imaginary lines drawn on earth so that you can accurately pinpoint any location on the world . simply put they are the X and Y coords of a plane.
Latitude is a vertical line running from north to south with its 90 deg at the north pole and -90deg at the south pole.
Longitude on the other hand is a horizontal line running east to south with -180deg in the west and 180deg in the east.
you can convert the latLng into pixel coords as by assuming that the width of the html container is the width of the world and the same applies to the the height.
Formula - Longitude - pixel
(givenLng*widthOfContainerElement)/360
where 360 is the total longitude in degrees
Formula -Latitude - pixel
(givenLat*heightOfContainerElement)/180
where 180 is the total latitude in degree
//Height is calculated from the bottom
you can find a working implementation of this formula here, on my website (it uses JavaScript only)
http://www.learntby.me/javascript/latLngconversion.php
let me know if you still need any clarifications.
There are many different map projection schemes. You would have to know which one(s) are used by your maps.
For more information about map projection algorithms and forward/reverse mapping check out this link. It provides the formulas for a number of common projections.
Just make this(for Mercator projection map):
extension UIView
{
func addLocation(coordinate: CLLocationCoordinate2D)
{
// max MKMapPoint values
let maxY = Double(267995781)
let maxX = Double(268435456)
let mapPoint = MKMapPointForCoordinate(coordinate)
let normalizatePointX = CGFloat(mapPoint.x / maxX)
let normalizatePointY = CGFloat(mapPoint.y / maxY)
let pointView = UIView(frame: CGRectMake(0, 0, 5, 5))
pointView.center = CGPointMake(normalizatePointX * frame.width, normalizatePointY * frame.height)
pointView.backgroundColor = UIColor.blueColor()
addSubview(pointView)
}
}
My simple project for adding coordinate on UIView: https://github.com/Glechik/MapCoordinateDrawer
<!DOCTYPE html>
<html>
<head>
<style>
#point{font-face:Arial; font-size:18px; color:#FFFF00; width:12px; height:12px;text-shadow: 2px 2px #000000}
#canvas {position: absolute; top: 0px; left: 0px; z-index: -2}
html,
body,
#canvas {
width: 100%;
height: 100%;
overflow: hidden;
margin: 0
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js"></script>
<script>
$(window).on("load resize",function(e){
var w = $("#canvas").width();
var h = $("#canvas").height();
// New York, NY (https://maps.googleapis.com/maps/api/geocode/json?address=New%20York,%20NY)
var lat = 40.91525559999999;
var long = -73.70027209999999;
var x = ((w/360) * (180 + long)) - 9;
var y = ((h/180) * (90 - lat)) - 18;
$("#text").text('X:'+x+', Y:'+y);
$("#point").offset({ top: y, left: x });
});
</script>
</head>
<body>
<div id="text"></div>
<div id="point">▼</div>
<img id="canvas" border="0" src="http://friday.westnet.com/~crywalt/dymaxion_2003/earthmap10k.reduced.jpg">
</body>
</html>
I have tried this approach:
int x = (int) ((MAP_WIDTH/360.0) * (180 + lon));
int y = (int) ((MAP_HEIGHT/180.0) * (90 - lat));
but this one works better for me : https://medium.com/#suverov.dmitriy/how-to-convert-latitude-and-longitude-coordinates-into-pixel-offsets-8461093cb9f5
here is a shortcut to code part of the article above :
https://gist.github.com/blaurt/b0ca054a7384ebfbea2d5fce69ae9bf4#file-latlontooffsets-js