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

org.graphstream.ui.j2dviewer.Backend.scala Maven / Gradle / Ivy

package org.graphstream.ui.j2dviewer

import java.awt.RenderingHints
import java.awt.geom.Point2D
import java.awt.geom.AffineTransform
import scala.collection.mutable.ArrayStack
import java.awt.Graphics2D
import org.graphstream.ui.sgeom.Point3
import org.graphstream.ui.j2dviewer.renderer.GraphBackgroundRenderer
import org.graphstream.ui.j2dviewer.renderer.shape.Shape
import org.graphstream.ui.graphicGraph.StyleGroup

/**
 * The graphic driver.
 * 
 * The back-end can be for example Java2D or OpenGL.
 */
abstract class Backend {
	// TODO, one day.
    // The goal is to replace the use of Java2D by the back-end
    // Then to produce a new back-end using OpenGL to accelerate
    // thinks, since Java is a big Mammoth that will never follow
    // actual technologies (on Linux, I doubt it will ever get
    // real good Java2D implementation).
    
    /** Setup the backend for a new rendering session. */
    def prepareNewFrame(g2:Graphics2D)
    
    /**
     * Transform a point in graph units into pixel units.
     * @return the transformed point.
     */
    def transform(x:Double, y:Double, z:Double):Point3
    
    /**
     * Pass a point in transformed coordinates (pixels) into the reverse transform (into
     * graph units).
     * @return the transformed point.
     */
    def inverseTransform(x:Double, y:Double, z:Double):Point3
    
    /** 
     * Transform a point in graph units into pixel units, the given point is transformed in place
     * and also returned. 
     */
    def transform(p:Point3):Point3
    
    /**
     * Transform a point in pixel units into graph units, the given point is transformed in
     * place and also returned.
     */
    def inverseTransform(p:Point3):Point3
    
    /**
     * Push the actual transformation on the matrix stack, installing
     * a copy of it on the top of the stack.
     */
    def pushTransform()
 
    /**
     * Begin the work on the actual transformation matrix.
     */
    def beginTransform

    /**
     * Make the top-most matrix as an identity matrix.
     */
    def setIdentity()
    
    /**
     * Multiply the to-most matrix by a translation matrix.
     */
    def translate(tx:Double, ty:Double, tz:Double)
    
    /**
     * Multiply the top-most matrix by a rotation matrix.
     */
    def rotate(angle:Double, ax:Double, ay:Double, az:Double)
    
    /**
     * Multiply the top-most matrix by a scaling matrix.
     */
    def scale(sx:Double, sy:Double, sz:Double)
    
    /**
     * End the work on the actual transformation matrix, installing it as the actual modelview
     * matrix. If you do not call this method, all the scaling, translation and rotation are
     * lost.
     */
    def endTransform
    
    /**
     * Pop the actual transformation of the matrix stack, restoring
     * the previous one in the stack.
     */
    def popTransform()

    /**
     * Enable or disable anti-aliasing.
     */
    def setAntialias(on:Boolean)
    
    /**
     * Enable or disable the hi-quality mode.
     */
    def setQuality(on:Boolean)

    /**
     * The Java2D graphics.
     */
    def graphics2D:Graphics2D
    
    def chooseNodeShape(oldShape:Shape, group:StyleGroup):Shape
    def chooseEdgeShape(oldShape:Shape, group:StyleGroup):Shape
    def chooseEdgeArrowShape(oldShape:Shape, group:StyleGroup):Shape
    def chooseSpriteShape(oldShape:Shape, group:StyleGroup):Shape
    def chooseGraphBackgroundRenderer():GraphBackgroundRenderer
}

/**
 * A full Java-2D rendering back-end.
 */
class BackendJ2D extends Backend {
	protected var g2:Graphics2D = null
    
    protected val matrixStack = new ArrayStack[AffineTransform]()
    
    protected var Tx:AffineTransform = null
    
    protected var xT:AffineTransform = null
    
    protected val dummyPoint = new Point2D.Double()
    
	def graphics2D:Graphics2D = g2
	
