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}