2

I would like to rotate a polygon I have array of polygon like this [ [-17.999999999999986, 587.25], [-14, 197.25], [544, 169.25], [554, 551.25] ]

Fist step: I calculate the Centroid

function getCentroid(coord) {
    var center = coord.reduce(function (x,y) {
        return [x[0] + y[0]/coord.length, x[1] + y[1]/coord.length] 
    }, [0,0])
    return center;
}

Seconde Step: Rotation:

function rotate(CX, CY, X, Y, angle) {
    var rad = angle * (Math.PI / 180.0);
    var nx = Math.cos(rad) * (X-CX) - Math.sin(rad) * (Y-CY) + CX;
    var ny = Math.sin(rad) * (X-CX) + Math.cos(rad) * (Y-CY) + CY;
    return [nx,ny];
}

the problem is every time I rotate the polygon it become biger. Maybe I have a problem in the formula but this one is used by alot of programmers.

Thank you for your answers.

imtah
  • 409
  • 1
  • 6
  • 16
  • Can you provide more code? Full HTML and JavaScript code so we can test it all in a snippet? – Guillaume Georges May 30 '18 at 10:06
  • 1
    The centroid calculation looks off. Compare with this: https://github.com/ayamflow/polygon-centroid/blob/master/index.js – Robby Cornelissen May 30 '18 at 10:18
  • @RobbyCornelissen there is nothing wrong with direcly dividing by the length instead of doing it at the end. His function does the same as in your link. The naming is just a bit off. My answer uses the function in the second example and it works like a charm – Fuzzyma May 31 '18 at 08:06
  • @Fuzzyma Yeah, you're right. I guess I got confused by the `x` and `y` naming for accumulator and current value. – Robby Cornelissen May 31 '18 at 08:10
  • I addded a pimped version of it to the end of my answer. Maybe that one looks better – Fuzzyma May 31 '18 at 08:17
  • Please provide a [mcve]. Your functions look okay at first glance, so maybe it's the way you are using them that's faulty. – Paul LeBeau May 31 '18 at 13:07

1 Answers1

1

You tagged svg.js so I assume that you are using it. So here is how I would do it.

// assuming that you have a div with the id "canvas" here
var canvas = SVG('canvas')

var angle = 20

// draw polygon
var polygon = canvas.polygon([ [-18, 587.25], [-14, 197.25], [544, 169.25], [554, 551.25] ])
    .fill('none')
    .stroke('black')

// we clone it so we have something to compare 
var clone = polygon.clone()

// get center of polygon
var box = polygon.bbox()
var {cx, cy} = box

// get the values of the points
var rotatedPoints = polygon.array().valueOf().map((p) => {

  // transform every point
  var {x, y} = new SVG.Point(p)
    .transform(new SVG.Matrix().rotate(angle, cx, cy))

  return [x, y]
})


// update polygon with points
polygon.plot(rotatedPoints)

Fiddle: https://jsfiddle.net/Fuzzy/3qzubk5y/1/

Ofc you dont need to make a polygon first to rotate the points. You can go straight withy our array and call the same map function on it. But in this case you need to figure out the cx and cy yourself:

function getCentroid(coord) {
    var center = coord.reduce(function (x,y) {
        return [x[0] + y[0]/coord.length, x[1] + y[1]/coord.length] 
    }, [0,0])
    return center;
}

var canvas = SVG("canvas")
var points = [ [-18, 587.25], [-14, 197.25], [544, 169.25], [554, 551.25] ]
var center = getCentroid(points)
var angle = 20

// polygon before rotation
canvas.polygon(points).fill('none').stroke('black')

// get the values of the points
var rotatedPoints = points.map((p) => {

  // transform every point
  var {x, y} = new SVG.Point(p)
    .transform(new SVG.Matrix().rotate(angle, center[0], center[1]))

  return [x, y]
})

// polygon after rotation
canvas.polygon(rotatedPoints).fill('none').stroke('black')

Fiddle: https://jsfiddle.net/Fuzzy/g90w10gg/

So since your centroid function seems to work, your mistake has to be somewhere in your rotate function. However, I prefer to use the capcabilities of the libraries when I have them there. No need to reinvent the weel :)

// EDIT: I pimped your centroid function a bit so the variable naming is a bit more clear:

function getCentroid(coord) {
    var length = coord.length
    var center = coord.reduce(function (last, current) {
        last.x += current[0] / length
        last.y += current[1] / length
        return last
    }, {x: 0, y: 0})

    return center;
}
Fuzzyma
  • 7,619
  • 6
  • 28
  • 60