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     this.setCoordinates(method, coordinates);
 65 };
 66 
 67 JXG.extend(JXG.Coords.prototype, /** @lends JXG.Coords.prototype */ {
 68     /**
 69      * Normalize homogeneous coordinates
 70      * @private
 71      */
 72     normalizeUsrCoords: function () {
 73         var eps = JXG.Math.eps;
 74         if (Math.abs(this.usrCoords[0]) > eps) {
 75             this.usrCoords[1] /= this.usrCoords[0];
 76             this.usrCoords[2] /= this.usrCoords[0];
 77             this.usrCoords[0] = 1.0;
 78         }
 79     },
 80 
 81     /**
 82      * Compute screen coordinates out of given user coordinates.
 83      * @private
 84      */
 85     usr2screen: function (doRound) {
 86         var mround = Math.round,  // Is faster on IE, maybe slower with JIT compilers
 87             b = this.board,
 88             uc = this.usrCoords,
 89             oc = b.origin.scrCoords;
 90 
 91         if (doRound === null || doRound) {
 92             this.scrCoords[0] = mround(uc[0]);
 93             this.scrCoords[1] = mround(uc[0]*oc[1] + uc[1]*b.unitX);
 94             this.scrCoords[2] = mround(uc[0]*oc[2] - uc[2]*b.unitY);
 95         } else {
 96             this.scrCoords[0] = uc[0];
 97             this.scrCoords[1] = uc[0]*oc[1] + uc[1]*b.unitX;
 98             this.scrCoords[2] = uc[0]*oc[2] - uc[2]*b.unitY;
 99         }
100     },
101 
102     /**
103      * Compute user coordinates out of given screen coordinates.
104      * @private
105      */
106     screen2usr: function () {
107         var o = this.board.origin.scrCoords,
108             sc = this.scrCoords,
109             b = this.board;
110         this.usrCoords[0] =  1.0;
111         this.usrCoords[1] = (sc[1] - o[1])/b.unitX;
112         this.usrCoords[2] = (o[2] - sc[2])/b.unitY;
113     },
114 
115     /**
116      * Calculate distance of one point to another.
117      * @param {Number} coord_type The type of coordinates used here. Possible values are <b>JXG.COORDS_BY_USER</b> and <b>JXG.COORDS_BY_SCREEN</b>.
118      * @param {JXG.Coords} coordinates The Coords object to which the distance is calculated.
119      * @returns {Number} The distance
120      */
121     distance: function (coord_type, coordinates) {
122         var sum = 0,
123             c,
124             ucr = this.usrCoords,
125             scr = this.scrCoords,
126             f;
127 
128         if (coord_type === JXG.COORDS_BY_USER) {
129             c = coordinates.usrCoords;
130             f = ucr[0]-c[0];
131             sum = f*f;
132             if (sum>JXG.Math.eps) {
133                 return Number.POSITIVE_INFINITY;
134             }
135             f = ucr[1]-c[1];
136             sum += f*f;
137             f = ucr[2]-c[2];
138             sum += f*f;
139         } else {
140             c = coordinates.scrCoords;
141             //f = scr[0]-c[0];
142             //sum = f*f;
143             f = scr[1]-c[1];
144             sum += f*f;
145             f = scr[2]-c[2];
146             sum += f*f;
147         }
148 
149         return Math.sqrt(sum);
150     },
151 
152     /**
153      * Set coordinates by either user coordinates or screen coordinates and recalculate the other one.
154      * @param {Number} coord_type The type of coordinates used here. Possible values are <b>COORDS_BY_USER</b> and <b>COORDS_BY_SCREEN</b>.
155      * @param {Array} coordinates An array of affine coordinates the Coords object is set to.
156      * @param {Boolean} [doRound=true] flag If true or null round the coordinates in usr2screen. This is used in smooth curve plotting.
157      * The IE needs rounded coordinates. Id doRound==false we have to round in updatePathString.
158      * @returns {JXG.Coords} Reference to the coords object.
159      */
160     setCoordinates: function (coord_type, coordinates, doRound) {
161         var uc = this.usrCoords,
162             sc = this.scrCoords;
163 
164         if (coord_type === JXG.COORDS_BY_USER) {
165             if (coordinates.length === 2) { // Euclidean coordinates
166                 uc[0] = 1.0;
167                 uc[1] = coordinates[0];
168                 uc[2] = coordinates[1];
169             } else { // Homogeneous coordinates (normalized)
170                 uc[0] = coordinates[0];
171                 uc[1] = coordinates[1];
172                 uc[2] = coordinates[2];
173                 this.normalizeUsrCoords();
174             }
175             this.usr2screen(doRound);
176         } else {
177             sc[1] = coordinates[0];
178             sc[2] = coordinates[1];
179             this.screen2usr();
180         }
181 
182         return this;
183     }
184 });
185