001/* 002 * Copyright 2006 - 2013 003 * Stefan Balev <stefan.balev@graphstream-project.org> 004 * Julien Baudry <julien.baudry@graphstream-project.org> 005 * Antoine Dutot <antoine.dutot@graphstream-project.org> 006 * Yoann Pigné <yoann.pigne@graphstream-project.org> 007 * Guilhelm Savin <guilhelm.savin@graphstream-project.org> 008 * 009 * This file is part of GraphStream <http://graphstream-project.org>. 010 * 011 * GraphStream is a library whose purpose is to handle static or dynamic 012 * graph, create them from scratch, file or any source and display them. 013 * 014 * This program is free software distributed under the terms of two licenses, the 015 * CeCILL-C license that fits European law, and the GNU Lesser General Public 016 * License. You can use, modify and/ or redistribute the software under the terms 017 * of the CeCILL-C license as circulated by CEA, CNRS and INRIA at the following 018 * URL <http://www.cecill.info> or under the terms of the GNU LGPL as published by 019 * the Free Software Foundation, either version 3 of the License, or (at your 020 * option) any later version. 021 * 022 * This program is distributed in the hope that it will be useful, but WITHOUT ANY 023 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 024 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. 025 * 026 * You should have received a copy of the GNU Lesser General Public License 027 * along with this program. If not, see <http://www.gnu.org/licenses/>. 028 * 029 * The fact that you are presently reading this means that you have had 030 * knowledge of the CeCILL-C and LGPL licenses and that you accept their terms. 031 */ 032package org.graphstream.ui.layout.springbox.implementations; 033 034import java.util.Iterator; 035 036import org.graphstream.ui.geom.Vector3; 037import org.graphstream.ui.layout.springbox.EdgeSpring; 038import org.graphstream.ui.layout.springbox.Energies; 039import org.graphstream.ui.layout.springbox.GraphCellData; 040import org.graphstream.ui.layout.springbox.NodeParticle; 041import org.miv.pherd.Particle; 042import org.miv.pherd.ParticleBox; 043import org.miv.pherd.ntree.Cell; 044 045public class LinLogNodeParticle extends NodeParticle { 046 /** 047 * New node. 048 * 049 * The node is placed at random in the space of the simulation. 050 * 051 * @param box 052 * The spring box. 053 * @param id 054 * The node identifier. 055 */ 056 public LinLogNodeParticle(LinLog box, String id) { 057 this(box, id, (box.getRandom().nextDouble() * 2 * box.k) - box.k, (box 058 .getRandom().nextDouble() * 2 * box.k) - box.k, 059 box.is3D() ? (box.getRandom().nextDouble() * 2 * box.k) - box.k 060 : 0); 061 062 this.box = box; 063 } 064 065 /** 066 * New node at a given position. 067 * 068 * @param box 069 * The spring box. 070 * @param id 071 * The node identifier. 072 * @param x 073 * The abscissa. 074 * @param y 075 * The ordinate. 076 * @param z 077 * The depth. 078 */ 079 public LinLogNodeParticle(LinLog box, String id, double x, double y, 080 double z) { 081 super(box, id, x, y, z); 082 } 083 084 @Override 085 protected void repulsionN2(Vector3 delta) { 086 LinLog box = (LinLog) this.box; 087 boolean is3D = box.is3D(); 088 ParticleBox nodes = box.getSpatialIndex(); 089 Energies energies = box.getEnergies(); 090 Iterator<Object> i = nodes.getParticleIdIterator(); 091 int deg = neighbours.size(); 092 093 while (i.hasNext()) { 094 LinLogNodeParticle node = (LinLogNodeParticle) nodes 095 .getParticle(i.next()); 096 097 if (node != this) { 098 delta.set(node.pos.x - pos.x, node.pos.y - pos.y, 099 is3D ? node.pos.z - pos.z : 0); 100 101// double len = delta.normalize(); 102 double len = delta.length(); 103 104 if(len > 0) { 105 double degFactor = box.edgeBased ? deg * node.neighbours.size() : 1; 106 double factor = 1; 107 double r = box.r; 108 109 factor = -degFactor * (Math.pow(len, r-2)) * node.weight * weight * box.rFactor; 110 111 if(factor < -box.maxR) { factor = -box.maxR; } 112 113 energies.accumulateEnergy(factor); // TODO check this 114 delta.scalarMult(factor); 115 disp.add(delta); 116 repE += factor; 117 } 118 } 119 } 120 } 121 122 @Override 123 protected void repulsionNLogN(Vector3 delta) { 124 // Explore the n-tree from the root cell and consider the contents 125 // of one cell only if it does intersect an area around the current 126 // node. Else take its (weighted) barycenter into account. 127 128 recurseRepulsion(box.getSpatialIndex().getNTree().getRootCell(), delta); 129 } 130 131 protected void recurseRepulsion(Cell cell, Vector3 delta) { 132 LinLog box = (LinLog) this.box; 133 boolean is3D = box.is3D(); 134 Energies energies = box.getEnergies(); 135 int deg = neighbours.size(); 136 137 if (intersection(cell)) { 138 if (cell.isLeaf()) { 139 Iterator<? extends Particle> i = cell.getParticles(); 140 141 while (i.hasNext()) { 142 LinLogNodeParticle node = (LinLogNodeParticle) i.next(); 143 144 if (node != this) { 145 delta.set(node.pos.x - pos.x, node.pos.y - pos.y, is3D ? node.pos.z 146 - pos.z : 0); 147 148 //double len = delta.normalize(); 149 double len = delta.length(); 150 151 if (len > 0) { 152 double degFactor = box.edgeBased ? deg * node.neighbours.size() : 1; 153 double factor = 1; 154 double r = box.r; 155 156 factor = -degFactor * (Math.pow(len, r-2)) * node.weight * weight * box.rFactor; 157 158 if(factor < -box.maxR) { factor = -box.maxR; } 159 160 energies.accumulateEnergy(factor); // TODO check this 161 delta.scalarMult(factor); 162 disp.add(delta); 163 repE += factor; 164 } 165 } 166 } 167 } else { 168 int div = cell.getSpace().getDivisions(); 169 170 for (int i = 0; i < div; i++) 171 recurseRepulsion(cell.getSub(i), delta); 172 } 173 } else { 174 if (cell != this.cell) { 175 GraphCellData bary = (GraphCellData) cell.getData(); 176 double dist = bary.distanceFrom(pos); 177 double size = cell.getSpace().getSize(); 178 179 if ((!cell.isLeaf()) 180 && ((size / dist) > box.getBarnesHutTheta())) { 181 int div = cell.getSpace().getDivisions(); 182 183 for (int i = 0; i < div; i++) 184 recurseRepulsion(cell.getSub(i), delta); 185 } else { 186 if (bary.weight != 0) { 187 delta.set(bary.center.x - pos.x, bary.center.y - pos.y, 188 is3D ? bary.center.z - pos.z : 0); 189 190 //double len = delta.normalize(); 191 double len = delta.length(); 192 193 if (len > 0) { 194 double degFactor = box.edgeBased ? deg * bary.degree : 1; 195 double factor = 1; 196 double r = box.r; 197 198 factor = -degFactor * (Math.pow(len, r-2)) * bary.weight * weight * box.rFactor; 199 200 if(factor < -box.maxR) { factor = -box.maxR; } 201 202 energies.accumulateEnergy(factor); // TODO check this 203 delta.scalarMult(factor); 204 disp.add(delta); 205 repE += factor; 206 } 207 } 208 } 209 } 210 } 211 } 212 213 @Override 214 protected void attraction(Vector3 delta) { 215 LinLog box = (LinLog) this.box; 216 boolean is3D = box.is3D(); 217 Energies energies = box.getEnergies(); 218 219 for (EdgeSpring edge : neighbours) { 220 if (!edge.ignored) { 221 LinLogNodeParticle other = (LinLogNodeParticle) edge.getOpposite(this); 222 223 delta.set(other.pos.x - pos.x, other.pos.y - pos.y, is3D ? other.pos.z - pos.z : 0); 224 225// double len = delta.normalize(); 226 double len = delta.length(); 227 228 if(len > 0) { 229 double factor = 1; 230 double a = box.a; 231 232 factor = (Math.pow(len, a-2)) * edge.weight * box.aFactor; 233 234 energies.accumulateEnergy(factor); 235 delta.scalarMult(factor); 236 disp.add(delta); 237 attE += factor; 238 } 239 } 240 } 241 } 242 243 @Override 244 protected void gravity(Vector3 delta) { 245 } 246 247 protected boolean intersection(Cell cell) { 248 LinLog box = (LinLog) this.box; 249 250 double k = box.k; 251 double vz = box.getViewZone(); 252 253 double x1 = cell.getSpace().getLoAnchor().x; 254 double y1 = cell.getSpace().getLoAnchor().y; 255 double z1 = cell.getSpace().getLoAnchor().z; 256 257 double x2 = cell.getSpace().getHiAnchor().x; 258 double y2 = cell.getSpace().getHiAnchor().y; 259 double z2 = cell.getSpace().getHiAnchor().z; 260 261 double X1 = pos.x - (k * vz); 262 double Y1 = pos.y - (k * vz); 263 double Z1 = pos.z - (k * vz); 264 double X2 = pos.x + (k * vz); 265 double Y2 = pos.y + (k * vz); 266 double Z2 = pos.z + (k * vz); 267 268 if (X2 < x1 || X1 > x2) 269 return false; 270 271 if (Y2 < y1 || Y1 > y2) 272 return false; 273 274 if (Z2 < z1 || Z1 > z2) 275 return false; 276 277 return true; 278 } 279}