src/warpcoord.h

00001 /* This file is part of WarpTree
00002  *
00003  * Copyright (C) 2007 Jos van den Oever <jos@vandenoever.info>
00004  *
00005  * This library is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU Library General Public
00007  * License as published by the Free Software Foundation; either
00008  * version 2 of the License, or (at your option) any later version.
00009  *
00010  * This library is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * Library General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Library General Public License
00016  * along with this library; see the file COPYING.LIB.  If not, write to
00017  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
00019  */
00020 
00021 // code for transformations was adapted from HyperTree published under
00022 // MIT License 2001 www.bouthier.net
00023 
00024 #ifndef WARPTREE_H
00025 #define WARPTREE_H
00026 
00027 #include <iostream>
00028 #include <cmath>
00029 #include <cassert>
00030 #include <cstdlib>
00031 
00032 /* This class provides the methods to handle the points in the graph.
00033  * It allows points to be translated in the unit square.
00034  */
00035 
00036 #define ZONE_LENGTH 4 // size of the zone
00037 
00038 // if WARPCOORD is not defined, the standard Poincare disk projection is used
00039 #define WARPCOORD
00040 
00041 class WarpCoord;
00042 std::ostream& operator<<(std::ostream& o, const WarpCoord& e);
00043 class WarpCoord {
00044 private:
00045     float mx;
00046     float my;
00047     float md;
00048 
00049     /* the value for d is cached in this class. This function updates the
00050        value */
00051     inline void updateD() {
00052         md = sqrt(d2());
00053     }
00054     /* multiply this point with point z */
00055     void
00056     operator*=(const WarpCoord& z) {
00057         float tx = mx;
00058         mx = tx*z.mx - my * z.my;
00059         my = tx*z.my + my * z.mx;
00060         updateD();
00061     }
00062     /* divide this point by point z */
00063     void
00064     operator/=(const WarpCoord& z) {
00065         float d2 = z.d2();
00066         float tx = mx;
00067         mx = (tx*z.mx + my*z.my) / d2;
00068         my = (my*z.mx - tx*z.my) / d2;
00069         updateD();
00070     }
00071 public:
00072     WarpCoord() :mx(0), my(0), md(0) {}
00073     WarpCoord(float x, float y) :mx(x), my(y) {
00074         updateD();
00075     }
00076     inline float x() const { return mx; }
00077     inline float y() const { return my; }
00078     inline float d() const { return md; }
00079     inline float d2() const { return mx*mx + my*my; }
00080     /* calculate the arg of this point */
00081     float arg() const {
00082         float a = atan(my / mx);
00083         if (mx < 0) {
00084             a += M_PI;
00085         } else if (my < 0) {
00086             a += 2 * M_PI;
00087         }
00088         return a;
00089     }
00090     /* translate this point by adding the vector t */
00091     void translate(const WarpCoord& t) {
00092         float denX = mx * t.mx + my * t.my + 1;
00093         float denY = my * t.mx - mx * t.my;
00094         float dd = denX * denX + denY * denY;
00095 
00096         double numX = mx + t.mx;
00097         double numY = my + t.my;
00098 
00099         mx = (numX * denX + numY * denY) / dd;
00100         my = (numY * denX - numX * denY) / dd;
00101         updateD();
00102     }
00103     /* zoom this point. this means the point move closer to or away from the
00104        center of the square */
00105     void zoom(float f) {
00106         assert(f > 0);
00107         if (md < 0.001) return;
00108         float r = md;
00109         float c = pow((1+md)/(1-md),f);
00110         c = (c-1)/(c+1)/r;
00111         mx *= c;
00112         my *= c;
00113         md *= c;
00114     }
00115     /* move this point from the disk positiong to the square position */
00116     void stretch() {
00117         if (md < 0.0001) return;
00118 #ifdef WARPCOORD
00119         float fx = fabs(mx);
00120         float fy = fabs(my);
00121         if (fy > 0 && fy > fx) {
00122             float f = md/fy;
00123             my = (my>0) ?md :-md;
00124             mx *= f;
00125             md *= f;
00126         } else if (fx > 0) {
00127             float f = md/fx;
00128             mx = (mx>0) ?md :-md;
00129             my *= f;
00130             md *= f;
00131         }
00132 #endif
00133     }
00134     /* move this point from the square position to the disk position */
00135     void unstretch() {
00136         assert(md >= 0);
00137         if (md < 0.0001) return;
00138 #ifdef WARPCOORD
00139         float f = 1;
00140         float fx = fabs(mx);
00141         float fy = fabs(my);
00142         if (fy > 0 && fy > fx) {
00143             f = md/fy;
00144             md = (my>0) ?my :-my;
00145         } else if (fx > 0) {
00146             f = md/fx;
00147             md = (mx>0) ?mx :-mx;
00148         }
00149         mx /= f;
00150         my /= f;
00151 #endif
00152     }
00153     /* is this point visible, in other words, is it not too close to the edge
00154        of the unit square */
00155     inline bool visible() const {
00156         return mx > -0.95 && mx < 0.95 && my > -0.95 && my < 0.95;
00157     }
00158     /* is this point valid, in other words, does it lie inside the unit
00159        square */
00160     inline bool valid() const {
00161         return mx > -1 && mx < 1 && my > -1 && my < 1;
00162     }
00163     /* return the negative value of this point */
00164     inline WarpCoord operator-() const {
00165         return WarpCoord(-mx, -my);
00166     }
00167     /* substract the value of point e from this point. Note that this is not
00168        equal to translation. */
00169     inline void operator-=(const WarpCoord& e) {
00170         mx -= e.mx;
00171         my -= e.my;
00172         updateD();
00173     }
00174     /* apply the translation that is needed to get from point c1 to c2 to this
00175        point */
00176     void transform(const WarpCoord& c1, const WarpCoord& c2) {
00177         WarpCoord p(c1.mx + c2.mx, c1.my + c2.my);
00178 
00179         WarpCoord d(c2.mx, -c2.my);
00180         d *= c1;
00181         d.mx += 1;
00182         p /= d;
00183 
00184         WarpCoord o(c1.mx, -c1.my);
00185         o *= c2;
00186         o.mx += 1;
00187         o /= d;
00188 
00189         WarpCoord z(*this);
00190         *this *= o;
00191         mx += p.mx;
00192         my += p.my;
00193 
00194         d.set(p.mx, -p.my);
00195         d *= z;
00196         d *= o;
00197         d.mx += 1;
00198 
00199         *this /= d;
00200         updateD();
00201     }
00202     /* change the value of this point */
00203     inline void set(float x, float y) {
00204         mx = x;
00205         my = y;
00206         updateD();
00207     }
00208 };
00209 
00210 #endif 

Generated on Sat Jun 2 19:18:06 2007 for WarpTree by  doxygen 1.5.0