Avatar billede fredand Forsker
10. juli 2005 - 20:47 Der er 26 kommentarer og
1 løsning

How to rotate a figure in a coordinate system?

Hello!
I'm struggling with a coordinate-trigonometry-problem.

I'm trying to create a 2D-shape program in Java. The idea is that the user should be able to mark a couple of coordinates in a 2D-coordinate-system, which will be joined together with lines to form a shape of a figure.

One feature will be that the user can rotate the figure by an angle. All the coordinates of the shape should be recalculated and the figure should be rotated and re-drawn by the new coordinates.

My problem is that when I recalculate the coordinates the figure gets a bit deformed and does not exactly look like the original figure. My goal is of course that the figure will be able to rotate without getting derfomed.

When I look at other programs like 3D-studio max they are able to create a figure upon coordinates (the "spine" tool), as can I. But when they rotate their figures the figure stay in the orginal shape without any deformation.

Below I got a link to an image where this is described. The gray image is created by 3D-studio and the yellow is created by my program.

http://www.dsv.su.se/~fr-ander/rot.gif (You may have to click to enlarge the image in the browser.)

The image shows 6 gray images from 3D-studio max showing a figure rotated. The first image is the upper left one. It also shows 2 yellow images from my program. With 3D-studio max you can rotate the figure in any angle without any deformation. The images from my program shows the figure from the begining and after 72 rotations with 5 deg. As you can see the shape gets deformed.

The coordinate-system in my program is a regular x-axis, negative to the left and positive to the right. The y-axis is negative above the origo and positive below the origo.

The coordinates for the shapes are not exactly the same in the two programs, but I do not think that it matters to describe this problem. If you look at the last image you will see the deformation that I talk about.

For each rotation I use this formula, described below, in my program. All the coordinates are saved inside a list/array/vector, below I just refer to it like variables.

(Step 1-3 are only calculated once)
1) When the shape is created for the first time I get the center like this:
a) find the xMin and xMax by searching all the xValues of the coordinates
b) find the yMin and yMax by searching all the yValues of the coordinates
c) Get the xCenter like (xMax+xMin)/2
d) Get the yCenter like (yMax+yMin)/2

2) When the shape is created for the first time I calculate all the differenses between xCenter and xValues and between yCenter and yValues. I do this for all of the coordinates of the shape with this formula:
xDiff = xValues - xCenter
yDiff = yValues - yCenter

3) Now I'm able to find all the radius between the center coordinate (xCenter, yCenter) and all the coordinates of the shape with this formula:
radius = Math.sqrt( (xDiff^2*xDiff^2) + (yDiff^2*yDiff^2))

(Below (step 4-6) get repeated every time I rotate. I guess that I could do step 4 once, as above.)
4) Now I'm able to find the present angles like:
if(yDiff > 0)
{
angle = Math.acos( xDiff / radius );
}
else
{
angle = (2*Math.PI) - Math.acos( xDiff / radius )
}

5) Now I recalculate all the coordinates like:
xNew = xCenter + 1 * ( (xValue-xCenter) * Math.cos( ((2*Math.PI)/72)*dir ) - (yValue-yCenter) * Math.sin( ((2*Math.PI)/72) ) )
yNew = yCenter + 1 * ( (xValue-xCenter) * Math.sin( ((2*Math.PI)/72)*dir ) + (yValue-yCenter) * Math.cos( ((2*Math.PI)/72)) )

btw I have also tried this formula with the same result.
xNew = (xPresent-xCenter) * Math.cos(angle) + (yPresent-yCenter) * Math.sin(angle)) + xCenter
yNew = - (xPresent-xCenter) * Math.sin(angle) + (yPresent-yCenter) * Math.cos(angle)) + yCenter

6) Since computer screens work with pixles I round each xNew and yNew to an integer. All other values is stored like "double" (numbers with decimals). If you are familiar with Java I use Math.round to get a proper integer.

For my figure I get these coordinates when the figure is created:
-40,-40
40,-40
40,40
8,68
-12,80
-28,72
-40,60
-60,40
-80,0
-40,-40

With the above formula I get these coordinates after 72 (may have been 73) rotations with 5 degr ((2*Math.PI)/72))
-35,-40
40,-40
41,36
-2,73
-12,81
-33,71
-47,55
-63,31
-81,4
-35,-40

So if you see what I'm doing wrong to cause the deformation of the shape/figure, please let me know. How do you think they do it in the 3D-studio max application? If they can do it, anyone can do it, I guess.

My guess is that the rounding makes the deform, but how do they do it in 3D-studio max then? Magic??

Best regards
Fredrik
Avatar billede nielle Nybegynder
10. juli 2005 - 21:07 #1
Drop steps 3-4; They are not needed.

5')

xDiffNew = xDiff*Math.cos(rotationAngle) - yDiff*Math.sin(rotationAngle)

yDiffNew = -xDiff-Math.sin(rotationAngle) + yDiff*Math.cos(rotationAngle)

Remember that the rotationAngle is in radians, anf if you want it in degrees then you will have to make a small transform:

rotationAngle = Math.PI*rotationAngleDeg/Math.PI

Recalculate the new x- and y-coordinates by adding xCenter and yCenter:

xNew = xCenter + xDiffNew
yNew = yCenter + yDiffNew
Avatar billede nielle Nybegynder
10. juli 2005 - 21:08 #2
yDiffNew = -xDiff*Math.sin(rotationAngle) + yDiff*Math.cos(rotationAngle)
Avatar billede javascript Nybegynder
11. juli 2005 - 20:23 #3
hvorfor skrive det på engelsk? "fredand" lyder ikke som en englænder !-)
Avatar billede javascript Nybegynder
11. juli 2005 - 20:24 #4
Ah, så lige de mange spørgsmål på engelsk, jeg må hellere holde mig væk !-)
Avatar billede simonvalter Praktikant
11. juli 2005 - 20:31 #5
Jeg mener at Fredrik er svensker? så han forstår vist godt når vi svarer på dansk.. jeg har det også med at snakke engelsk når jeg taler med svenskere eller nordmænd. En anden grund kan være hvis man smider spørgsmålet andre internationale steder og ikke gider oversætte... og i IT branchen burde de fleste af os kunne lidt engelsk.
Avatar billede fredand Forsker
11. juli 2005 - 21:01 #6
Hello Mates!

Yes I'm swedish and my name is Fredrik Andersson.

I understand a bit Danish, but sometimes I do not. I'm sorry for that since I know that I should understand it since I am swedish. The differens aint so big. I do feel ridicolous.

To me my questions are very importent so I really need to understand your excellent answers.

Btw I can tell you that I do not know any site on the Internet that is so good that eksperten.dk, thanks to your knowledge! So I hope you excuse me and my bad english.

Thanks!

Best regards
Fredrik
Avatar billede nielle Nybegynder
11. juli 2005 - 21:23 #7
Feel free to ask anything regarding the math.
Avatar billede fredand Forsker
11. juli 2005 - 21:48 #8
Hello!

Thanks for your reply about the rotation problem.

I tried what you said but perhaps I did it wrong:

After 11 rotations about 5 deg I got this result:

14,-42
125,-125
42,-14
-31,57
-71,95
-85,100
-89,96
-96,89
-82,54
14,-42

An easier way to see the result is this image:
http://www.dsv.su.se/~fr-ander/rot3.gif

The starting coordinates is the same as before.

My code for this look like:

I recalculate the diffs like this that I have stored in a list
for(int j = 0; j < coordinatesXYdiff[i].length; j++)
{
    double xDiffNew = coordinatesXYdiff[i][j]*Math.cos(((2*Math.PI)/72)) - coordinatesXYdiff[i][j+1]*Math.sin(((2*Math.PI)/72));
    double yDiffNew = -coordinatesXYdiff[i][j]*Math.sin(((2*Math.PI)/72)) + coordinatesXYdiff[i][j+1]*Math.cos(((2*Math.PI)/72));
    coordinatesXYdiff[i][j] = xDiffNew;
    coordinatesXYdiff[i][j+1] = yDiffNew;
    j++;
}

Then I recalulate the new coodinates like

for(int j = 0; j < coordinatesXY[i].length; j++)
{
    double x = center[0] + coordinatesXYdiff[i][j];
    double y = center[1] + coordinatesXYdiff[i][j+1];

    coordinatesXY[j] = Math.round(x);
    coordinatesXY[j+1] = Math.round(y);
   
    j++;
    index++;
}