    override def prepareNewFrame(g2:Graphics2D) {
	    this.g2 = g2
        Tx = g2.getTransform
        matrixStack.clear
        matrixStack.push(Tx)
    }

	def beginTransform() {
	}
	
    def endTransform() {
        g2.setTransform(Tx)
        computeInverse
    }

    protected def computeInverse() {
        try {
        	xT = new AffineTransform(Tx)
        	xT.invert
        } catch {
            case _ => Console.err.println("Cannot inverse matrix")
        }
    }
    
    def transform(x:Double, y:Double, z:Double):Point3 = {
        dummyPoint.setLocation(x,y)
        Tx.transform(dummyPoint, dummyPoint)
        new Point3(dummyPoint.x, dummyPoint.y, 0)
    }
    
    def inverseTransform(x:Double, y:Double, z:Double):Point3 = {
        dummyPoint.setLocation(x, y)
        xT.transform(dummyPoint, dummyPoint)
        new Point3(dummyPoint.x, dummyPoint.y, 0)
    }
    
    def transform(p:Point3):Point3 = {
        dummyPoint.setLocation(p.x, p.y)
        Tx.transform(dummyPoint, dummyPoint)
        p.set(dummyPoint.x, dummyPoint.y, 0)
        p
    }
    
    def inverseTransform(p:Point3):Point3 = {
        dummyPoint.setLocation(p.x, p.y)
        xT.transform(dummyPoint, dummyPoint)
        p.set(dummyPoint.x, dummyPoint.y, 0)
        p
    }
    
    /**
     * Push the actual transformation on the matrix stack, installing
     * a copy of it on the top of the stack.
     */
    def pushTransform() {
        val newTx = new AffineTransform(Tx)
        matrixStack.push(newTx)
        g2.setTransform(newTx)
        Tx = newTx
        // xT inchanged, since newTx is a copy of Tx
    }
    
    /**
     * Pop the actual transformation of the matrix stack, installing
     * the previous one in the stack.
     */
    def popTransform() {
        assert(!matrixStack.isEmpty)
        matrixStack.pop
        //Tx = matrixStack.top
        g2.setTransform(matrixStack.top)
        //computeInverse
    }
    
    def setIdentity() {
        Tx.setToIdentity
    }
    
    def translate(tx:Double, ty:Double, tz:Double) {
        Tx.translate(tx, ty)
    }
    
    def rotate(angle:Double, ax:Double, ay:Double, az:Double) {
        Tx.rotate(angle)
    }
    
    def scale(sx:Double, sy:Double, sz:Double) {
        Tx.scale(sx, sy)
    }
    
    def setAntialias(on:Boolean) {
       import RenderingHints._
	   if(on) {
		   g2.setRenderingHint(KEY_STROKE_CONTROL,    VALUE_STROKE_PURE)
		   g2.setRenderingHint(KEY_TEXT_ANTIALIASING, VALUE_TEXT_ANTIALIAS_ON)
		   g2.setRenderingHint(KEY_ANTIALIASING,      VALUE_ANTIALIAS_ON)
	   } else {
		   g2.setRenderingHint(KEY_STROKE_CONTROL,    VALUE_STROKE_DEFAULT)
		   g2.setRenderingHint(KEY_TEXT_ANTIALIASING, VALUE_TEXT_ANTIALIAS_OFF)
		   g2.setRenderingHint(KEY_ANTIALIASING,      VALUE_ANTIALIAS_OFF)
	   }
        
    }
    
    def setQuality(on:Boolean) {
       import RenderingHints._
       if(on) {
		   g2.setRenderingHint(KEY_RENDERING,           VALUE_RENDER_SPEED)
		   g2.setRenderingHint(KEY_INTERPOLATION,       VALUE_INTERPOLATION_NEAREST_NEIGHBOR)
		   g2.setRenderingHint(KEY_COLOR_RENDERING,     VALUE_COLOR_RENDER_SPEED)
		   g2.setRenderingHint(KEY_ALPHA_INTERPOLATION, VALUE_ALPHA_INTERPOLATION_SPEED)
	   } else {
		   g2.setRenderingHint(KEY_RENDERING,           VALUE_RENDER_QUALITY)
		   g2.setRenderingHint(KEY_INTERPOLATION,       VALUE_INTERPOLATION_BICUBIC)
		   g2.setRenderingHint(KEY_COLOR_RENDERING,     VALUE_COLOR_RENDER_QUALITY)
		   g2.setRenderingHint(KEY_ALPHA_INTERPOLATION, VALUE_ALPHA_INTERPOLATION_QUALITY)
	   }
    }
    
    def chooseNodeShape(oldShape:Shape, group:StyleGroup):Shape = {
        import org.graphstream.ui.graphicGraph.stylesheet.StyleConstants.Shape._
        import org.graphstream.ui.j2dviewer.renderer.shape._
		group.getShape match {
			case CIRCLE         => if(oldShape.isInstanceOf[CircleShape])         oldShape else new CircleShape 
		  	case BOX            => if(oldShape.isInstanceOf[SquareShape])         oldShape else new SquareShape
		  	case ROUNDED_BOX    => if(oldShape.isInstanceOf[RoundedSquareShape])  oldShape else new RoundedSquareShape
		  	case DIAMOND        => if(oldShape.isInstanceOf[DiamondShape])        oldShape else new DiamondShape
		    case TRIANGLE       => if(oldShape.isInstanceOf[TriangleShape])       oldShape else new TriangleShape
		    case CROSS          => if(oldShape.isInstanceOf[CrossShape])          oldShape else new CrossShape
		    case FREEPLANE      => if(oldShape.isInstanceOf[FreePlaneNodeShape])  oldShape else new FreePlaneNodeShape
		    case PIE_CHART      => if(oldShape.isInstanceOf[PieChartShape])       oldShape else new PieChartShape
		  	case POLYGON        => if(oldShape.isInstanceOf[PolygonShape])        oldShape else new PolygonShape
		  	// ------------------------------------------
		    case TEXT_BOX       => Console.err.printf( "** SORRY text-box shape not yet implemented **%n" );     new SquareShape
		    case TEXT_PARAGRAPH => Console.err.printf( "** SORRY text-para shape not yet implemented **%n" );    new SquareShape
		    case TEXT_CIRCLE    => Console.err.printf( "** SORRY text-circle shape not yet implemented **%n" );  new CircleShape
		    case TEXT_DIAMOND   => Console.err.printf( "** SORRY text-diamond shape not yet implemented **%n" ); new CircleShape
		    case ARROW          => Console.err.printf( "** SORRY arrow shape not yet implemented **%n" );        new CircleShape
		    case IMAGES         => Console.err.printf( "** SORRY images shape not yet implemented **%n" );       new SquareShape 
		  	// ------------------------------------------
		    case JCOMPONENT     => throw new RuntimeException("WTF, jcomponent should have its own renderer")
		    case x              => throw new RuntimeException("%s shape cannot be set for nodes".format(x.toString))
		}
    }

    def chooseEdgeShape(oldShape:Shape, group:StyleGroup):Shape = {
        import org.graphstream.ui.graphicGraph.stylesheet.StyleConstants.Shape._
        import org.graphstream.ui.j2dviewer.renderer.shape._
		group.getShape match {
			case LINE        => if(oldShape.isInstanceOf[LineShape])                 oldShape else new LineShape
		  	case ANGLE       => if(oldShape.isInstanceOf[AngleShape])                oldShape else new AngleShape
    		case BLOB        => if(oldShape.isInstanceOf[BlobShape])                 oldShape else new BlobShape
		  	case CUBIC_CURVE => if(oldShape.isInstanceOf[CubicCurveShape])           oldShape else new CubicCurveShape
		  	case FREEPLANE   => if(oldShape.isInstanceOf[FreePlaneEdgeShape])        oldShape else new FreePlaneEdgeShape
    		case POLYLINE    => if(oldShape.isInstanceOf[PolylineEdgeShape])         oldShape else new PolylineEdgeShape
    		case SQUARELINE  => Console.err.printf("** SORRY square-line shape not yet implemented **"); new HorizontalSquareEdgeShape 
    		case LSQUARELINE => if(oldShape.isInstanceOf[HorizontalSquareEdgeShape]) oldShape else new LSquareEdgeShape 
    		case HSQUARELINE => if(oldShape.isInstanceOf[HorizontalSquareEdgeShape]) oldShape else new HorizontalSquareEdgeShape 
    		case VSQUARELINE => Console.err.printf("** SORRY square-line shape not yet implemented **"); new HorizontalSquareEdgeShape 
		    case x           => throw new RuntimeException("%s shape cannot be set for edges".format(x.toString))
		}

    }
    
    def chooseEdgeArrowShape(oldShape:Shape, group:StyleGroup):Shape = {
        import org.graphstream.ui.j2dviewer.renderer.shape._
 		import org.graphstream.ui.graphicGraph.stylesheet.StyleConstants.ArrowShape._
		group.getArrowShape match {
			case NONE    => null
			case ARROW   => if(oldShape.isInstanceOf[ArrowOnEdge])   oldShape else new ArrowOnEdge
			case CIRCLE  => if(oldShape.isInstanceOf[CircleOnEdge])  oldShape else new CircleOnEdge
			case DIAMOND => if(oldShape.isInstanceOf[DiamondOnEdge]) oldShape else new DiamondOnEdge
			case IMAGE   => if(oldShape.isInstanceOf[ImageOnEdge])   oldShape else new ImageOnEdge
		    case x       => throw new RuntimeException("%s shape cannot be set for edge arrows".format(x.toString))
		}        
    }

    def chooseSpriteShape(oldShape:Shape, group:StyleGroup):Shape = {
        import org.graphstream.ui.j2dviewer.renderer.shape._
        import org.graphstream.ui.graphicGraph.stylesheet.StyleConstants.Shape._
		group.getShape match {
			case CIRCLE         => if(oldShape.isInstanceOf[CircleShape])           oldShape else new CircleShape 
		  	case BOX            => if(oldShape.isInstanceOf[OrientableSquareShape]) oldShape else new OrientableSquareShape
		  	case ROUNDED_BOX    => if(oldShape.isInstanceOf[RoundedSquareShape])    oldShape else new RoundedSquareShape
		  	case DIAMOND        => if(oldShape.isInstanceOf[DiamondShape])          oldShape else new DiamondShape
		    case TRIANGLE       => if(oldShape.isInstanceOf[TriangleShape])         oldShape else new TriangleShape
		    case CROSS          => if(oldShape.isInstanceOf[CrossShape])            oldShape else new CrossShape
		    case ARROW          => if(oldShape.isInstanceOf[SpriteArrowShape])      oldShape else new SpriteArrowShape
		    case FLOW           => if(oldShape.isInstanceOf[SpriteFlowShape])       oldShape else new SpriteFlowShape
		    case PIE_CHART      => if(oldShape.isInstanceOf[PieChartShape])         oldShape else new PieChartShape
		  	case POLYGON        => if(oldShape.isInstanceOf[PolygonShape])          oldShape else new PolygonShape
		  	// ------------------------------------------
		    case TEXT_BOX       => Console.err.printf( "** SORRY text-box shape not yet implemented **%n" );     new SquareShape
		    case TEXT_PARAGRAPH => Console.err.printf( "** SORRY text-para shape not yet implemented **%n" );    new SquareShape
		    case TEXT_CIRCLE    => Console.err.printf( "** SORRY text-circle shape not yet implemented **%n" );  new CircleShape
		    case TEXT_DIAMOND   => Console.err.printf( "** SORRY text-diamond shape not yet implemented **%n" ); new CircleShape
		    case IMAGES         => Console.err.printf( "** SORRY images shape not yet implemented **%n" );       new SquareShape 
		  	// ------------------------------------------
		    case JCOMPONENT     => throw new RuntimeException("WTF, jcomponent should have its own renderer")
		    case x              => throw new RuntimeException("%s shape cannot be set for sprites".format(x.toString))
		}
    }

    def chooseGraphBackgroundRenderer():GraphBackgroundRenderer = {
        null
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy