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.graphicGraph; 033 034import org.graphstream.graph.Edge; 035import org.graphstream.graph.Graph; 036import org.graphstream.graph.Node; 037import org.graphstream.ui.geom.Point2; 038import org.graphstream.ui.geom.Point3; 039import org.graphstream.ui.geom.Vector2; 040import org.graphstream.ui.geom.Vector3; 041 042/** 043 * Lots of small often used measuring algorithms on graphs. 044 * 045 * <p> 046 * Use this class with a static import. 047 * </p> 048 */ 049public class GraphPosLengthUtils { 050 /** 051 * Retrieve a node position from its attributes ("x", "y", "z", or "xy", or 052 * "xyz"). 053 * 054 * @param id 055 * The node identifier. 056 * @return A newly allocated array of three floats containing the (x,y,z) 057 * position of the node, or null if the node is not part of the 058 * graph. 059 */ 060 public static double[] nodePosition(Graph graph, String id) { 061 Node node = graph.getNode(id); 062 063 if (node != null) 064 return nodePosition(node); 065 066 return null; 067 } 068 069 /** 070 * Retrieve a node position from its attributes ("x", "y", "z", or "xy", or 071 * "xyz"). 072 * 073 * @param id 074 * The node identifier. 075 * @return A newly allocated point containing the (x,y,z) 076 * position of the node, or null if the node is not part of the 077 * graph. 078 */ 079 public static Point3 nodePointPosition(Graph graph, String id) { 080 Node node = graph.getNode(id); 081 082 if (node != null) 083 return nodePointPosition(node); 084 085 return null; 086 } 087 088 /** 089 * Like {@link #nodePosition(Graph,String)} but use an existing node as 090 * argument. 091 * 092 * @param node 093 * The node to consider. 094 * @return A newly allocated array of three floats containing the (x,y,z) 095 * position of the node. 096 */ 097 public static double[] nodePosition(Node node) { 098 double xyz[] = new double[3]; 099 100 nodePosition(node, xyz); 101 102 return xyz; 103 } 104 105 /** 106 * Like {@link #nodePointPosition(Graph,String)} but use an existing node as 107 * argument. 108 * 109 * @param node 110 * The node to consider. 111 * @return A newly allocated point containing the (x,y,z) 112 * position of the node. 113 */ 114 public static Point3 nodePointPosition(Node node) { 115 Point3 pos = new Point3(); 116 117 nodePosition(node, pos); 118 119 return pos; 120 } 121 122 /** 123 * Like {@link #nodePosition(Graph,String)}, but instead of returning a 124 * newly allocated array, fill up the array given as parameter. This array 125 * must have at least three cells. 126 * 127 * @param id 128 * The node identifier. 129 * @param xyz 130 * An array of at least three cells. 131 * @throws RuntimeException 132 * If the node with the given identifier does not exist. 133 */ 134 public static void nodePosition(Graph graph, String id, double xyz[]) { 135 Node node = graph.getNode(id); 136 137 if (node != null) 138 nodePosition(node, xyz); 139 140 throw new RuntimeException("node '" + id + "' does not exist"); 141 } 142 143 /** 144 * Like {@link #nodePointPosition(Graph,String)}, but instead of returning a 145 * newly allocated array, fill up the array given as parameter. This array 146 * must have at least three cells. 147 * 148 * @param id 149 * The node identifier. 150 * @param pos 151 * A point that will receive the node position. 152 * @throws RuntimeException 153 * If the node with the given identifier does not exist. 154 */ 155 public static void nodePosition(Graph graph, String id, Point3 pos) { 156 Node node = graph.getNode(id); 157 158 if (node != null) 159 nodePosition(node, pos); 160 161 throw new RuntimeException("node '" + id + "' does not exist"); 162 } 163 164 /** 165 * Like {@link #nodePosition(Graph,String,double[])} but use an existing node 166 * as argument. 167 * 168 * @param node 169 * The node to consider. 170 * @param xyz 171 * An array of at least three cells. 172 */ 173 public static void nodePosition(Node node, double xyz[]) { 174 if (xyz.length < 3) 175 return; 176 177 if (node.hasAttribute("xyz") || node.hasAttribute("xy")) { 178 Object o = node.getAttribute("xyz"); 179 180 if (o == null) 181 o = node.getAttribute("xy"); 182 183 if (o != null) { 184 positionFromObject(o, xyz); 185 } 186 187 } else if (node.hasAttribute("x")) { 188 xyz[0] = (double) node.getNumber("x"); 189 190 if (node.hasAttribute("y")) 191 xyz[1] = (double) node.getNumber("y"); 192 193 if (node.hasAttribute("z")) 194 xyz[2] = (double) node.getNumber("z"); 195 } 196 } 197 198 /** 199 * Like {@link #nodePosition(Graph,String,Point3)} but use an existing node 200 * as argument. 201 * 202 * @param node 203 * The node to consider. 204 * @param pos 205 * A point that will receive the node position. 206 */ 207 public static void nodePosition(Node node, Point3 pos) { 208 if (node.hasAttribute("xyz") || node.hasAttribute("xy")) { 209 Object o = node.getAttribute("xyz"); 210 211 if (o == null) 212 o = node.getAttribute("xy"); 213 214 if (o != null) { 215 positionFromObject(o, pos); 216 } 217 } else if (node.hasAttribute("x")) { 218 pos.x = (double) node.getNumber("x"); 219 220 if (node.hasAttribute("y")) 221 pos.y = (double) node.getNumber("y"); 222 223 if (node.hasAttribute("z")) 224 pos.z = (double) node.getNumber("z"); 225 } 226 227// if (node.hasAttribute("xyz") || node.hasAttribute("xy")) { 228// Object o = node.getAttribute("xyz"); 229// 230// if (o == null) 231// o = node.getAttribute("xy"); 232// 233// if (o != null && o instanceof Object[]) { 234// Object oo[] = (Object[]) o; 235// 236// if (oo.length > 0 && oo[0] instanceof Number) { 237// pos.x = ((Number) oo[0]).doubleValue(); 238// 239// if (oo.length > 1) 240// pos.y = ((Number) oo[1]).doubleValue(); 241// if (oo.length > 2) 242// pos.z = ((Number) oo[2]).doubleValue(); 243// } 244// } 245// } else if (node.hasAttribute("x")) { 246// pos.x = (double) node.getNumber("x"); 247// 248// if (node.hasAttribute("y")) 249// pos.y = (double) node.getNumber("y"); 250// 251// if (node.hasAttribute("z")) 252// pos.z = (double) node.getNumber("z"); 253// } 254 } 255 256 /** 257 * Try to convert an object to a position. The object can be an array of 258 * numbers, an array of base numeric types or their object counterparts. 259 * @param o The object to try to convert. 260 * @param xyz The result. 261 */ 262 public static void positionFromObject(Object o, double xyz[]) { 263 if(o instanceof Object[]) { 264 Object oo[] = (Object[]) o; 265 266 if (oo.length > 0 && oo[0] instanceof Number) { 267 xyz[0] = ((Number) oo[0]).doubleValue(); 268 if (oo.length > 1) xyz[1] = ((Number) oo[1]).doubleValue(); 269 if (oo.length > 2) xyz[2] = ((Number) oo[2]).doubleValue(); 270 } 271 } else if(o instanceof Double[]) { 272 Double oo[] = (Double[]) o; 273 if(oo.length > 0) xyz[0] = oo[0]; 274 if(oo.length > 1) xyz[1] = oo[1]; 275 if(oo.length > 2) xyz[2] = oo[2]; 276 } else if(o instanceof Float[]) { 277 Float oo[] = (Float[]) o; 278 if(oo.length > 0) xyz[0] = oo[0]; 279 if(oo.length > 1) xyz[1] = oo[1]; 280 if(oo.length > 2) xyz[2] = oo[2]; 281 } else if(o instanceof Integer[]) { 282 Integer oo[] = (Integer[]) o; 283 if(oo.length > 0) xyz[0] = oo[0]; 284 if(oo.length > 1) xyz[1] = oo[1]; 285 if(oo.length > 2) xyz[2] = oo[2]; 286 } else if(o instanceof double[]) { 287 double oo[] = (double[]) o; 288 if(oo.length > 0) xyz[0] = oo[0]; 289 if(oo.length > 1) xyz[1] = oo[1]; 290 if(oo.length > 2) xyz[2] = oo[2]; 291 } else if(o instanceof float[]) { 292 float oo[] = (float[]) o; 293 if(oo.length > 0) xyz[0] = oo[0]; 294 if(oo.length > 1) xyz[1] = oo[1]; 295 if(oo.length > 2) xyz[2] = oo[2]; 296 } else if(o instanceof int[]) { 297 int oo[] = (int[]) o; 298 if(oo.length > 0) xyz[0] = oo[0]; 299 if(oo.length > 1) xyz[1] = oo[1]; 300 if(oo.length > 2) xyz[2] = oo[2]; 301 } else if(o instanceof Number[]) { 302 Number oo[] = (Number[]) o; 303 if(oo.length > 0) xyz[0] = oo[0].doubleValue(); 304 if(oo.length > 1) xyz[1] = oo[1].doubleValue(); 305 if(oo.length > 2) xyz[2] = oo[2].doubleValue(); 306 } else if(o instanceof Point3) { 307 Point3 oo = (Point3) o; 308 xyz[0] = oo.x; 309 xyz[1] = oo.y; 310 xyz[2] = oo.z; 311 } else if(o instanceof Vector3) { 312 Vector3 oo = (Vector3) o; 313 xyz[0] = oo.data[0]; 314 xyz[1] = oo.data[1]; 315 xyz[2] = oo.data[2]; 316 } else if(o instanceof Point2) { 317 Point2 oo = (Point2) o; 318 xyz[0] = oo.x; 319 xyz[1] = oo.y; 320 xyz[2] = 0; 321 } else if(o instanceof Vector2) { 322 Vector2 oo = (Vector2) o; 323 xyz[0] = oo.data[0]; 324 xyz[1] = oo.data[1]; 325 xyz[2] = 0; 326 } else { 327 System.err.printf("Do not know how to handle xyz attribute %s%n", o.getClass().getName()); 328 } 329 } 330 331 /** 332 * Try to convert an object to a position. The object can be an array of 333 * numbers, an array of base numeric types or their object counterparts. 334 * @param o The object to try to convert. 335 * @param pos The result. 336 */ 337 public static void positionFromObject(Object o, Point3 pos) { 338 if(o instanceof Object[]) { 339 Object oo[] = (Object[]) o; 340 341 if (oo.length > 0 && oo[0] instanceof Number) { 342 pos.x = ((Number) oo[0]).doubleValue(); 343 if (oo.length > 1) pos.y = ((Number) oo[1]).doubleValue(); 344 if (oo.length > 2) pos.z = ((Number) oo[2]).doubleValue(); 345 } 346 } else if(o instanceof Double[]) { 347 Double oo[] = (Double[]) o; 348 if(oo.length > 0) pos.x = oo[0]; 349 if(oo.length > 1) pos.y = oo[1]; 350 if(oo.length > 2) pos.z = oo[2]; 351 } else if(o instanceof Float[]) { 352 Float oo[] = (Float[]) o; 353 if(oo.length > 0) pos.x = oo[0]; 354 if(oo.length > 1) pos.y = oo[1]; 355 if(oo.length > 2) pos.z = oo[2]; 356 } else if(o instanceof Integer[]) { 357 Integer oo[] = (Integer[]) o; 358 if(oo.length > 0) pos.x = oo[0]; 359 if(oo.length > 1) pos.y = oo[1]; 360 if(oo.length > 2) pos.z = oo[2]; 361 } else if(o instanceof double[]) { 362 double oo[] = (double[]) o; 363 if(oo.length > 0) pos.x = oo[0]; 364 if(oo.length > 1) pos.y = oo[1]; 365 if(oo.length > 2) pos.z = oo[2]; 366 } else if(o instanceof float[]) { 367 float oo[] = (float[]) o; 368 if(oo.length > 0) pos.x = oo[0]; 369 if(oo.length > 1) pos.y = oo[1]; 370 if(oo.length > 2) pos.z = oo[2]; 371 } else if(o instanceof int[]) { 372 int oo[] = (int[]) o; 373 if(oo.length > 0) pos.x = oo[0]; 374 if(oo.length > 1) pos.y = oo[1]; 375 if(oo.length > 2) pos.z = oo[2]; 376 } else if(o instanceof Number[]) { 377 Number oo[] = (Number[]) o; 378 if(oo.length > 0) pos.x = oo[0].doubleValue(); 379 if(oo.length > 1) pos.y = oo[1].doubleValue(); 380 if(oo.length > 2) pos.z = oo[2].doubleValue(); 381 } else if(o instanceof Point3) { 382 Point3 oo = (Point3) o; 383 pos.x = oo.x; 384 pos.y = oo.y; 385 pos.z = oo.z; 386 } else if(o instanceof Vector3) { 387 Vector3 oo = (Vector3) o; 388 pos.x = oo.data[0]; 389 pos.y = oo.data[1]; 390 pos.z = oo.data[2]; 391 } else if(o instanceof Point2) { 392 Point2 oo = (Point2) o; 393 pos.x = oo.x; 394 pos.y = oo.y; 395 pos.z = 0; 396 } else if(o instanceof Vector2) { 397 Vector2 oo = (Vector2) o; 398 pos.x = oo.data[0]; 399 pos.y = oo.data[1]; 400 pos.z = 0; 401 } else { 402 System.err.printf("Do not know how to handle xyz attribute %s%n", o.getClass().getName()); 403 } 404 } 405 406 /** 407 * Compute the edge length of the given edge according to its two nodes 408 * positions. 409 * 410 * @param id 411 * The identifier of the edge. 412 * @return The edge length or -1 if the nodes of the edge have no positions. 413 * @throws RuntimeException 414 * If the edge cannot be found. 415 */ 416 public static double edgeLength(Graph graph, String id) { 417 Edge edge = graph.getEdge(id); 418 419 if (edge != null) 420 return edgeLength(edge); 421 422 throw new RuntimeException("edge '" + id + "' cannot be found"); 423 } 424 425 /** 426 * Like {@link #edgeLength(Graph,String)} but use an existing edge as 427 * argument. 428 * 429 * @param edge 430 * @return The edge length or -1 if the nodes of the edge have no positions. 431 */ 432 public static double edgeLength(Edge edge) { 433 double xyz0[] = nodePosition(edge.getNode0()); 434 double xyz1[] = nodePosition(edge.getNode1()); 435 436 if (xyz0 == null || xyz1 == null) 437 return -1; 438 439 xyz0[0] = xyz1[0] - xyz0[0]; 440 xyz0[1] = xyz1[1] - xyz0[1]; 441 xyz0[2] = xyz1[2] - xyz0[2]; 442 443 return Math.sqrt(xyz0[0] * xyz0[0] + xyz0[1] * xyz0[1] 444 + xyz0[2] * xyz0[2]); 445 } 446}