I have left out some  of the code that I do not think matters (I hope I got the important part). But if you see anything worng please let me know!

Best regards
Fredrik
Avatar billede nielle Nybegynder
11. juli 2005 - 22:21 #9
I'm sorry, I can't make much sense of your code except that something is very fishy about it.

This is how I would do it in a single loop:

for (int coordinateNo=1; coordinateNo<=noOfCoordinates; coordinateNo++)
{
    // Calculate the diffs from center.
    double xDiff = coordinatesX[coordinateNo] - centerX;
    double yDiff = coordinatesY[coordinateNo] - centerY;

    // Rotate 2*72=144 degrees around center.
    // 72 degres would be Math.PI/72, not 2*Math.PI/72.
    double xDiffNew = xDiff * Math.cos(2*Math.PI/72) - yDiff * Math.sin(2*Math.PI/72);
    double yDiffNew = -xDiff * Math.sin(2*Math.PI)/72) + yDiff * Math.cos(2*Math.PI/72);

    // Add the center, and round.
    coordinatesX[coordinateNo] = Math.round(xDiffNew + centerX);
    coordinatesY[coordinateNo] = Math.round(yDiffNew + centerY);
}
Avatar billede fredand Forsker
13. juli 2005 - 10:46 #10
Hello!

I translated your code into mine, se below. First I guess I need to explaine some part.

When the shape is created i store the coordinates in a 2-dim array called coordinatesXY.

Now I just got one shape but if it would 2 shapes based on 3 and 4 points each it would look like:
coordinatesXY[0] = {(x,y), (x,y), (x,y), (x,y)};
coordinatesXY[1] = {(x,y), (x,y), (x,y), (x,y), (x,y)};
or with real numbers:
coordinatesXY[0] = {-40,-40, 40,-40, 40,40, -40,-40};
coordinatesXY[1] = {-40,-40, 40,-40, 40,40, 69,70, -40,-40};


Hope you get the structure. To bind the shape together, the last coord is the same as the first.

When the shape is created at the first time the center is calculated by this formula one time only.

    public static double[] getCenterCoordinateOfShape(int[] coordinates)
    {
        double[] center = new double[2];

        int xMin = coordinates[0];
        int xMax = coordinates[0];
        int yMin = coordinates[1];
        int yMax = coordinates[1];

        for(int i = 0; i < coordinates.length; i = i+2)
        {
            if(coordinates[i] < xMin)
            {
                xMin = coordinates[i];
            }
            if(coordinates[i] > xMax)
            {
                xMax = coordinates[i];
            }
        }

        for(int i = 1; i < coordinates.length; i = i+2)
        {
            if(coordinates[i] < yMin)
            {
                yMin = coordinates[i];
            }
            if(coordinates[i] > yMax)
            {
                yMax = coordinates[i];
            }
        }

        //center[0] = ((xMax - xMin)/2) + xMin;
        //center[1] = ((yMax - yMin)/2) + yMin;

            center[0] = (xMax+xMin)/2;
            center[1] = (yMax+yMin)/2;


        return center;
    }

This method is called when the shape is created like:
centerCoordinatesXY[0] = getCenterCoordinateOfShape(coordinatesXY[0]);

Then this list is used just before your code like, btw all is inside a loop that looks like:

for(int i = 0; i < coordinatesXZ.length; i++) //to rotate all shapes
{

double[] center = centerCoordinatesXZ[i];

//Your code
for(int j = 0; j < coordinatesXY[i].length; j++)
{
    // Calculate the diffs from center.
    double xDiff = coordinatesXY[i][j] - center[0];
    double yDiff = coordinatesXY[i][j+1] - center[1];

    // Rotate 2*72=144 degrees around center.
    // 72 degres would be Math.PI/72, not 2*Math.PI/72.

    //I guess this is 5 deg
    double xDiffNew = xDiff * Math.cos(2*Math.PI/72) - yDiff * Math.sin(2*Math.PI/72);
    double yDiffNew = -xDiff * Math.sin(2*Math.PI/72) + yDiff * Math.cos(2*Math.PI/72);

    // Add the center, and round.
    Long x = new Long(Math.round(xDiffNew + center[0]));
    coordinatesXY[i][j] = x.intValue();
    Long y = new Long(Math.round(yDiffNew + center[1]));
    coordinatesXY[i][j+1] = y.intValue();
    j++;
}
}
After this I do a repaint upon the updated coords of course

