mev-4.0.01/source/org/tigr/microarray/mev/cluster/algorithm/impl/terrain/FDGLAlgoT.java

Code
Comments
Other
Rev Date Author Line
2 26 Feb 07 jari 1 /*
2 26 Feb 07 jari 2 Copyright @ 1999-2003, The Institute for Genomic Research (TIGR).
2 26 Feb 07 jari 3 All rights reserved.
2 26 Feb 07 jari 4 */
2 26 Feb 07 jari 5 /*
2 26 Feb 07 jari 6  * $RCSfile: FDGLAlgoT.java,v $
2 26 Feb 07 jari 7  * $Revision: 1.4 $
2 26 Feb 07 jari 8  * $Date: 2006/02/23 20:59:46 $
2 26 Feb 07 jari 9  * $Author: caliente $
2 26 Feb 07 jari 10  * $State: Exp $
2 26 Feb 07 jari 11  */
2 26 Feb 07 jari 12 package org.tigr.microarray.mev.cluster.algorithm.impl.terrain; 
2 26 Feb 07 jari 13
2 26 Feb 07 jari 14 import javax.vecmath.Vector2f;
2 26 Feb 07 jari 15
2 26 Feb 07 jari 16 import org.tigr.microarray.mev.cluster.algorithm.impl.util.FloatArray;
2 26 Feb 07 jari 17 import org.tigr.microarray.mev.cluster.algorithm.impl.util.IntArray;
2 26 Feb 07 jari 18
2 26 Feb 07 jari 19 public class FDGLAlgoT { // Force Directed Graph Layout algorithm
2 26 Feb 07 jari 20
2 26 Feb 07 jari 21     public static final float c_AttractiveRadius  = 0f;     // the radius, from which attractive force begin to work == min(0,R^2-c_AttractiveRadius^2; c_RepulsiveRadius^2)
2 26 Feb 07 jari 22     public static final float c_RepulsiveRadius   = 200f;   // the radius of repulsive force== min(0,c_RepulsiveRadius^2-R^2)
2 26 Feb 07 jari 23     public static final float c_dblFDGLAlgoThreshold = 1f;
2 26 Feb 07 jari 24     public static final int   c_iQuadTreeDepth    = 5;
2 26 Feb 07 jari 25     public static final int   c_iHistoryQueueSize = 10;
2 26 Feb 07 jari 26
2 26 Feb 07 jari 27     private Vector2f[] m_arrPoints;  // the array of coordinates
2 26 Feb 07 jari 28     private SLink[][] m_arrLinks;    // the array of links
2 26 Feb 07 jari 29     private Vector2f m_rPt;
2 26 Feb 07 jari 30
2 26 Feb 07 jari 31     private QuadTreeT m_QTree;               // QuadTree used for optimization puposes
2 26 Feb 07 jari 32     private InterfaceToObjects m_pInterface; // use this interface to have a deal with objects
2 26 Feb 07 jari 33
2 26 Feb 07 jari 34     private Vector2f[] m_arrForceField; // defines the direction and intensivity of force affecting the node
2 26 Feb 07 jari 35     private float m_dblMaxForceLength;
2 26 Feb 07 jari 36     private int   m_iDoNotMove;
2 26 Feb 07 jari 37     private float m_arrEnergyHist[] = new float[] {-1,-1,-1,-1};  // TODO: change 10 to appropriate constant name
2 26 Feb 07 jari 38     private int   m_iEnergyIndex=0;
2 26 Feb 07 jari 39
2 26 Feb 07 jari 40     public FDGLAlgoT(InterfaceToObjects pInterface) {
2 26 Feb 07 jari 41         m_pInterface = pInterface;
2 26 Feb 07 jari 42         m_QTree = new QuadTreeT(c_iQuadTreeDepth, pInterface);
2 26 Feb 07 jari 43         m_rPt = new Vector2f(0,0);
2 26 Feb 07 jari 44         m_iDoNotMove=-1; 
2 26 Feb 07 jari 45     }
2 26 Feb 07 jari 46
2 26 Feb 07 jari 47     private void PushEnergy(float fltEnergyValue) {
2 26 Feb 07 jari 48         m_arrEnergyHist[3] = m_arrEnergyHist[2];
2 26 Feb 07 jari 49         m_arrEnergyHist[2] = m_arrEnergyHist[1];
2 26 Feb 07 jari 50         m_arrEnergyHist[1] = m_arrEnergyHist[0];
2 26 Feb 07 jari 51         m_arrEnergyHist[0] = fltEnergyValue;
2 26 Feb 07 jari 52     }
2 26 Feb 07 jari 53
2 26 Feb 07 jari 54     static final float MAX_ENERGY = 100f; //1000f;
2 26 Feb 07 jari 55
2 26 Feb 07 jari 56     public float getPercentage() {
2 26 Feb 07 jari 57         return 100f*m_iEnergyIndex/MAX_ENERGY;
2 26 Feb 07 jari 58     }
2 26 Feb 07 jari 59
2 26 Feb 07 jari 60     public boolean shouldStop() {
2 26 Feb 07 jari 61         if (m_iEnergyIndex>MAX_ENERGY)
2 26 Feb 07 jari 62             return true;
2 26 Feb 07 jari 63         if (m_arrEnergyHist[3]<0)
2 26 Feb 07 jari 64             return false;
2 26 Feb 07 jari 65         // TODO:
2 26 Feb 07 jari 66         //(cool_max_force_4 != 0.0) &&
2 26 Feb 07 jari 67         //Math.abs(m_arrEnergyHist[0]-m_arrEnergyHist[2])/m_arrEnergyHist[0]<vibration &&
2 26 Feb 07 jari 68         //Math.abs(m_arrEnergyHist[1]-m_arrEnergyHist[3])/m_arrEnergyHist[1]<vibration &&
2 26 Feb 07 jari 69         return false;
2 26 Feb 07 jari 70     }
2 26 Feb 07 jari 71
2 26 Feb 07 jari 72     // helper functions
2 26 Feb 07 jari 73     private static float CalcAttractiveForceFromR2(float R2) {
2 26 Feb 07 jari 74         float tmpVal=R2-(c_AttractiveRadius*c_AttractiveRadius);
2 26 Feb 07 jari 75         if (R2>(c_RepulsiveRadius*c_RepulsiveRadius))        // upper boundary, R2 is too much
2 26 Feb 07 jari 76             return(c_RepulsiveRadius*c_RepulsiveRadius);
2 26 Feb 07 jari 77         if (tmpVal<0)
2 26 Feb 07 jari 78             return 0;
2 26 Feb 07 jari 79         return tmpVal;
2 26 Feb 07 jari 80     }
2 26 Feb 07 jari 81
2 26 Feb 07 jari 82     private static float CalcRepulsiveForceFromR2(float R2) {
2 26 Feb 07 jari 83         float tmpVal=c_RepulsiveRadius*c_RepulsiveRadius-R2;
2 26 Feb 07 jari 84         if (tmpVal<0)
2 26 Feb 07 jari 85             return 0;
2 26 Feb 07 jari 86         return tmpVal;
2 26 Feb 07 jari 87     }
2 26 Feb 07 jari 88
2 26 Feb 07 jari 89     private Vector2f CalcAttractiveForcesAt(int iNode) {
2 26 Feb 07 jari 90         SLink[] rArrAdjNodes = m_arrLinks[iNode];
2 26 Feb 07 jari 91         int nAdjNodeSize= rArrAdjNodes.length;
2 26 Feb 07 jari 92
2 26 Feb 07 jari 93         Vector2f vectResult = new Vector2f();
2 26 Feb 07 jari 94         if (nAdjNodeSize>0) {   // if no adjacent links
2 26 Feb 07 jari 95             float dblCurX=m_arrPoints[iNode].x;
2 26 Feb 07 jari 96             float dblCurY=m_arrPoints[iNode].y;
2 26 Feb 07 jari 97
2 26 Feb 07 jari 98             Vector2f curVector = new Vector2f();
2 26 Feb 07 jari 99             for (int i=0; i<nAdjNodeSize; i++) {
2 26 Feb 07 jari 100                 Vector2f rCurAdjNode = m_arrPoints[rArrAdjNodes[i].m_iToId];
2 26 Feb 07 jari 101                 float CurWeight=rArrAdjNodes[i].m_Weight;
2 26 Feb 07 jari 102                 curVector.set(rCurAdjNode.x-dblCurX, rCurAdjNode.y-dblCurY);
2 26 Feb 07 jari 103
2 26 Feb 07 jari 104                 float Norm=curVector.length();
2 26 Feb 07 jari 105                 if (Norm<=0)
2 26 Feb 07 jari 106                     continue;
2 26 Feb 07 jari 107                 float Norm2 =Norm*Norm;
2 26 Feb 07 jari 108                 float attractive_factor  = (float)(CalcAttractiveForceFromR2(Norm2));
2 26 Feb 07 jari 109                 curVector.scale(CurWeight*attractive_factor/Norm);
2 26 Feb 07 jari 110                 vectResult.add(curVector);
2 26 Feb 07 jari 111             }
2 26 Feb 07 jari 112         }
2 26 Feb 07 jari 113         return vectResult;
2 26 Feb 07 jari 114     }
2 26 Feb 07 jari 115
2 26 Feb 07 jari 116     private Vector2f CalcRepulsiveForcesAtBruteForce(float dblX, float dblY) {
2 26 Feb 07 jari 117         // Complexity:O(n^2) where n is the number of nodes in the graph
2 26 Feb 07 jari 118         int iSize=m_arrPoints.length;
2 26 Feb 07 jari 119         Vector2f vectResult = new Vector2f();
2 26 Feb 07 jari 120         Vector2f curVector = new Vector2f();
2 26 Feb 07 jari 121         for (int i=0; i<iSize; i++) {
2 26 Feb 07 jari 122             curVector.set(dblX-m_arrPoints[i].x, dblY-m_arrPoints[i].y);
2 26 Feb 07 jari 123             float Norm=curVector.length();
2 26 Feb 07 jari 124             float Norm2=Norm*Norm;
2 26 Feb 07 jari 125             if (Norm2<=0)
2 26 Feb 07 jari 126                 continue;
2 26 Feb 07 jari 127             if (Norm<=0)
2 26 Feb 07 jari 128                 continue;
2 26 Feb 07 jari 129             float repulsive_factor  = (float)(CalcRepulsiveForceFromR2(Norm2));
2 26 Feb 07 jari 130             curVector.scale(repulsive_factor/Norm);
2 26 Feb 07 jari 131             vectResult.add(curVector);
2 26 Feb 07 jari 132         }
2 26 Feb 07 jari 133         return vectResult;
2 26 Feb 07 jari 134     }
2 26 Feb 07 jari 135
2 26 Feb 07 jari 136     protected Vector2f CalcRepulsiveForcesAt(float X, float Y) {
2 26 Feb 07 jari 137         // Complexity:O(n*log2(n), uses QuadTree structure
2 26 Feb 07 jari 138         m_rPt.x=X;
2 26 Feb 07 jari 139         m_rPt.y=Y;
2 26 Feb 07 jari 140         return GetRepulsiveForceFrom(0);
2 26 Feb 07 jari 141     }
2 26 Feb 07 jari 142
2 26 Feb 07 jari 143     protected Vector2f GetRepulsiveForceFrom(int iNode) {
2 26 Feb 07 jari 144         Vector2f ptRes = new Vector2f(0,0);
2 26 Feb 07 jari 145         if (iNode<0)
2 26 Feb 07 jari 146             return ptRes;
2 26 Feb 07 jari 147         QuadTreeT.SNode rQuadTreeNode = m_QTree.m_arrNodes[iNode];  // Current node
2 26 Feb 07 jari 148         if (rQuadTreeNode.m_iPointNumBehind == 0)
2 26 Feb 07 jari 149             return ptRes;
2 26 Feb 07 jari 150         if (rQuadTreeNode.m_iPointNumBehind==1) {
2 26 Feb 07 jari 151             // prepare ptRes
2 26 Feb 07 jari 152             ptRes.x=m_rPt.x-m_arrPoints[rQuadTreeNode.m_arrPointsIds[0]].x;
2 26 Feb 07 jari 153             ptRes.y=m_rPt.y-m_arrPoints[rQuadTreeNode.m_arrPointsIds[0]].y;
2 26 Feb 07 jari 154             float Norm=ptRes.length();
2 26 Feb 07 jari 155             if (Norm<=0)
2 26 Feb 07 jari 156                 return ptRes;
2 26 Feb 07 jari 157             float Norm2=Norm*Norm;
2 26 Feb 07 jari 158             float repulsive_factor  = (float)(CalcRepulsiveForceFromR2(Norm2));
2 26 Feb 07 jari 159             ptRes.scale(repulsive_factor/Norm);
2 26 Feb 07 jari 160             return ptRes;
2 26 Feb 07 jari 161         }
2 26 Feb 07 jari 162         boolean bPtInCurRect = rQuadTreeNode.m_Rect.PtInRect(m_rPt);
2 26 Feb 07 jari 163         boolean bUseAveragePt = false;
2 26 Feb 07 jari 164         boolean bIsLeaf = rQuadTreeNode.IsLeaf();
2 26 Feb 07 jari 165         if (!bPtInCurRect)
2 26 Feb 07 jari 166             bUseAveragePt=rQuadTreeNode.m_Rect.Distance(m_rPt)/Math.max(rQuadTreeNode.m_Rect.Width(), rQuadTreeNode.m_Rect.Height())>=c_dblFDGLAlgoThreshold;    // TODO: may be change to quadratic criteria?
2 26 Feb 07 jari 167         if (!bIsLeaf&&!bUseAveragePt) {   //then definitely go down
2 26 Feb 07 jari 168             int iChild=m_QTree.GetChild(iNode, QuadTreeT.LEFT_UP);
2 26 Feb 07 jari 169             ptRes =GetRepulsiveForceFrom(iChild);
2 26 Feb 07 jari 170             iChild=m_QTree.GetChild(iNode, QuadTreeT.RIGHT_UP);
2 26 Feb 07 jari 171             ptRes.add(GetRepulsiveForceFrom(iChild));
2 26 Feb 07 jari 172             iChild=m_QTree.GetChild(iNode, QuadTreeT.LEFT_DOWN);
2 26 Feb 07 jari 173             ptRes.add(GetRepulsiveForceFrom(iChild));
2 26 Feb 07 jari 174             iChild=m_QTree.GetChild(iNode, QuadTreeT.RIGHT_DOWN);
2 26 Feb 07 jari 175             ptRes.add(GetRepulsiveForceFrom(iChild));
2 26 Feb 07 jari 176             return ptRes;
2 26 Feb 07 jari 177         }
2 26 Feb 07 jari 178         if (bUseAveragePt) {  // the condition to use the average point 
2 26 Feb 07 jari 179             // prepare ptRes
2 26 Feb 07 jari 180             ptRes.x=m_rPt.x-rQuadTreeNode.m_ptAvg.x;
2 26 Feb 07 jari 181             ptRes.y=m_rPt.y-rQuadTreeNode.m_ptAvg.y;
2 26 Feb 07 jari 182             //System.out.println("rQuadTreeNode.m_ptAvg="+rQuadTreeNode.m_ptAvg);
2 26 Feb 07 jari 183
2 26 Feb 07 jari 184             float Norm=ptRes.length();
2 26 Feb 07 jari 185             if (Norm<=0)
2 26 Feb 07 jari 186                 return ptRes;
2 26 Feb 07 jari 187             float Norm2=Norm*Norm;
2 26 Feb 07 jari 188             float repulsive_factor  = (float)(CalcRepulsiveForceFromR2(Norm2));
2 26 Feb 07 jari 189             if (repulsive_factor<=0) {
2 26 Feb 07 jari 190                 ptRes.x=0;
2 26 Feb 07 jari 191                 ptRes.y=0;
2 26 Feb 07 jari 192                 return ptRes;
2 26 Feb 07 jari 193             }
2 26 Feb 07 jari 194             ptRes.scale(repulsive_factor*(float)rQuadTreeNode.m_iPointNumBehind/Norm);
2 26 Feb 07 jari 195             return ptRes;
2 26 Feb 07 jari 196         }
2 26 Feb 07 jari 197         // otherwise, brute force strategy
2 26 Feb 07 jari 198         //ASSERT(bIsLeaf);
2 26 Feb 07 jari 199
2 26 Feb 07 jari 200         Vector2f curVector = new Vector2f();
2 26 Feb 07 jari 201         int iSize=rQuadTreeNode.m_arrPointsIds.length;
2 26 Feb 07 jari 202         for (int i=0; i<iSize; i++) {
2 26 Feb 07 jari 203             curVector.set(m_rPt.x-m_arrPoints[rQuadTreeNode.m_arrPointsIds[i]].x, m_rPt.y-m_arrPoints[rQuadTreeNode.m_arrPointsIds[i]].y);
2 26 Feb 07 jari 204             float Norm=curVector.length();
2 26 Feb 07 jari 205             if (Norm<=0)
2 26 Feb 07 jari 206                 return ptRes;
2 26 Feb 07 jari 207             float Norm2=Norm*Norm;
2 26 Feb 07 jari 208             float repulsive_factor  = (float)(CalcRepulsiveForceFromR2(Norm2));
2 26 Feb 07 jari 209             curVector.scale(repulsive_factor/Norm);
2 26 Feb 07 jari 210             ptRes.add(curVector);
2 26 Feb 07 jari 211         }
2 26 Feb 07 jari 212         return ptRes;
2 26 Feb 07 jari 213     }
2 26 Feb 07 jari 214
2 26 Feb 07 jari 215     public void DoNotMove(int i) {
2 26 Feb 07 jari 216         m_iDoNotMove=i;
2 26 Feb 07 jari 217     }
2 26 Feb 07 jari 218
2 26 Feb 07 jari 219     public void CalculateForceField() {  // Force vector field
2 26 Feb 07 jari 220         int iSize=m_arrPoints.length;
2 26 Feb 07 jari 221         m_arrForceField = new Vector2f[iSize];
2 26 Feb 07 jari 222         m_dblMaxForceLength=0;
2 26 Feb 07 jari 223
2 26 Feb 07 jari 224         // Let's build QuadTree first. This will be used in CalcRepulsiveForcesAt method
2 26 Feb 07 jari 225         m_QTree.Initialize();
2 26 Feb 07 jari 226
2 26 Feb 07 jari 227         for (int i=0; i<iSize; i++) {
2 26 Feb 07 jari 228             m_arrForceField[i]=CalcAttractiveForcesAt(i);
2 26 Feb 07 jari 229             m_arrForceField[i].add(CalcRepulsiveForcesAt(m_arrPoints[i].x, m_arrPoints[i].y)); //BruteForce
2 26 Feb 07 jari 230             float dblCurLength=m_arrForceField[i].length();
2 26 Feb 07 jari 231             if (m_dblMaxForceLength<dblCurLength)   // find also the max length of forces
2 26 Feb 07 jari 232                 m_dblMaxForceLength=dblCurLength;
2 26 Feb 07 jari 233         }
2 26 Feb 07 jari 234     }
2 26 Feb 07 jari 235
2 26 Feb 07 jari 236     public void MoveSystem() {           // Moves system depending on vector field
2 26 Feb 07 jari 237         m_iEnergyIndex++;
2 26 Feb 07 jari 238
2 26 Feb 07 jari 239 //     // Test ob Graph schwingt 
2 26 Feb 07 jari 240 //     if ( (cool_max_force_4 != 0.0) &&
2 26 Feb 07 jari 241 //          (fabs((cool_max_force_1 - cool_max_force_3) / cool_max_force_1) < springembedder_rf_settings.vibration) &&
2 26 Feb 07 jari 242 //          (fabs((cool_max_force_2 - cool_max_force_4) / cool_max_force_2) < springembedder_rf_settings.vibration) )
2 26 Feb 07 jari 243 //     {  cool_phase = 2;
2 26 Feb 07 jari 244 //     }
2 26 Feb 07 jari 245 //     if ( cool_phase == 1 )
2 26 Feb 07 jari 246 //     {  temperature = sqrt( max_force );
2 26 Feb 07 jari 247 //     }
2 26 Feb 07 jari 248 //     else 
2 26 Feb 07 jari 249 //     {  // cool_phase 2 
2 26 Feb 07 jari 250 //        temperature = sqrt( max_force ) / 15;
2 26 Feb 07 jari 251 //     }
2 26 Feb 07 jari 252
2 26 Feb 07 jari 253         if (m_dblMaxForceLength<=0)
2 26 Feb 07 jari 254             return;
2 26 Feb 07 jari 255
2 26 Feb 07 jari 256         float dblFactor=(float)Math.sqrt((Math.sqrt(m_dblMaxForceLength)));   // TODO: do something with dblFActor
2 26 Feb 07 jari 257         if (dblFactor<=0)
2 26 Feb 07 jari 258             return;
2 26 Feb 07 jari 259         int iSize=m_arrPoints.length;
2 26 Feb 07 jari 260
2 26 Feb 07 jari 261         for (int i=0; i<iSize; i++) {
2 26 Feb 07 jari 262             if (i==m_iDoNotMove)
2 26 Feb 07 jari 263                 continue;
2 26 Feb 07 jari 264             float  abs_force = m_arrForceField[i].length();
2 26 Feb 07 jari 265             if (abs_force < dblFactor) {
2 26 Feb 07 jari 266                 m_arrPoints[i].x+=m_arrForceField[i].x; 
2 26 Feb 07 jari 267                 m_arrPoints[i].y+=m_arrForceField[i].y;
2 26 Feb 07 jari 268             } else {
2 26 Feb 07 jari 269                 m_arrPoints[i].x+=m_arrForceField[i].x/abs_force*dblFactor; 
2 26 Feb 07 jari 270                 m_arrPoints[i].y+=m_arrForceField[i].y/abs_force*dblFactor;
2 26 Feb 07 jari 271             }
2 26 Feb 07 jari 272         }
2 26 Feb 07 jari 273         PushEnergy(m_dblMaxForceLength);
2 26 Feb 07 jari 274     }
2 26 Feb 07 jari 275
2 26 Feb 07 jari 276     public void UpdateSource() {
2 26 Feb 07 jari 277         // Update the source coordinates via InterfaceToObjects
2 26 Feb 07 jari 278         // TODO: calc energies here
2 26 Feb 07 jari 279         m_pInterface.SetObjectGeom(m_arrPoints/*, Terrain.createEnergy(m_arrPoints.length)*/);
2 26 Feb 07 jari 280     }
2 26 Feb 07 jari 281
2 26 Feb 07 jari 282     public void InitFromInterface() {
2 26 Feb 07 jari 283         // Initialization(caching) of internal data from the interface to objects
2 26 Feb 07 jari 284         int[] arrObjIds = m_pInterface.GetAllObjectsIds();
2 26 Feb 07 jari 285
2 26 Feb 07 jari 286         int n=arrObjIds.length;
2 26 Feb 07 jari 287         // Alloc memory first
2 26 Feb 07 jari 288         m_arrLinks = new SLink[n][];
2 26 Feb 07 jari 289         m_arrPoints = new Vector2f[n];
2 26 Feb 07 jari 290         for (int i=0; i<m_arrPoints.length; i++)
2 26 Feb 07 jari 291             m_arrPoints[i] = new Vector2f();
2 26 Feb 07 jari 292         //m_arrEnergy.SetSize(n);
2 26 Feb 07 jari 293
2 26 Feb 07 jari 294         Vector2f pdDbl = new Vector2f();
2 26 Feb 07 jari 295         for (int i=0; i<n; i++) {
2 26 Feb 07 jari 296             //m_arrEnergy[i]=0;
2 26 Feb 07 jari 297             m_pInterface.GetObjectGeom(arrObjIds[i], pdDbl);
2 26 Feb 07 jari 298             m_arrPoints[i].x=pdDbl.x;
2 26 Feb 07 jari 299             m_arrPoints[i].y=pdDbl.y;
2 26 Feb 07 jari 300             FloatArray arrWeight = new FloatArray(); 
2 26 Feb 07 jari 301             IntArray arrAdjNodes = new IntArray(); 
2 26 Feb 07 jari 302             m_pInterface.GetAdjInfoFor(arrObjIds[i], arrAdjNodes, arrWeight);
2 26 Feb 07 jari 303             int nAdjNodesCouns=arrAdjNodes.getSize();
2 26 Feb 07 jari 304             m_arrLinks[i] = new SLink[nAdjNodesCouns];
2 26 Feb 07 jari 305             for (int j=0; j<nAdjNodesCouns; j++) {    // fill up adj nodes
2 26 Feb 07 jari 306                 m_arrLinks[i][j] = new SLink();
2 26 Feb 07 jari 307                 m_arrLinks[i][j].m_iToId=arrAdjNodes.get(j);
2 26 Feb 07 jari 308                 m_arrLinks[i][j].m_Weight=arrWeight.get(j);
2 26 Feb 07 jari 309             }
2 26 Feb 07 jari 310         }
2 26 Feb 07 jari 311     }
2 26 Feb 07 jari 312
2 26 Feb 07 jari 313     public QuadTreeT GetQuadTree() {
2 26 Feb 07 jari 314         return m_QTree;
2 26 Feb 07 jari 315     }
2 26 Feb 07 jari 316
2 26 Feb 07 jari 317     public class SLink {
2 26 Feb 07 jari 318         int m_iToId;
2 26 Feb 07 jari 319         float m_Weight;
2 26 Feb 07 jari 320     }
2 26 Feb 07 jari 321 }