/* * JAME 6.2.1 * http://jame.sourceforge.net * * Copyright 2001, 2016 Andrea Medeghini * * This file is part of JAME. * * JAME is an application for creating fractals and other graphics artifacts. * * JAME is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * JAME 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with JAME. If not, see <http://www.gnu.org/licenses/>. * */ package net.sf.jame.contextfree.renderer.support; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; public class CFBounds { private double minX = Double.MAX_VALUE; private double minY = Double.MAX_VALUE; private double maxX = Double.MIN_VALUE; private double maxY = Double.MIN_VALUE; public CFBounds() { } public CFBounds(CFPath path, CFPathAttribute attribute, float dilation, float scale) { float[] src = new float[2]; float[] dst = new float[2]; src[0] = (float) attribute.getCentroid().getX(); src[1] = (float) attribute.getCentroid().getY(); attribute.getModification().transform(src, dst); double centroidX = dst[0]; double centroidY = dst[1]; Rectangle2D bounds = path.getBounds(attribute.getModification().getTransform(), scale); minX = bounds.getMinX(); maxX = bounds.getMaxX(); minY = bounds.getMinY(); maxY = bounds.getMaxY(); if (isValid() && dilation != 1.0) { minX = dilation * (minX - centroidX) + centroidX; maxX = dilation * (maxX - centroidX) + centroidX; minY = dilation * (minY - centroidY) + centroidY; maxY = dilation * (maxY - centroidY) + centroidY; } } public double getMinX() { return minX; } public double getMinY() { return minY; } public double getMaxX() { return maxX; } public double getMaxY() { return maxY; } public double getSizeX() { return maxX - minX; } public double getSizeY() { return maxY - minY; } public void merge(CFBounds bounds) { if (!bounds.isValid()) return; if (!isValid()) { maxX = bounds.maxX; minX = bounds.minX; maxY = bounds.maxY; minY = bounds.minY; return; } if (maxX < bounds.maxX) maxX = bounds.maxX; if (minX > bounds.minX) minX = bounds.minX; if (maxY < bounds.maxY) maxY = bounds.maxY; if (minY > bounds.minY) minY = bounds.minY; } public boolean isValid() { return (maxX - minX) > 0 || (maxY - minY) > 0; } @Override public String toString() { return "CFBounds [minX=" + minX + ", maxX=" + maxX + ", minY=" + minY + ", maxY=" + maxY + "]"; } public void update(CFPath path, CFPathAttribute attribute, float scale) { merge(new CFBounds(path, attribute, 1.0f, scale)); } public float computeScale(int width, int height, float border, boolean exact) { return (float) computeScale(width, height, border, null, exact); } public CFBounds interpolate(CFBounds other, double alpha) { double beta = 1.0 - alpha; CFBounds result = new CFBounds(); if (!isValid() || !other.isValid()) return result; result.maxX = beta * maxX + alpha * other.maxX; result.minX = beta * minX + alpha * other.minX; result.maxY = beta * maxY + alpha * other.maxY; result.minY = beta * minY + alpha * other.minY; return result; } public CFBounds slewCenter(CFBounds other, double alpha) { CFBounds result = new CFBounds(); if (!isValid() || !other.isValid()) return result; double offsetX = alpha * ((other.maxX + other.minX) - (maxX + minX)) / 2.0; double offsetY = alpha * ((other.maxY + other.minY) - (maxY + minY)) / 2.0; double absX = Math.abs(offsetX); double absY = Math.abs(offsetY); result.maxX = maxX + absX + offsetX; result.minX = minX - absX + offsetX; result.maxY = maxY + absY + offsetY; result.minY = minY - absY + offsetY; return result; } public void gather(CFBounds other, double weight) { if (!other.isValid()) return; if (!isValid()) { maxX = weight * other.maxX; minX = weight * other.minX; maxY = weight * other.maxY; minY = weight * other.minY; return; } maxX += weight * other.maxX; minX += weight * other.minX; maxY += weight * other.maxY; minY += weight * other.minY; } public double computeScale(int width, int height, float border, AffineTransform transform, boolean exact) { double scale; double virtual_width = maxX - minX; double virtual_height = maxY - minY; double target_width = width - 2 * border; double target_height = height - 2 * border; double center_x = (maxX + minX) / 2.0; double center_y = (maxY + minY) / 2.0; if (!isValid()) { virtual_width = virtual_height = 1; center_x = 0; center_y = 0; } int newWidth = width; int newHeight = height; if (virtual_width / target_width > virtual_height / target_height) { scale = target_width / virtual_width; newHeight = (int) Math.floor(scale * virtual_height + 2 * border + 0.5); if (!exact) { newHeight = newHeight + ((newHeight ^ height) & 0x1); } } else { scale = target_height / virtual_height; newWidth = (int) Math.floor(scale * virtual_width + 2 * border + 0.5); if (!exact) { newWidth = newWidth + ((newWidth ^ width) & 0x1); } } if (transform != null) { double offsetX = center_x - (target_width / 2.0) / scale; double offsetY = center_y - (target_height / 2.0) / scale; transform.setToScale(scale, scale); transform.translate(-offsetX, -offsetY); } return scale; } public void setMinX(double value) { this.minX = value; } public void setMaxX(double value) { this.maxX = value; } public void setMinY(double value) { this.minY = value; } public void setMaxY(double value) { this.maxY = value; } public double getCenterX() { return (maxX + minX) / 2; } public double getCenterY() { return (maxY + minY) / 2; } }