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

edu.uci.ics.jung.visualization.transform.HyperbolicTransformer Maven / Gradle / Ivy

/*
 * Copyright (c) 2003, The JUNG Authors
 * All rights reserved.
 *
 * This software is open-source under the BSD license; see either "license.txt"
 * or https://github.com/jrtom/jung/blob/master/LICENSE for a description.
 *
 */
package edu.uci.ics.jung.visualization.transform;

import edu.uci.ics.jung.layout.model.Point;
import edu.uci.ics.jung.layout.model.PolarPoint;
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * HyperbolicTransformer wraps a MutableAffineTransformer and modifies the transform and
 * inverseTransform methods so that they create a fisheye projection of the graph points, with
 * points near the center spread out and points near the edges collapsed onto the circumference of
 * an ellipse.
 *
 * 

HyperbolicTransformer is not an affine transform, but it uses an affine transform to cause * translation, scaling, rotation, and shearing while applying a non-affine hyperbolic filter in its * transform and inverseTransform methods. * * @author Tom Nelson */ public class HyperbolicTransformer extends LensTransformer implements MutableTransformer { private static final Logger log = LoggerFactory.getLogger(HyperbolicTransformer.class); /** * Create an instance, setting values from the passed component and registering to listen for * layoutSize changes on the component. * * @param d the size used for the lens */ public HyperbolicTransformer(Dimension d) { this(d, new MutableAffineTransformer()); } /** * create an instance, setting values from the passed component and registering to listen for * layoutSize changes on the component * * @param d the size used for the lens */ public HyperbolicTransformer(Dimension d, MutableTransformer delegate) { super(d, delegate); } /** * Create an instance with a possibly shared transform. * * @param lens a lens created elsewhere, but on the same component */ public HyperbolicTransformer(Lens lens, MutableTransformer delegate) { super(lens, delegate); } /** override base class transform to project the fisheye effect */ public Point2D transform(Point2D graphPoint) { if (graphPoint == null) { return null; } Ellipse2D lensEllipse = (Ellipse2D) lens.getLensShape(); if (lensEllipse.contains(graphPoint)) { log.trace("lens {} contains graphPoint{}", lensEllipse, graphPoint); } else { log.trace("lens {} does not contain graphPoint {}", lensEllipse, graphPoint); } Point2D viewCenter = lens.getCenter(); double viewRadius = lens.getRadius(); double ratio = lens.getRatio(); // transform the point from the graph to the view Point2D viewPoint = delegate.transform(graphPoint); if (lensEllipse.contains(viewPoint)) { log.trace("lens {} contains viewPoint {}", lensEllipse, viewPoint); } else { log.trace("lens {} does not contain viewPoint {}", lensEllipse, viewPoint); } // calculate point from center double dx = viewPoint.getX() - viewCenter.getX(); double dy = viewPoint.getY() - viewCenter.getY(); // factor out ellipse dx *= ratio; Point pointFromCenter = Point.of(dx, dy); PolarPoint polar = PolarPoint.cartesianToPolar(pointFromCenter); double theta = polar.theta; double radius = polar.radius; if (radius > viewRadius) { log.trace("outside point radius {} > viewRadius {}", radius, viewRadius); return viewPoint; } else { log.trace("inside point radius {} >= viewRadius {}", radius, viewRadius); } double mag = Math.tan(Math.PI / 2 * lens.getMagnification()); radius *= mag; radius = Math.min(radius, viewRadius); radius /= viewRadius; radius *= Math.PI / 2; radius = Math.abs(Math.atan(radius)); radius *= viewRadius; Point projectedPoint = PolarPoint.polarToCartesian(theta, radius); projectedPoint = Point.of(projectedPoint.x / ratio, projectedPoint.y); Point2D translatedBack = new Point2D.Double( projectedPoint.x + viewCenter.getX(), projectedPoint.y + viewCenter.getY()); return translatedBack; } /** override base class to un-project the fisheye effect */ public Point2D inverseTransform(Point2D viewPoint) { Ellipse2D lensEllipse = (Ellipse2D) lens.getLensShape(); if (lensEllipse.contains(viewPoint)) { log.trace("lens {} contains viewPoint{}", lensEllipse, viewPoint); } else { log.trace("lens {} does not contain viewPoint {}", lensEllipse, viewPoint); } Point2D viewCenter = lens.getCenter(); double viewRadius = lens.getRadius(); double ratio = lens.getRatio(); double dx = viewPoint.getX() - viewCenter.getX(); double dy = viewPoint.getY() - viewCenter.getY(); // factor out ellipse dx *= ratio; Point pointFromCenter = Point.of(dx, dy); PolarPoint polar = PolarPoint.cartesianToPolar(pointFromCenter); double radius = polar.radius; if (radius > viewRadius) { log.trace("outside point radius {} > viewRadius {}", radius, viewRadius); } else { log.trace("inside point radius {} <= viewRadius {}", radius, viewRadius); } if (radius > viewRadius) { return delegate.inverseTransform(viewPoint); } radius /= viewRadius; radius = Math.abs(Math.tan(radius)); radius /= Math.PI / 2; radius *= viewRadius; double mag = Math.tan(Math.PI / 2 * lens.getMagnification()); radius /= mag; polar = polar.newRadius(radius); Point projectedPoint = PolarPoint.polarToCartesian(polar); projectedPoint = Point.of(projectedPoint.x / ratio, projectedPoint.y); Point2D translatedBack = new Point2D.Double( projectedPoint.x + viewCenter.getX(), projectedPoint.y + viewCenter.getY()); return delegate.inverseTransform(translatedBack); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy