Scaling SVG objects defined in pixels to physical units? - svg

I have an SVG element defined with a width and height of "297mm" and "210mm", and no viewbox. I do this because I want to work inside an A4 viewport, but I want to create elements in pixels.
At some point, I need to scale up an object defined in pixels so that it fits into part of the A4 page. For example, I might have an object which is 100 px wide, that I want to scale to 30mm horizontally.
Is this possible? I think I need a second container with a new co-ordinate system, but I can't find any way to do this.
EDIT
It seems that I (or SVG) has misunderstood what a pixel is. I realised that I could size a line to 100%, and then get it's pixel size with getBBox to find the scaling required. I wrote this code and ran it on 2 clients, one with a 1280x1024 monitor (80dpi), and one with a 1680x1050 LCD (90dpi):
function getDotsPerInch() {
var hgroup, vgroup, hdpi, vdpi;
hgroup = svgDocument.createElementNS(svgNS, "g");
vgroup = svgDocument.createElementNS(svgNS, "g");
svgRoot.appendChild(hgroup);
svgRoot.appendChild(vgroup);
drawLine(hgroup, 0, 100, "100%", 100, "#202020", 1, 1);
drawLine(vgroup, 100, 0, 100, "100%", "#202020", 1, 1);
hdpi = hgroup.getBBox().width * 25.4 / WIDTH;
vdpi = vgroup.getBBox().height * 25.4 / HEIGHT;
drawText(hgroup, "DPI, horizontal: " + hdpi.toFixed(2), 100, 100);
drawText(hgroup, "DPI, vertical: " + vdpi.toFixed(2), 100, 120);
}
IE9, FF, Opera, and Chrome all agree that both monitors are 96 dpi horizontally and vertically (although Opera's slightly inaccurate), and Safari reports 0 dpi on both monitors. So svg just appears to have defined "pixels" as "96dpi". some quick Googling appears to confirm this, though I haven't found anything definitive, and most hits give 90dpi, with 96dpi as the FF variant.

You can nest <svg> elements and use the viewBox attribute on the child element to get a new coordinate system. Give the child <svg> element x, y, width and height attributes of where you want it to appear on the parent in the parent's co-ordinate system.

Related

Why are some parts not rendered on a bigger window?

If I change the window size the objects are deformed(as I know).
So Im trying to calculate the aspect but If I do this and I increase the window size only a smal rectangle is rendered.
This are the relevant parts of the code :
Reshape function :
void ReshapeFunc(int x, int y)
{
aspect = (float) x/y;
}
(apect is defined global)
gluPerspective :
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(90, aspect, near, far);
You need to call glViewport(0, 0, width, height) anytime you change the size of the window.

Direct3D Window->Bounds.Width/Height differs from real resolution

I noticed a strange behaviour with Direct3D while doing this tutorial.
The dimensions I am getting from the Window Object differ from the configured resolution of windows. There I set 1920*1080, the width and height from the Winows Object is 1371*771.
CoreWindow^ Window = CoreWindow::GetForCurrentThread();
// set the viewport
D3D11_VIEWPORT viewport = { 0 };
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.Width = Window->Bounds.Width; //should be 1920, actually is 1371
viewport.Height = Window->Bounds.Height; //should be 1080, actually is 771
I am developing on an Alienware 14, maybe this causes this problem, but I could not find any answers, yet.
CoreWindow sizes, pointer locations, etc. are not expressed in pixels. They are expressed in Device Independent Pixels (DIPS). To convert to/from pixels you need to use the Dots Per Inch (DPI) value.
inline int ConvertDipsToPixels(float dips) const
{
return int(dips * m_DPI / 96.f + 0.5f);
}
inline float ConvertPixelsToDips(int pixels) const
{
return (float(pixels) * 96.f / m_DPI);
}
m_DPI comes from DisplayInformation::GetForCurrentView()->LogicalDpi and you get the DpiChanged event when and if it changes.
See DPI and Device-Independent Pixels for more details.
You should take a look at the Direct3D UWP Game templates on GitHub, and check out how this is handled in Main.cpp.

LWJGL Fullscreen while keeping aspect ratio?

I want to have a fullscreen mode that keeps the aspect ratio by adding black bars on either side. I tried just creating a display mode, but I can't make it fullscreen unless it's a pre-approved resolution, and when I use a bigger diaplay than the native resolution the pixels become messed up, and lines appeared between all of the tiles in the game for some reason.
I think I need to use FBOs to render the scenario to a texture instead of the window, and then just use a fullscreen approved resolution and render the texture properly stretched out in the center of the screen, but I just don't understand how to render to a texture in order to do that, or how to stretch an image. Could someone please help me?
EDIT
I got fullscreen working, but it makes everything all broken looking There are random lines on the edges of anything that's written to the window. There are no glitchy lines when it's in native resolution though. Here's my code:
Display.setTitle("Mega Man");
try{
Display.setDisplayMode(Display.getDesktopDisplayMode());
Display.create();
}catch(LWJGLException e){
e.printStackTrace();
}
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0,WIDTH,HEIGHT,0,1,-1);
glMatrixMode(GL_MODELVIEW);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
try{Display.setFullscreen(true);}catch(Exception e){}
int sh=Display.getHeight();
int sw=WIDTH*sh/HEIGHT;
GL11.glViewport(Display.getWidth()/2-sw/2, 0, sw, sh);
Screenshot of the glitchy fullscreen here: http://sta.sh/021fohgnmxwa
EDIT
Here is the texture rendering code that I use to draw everything:
public static void DrawQuadTex(Texture tex, int x, int y, float width, float height, float texWidth, float texHeight, float subx, float suby, float subd, String mirror){
if (tex==null){return;}
if (mirror==null){mirror = "";}
//subx, suby, and subd are to grab sprites from a sprite sheet. subd is the measure of both the width and length of the sprite, as only images with dimensions that are the same and are powers of 2 are properly displayed.
int xinner = 0;
int xouter = (int) width;
int yinner = 0;
int youter = (int) height;
if (mirror.indexOf("h")>-1){
xinner = xouter;
xouter = 0;
}
if (mirror.indexOf("v")>-1){
yinner = youter;
youter = 0;
}
tex.bind();
glTranslatef(x,y,0);
glBegin(GL_QUADS);
glTexCoord2f(subx/texWidth,suby/texHeight);
glVertex2f(xinner,yinner);
glTexCoord2f((subx+subd)/texWidth,suby/texHeight);
glVertex2f(xouter,yinner);
glTexCoord2f((subx+subd)/texWidth,(suby+subd)/texHeight);
glVertex2f(xouter,youter);
glTexCoord2f(subx/texWidth,(suby+subd)/texHeight);
glVertex2f(xinner,youter);
glEnd();
glLoadIdentity();
}
Just to keep it clean I give you a real answer and not just a comment.
The aspect ratio problem can be solved with help of glViewport. Using this method you can decide which area of the surface that will be rendered to. The default viewport will cover the whole surface.
Since the second problem with the corrupt rendering (also described here https://stackoverflow.com/questions/28846531/sprite-game-in-full-screen-aliasing-issue) appeared after changing viewport I will give my thought about it in this answer as well.
Without knowing exactly how the rendering code for the tile background looks. I would guess that the problem is due to any differences in the resolution between the glViewport and glOrtho calls.
Example: If the glOrtho resolution is half the viewport resolution then each openGL unit is actually 2 pixels. If you then renders a tile between x=0 and x=9 and then the next one between x=10 and x=19 you will get an empty space between them.
To solve this you can change the resolution so that they are the same. Or you can render the tile to overlap, first one x=0 to x=10 second one x=10 to x=20 and so on.
Without seeing the tile rendering code I can't verify it this is the problem though.

Three.js normals update on object rotation

I use a 3D object as a container for a few meshes. I am using an Orthographic camera. I vertically rotate the container by 90° like this:
meshContainer.rotation.x = 0;
meshContainer.rotation.y = - 90 * Math.PI / 180;
meshContainer.rotation.z = 0;
camera.updateProjectionMatrix();
I have to do operations on the meshes inside the container depending on their orientation relative to the camera. So, i do this test:
var vector = new THREE.Vector3( 0, 0, -1 );
vector.applyQuaternion(camera.quaternion);
if (vector.dot(geom.faces[i].normal) < 0) { ... }
goem is the geometry of one mesh inside the container.
I just want to check if each face is 'looking at' the camera or not. It works fine when I rotate the container with mouse controls but not with a rotation as above. When I look at the mesh geometries, it seems that the normals of the faces are not udpated when I do the container rotation.
I tried this :
mesh[value].geometry.computeFaceNormals();
mesh[value].geometry.computeVertexNormals();
on each mesh after the container rotation, but with no results.
Does anybody know what to do?
The camera position must be changed but not the mesh container and everything is fine

How do you rotate SVG images in processing.js

I am just staring with processing.js and I have been having trouble because every time I rotate an image it also changes its location on the screen. So what processing seems to do is, rotate my image around the point I told it to place it, instead of rotating it first around its own axis and then placing it where I told it to (which I figured cannot be done in that way/order).
This is the code
PShape s;
float angle = 0.1; //rads
s = loadShape("sensor.svg");
s.rotate(angle);
//I change this angle manually or with my clickMouse function which isnt shown.
void setup(){
size(400,350);
frameRate(30); //30 frames per seconds
}
void draw(){ //shape( shape, x, y, width, height);
smooth();
fill(153);
ellipse(200, 350/2, 100, 100);
shape(s, 200, 350/2, 20, 20);
ellipse(200, 350/2, 2, 2);
}
What I am basically trying to do is make this "sensor" image rotate in the correct orientation around the circle (ellipse) that I drew. Thats the idea. Its doing neither. Maybe having a click function that rotates the SVG image around the circle. But instead it rotates around the coordinates of the shape(image, x_coord, y_coord, width, height) function. If anyone has any suggestions, I would be so happy! Hope my question makes sense, if it doesnt I would be more than happy to clarify any part of it.
Thanks! :)
It's much easier not to rotate your shape, but to rotate the coordinate system.
void draw() {
translate(s.width/2,s.height/2);
rotate(PI/4);
shape(s);
resetMatrix();
// keep on drawing here
}
This first moves the coordinate system so that (0,0) is on top of the center of your shape, then rotates the entire coordinate system by 45 degrees, then draws your shape. Then you reset the coordinate system and keep drawing as usual.

Resources