      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