/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.scenegraph.g2d.nodes; import java.awt.Graphics2D; import java.awt.Paint; import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; /** * A scene graph node that renders multiple separately transformed instances of * a {@link Shape} by optionally filling or stroking it. * * If filling is enabled, it will be performed before stroking the shape. * * @author Tuukka Lehtonen */ public class InstancingShapeNode extends ShapeNode { private static final long serialVersionUID = -681327976554446434L; AffineTransform[] transforms = {}; Paint[] paints = {}; @SyncField({"instances", "paints"}) public void setInstances(AffineTransform[] transforms, Paint[] paints) { if (transforms.length != paints.length) throw new IllegalArgumentException("transforms.length (" + transforms.length + ") != paints.length (" + paints.length + ")"); this.transforms = transforms; this.paints = paints; } @Override public void render(Graphics2D g2d) { if (shape == null) return; if (transforms == null || transforms.length == 0) return; setupRender(g2d); AffineTransform startTr = g2d.getTransform(); Paint startPaint = g2d.getPaint(); for (int i = 0; i < transforms.length; ++i) { if (transforms[i] != null) g2d.transform(transforms[i]); if (paints[i] != null) g2d.setPaint(paints[i]); else g2d.setPaint(startPaint); renderShape(g2d, shape); g2d.setTransform(startTr); } } @Override public Rectangle2D getBoundsInLocal() { if (shape == null) return null; if (transforms == null || transforms.length == 0) return null; Rectangle2D result = null; Rectangle2D sb = shape.getBounds2D(); for (AffineTransform at : transforms) { Rectangle2D instanceBounds = at.createTransformedShape(sb).getBounds2D(); if (result == null) result = instanceBounds; else Rectangle2D.union(result, instanceBounds, result); } return result; } }