How ever I end up like my first attempt and got this coords after 2 rotations:
-30,-36
50,-50
36,30
0,63
-22,79
-37,73
-47,64
-64,47
-76,10
-30,-36

The behavior is the same as http://www.dsv.su.se/~fr-ander/rot3.gif , the shape is getting stretched like the image before.

So if you got the time and are able to see anything wrong, please let me know.

Best regards
Fredrik
Avatar billede nielle Nybegynder
13. juli 2005 - 18:23 #11
Why are you not using a two-dimensional array instead of:

coordinatesXY[0] = {-40,-40, 40,-40, 40,40, -40,-40};
coordinatesXY[1] = {-40,-40, 40,-40, 40,40, 69,70, -40,-40};

- which is basically 1-dimensional.

It would make things so much more simple to program. Not to mention easier to read.
Avatar billede nielle Nybegynder
13. juli 2005 - 19:07 #12
(1) 2-dimensional array:

int[][] coordinatesXY = {{-40, -40}, {40, -40}, {40, 40}, {-40,-40}};


(2) Calculate center:

public static double[] getCenterCoordinateOfShape(int[][] coordinates)
{
    int xMin = coordinates[0][0];
    int xMax = coordinates[0][0];

    int yMin = coordinates[0][1];
    int yMax = coordinates[0][1];

    for (int i=1;i<coordinates.length; i++)  // No reason to start with index 0!
    {
        xMin = Math.min(xMin, coordinates[i][0]);
        xMax = Math.max(xMax, coordinates[i][0]);

        yMin = Math.min(yMin, coordinates[i][1]);
        yMax = Math.max(yMax, coordinates[i][1]);
            }
        }

    double[] center = new double[2];
    center[0] = (xMax+xMin)/2.0;  // Force float-division
    center[1] = (yMax+yMin)/2.0;

    return center;
}


(3) Rotate the figure:

// Place the calculations on the rotationangle outside the loop for efficiency:
double angleAsDegres = 5;
double angleAsRadians = angleAsDegres * (Math.PI/180);

for (int j=0; j<coordinatesXY.length; j++)
{
    // Calculate the diffs from center.
    double xDiff = coordinatesXY[j][0] - center[0];
    double yDiff = coordinatesXY[j][1] - center[1];

    // Rotate angleAsRadians radians around the center.
    double xDiffNew = xDiff * Math.cos(angleAsRadians) - yDiff * Math.sin(angleAsRadians);
    double yDiffNew = -xDiff * Math.sin(angleAsRadians) + yDiff * Math.cos(angleAsRadians);

    // Add the center, and round.
    coordinatesXY[j][0] = Math.round(xDiffNew + center[0]).intValue();
    coordinatesXY[j][1] = Math.round(yDiffNew + center[1]).intValue();
}
Avatar billede fredand Forsker
14. juli 2005 - 12:45 #13
Hello!

You may be right that it would be easier to use your structure. But I do not think that matter in this problem.

How ever my program is to big right now to change it.

I use the 2-dim array to be able to store coords for more then one shape. In this example (the images) shows just 1 shape.

But when I use your formula, the shape is getteing stretched instead of rotatede, please see this image:
http://www.dsv.su.se/~fr-ander/rot4.gif

This is how it looks after 2 rot a 5 deg.

My starting coords was:
-40,-40
40,-40
40,40
8,68
-12,80
-28,72
-40,60
-60,40
-80,0
-40,-40

After 1 rot with 5 deg:
-35,-38
45,-45
38,35
4,65
-17,79
-33,72
-43,62
-62,43
-78,5
-35,-38

After 1 more rot with 5 deg:
-30,-36
50,-50
36,30
0,63
-22,79
-37,73
-47,64
-64,47
-76,10
-30,-36

I really suck at math and are not able to tell why this stretch the image rather then rotate, so if you can tell me it would be great:

The code for the rot is as before:
for (int j=0; j<coordinatesXY[i].length; j++)
{
    // Calculate the diffs from center.
    double xDiff = coordinatesXY[i][j] - center[0];
    double yDiff = coordinatesXY[i][j+1] - center[1];

    // Rotate angleAsRadians radians around the center.
    double xDiffNew = xDiff * Math.cos(angleAsRadians) - yDiff * Math.sin(angleAsRadians);
    double yDiffNew = -xDiff * Math.sin(angleAsRadians) + yDiff * Math.cos(angleAsRadians);

    // Add the center, and round.
    Long x = new Long(Math.round(xDiffNew + center[0]));
    Long y = new Long(Math.round(yDiffNew + center[1]));
    coordinatesXY[i][j] = x.intValue();
    coordinatesXY[i][j+1] = y.intValue();
    j++:
}

Do you see the error?

Best regards
Fredrik
Avatar billede nielle Nybegynder
16. juli 2005 - 08:09 #14
Could you please post all the relevant code?
Avatar billede fredand Forsker
17. juli 2005 - 19:58 #15
Hello!

The code that matters is in fact the code that you suggested, I'm using it:
for (int coordinateNo=1; coordinateNo<=noOfCoordinates; coordinateNo++)
{
    // Calculate the diffs from center.
    double xDiff = coordinatesX[coordinateNo] - centerX;
    double yDiff = coordinatesY[coordinateNo] - centerY;

    // Rotate 2*72=144 degrees around center.
    // 72 degres would be Math.PI/72, not 2*Math.PI/72.
    double xDiffNew = xDiff * Math.cos(2*Math.PI/72) - yDiff * Math.sin(2*Math.PI/72);
    double yDiffNew = -xDiff * Math.sin(2*Math.PI)/72) + yDiff * Math.cos(2*Math.PI/72);

    // Add the center, and round.
    coordinatesX[coordinateNo] = Math.round(xDiffNew + centerX);
    coordinatesY[coordinateNo] = Math.round(yDiffNew + centerY);
}
(Please se next comment for my exact code, I got the code on my other computer.)

The whole program contains code of 50 kb so it is quite large by now.

I tried to calculate by that my self with my own calculator, and I ended up the same. The shape is getting strechted rather than rotatede. After each rotation I print out the coords in my progarm and they are the same as those I calculated as below.

This is the start coords
Start coords
-40,    -40
40,    -40
40,    40
8,    68
-12,    80
-28,    72
-40,    60
-60,    40
-80,    0
-40,    -40

I calculate the center like;
center[0] = (xMax+xMin)/2;
center[1] = (yMax+yMin)/2;
center -20, 20

I calculate the Diffs
double xDiff = coordinatesX[coordinateNo] - centerX;
double yDiff = coordinatesY[coordinateNo] - centerY;
-20,    -60
60    -60
60    20
28    48
8    60
-8    52
-20    40
-40    20
-60    -20
-20    -60

I calculate the new coords (2*Math.PI/72 == 5 deg)
double xNew = (xDiff * Math.cos(5) - yDiff * Math.sin(5)) + centerX;
double yNew = (-xDiff * Math.sin(5) + yDiff * Math.cos(5)) + centerY;

(In my program I round them of course, but I have checked they are ok)
-34.7,    -38.0
45.0,      -45.0
38.0,    34.7
3.7,    65.4
-17.3,    79.1
-32.5    72.5
-43.4,    61.6
-61.5,  43.4   
-78.0,    5.3
-34.7,    -38.0

Recording to me this is giving me a strecheted figure rather than rotatede.

See image below that shows start coords and after 5 deg rotation by the above formula.
http://www.dsv.su.se/~fr-ander/rot5.gif

Perhaps we are missing something in the formula since we are stretching instead of rotateting.

If you got the time, please check the formula your self and see if you agree with me about this stretching thing, I may be wrong!

Best regards and you should know that I appreciate all your help!!!
Fredrik
Avatar billede fredand Forsker
17. juli 2005 - 20:01 #16
The exact code, but please see comment above:

double angleAsDegres = 5;
double angleAsRadians = angleAsDegres * (Math.PI/180);

