1 /* 
  2     Copyright 2008,2009
  3         Matthias Ehmann,
  4         Michael Gerhaeuser,
  5         Carsten Miller,
  6         Bianca Valentin,
  7         Alfred Wassermann,
  8         Peter Wilfahrt
  9 
 10     This file is part of JSXGraph.
 11 
 12     JSXGraph is free software: you can redistribute it and/or modify
 13     it under the terms of the GNU Lesser General Public License as published by
 14     the Free Software Foundation, either version 3 of the License, or
 15     (at your option) any later version.
 16 
 17     JSXGraph is distributed in the hope that it will be useful,
 18     but WITHOUT ANY WARRANTY; without even the implied warranty of
 19     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 20     GNU Lesser General Public License for more details.
 21 
 22     You should have received a copy of the GNU Lesser General Public License
 23     along with JSXGraph.  If not, see <http://www.gnu.org/licenses/>.
 24 */
 25 
 26 /** 
 27  * @fileoverview In this file the Coords object is defined, a class to manage all
 28  * properties and methods coordinates usually have.
 29  * @author graphjs
 30  * @version 0.1
 31  */
 32 
 33 JXG.COORDS_BY_USER = 0x0001;
 34 JXG.COORDS_BY_SCREEN = 0x0002;
 35 
 36 /**
 37  * Constructs a new Coordinates object.
 38  * @class This is the Coordinates class.  
 39  * All members a coordinate has to provide
 40  * are defined here.
 41  * @param {int} method The type of coordinates given by the user. Accepted values are <b>COORDS_BY_SCREEN</b> and <b>COORDS_BY_USER</b>.
 42  * @param {Array} coordinates An array of affine coordinates.
 43  * @param {JXG.AbstractRenderer} renderer A reference to a Renderer.
 44  * @constructor
 45  */
 46 JXG.Coords = function (method, coordinates, board) {
 47     /**
 48      * Stores the board the object is used on.
 49      * @type JXG.Board
 50      */
 51     this.board = board;
 52     
 53     /**
 54      * Stores coordinates for user view as homogeneous coordinates.
 55      * @type Array
 56      */
 57     this.usrCoords = [];
 58     /**
 59      * Stores coordinates for screen view as homogeneous coordinates.
 60      * @type Array
 61      */
 62     this.scrCoords = [];
 63     
 64     if(method == JXG.COORDS_BY_USER) {
 65         if (coordinates.length<=2) {
 66             this.usrCoords[0] = 1.0;
 67             this.usrCoords[1] = coordinates[0];
 68             this.usrCoords[2] = coordinates[1];
 69         } else {  // homogeneous coordinates
 70             this.usrCoords[0] = coordinates[0];
 71             this.usrCoords[1] = coordinates[1];
 72             this.usrCoords[2] = coordinates[2];
 73             this.normalizeUsrCoords();
 74         }
 75         this.usr2screen();
 76     } else {
 77         this.scrCoords[0] = 1.0;
 78         this.scrCoords[1] = coordinates[0];
 79         this.scrCoords[2] = coordinates[1];
 80         this.screen2usr();
 81     }
 82 };
 83 
 84 /**
 85     * Normalize homogeneous coordinates
 86     * @private
 87     */
 88 JXG.Coords.prototype.normalizeUsrCoords = function() {
 89     var eps = 0.000001;
 90     if (Math.abs(this.usrCoords[0])>eps) {
 91         this.usrCoords[1] /= this.usrCoords[0];
 92         this.usrCoords[2] /= this.usrCoords[0];
 93         this.usrCoords[0] = 1.0;
 94     }
 95 };
 96 
 97 /**
 98  * Compute screen coordinates out of given user coordinates.
 99  * @private
100  */
101 JXG.Coords.prototype.usr2screen = function(doRound) {
102     var mround = Math.round,  // Is faster on IE, maybe slower with JIT compilers
103         b = this.board,
104         uc = this.usrCoords,
105         oc = b.origin.scrCoords;
106         
107     if (doRound==null || doRound) {
108         this.scrCoords[0] = mround(uc[0]);
109         this.scrCoords[1] = mround(uc[0]*oc[1] + uc[1]*b.stretchX);
110         this.scrCoords[2] = mround(uc[0]*oc[2] - uc[2]*b.stretchY);
111     } else {
112         this.scrCoords[0] = uc[0];
113         this.scrCoords[1] = uc[0]*oc[1] + uc[1]*b.stretchX;
114         this.scrCoords[2] = uc[0]*oc[2] - uc[2]*b.stretchY;
115     }
116 };
117 
118 /**
119  * Compute user coordinates out of given screen coordinates.
120  * @private
121  */
122 JXG.Coords.prototype.screen2usr = function() {
123     var o = this.board.origin.scrCoords,
124         sc = this.scrCoords,
125         b = this.board;
126     this.usrCoords[0] =  1.0;
127     this.usrCoords[1] = (sc[1] - o[1])/b.stretchX;
128     this.usrCoords[2] = (o[2] - sc[2])/b.stretchY;
129 };
130 
131 /**
132  * Calculate distance of one point to another.
133  * @param {int} method The type of coordinates used here. Possible values are <b>JXG.COORDS_BY_USER</b> and <b>JXG.COORDS_BY_SCREEN</b>.
134  * @param {JXG.Coords} coordinates The Coords object to which the distance is calculated.
135  */
136 JXG.Coords.prototype.distance = function(meth, crd) {
137     var sum = 0,
138         c,
139         ucr = this.usrCoords,
140         scr = this.scrCoords,
141         f;
142         
143     if (meth == JXG.COORDS_BY_USER) {
144         c = crd.usrCoords;
145         f = ucr[0]-c[0];
146         sum = f*f;
147         f = ucr[1]-c[1];
148         sum += f*f;
149         f = ucr[2]-c[2];
150         sum += f*f;
151     } else {
152         c = crd.scrCoords;
153         f = scr[0]-c[0];
154         sum = f*f;
155         f = scr[1]-c[1];
156         sum += f*f;
157         f = scr[2]-c[2];
158         sum += f*f;
159     }
160 
161     return Math.sqrt(sum);
162 };
163 
164 /**
165  * Set coordinates by method
166  * @param {int} method The type of coordinates used here. Possible values are <b>COORDS_BY_USER</b> and <b>COORDS_BY_SCREEN</b>.
167  * @param {Array} coordinates An array of affine coordinates the Coords object is set to.
168  * @param {boolean} optional flag If true or null round the coordinates in usr2screen. This is used in smooth curve plotting.
169  * The IE needs rounded coordinates. Id doRound==false we have to round in updatePathString.
170  */
171 JXG.Coords.prototype.setCoordinates = function(method, crd, doRound) {
172     var uc = this.usrCoords,
173         sc = this.scrCoords;
174         
175     if (method == JXG.COORDS_BY_USER) {
176         if (crd.length==2) { // Euclidean coordinates
177             uc[0] = 1.0;
178             uc[1] = crd[0];
179             uc[2] = crd[1];
180         } else { // Homogeneous coordinates (normalized)
181             uc[0] = crd[0];
182             uc[1] = crd[1];
183             uc[2] = crd[2];
184             this.normalizeUsrCoords();
185         }
186         this.usr2screen(doRound);
187     } else {
188         sc[1] = crd[0];
189         sc[2] = crd[1];
190         this.screen2usr();
191     }
192 };
193