Повернуть набор координат объекта - PullRequest
3 голосов
/ 18 августа 2011

У меня есть набор объектов (ActiveRecord), которые имеют координаты x и y относительно элемента холста HTML5.Мне нужно повернуть их наборы на различное число градусов (с шагом 90 градусов), а затем сохранить их снова для однократной миграции данных.

Все эти объекты относятся к элементу canvas, поэтому координаты начинаются с(0,0), и я бы хотел, чтобы они оставались в этом квадранте (справа внизу), если это возможно.Я предполагаю, что мне нужно сделать вращение вокруг (0,0), а затем перевод вниз и вправо.

Есть ли способ, которым я могу написать блок, который будет делать это?Любая помощь приветствуется.

Обновление : внесены некоторые изменения, чтобы сделать его более понятным после некоторых вопросов.

Спасибо.

1 Ответ

9 голосов
/ 18 августа 2011
  1. Чтобы повернуть точку P количество R градусов вокруг начала координат:
    P2.x = P.x * cos ( R ) - P.y * sin ( R )
    P2.y = P.x * sin ( R ) + P.y * cos ( R )
    [править]

  2. Вы, вероятно, хотите повернуть вокруг произвольной точки в центре квадранта, в котором вы храните объекты. Если ваш квадрант имеет ширину 200x100 единиц, вам нужно будет вращаться вокруг точки <100,50>.

    Чтобы повернуть точку P вокруг местоположения C , отличного от начала координат, необходимо сначала перевести местоположение в начало координат, затем повернуть вокруг начала координат и затем перевести обратно на C. Другими словами,
    P2 = P - C
    P3 = поворот ( P2 )
    P4 = P3 + C

    Вы можете увидеть это в действии на http://phrogz.net/SVG/rotations.xhtml - щелкните, чтобы установить центр вращения или изменить величину вращения, и для группы точек будет установлено преобразование, которое переводится в начало координат, вращается, а затем переводит обратно снова.

Соберите все вместе, и чтобы повернуть точку с атрибутами x и y вокруг произвольной точки в Ruby, вы должны использовать такой код:

Point = Struct.new(:x,:y) do
  def self.to_proc
    lambda{ |x| self.new *x }
  end

  def rotate( degrees, origin=Point.new(0,0) )
    radians = degrees * Math::PI/180
    x2 = x-origin.x; y2 = y-origin.y
    cos = Math.cos(radians); sin = Math.sin(radians)
    self.class.new(
      x2*cos - y2*sin + origin.x, 
      x2*sin + y2*cos + origin.y 
    )
  end

  def inspect
    "<%.1f,%.1f>" % [x,y]
  end
end

points = [ [0,0], [1,2], [3,4], [5,6] ].map(&Point)
p points
#=> [<0.0,0.0>, <1.0,2.0>, <3.0,4.0>, <5.0,6.0>]

p points.map{ |p| p.rotate(90) }
#=> [<0.0,0.0>, <-2.0,1.0>, <-4.0,3.0>, <-6.0,5.0>]

p points.map{ |p| p.rotate(90,Point.new(3,4)) }
#=> [<7.0,1.0>, <5.0,2.0>, <3.0,4.0>, <1.0,6.0>]
...