for (int j=0; j<coordinatesXY[i].length; j++)
{
    // Calculate the diffs from center.
    double xDiff = coordinatesXY[i][j] - center[0];
    double yDiff = coordinatesXY[i][j+1] - center[1];

    // Rotate angleAsRadians radians around the center.
    double xDiffNew = xDiff * Math.cos(angleAsRadians) - yDiff * Math.sin(angleAsRadians);
    double yDiffNew = -xDiff * Math.sin(angleAsRadians) + yDiff * Math.cos(angleAsRadians);

    // Add the center, and round.
    Long x = new Long(Math.round(xDiffNew + center[0]));
    Long y = new Long(Math.round(yDiffNew + center[1]));
    coordinatesXY[i][j] = x.intValue();
    coordinatesXY[i][j+1] = y.intValue();
    j++;
}

Best regards
Fredrik
Avatar billede nielle Nybegynder
18. juli 2005 - 22:23 #17
I've checked and double-checked... An I've found the error. Unfortunately I'm the one to blame for introducing it in the first place. :^(

The formula for rotation should look like this:

    double xDiffNew = xDiff * Math.cos(angleAsRadians) - yDiff * Math.sin(angleAsRadians);
    double yDiffNew = xDiff * Math.sin(angleAsRadians) + yDiff * Math.cos(angleAsRadians);

- with *no* minus-sign on the first partial expression of the formula for yDiffNew.

An other source for error is when you rotate; Each time you round after a rotation you introduce an error. And when you rotate 5 deg, round and then rotate 5 deg once more based on the rounded numbers, then you make this error worse and worse. Instead you should rotate the whole 10 deg and the round. This will minimize the error.
Avatar billede nielle Nybegynder
28. juli 2005 - 21:49 #18
Some response, please.
Avatar billede fredand Forsker
29. juli 2005 - 08:27 #19
Hello Nielle!

Thanks for all your help!

I have not been able to do the changes yet (with *no* minus-sign). My Boss is on to me that I have to do some stuff that he pays me for. I guess you know what I mean?;-)

How ever, with your help, I guess me new strategy will be:
1) When a shape is created, store those coordinates as some original coordinates.
2) When rotation is choosed, always create a copy of the orginal and rotate those coordinates. So when ever a rotation will be done - Calculate from the orginal coordinates.

I guess that will take care of the deformation.

I will try this out as soon as possible (when my boss take his regular powernap ;-) ).

Btw I would never mange this with out you. But I will get back soon on this.

Thanks mate!
Fredrik
Avatar billede nielle Nybegynder
29. juli 2005 - 17:36 #20
That sounds about right.

Another thing that you might consider is the center of the rotation. If  you were to:

1) rotate, then round of to integer coordinates, and
2) then rotate again

- then the center of the figure would not be the same for the two subsequent rotations. That would cause the figure to “wobble” around its center of rotation. This is not a serious problem, but it wouldn't look nice either.
Avatar billede nielle Nybegynder
12. august 2005 - 08:50 #21
Yo?
Avatar billede fredand Forsker
12. august 2005 - 09:57 #22
Hello Nielle!

I have been so busy with some otehr work that I have not manage to look more at this.
But be sure I will get back on you as soon as I can.

I will go an one week vacation today and be back 22 of august. That week looks pretty busy too. But after that I think everything will calm down around here hopefully.

Best regards
Fredrik
Avatar billede nielle Nybegynder
12. august 2005 - 11:32 #23
Have a very nice vacation then :^)
Avatar billede nielle Nybegynder
30. november 2005 - 22:36 #24
Time to finish this one?
Avatar billede nielle Nybegynder
10. januar 2006 - 22:01 #25
??
Avatar billede fredand Forsker
11. januar 2006 - 18:08 #26
Hello!

I guess the solution (I have not tried it yet) will be:
When time to rotate for eg 10 deg
1) Store original coords
2) Copy the original coords
3) Rotate the copy 10 deg.

At the next time to rotate for an other 15 deg start over at no 2 but rotate 25 deg instead of 10 this time.

I guess this will work

Give a svar all you guys so I can splite the points among you!!

Best regards
Fredrik

At next rotation
Avatar billede nielle Nybegynder
11. januar 2006 - 18:11 #27
Oki :^)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester