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 java.util.Iterator; 035 036import org.graphstream.graph.Node; 037import org.graphstream.stream.SourceBase.ElementType; 038import org.graphstream.ui.graphicGraph.stylesheet.Selector; 039import org.graphstream.ui.graphicGraph.stylesheet.Style; 040import org.graphstream.ui.graphicGraph.stylesheet.StyleConstants; 041import org.graphstream.ui.graphicGraph.stylesheet.Values; 042 043/** 044 * A small gentle sprite. 045 */ 046public class GraphicSprite extends GraphicElement { 047 // Attributes 048 049 /** 050 * The node this sprite is attached to. 051 */ 052 protected GraphicNode node; 053 054 /** 055 * The edge this sprite is attached to. 056 */ 057 protected GraphicEdge edge; 058 059 /** 060 * Sprite position. 061 */ 062 public Values position = new Values(StyleConstants.Units.GU, 0, 0, 0); 063 064 // Constructors 065 066 /** 067 * New sprite. 068 * 069 * @param id 070 * The sprite unique identifier. 071 * @param graph 072 * The graph containing this sprite. 073 */ 074 public GraphicSprite(String id, GraphicGraph graph) { 075 super(id, graph); 076 077 // Get the position of a random node. 078 079 if (graph.getNodeCount() > 0) { 080 Iterator<? extends Node> nodes = graph.getNodeIterator(); 081 082 GraphicNode node = (GraphicNode) nodes.next(); 083 084 position.setValue(0, node.x); 085 position.setValue(1, node.y); 086 position.setValue(2, node.z); 087 } 088 089 String myPrefix = String.format("ui.sprite.%s", id); 090 091 if (mygraph.getAttribute(myPrefix) == null) 092 mygraph.addAttribute(myPrefix, position); 093 } 094 095 // Access 096 097 /** 098 * The node this sprite is attached to or null if not attached to an edge. 099 * 100 * @return A graphic node. 101 */ 102 public GraphicNode getNodeAttachment() { 103 return node; 104 } 105 106 /** 107 * The edge this sprite is attached to or null if not attached to an edge. 108 * 109 * @return A graphic edge. 110 */ 111 public GraphicEdge getEdgeAttachment() { 112 return edge; 113 } 114 115 /** 116 * Return the graphic object this sprite is attached to or null if not 117 * attached. 118 * 119 * @return A graphic object or null if no attachment. 120 */ 121 public GraphicElement getAttachment() { 122 GraphicNode n = getNodeAttachment(); 123 124 if (n != null) 125 return n; 126 127 return getEdgeAttachment(); 128 } 129 130 /** 131 * True if the sprite is attached to a node or edge. 132 */ 133 public boolean isAttached() { 134 return (edge != null || node != null); 135 } 136 137 /** 138 * True if the sprite is attached to a node. 139 */ 140 public boolean isAttachedToNode() { 141 return node != null; 142 } 143 144 /** 145 * True if the node is attached to an edge. 146 */ 147 public boolean isAttachedToEdge() { 148 return edge != null; 149 } 150 151 @Override 152 public Selector.Type getSelectorType() { 153 return Selector.Type.SPRITE; 154 } 155 156 @Override 157 public double getX() { 158 return position.get(0); 159 } 160 161 @Override 162 public double getY() { 163 return position.get(1); 164 } 165 166 @Override 167 public double getZ() { 168 return position.get(2); 169 } 170 171 public Style.Units getUnits() { 172 return position.getUnits(); 173 } 174 175 // Commands 176 177 @Override 178 public void move(double x, double y, double z) { 179 setPosition(x, y, z, Style.Units.GU); 180 } 181 182 /** 183 * Attach this sprite to the given node. 184 * 185 * @param node 186 * A graphic node. 187 */ 188 public void attachToNode(GraphicNode node) { 189 this.edge = null; 190 this.node = node; 191 192 String prefix = String.format("ui.sprite.%s", getId()); 193 194 if (this.node.getAttribute(prefix) == null) 195 this.node.addAttribute(prefix); 196 197 mygraph.graphChanged = true; 198 } 199 200 /** 201 * Attach this sprite to the given edge. 202 * 203 * @param edge 204 * A graphic edge. 205 */ 206 public void attachToEdge(GraphicEdge edge) { 207 this.node = null; 208 this.edge = edge; 209 210 String prefix = String.format("ui.sprite.%s", getId()); 211 212 if (this.edge.getAttribute(prefix) == null) 213 this.edge.addAttribute(prefix); 214 215 mygraph.graphChanged = true; 216 } 217 218 /** 219 * Detach this sprite from the edge or node it was attached to. 220 */ 221 public void detach() { 222 String prefix = String.format("ui.sprite.%s", getId()); 223 224 if (this.node != null) 225 this.node.removeAttribute(prefix); 226 else if (this.edge != null) 227 this.edge.removeAttribute(prefix); 228 229 this.edge = null; 230 this.node = null; 231 mygraph.graphChanged = true; 232 } 233 234 /** 235 * Reposition this sprite. 236 * 237 * @param value 238 * The coordinate. 239 */ 240 public void setPosition(double value) { 241 setPosition(value, 0, 0, getUnits()); 242 } 243 244 /** 245 * Reposition this sprite. 246 * 247 * @param x 248 * First coordinate. 249 * @param y 250 * Second coordinate. 251 * @param z 252 * Third coordinate. 253 * @param units 254 * The units to use for lengths and radii, null means 255 * "unchanged". 256 */ 257 public void setPosition(double x, double y, double z, Style.Units units) { 258 /* 259 * if( node != null ) { y = checkAngle( y ); z = checkAngle( z ); } else 260 */if (edge != null) { 261 if (x < 0) 262 x = 0; 263 else if (x > 1) 264 x = 1; 265 } 266 267 boolean changed = false; 268 269 if (getX() != x) { 270 changed = true; 271 position.setValue(0, x); 272 } 273 if (getY() != y) { 274 changed = true; 275 position.setValue(1, y); 276 } 277 if (getZ() != z) { 278 changed = true; 279 position.setValue(2, z); 280 } 281 if (getUnits() != units) { 282 changed = true; 283 position.setUnits(units); 284 } 285 286 if (changed) { 287 mygraph.graphChanged = true; 288 mygraph.boundsChanged = true; 289 290 String prefix = String.format("ui.sprite.%s", getId()); 291 292 mygraph.setAttribute(prefix, position); 293 } 294 } 295 296 public void setPosition(Values values) { 297 double x = 0; 298 double y = 0; 299 double z = 0; 300 301 if (values.getValueCount() > 0) 302 x = values.get(0); 303 if (values.getValueCount() > 1) 304 y = values.get(1); 305 if (values.getValueCount() > 2) 306 z = values.get(2); 307 308 // System.err.printf( 309 // "setting %s position x=%f y=%f z=%f units=%s (value in=%s)%n", 310 // getId(), x, y, z, values.units, values ); 311 if (x == 1 && y == 1 && z == 1) 312 throw new RuntimeException("WTF !!!"); 313 setPosition(x, y, z, values.units); 314 } 315 316 protected double checkAngle(double angle) { 317 if (angle > Math.PI * 2) 318 angle = angle % (Math.PI * 2); 319 else if (angle < 0) 320 angle = (Math.PI * 2) - (angle % (Math.PI * 2)); 321 322 return angle; 323 } 324 325 @Override 326 protected void attributeChanged(AttributeChangeEvent event, 327 String attribute, Object oldValue, Object newValue) { 328 super.attributeChanged(event, attribute, oldValue, newValue); 329 330 // if( attribute.equals( "ui.clicked" ) ) // Filter the clicks to avoid 331 // loops XXX BAD !!! XXX 332 // return; 333 334 String completeAttr = String.format("ui.sprite.%s.%s", getId(), 335 attribute); 336 // System.err.printf( "GSprite add attribute %s %s (old=%s) (new=%s)%n", 337 // event, attribute, oldValue, newValue ); 338 339 mygraph.listeners.sendAttributeChangedEvent(mygraph.getId(), 340 ElementType.GRAPH, completeAttr, event, oldValue, newValue); 341 } 342 343 @Override 344 protected void removed() { 345 } 346}