From 3353bd5f6941f2b06c008ac2c3c4eab193bad453 Mon Sep 17 00:00:00 2001
From: Dominik Picheta <dominikpicheta@googlemail.com>
Date: Wed, 13 Aug 2014 15:52:20 +0100
Subject: [PATCH 01/10] Support other rotation angles.

---
 src/drawer.js    | 9 ++++++++-
 src/rectangle.js | 3 ---
 src/viewport.js  | 3 ---
 3 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/src/drawer.js b/src/drawer.js
index 0165d1f3..a8db0265 100644
--- a/src/drawer.js
+++ b/src/drawer.js
@@ -398,11 +398,18 @@ function updateViewport( drawer ) {
     }
 
     //Change bounds for rotation
-    if (degrees === 90 || degrees === 270) {
+    if (degrees !== 0) {
         var rotatedBounds = viewportBounds.rotate( degrees );
         viewportTL = rotatedBounds.getTopLeft();
         viewportBR = rotatedBounds.getBottomRight();
     }
+    else if (degrees !== 0) {
+        var factor = 0.5 / drawer.viewer.viewport.getZoom();
+        viewportTL.x -= factor;
+        viewportTL.y -= factor;
+        viewportBR.x += factor;
+        viewportBR.y += factor;
+    }
 
     //Don't draw if completely outside of the viewport
     if  ( !drawer.wrapHorizontal &&
diff --git a/src/rectangle.js b/src/rectangle.js
index 99172e7d..b518190e 100644
--- a/src/rectangle.js
+++ b/src/rectangle.js
@@ -194,9 +194,6 @@ $.Rect.prototype = /** @lends OpenSeadragon.Rect.prototype */{
             newTopLeft;
 
         degrees = ( degrees + 360 ) % 360;
-        if( degrees % 90 !== 0 ) {
-            throw new Error('Currently only 0, 90, 180, and 270 degrees are supported.');
-        }
 
         if( degrees === 0 ){
             return new $.Rect(
diff --git a/src/viewport.js b/src/viewport.js
index ccc50a8a..fb64c1df 100644
--- a/src/viewport.js
+++ b/src/viewport.js
@@ -726,9 +726,6 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
         }
 
         degrees = ( degrees + 360 ) % 360;
-        if( degrees % 90 !== 0 ) {
-            throw new Error('Currently only 0, 90, 180, and 270 degrees are supported.');
-        }
         this.degrees = degrees;
         this.viewer.forceRedraw();
         

From 50f9a82089c134ed9f81295a294311563f8737ca Mon Sep 17 00:00:00 2001
From: Dominik Picheta <dominikpicheta@googlemail.com>
Date: Fri, 15 Aug 2014 15:47:50 +0100
Subject: [PATCH 02/10] Small rotation fixes.

---
 src/drawer.js | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/src/drawer.js b/src/drawer.js
index a8db0265..5e4b59b7 100644
--- a/src/drawer.js
+++ b/src/drawer.js
@@ -398,13 +398,20 @@ function updateViewport( drawer ) {
     }
 
     //Change bounds for rotation
-    if (degrees !== 0) {
+    if (degrees === 90 || degrees === 270) {
         var rotatedBounds = viewportBounds.rotate( degrees );
         viewportTL = rotatedBounds.getTopLeft();
         viewportBR = rotatedBounds.getBottomRight();
     }
     else if (degrees !== 0) {
-        var factor = 0.5 / drawer.viewer.viewport.getZoom();
+        /*
+        var factor1 = drawer.viewer.viewport.imageToViewportRectangle(0, 0, 256, 256);
+        viewportBounds.width += factor1.width;
+        viewportBounds.height += factor1.width;
+        viewportTL = viewportBounds.getTopLeft();
+        viewportBR = viewportBounds.getBottomRight();
+        */
+        var factor = 0.3 / drawer.viewer.viewport.getZoom();
         viewportTL.x -= factor;
         viewportTL.y -= factor;
         viewportBR.x += factor;

From e00e4c53ef5d38cfabf7bbad841fb665648f559c Mon Sep 17 00:00:00 2001
From: Dominik Picheta <dominikpicheta@googlemail.com>
Date: Tue, 19 Aug 2014 09:51:27 +0100
Subject: [PATCH 03/10] Proper viewport bounds changes for rotation.

---
 src/drawer.js | 17 +++++++----------
 1 file changed, 7 insertions(+), 10 deletions(-)

diff --git a/src/drawer.js b/src/drawer.js
index 5e4b59b7..64d2b671 100644
--- a/src/drawer.js
+++ b/src/drawer.js
@@ -404,18 +404,15 @@ function updateViewport( drawer ) {
         viewportBR = rotatedBounds.getBottomRight();
     }
     else if (degrees !== 0) {
-        /*
-        var factor1 = drawer.viewer.viewport.imageToViewportRectangle(0, 0, 256, 256);
-        viewportBounds.width += factor1.width;
-        viewportBounds.height += factor1.width;
+        var orthBounds = viewportBounds.rotate(90);
+        var halfWidth = orthBounds.width / 2;
+        var halfHeight = orthBounds.height / 2;
+        viewportBounds.x -= halfWidth / 2;
+        viewportBounds.y -= halfHeight / 2;
+        viewportBounds.width += halfWidth;
+        viewportBounds.height += halfHeight;
         viewportTL = viewportBounds.getTopLeft();
         viewportBR = viewportBounds.getBottomRight();
-        */
-        var factor = 0.3 / drawer.viewer.viewport.getZoom();
-        viewportTL.x -= factor;
-        viewportTL.y -= factor;
-        viewportBR.x += factor;
-        viewportBR.y += factor;
     }
 
     //Don't draw if completely outside of the viewport

From 1c63c96f0415ed2a1c65f6b438b24e3be8903904 Mon Sep 17 00:00:00 2001
From: Dominik Picheta <dominikpicheta@googlemail.com>
Date: Tue, 19 Aug 2014 15:56:23 +0100
Subject: [PATCH 04/10] Increase viewport bounds slightly for rotation.

---
 src/drawer.js | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/src/drawer.js b/src/drawer.js
index 64d2b671..248266ba 100644
--- a/src/drawer.js
+++ b/src/drawer.js
@@ -405,12 +405,10 @@ function updateViewport( drawer ) {
     }
     else if (degrees !== 0) {
         var orthBounds = viewportBounds.rotate(90);
-        var halfWidth = orthBounds.width / 2;
-        var halfHeight = orthBounds.height / 2;
-        viewportBounds.x -= halfWidth / 2;
-        viewportBounds.y -= halfHeight / 2;
-        viewportBounds.width += halfWidth;
-        viewportBounds.height += halfHeight;
+        viewportBounds.x -= orthBounds.width / 2;
+        viewportBounds.y -= orthBounds.height / 2;
+        viewportBounds.width += orthBounds.width;
+        viewportBounds.height += orthBounds.height;
         viewportTL = viewportBounds.getTopLeft();
         viewportBR = viewportBounds.getBottomRight();
     }

From ea80c05a05f2693f8df2ca88debca269ef40bc9a Mon Sep 17 00:00:00 2001
From: Dominik Picheta <dominikpicheta@googlemail.com>
Date: Wed, 20 Aug 2014 09:21:02 +0100
Subject: [PATCH 05/10] Replace error for non right-angle rotations in
 Rect.rotate.

---
 src/drawer.js    | 1 +
 src/navigator.js | 2 +-
 src/rectangle.js | 5 +++++
 3 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/src/drawer.js b/src/drawer.js
index 248266ba..34cf3506 100644
--- a/src/drawer.js
+++ b/src/drawer.js
@@ -404,6 +404,7 @@ function updateViewport( drawer ) {
         viewportBR = rotatedBounds.getBottomRight();
     }
     else if (degrees !== 0) {
+        // This is just an approximation.
         var orthBounds = viewportBounds.rotate(90);
         viewportBounds.x -= orthBounds.width / 2;
         viewportBounds.y -= orthBounds.height / 2;
diff --git a/src/navigator.js b/src/navigator.js
index d07a2bba..9e18d6ca 100644
--- a/src/navigator.js
+++ b/src/navigator.js
@@ -241,7 +241,7 @@ $.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /*
                     (this.container.clientHeight === 0 ? 1 : this.container.clientHeight)
                 );
             if ( !containerSize.equals( this.oldContainerSize ) ) {
-                var oldBounds = this.viewport.getBounds().rotate(this.viewport.degrees);
+                var oldBounds = this.viewport.getBounds();
                 var oldCenter = this.viewport.getCenter();
                 this.viewport.resize( containerSize, true );
                 var imageHeight = 1 / this.source.aspectRatio;
diff --git a/src/rectangle.js b/src/rectangle.js
index b518190e..1bac049f 100644
--- a/src/rectangle.js
+++ b/src/rectangle.js
@@ -195,6 +195,11 @@ $.Rect.prototype = /** @lends OpenSeadragon.Rect.prototype */{
 
         degrees = ( degrees + 360 ) % 360;
 
+        if (degrees % 90 !== 0)
+        {
+            throw new Error('Currently only 0, 90, 180, and 270 degrees are supported.');
+        }
+
         if( degrees === 0 ){
             return new $.Rect(
                 this.x,

From 097714cf39eac703a30ffd704a816d50d4426d79 Mon Sep 17 00:00:00 2001
From: Dominik Picheta <dominikpicheta@googlemail.com>
Date: Wed, 20 Aug 2014 09:58:40 +0100
Subject: [PATCH 06/10] Implements pinch rotate.

---
 src/viewer.js | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/src/viewer.js b/src/viewer.js
index 5435b3a0..0df3e77a 100644
--- a/src/viewer.js
+++ b/src/viewer.js
@@ -2465,6 +2465,12 @@ function onCanvasPinch( event ) {
             this.viewport.applyConstraints();
         }
     }
+    // Pinch rotate
+    var angle1 = Math.atan2(event.gesturePoints[0].currentPos.y - event.gesturePoints[1].currentPos.y,
+        event.gesturePoints[0].currentPos.x - event.gesturePoints[1].currentPos.x);
+    var angle2 = Math.atan2(event.gesturePoints[0].lastPos.y - event.gesturePoints[1].lastPos.y,
+        event.gesturePoints[0].lastPos.x - event.gesturePoints[1].lastPos.x);
+    this.viewport.setRotation(this.viewport.getRotation() + ((angle1 - angle2) * (180 / Math.PI)));
     /**
      * Raised when a pinch event occurs on the {@link OpenSeadragon.Viewer#canvas} element.
      *

From c3b292cfb16f041502dca3f0447cc4c2837142e9 Mon Sep 17 00:00:00 2001
From: Dominik Picheta <dominikpicheta@googlemail.com>
Date: Fri, 22 Aug 2014 14:57:20 +0100
Subject: [PATCH 07/10] Fix code style issue.

---
 src/rectangle.js | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/src/rectangle.js b/src/rectangle.js
index 1bac049f..4e3746eb 100644
--- a/src/rectangle.js
+++ b/src/rectangle.js
@@ -194,9 +194,7 @@ $.Rect.prototype = /** @lends OpenSeadragon.Rect.prototype */{
             newTopLeft;
 
         degrees = ( degrees + 360 ) % 360;
-
-        if (degrees % 90 !== 0)
-        {
+        if (degrees % 90 !== 0) {
             throw new Error('Currently only 0, 90, 180, and 270 degrees are supported.');
         }
 

From 0ff6eb443df152a997c7a2e154936484b0e6b40d Mon Sep 17 00:00:00 2001
From: Dominik Picheta <dominikpicheta@googlemail.com>
Date: Fri, 22 Aug 2014 15:22:00 +0100
Subject: [PATCH 08/10] Added pinchRotate option.

---
 src/openseadragon.js | 12 ++++++++----
 src/viewer.js        | 14 ++++++++------
 2 files changed, 16 insertions(+), 10 deletions(-)

diff --git a/src/openseadragon.js b/src/openseadragon.js
index a74bbfcc..fb915644 100644
--- a/src/openseadragon.js
+++ b/src/openseadragon.js
@@ -298,6 +298,7 @@
   * @property {Boolean} [gestureSettingsMouse.flickEnabled=false] - Enable flick gesture
   * @property {Number} [gestureSettingsMouse.flickMinSpeed=120] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second)
   * @property {Number} [gestureSettingsMouse.flickMomentum=0.25] - If flickEnabled is true, the momentum factor for the flick gesture
+  * @property {Boolean} [gestureSettingsMouse.pinchRotate=false] - If pinchRotate is true, the user will have the ability to rotate the image using their fingers.
   *
   * @property {OpenSeadragon.GestureSettings} [gestureSettingsTouch]
   *     Settings for gestures generated by a touch pointer device. (See {@link OpenSeadragon.GestureSettings})
@@ -309,6 +310,7 @@
   * @property {Boolean} [gestureSettingsTouch.flickEnabled=true] - Enable flick gesture
   * @property {Number} [gestureSettingsTouch.flickMinSpeed=120] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second)
   * @property {Number} [gestureSettingsTouch.flickMomentum=0.25] - If flickEnabled is true, the momentum factor for the flick gesture
+  * @property {Boolean} [gestureSettingsTouch.pinchRotate=false] - If pinchRotate is true, the user will have the ability to rotate the image using their fingers.
   *
   * @property {OpenSeadragon.GestureSettings} [gestureSettingsPen]
   *     Settings for gestures generated by a pen pointer device. (See {@link OpenSeadragon.GestureSettings})
@@ -320,6 +322,7 @@
   * @property {Boolean} [gestureSettingsPen.flickEnabled=false] - Enable flick gesture
   * @property {Number} [gestureSettingsPen.flickMinSpeed=120] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second)
   * @property {Number} [gestureSettingsPen.flickMomentum=0.25] - If flickEnabled is true, the momentum factor for the flick gesture
+  * @property {Boolean} [gestureSettingsPen.pinchRotate=false] - If pinchRotate is true, the user will have the ability to rotate the image using their fingers.
   *
   * @property {OpenSeadragon.GestureSettings} [gestureSettingsUnknown]
   *     Settings for gestures generated by unknown pointer devices. (See {@link OpenSeadragon.GestureSettings})
@@ -331,6 +334,7 @@
   * @property {Boolean} [gestureSettingsUnknown.flickEnabled=true] - Enable flick gesture
   * @property {Number} [gestureSettingsUnknown.flickMinSpeed=120] - If flickEnabled is true, the minimum speed to initiate a flick gesture (pixels-per-second)
   * @property {Number} [gestureSettingsUnknown.flickMomentum=0.25] - If flickEnabled is true, the momentum factor for the flick gesture
+  * @property {Boolean} [gestureSettingsUnknown.pinchRotate=false] - If pinchRotate is true, the user will have the ability to rotate the image using their fingers.
   *
   * @property {Number} [zoomPerClick=2.0]
   *     The "zoom distance" per mouse click or touch tap. <em><strong>Note:</strong> Setting this to 1.0 effectively disables the click-to-zoom feature (also see gestureSettings[Mouse|Touch|Pen].clickToZoom/dblClickToZoom).</em>
@@ -916,10 +920,10 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){
             dblClickDistThreshold:  20,
             springStiffness:        6.5,
             animationTime:          1.2,
-            gestureSettingsMouse:   { scrollToZoom: true,  clickToZoom: true,  dblClickToZoom: false, pinchToZoom: false, flickEnabled: false, flickMinSpeed: 120, flickMomentum: 0.25 },
-            gestureSettingsTouch:   { scrollToZoom: false, clickToZoom: false, dblClickToZoom: true,  pinchToZoom: true,  flickEnabled: true,  flickMinSpeed: 120, flickMomentum: 0.25 },
-            gestureSettingsPen:     { scrollToZoom: false, clickToZoom: true,  dblClickToZoom: false, pinchToZoom: false, flickEnabled: false, flickMinSpeed: 120, flickMomentum: 0.25 },
-            gestureSettingsUnknown: { scrollToZoom: false, clickToZoom: false, dblClickToZoom: true,  pinchToZoom: true,  flickEnabled: true,  flickMinSpeed: 120, flickMomentum: 0.25 },
+            gestureSettingsMouse:   { scrollToZoom: true,  clickToZoom: true,  dblClickToZoom: false, pinchToZoom: false, flickEnabled: false, flickMinSpeed: 120, flickMomentum: 0.25, pinchRotate: false },
+            gestureSettingsTouch:   { scrollToZoom: false, clickToZoom: false, dblClickToZoom: true,  pinchToZoom: true,  flickEnabled: true,  flickMinSpeed: 120, flickMomentum: 0.25, pinchRotate: false },
+            gestureSettingsPen:     { scrollToZoom: false, clickToZoom: true,  dblClickToZoom: false, pinchToZoom: false, flickEnabled: false, flickMinSpeed: 120, flickMomentum: 0.25, pinchRotate: false },
+            gestureSettingsUnknown: { scrollToZoom: false, clickToZoom: false, dblClickToZoom: true,  pinchToZoom: true,  flickEnabled: true,  flickMinSpeed: 120, flickMomentum: 0.25, pinchRotate: false },
             zoomPerClick:           2,
             zoomPerScroll:          1.2,
             zoomPerSecond:          1.0,
diff --git a/src/viewer.js b/src/viewer.js
index 0df3e77a..9fab1181 100644
--- a/src/viewer.js
+++ b/src/viewer.js
@@ -2464,13 +2464,15 @@ function onCanvasPinch( event ) {
             this.viewport.panBy( panByPt, true );
             this.viewport.applyConstraints();
         }
+        if ( gestureSettings.pinchRotate ) {
+            // Pinch rotate
+            var angle1 = Math.atan2(event.gesturePoints[0].currentPos.y - event.gesturePoints[1].currentPos.y,
+                event.gesturePoints[0].currentPos.x - event.gesturePoints[1].currentPos.x);
+            var angle2 = Math.atan2(event.gesturePoints[0].lastPos.y - event.gesturePoints[1].lastPos.y,
+                event.gesturePoints[0].lastPos.x - event.gesturePoints[1].lastPos.x);
+            this.viewport.setRotation(this.viewport.getRotation() + ((angle1 - angle2) * (180 / Math.PI)));
+        }
     }
-    // Pinch rotate
-    var angle1 = Math.atan2(event.gesturePoints[0].currentPos.y - event.gesturePoints[1].currentPos.y,
-        event.gesturePoints[0].currentPos.x - event.gesturePoints[1].currentPos.x);
-    var angle2 = Math.atan2(event.gesturePoints[0].lastPos.y - event.gesturePoints[1].lastPos.y,
-        event.gesturePoints[0].lastPos.x - event.gesturePoints[1].lastPos.x);
-    this.viewport.setRotation(this.viewport.getRotation() + ((angle1 - angle2) * (180 / Math.PI)));
     /**
      * Raised when a pinch event occurs on the {@link OpenSeadragon.Viewer#canvas} element.
      *

From e9382ffbf70be2369368994edc40748e4a8bd676 Mon Sep 17 00:00:00 2001
From: Dominik Picheta <dominikpicheta@googlemail.com>
Date: Tue, 26 Aug 2014 14:56:24 +0100
Subject: [PATCH 09/10] Fixes doc comment.

---
 src/viewport.js | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/src/viewport.js b/src/viewport.js
index 02b262f8..4de54f96 100644
--- a/src/viewport.js
+++ b/src/viewport.js
@@ -713,10 +713,7 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
     },
 
     /**
-     * Currently only 90 degree rotation is supported and it only works
-     * with the canvas. Additionally, the navigator does not rotate yet,
-     * debug mode doesn't rotate yet, and overlay rotation is only
-     * partially supported.
+     * Rotates this viewport to the angle specified.
      * @function
      * @return {OpenSeadragon.Viewport} Chainable.
      */

From bcb16de02bb3a6cbf1797bfd3f7d56022203b854 Mon Sep 17 00:00:00 2001
From: Ian Gilman <ian@iangilman.com>
Date: Tue, 26 Aug 2014 10:49:10 -0700
Subject: [PATCH 10/10] Changelog for #466 and #468

---
 changelog.txt | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/changelog.txt b/changelog.txt
index e9c895f1..1b701458 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -15,6 +15,8 @@ OPENSEADRAGON CHANGELOG
 * Debug mode now works with rotate images (#453)
 * Now supporting dzi xml with namespaces (#462)
 * You can now rotate the navigator along with the main viewer (#455)
+* Viewport.setRotation now allows all rotation angles (#466)
+* Pinch rotate is now available (defaults to off) (#468)
 
 1.1.1: