All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.graphstream.ui.swing.util.ShapeUtil Maven / Gradle / Ivy

The newest version!
/*
 * This file is part of GraphStream .
 * 
 * GraphStream is a library whose purpose is to handle static or dynamic
 * graph, create them from scratch, file or any source and display them.
 * 
 * This program is free software distributed under the terms of two licenses, the
 * CeCILL-C license that fits European law, and the GNU Lesser General Public
 * License. You can  use, modify and/ or redistribute the software under the terms
 * of the CeCILL-C license as circulated by CEA, CNRS and INRIA at the following
 * URL  or under the terms of the GNU LGPL as published by
 * the Free Software Foundation, either version 3 of the License, or (at your
 * option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see .
 * 
 * The fact that you are presently reading this means that you have had
 * knowledge of the CeCILL-C and LGPL licenses and that you accept their terms.
 */

 /**
  * @author Antoine Dutot 
  * @author Guilhelm Savin 
  * @author Hicham Brahimi 
  */
  
package org.graphstream.ui.swing.util;

import org.graphstream.ui.geom.Point3;
import org.graphstream.ui.graphicGraph.GraphicEdge;
import org.graphstream.ui.graphicGraph.GraphicElement;
import org.graphstream.ui.graphicGraph.GraphicNode;
import org.graphstream.ui.graphicGraph.stylesheet.Style;
import org.graphstream.ui.graphicGraph.stylesheet.StyleConstants.ShapeKind;
import org.graphstream.ui.graphicGraph.stylesheet.StyleConstants.StrokeMode;
import org.graphstream.ui.view.camera.DefaultCamera2D;
import org.graphstream.ui.swing.renderer.AreaSkeleton;
import org.graphstream.ui.swing.renderer.ConnectorSkeleton;
import org.graphstream.ui.swing.renderer.Skeleton;

public class ShapeUtil {
	
	/** Try to evaluate the "radius" of the edge target node shape along the edge. In other words
	  * this method computes the intersection point between the edge and the node shape contour.
	  * The returned length is the length of a line going from the center of the shape toward
	  * the point of intersection between the target node shape contour and the edge.
	  * @param edge The edge (it contains its target node).
	  * @param camera the camera.
	  * @return The radius. */
	public static double evalTargetRadius2D(GraphicEdge edge, DefaultCamera2D camera) {
		ConnectorSkeleton eskel = (ConnectorSkeleton)edge.getAttribute(Skeleton.attributeName);
		if(eskel != null) {
			return evalTargetRadius2D(
	    		edge.to.getStyle(),
	    		(AreaSkeleton)edge.to.getAttribute(Skeleton.attributeName),
	    		new Point3(eskel.from().x, eskel.from().y, eskel.from().z),
	    		new Point3(eskel.to().x, eskel.to().y, eskel.to().z),
	   	 		camera);
		} 
		else {
			throw new RuntimeException("no skeleton on edge ??");
		}
	}
	
	
	/** Try to evaluate the "radius" of the given node considering an edge between points `from` and `to`.
	  * In other words, this method computes the intersection point between the edge and the node
	  * shape contour. The returned length is the length of a line going from the center of the shape
	  * toward the point of intersection between the target node shape contour and the edge.
	  * @param from The origin point of the edge.
	  * @param to The target point of the edge.
	  * @param node The target node shape.
	  * @param the camera.
	  * @return The radius. */
	public static double evalTargetRadius2D(Point3 from, Point3 to, GraphicNode node, DefaultCamera2D camera) {
		return evalTargetRadius2D(node.getStyle(), (AreaSkeleton)node.getAttribute(Skeleton.attributeName),
	            from, null, null, to, camera);
	}
	
	
	/** Try to evaluate the "radius" of the given area skeleton considering an edge between points `p0` and
	  * point `p3` (the edge is considered a straight line). In other words, this method computes the intersection
	  * point between the edge and the area geometry. The returned length of the line going from the center of
	  * the skeleton geometry toward the point of intersection between the skeleton geometry and the edge.
	  * @param style The style of the area skeleton.
	  * @param skeleton The skeleton.
	  * @param p0 The origin point of the edge.
	  * @param p3 the target point of the edge.
	  * @param camera the camera.
	  * @return the radius. */
  	public static double evalTargetRadius2D(Style style, AreaSkeleton skeleton, Point3 p0, Point3 p3, DefaultCamera2D camera) {
  		return evalTargetRadius2D(style, skeleton, p0, null, null, p3, camera);
  	}
  	
  	/** Try to evaluate the "radius" of the given area skeleton considering a cubic curve edge between points `p0` and
	  * point `p3` and curving to control points `p1`  and `p2`. In other words, this method computes the intersection
	  * point between the edge and the area geometry. The returned length of the line going from the center of
	  * the skeleton geometry toward the point of intersection between the skeleton geometry and the edge.
	  * @param edge The edge.
	  * @param p0 The origin point of the edge.
	  * @param p3 the target point of the edge.
	  * @param camera the camera.
	  * @return the radius. */
 	public static double evalTargetRadius2D(GraphicEdge edge, Point3 p0, Point3 p1, Point3 p2, Point3 p3, DefaultCamera2D camera) {
 		return evalTargetRadius2D(edge.to.getStyle(),
 	 			(AreaSkeleton)edge.to.getAttribute(Skeleton.attributeName),
 	 			p0, p1, p2, p3, camera);
 	}
 	
 	/** Try to evaluate the "radius" of the given area skeleton considering a cubic curve edge between points `p0` and
	  * point `p3` and curving to control points `p1`  and `p2`. In other words, this method computes the intersection
	  * point between the edge and the area geometry. The returned length of the line going from the center of
	  * the skeleton geometry toward the point of intersection between the skeleton geometry and the edge.
	  * @param style The style of the area skeleton.
	  * @param skeleton The skeleton.
	  * @param p0 The origin point of the edge.
	  * @param p3 the target point of the edge.
	  * @param camera the camera.
	  * @return the radius. */
 	public static double evalTargetRadius2D(Style style, AreaSkeleton skeleton, Point3 p0, Point3 p1, Point3 p2, Point3 p3, DefaultCamera2D camera) { 
 	  	double w = 0.0;
 	  	double h = 0.0;
 	  	double s = 0f ;
 	  	if(style.getStrokeMode() != StrokeMode.NONE) 
 	  		s = camera.getMetrics().lengthToGu(style.getStrokeWidth());

 	  	if(skeleton != null) {
 	  		w = skeleton.theSize.x;
 	  		h = skeleton.theSize.y;
 	  	}
 	  	else {
 	  		w = camera.getMetrics().lengthToGu(style.getSize(), 0);
 	  		h = w ;
 	  		if(style.getSize().size() > 1)
 	  			h = camera.getMetrics().lengthToGu(style.getSize(), 1);
 	  		
 	  	}
 	  	
 	  	switch (style.getShape()) {
			case CIRCLE:		return evalEllipseRadius2D(p0, p1, p2, p3, w, h, s);
			case DIAMOND:		return evalEllipseRadius2D(p0, p1, p2, p3, w, h, s);
			case CROSS: 		return evalEllipseRadius2D(p0, p1, p2, p3, w, h, s);
			case TRIANGLE: 		return evalEllipseRadius2D(p0, p1, p2, p3, w, h, s);
			case TEXT_CIRCLE:	return evalEllipseRadius2D(p0, p1, p2, p3, w, h, s);
			case TEXT_DIAMOND:	return evalEllipseRadius2D(p0, p1, p2, p3, w, h, s);
			case PIE_CHART:		return evalEllipseRadius2D(p0, p1, p2, p3, w, h, s);
			case BOX:			return evalBoxRadius2D(p0, p1, p2, p3, w/2+s, h/2+s);
			case ROUNDED_BOX:	return evalBoxRadius2D(p0, p1, p2, p3, w/2+s, h/2+s);
			case TEXT_BOX:		return evalBoxRadius2D(p0, p1, p2, p3, w/2+s, h/2+s);
			case JCOMPONENT:	return evalBoxRadius2D(p0, p1, p2, p3, w/2+s, h/2+s);
			default: 			return evalBoxRadius2D(p0, p1, p2, p3, w/2+s, h/2+s) ;
		}
	}
 	
 	/** Compute the length of a (eventually cubic curve) vector along the edge from the ellipse center toward the intersection
  	  * point with the ellipse that match the ellipse radius. If `p1` and `p2` are null, the edge is considered
  	  * a straight line, else a cubic curve.
  	  * @param p0 the origin point of the edge
  	  * @param p1 the first cubic-curve control point or null for straight edge.
  	  * @param p2 the second cubic-curve control point or null for straight edge.
  	  * @param p3 the target point of the edge.
  	  * @param w the width of the ellipse.
  	  * @param h the height of the ellipse.
  	  * @param s the width of the stroke of the ellipse shape.
  	  */
 	public static double evalEllipseRadius2D(Point3 p0, Point3 p1, Point3 p2, Point3 p3, double w, double h, double s) {
 	  	if(w == h)
 	  		return (w / 2 + s) ;	// Welcome simplification for circles ...
 	  	else
 	  		return evalEllipseRadius2D(p0, p1, p2, p3, w/2 + s, h/2 + s);
 	}
 	
 	/** Compute the length of a vector along the edge from the ellipse center that match the
	  * ellipse radius.
	  * @param edge The edge representing the vector.
	  * @param w The ellipse first radius (width/2).
	  * @param h The ellipse second radius (height/2).
	  * @return The length of the radius along the edge vector. */
	public static double evalEllipseRadius2D(Point3 p0, Point3 p1, Point3 p2, Point3 p3, double w, double h) {
 	  	if(w == h) {
 	  		return (w / 2);	// Welcome simplification for circles ...
 	  	} 
 	  	else {
			// Vector of the entering edge.
	
			double dx = 0.0;
			double dy = 0.0;
	
			if(p1 != null && p2 != null) {
				dx = p3.x - p2.x; //( p2.x + ((p1.x-p2.x)/4) )	// Use the line going from the last control-point to target
				dy = p3.y - p2.y ;//( p2.y + ((p1.y-p2.y)/4) )	// center as the entering edge.
			} 
			else {
				dx = p3.x - p0.x;
				dy = p3.y - p0.y;
			}
			
			// The entering edge must be deformed by the ellipse ratio to find the correct angle.
	
			dy *= w / h;
	
			// Find the angle of the entering vector with (1,0).
	
			double d  = Math.sqrt(dx*dx + dy*dy);
			double a  = dx / d;
	
			// Compute the coordinates at which the entering vector and the ellipse cross.
	
			a  = Math.acos(a);
			dx = Math.cos(a) * w;
			dy = Math.sin(a) * h;
	
			// The distance from the ellipse center to the crossing point of the ellipse and
			// vector. Yo !
	
			return Math.sqrt(dx*dx + dy*dy);
 	  	}
	}
	
	/** Compute the length of a vector along the edge from the box center that match the box
	  * "radius".
	  * @param edge The edge representing the vector.
	  * @param w The box first radius (width/2).
	  * @param h The box second radius (height/2).
	  * @return The length of the radius along the edge vector. */
	public static double evalBoxRadius2D(Point3 p0, Point3 p1, Point3 p2, Point3 p3, double w, double h) {
		// Pythagora : Angle at which we compute the intersection with the height or the width.
	
		double da = w / (double)Math.sqrt(w*w + h*h);
		
		if(da < 0)
			da = -da;
		
		// Angle of the incident vector.
		double dx = 0.0;
		double dy = 0.0;

		if(p1 != null && p2 != null) {
			dx = p3.x - p2.x; // ( p2.x + ((p1.x-p2.x)/4) )	// Use the line going from the last control-point to target
			dy = p3.y - p2.y; //( p2.y + ((p1.y-p2.y)/4) )	// center as the entering edge.
		} 
		else {
			dx = p3.x - p0.x;
			dy = p3.y - p0.y;
		}
 
		double d = Math.sqrt(dx*dx + dy*dy);
		double a = dx/d;
		
		if(a < 0) 
			a = -a ;
		
		// Choose the side of the rectangle the incident edge vector crosses.
		
		if(da < a) {
			return (w / a);
		}
		else {
			a = dy/d;
			if(a < 0)
				a = -a;
			return (h / a);
		}
	}
	
	/** Compute if point `p` is inside of the shape of `elt` whose overall size is `w` x `h`. */
	public static boolean isPointIn(GraphicElement elt, Point3 p, double w, double h) {
		if ( elt.getStyle().getShape().kind == ShapeKind.RECTANGULAR) {
			return isPointIn2DBox( p, elt.getX(), elt.getY(), w, h ) ;
		}
		else if ( elt.getStyle().getShape().kind == ShapeKind.ELLIPSOID) {
			return isPointIn2DEllipse( p, elt.getX(), elt.getY(), w, h ) ;
		}
		else {
			return false ;
		}
	}
	
	/** Compute if point `p` is inside of a rectangular shape of overall size `w` x `h`. */
	public static boolean isPointIn2DBox(Point3 p, double x, double y, double w, double h) {
		double w2 = w/2;
		double h2 = h/2;
		return ( p.x > (x-w2) && p.x < (x+w2) && p.y > (y-h2) && p.y < (y+h2) );
	}
	
	/** Compute if point `p` is inside of a ellipsoid shape of overall size `w` x `h`. */
	public static boolean isPointIn2DEllipse(Point3 p, double x, double y, double w, double h) {
		double xx = p.x - x;
		double yy = p.y - y;
		double w2 = w/2;
		double h2 = h/2;
		
		return (((xx*xx)/(w2*w2)) + ((yy*yy)/(h2*h2)) < 1);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy