/* * Copyright 2006-2017 ICEsoft Technologies Canada Corp. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an "AS * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language * governing permissions and limitations under the License. */ package org.icepdf.core.pobjects; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.util.ArrayList; import java.util.List; /** * <p>A rectangle in a PDF document is slightly different than the <code>Rectangle</code> class * in Java. A PDF rectangle is written as an array of four numbers giving the * coordinates of a pair of diagonally opposite corners. Typically, the * array takes the form:</p> * <br> * <ul> * <li>[II<sub>x</sub> II<sub>y</sub> UR<sub>x</sub> UR<sub>y</sub>]</li> * </ul> * <br> * <p>This specifies the lower-left x, lower-left y, upper-right x, and upper-right y * coordinates of the rectangle, in that order. However, this format is not * guaranteed and this class normalizes such rectangles.</p> * <br> * <p>Another very important difference between PRectangles Rectangles is that * PRectangles use the Cartesian Coordinate system, where Rectangles use the * Java2D coordinates system. As a result, the user of this class must know the * context in which the PRectangle is being used. For example there is a significant * difference between the inherited method createIntersection and PRectangles * createCartesianIntersection.</p> * * @since 2.0 */ @SuppressWarnings("serial") public class PRectangle extends Rectangle2D.Float { private float p1x; private float p1y; private float p2x; private float p2y; /** * <p>Creates a new PRectangle object. The points are automatically normalized * by the constructor. These two coordinates represent the diagonal * corners of the rectangle. * * @param p1 first point of diagonal, in the Cartesian coordinate space * @param p2 second point of diagonal, in the Cartesian coordinate space */ public PRectangle(Point2D.Float p1, Point2D.Float p2) { super(); normalizeCoordinates(p1.x, p1.y, p2.x, p2.y); // assign original data p1x = p1.x; p1y = p1.y; p2x = p2.x; p2y = p2.y; } /** * <p>Creates a new PRectangle object assumed to be in the Cartesian coordinate * space.</p> * * @param x the specified x coordinate * @param y the specified y coordinate * @param width the width of the Rectangle * @param height the height of the Rectangle */ private PRectangle(float x, float y, float width, float height) { super(x, y, width, height); } /** * Creates a new PRectangle object. The points are automatically normalized * by the constructor. * * @param coordinates a vector containing four elements where the first and * second elements represent the x and y coordinates of one point and the * third and fourth elements represent the x and y cooordinates of the second * point. These two coordinates represent the diagonal corners of the * rectangle. * @throws IllegalArgumentException thrown if coordinates is null or does not * have four elements */ public PRectangle(List coordinates) throws IllegalArgumentException { if (coordinates == null || coordinates.size() < 4) throw new IllegalArgumentException(); float x1 = ((Number) coordinates.get(0)).floatValue(); float y1 = ((Number) coordinates.get(1)).floatValue(); float x2 = ((Number) coordinates.get(2)).floatValue(); float y2 = ((Number) coordinates.get(3)).floatValue(); // assign original data p1x = x1; p1y = y1; p2x = x2; p2y = y2; //System.out.println(x1 + " : " + y1 + " : " + x2 + " : " + y2 ); normalizeCoordinates(x1, y1, x2, y2); } /** * Returns a new PRectangle object representing the intersection of this * PRectangle with the specified PRectangle using the Cartesian coordinate * system. If a Java2D coordinate system is used, then the rectangle should * be first converted to that space {@link #toJava2dCoordinates() }. * * @param src2 the Rectangle2D to be intersected with this Rectangle2D. * @return object representing the intersection of the two PRectangles. */ public PRectangle createCartesianIntersection(PRectangle src2) { PRectangle rec = new PRectangle(src2.x, src2.y, src2.width, src2.height); float xLeft = (x > rec.x) ? x : rec.x; float xRight = ((x + width) > (rec.x + rec.width)) ? (rec.x + rec.width) : (x + width); float yBottom = ((y - height) < (rec.y - rec.height) ? (rec.y - rec.height) : (y - height)); float yTop = (y > rec.y) ? rec.y : y; rec.x = xLeft; rec.y = yTop; rec.width = xRight - xLeft; rec.height = yTop - yBottom; // If rectangles don't intersect, return zeroed intersection. if (rec.width < 0 || rec.height < 0) { rec.x = rec.y = rec.width = rec.height = 0; } return rec; } /** * <p>Gets the orgional two points that created the PRectangle object. The * first point is represented by the the rectangle positions x, y and the * second poitn is represented by the width and height of the rectangle. * * @return rectangle representing the PRectangle object initial two point. */ public Rectangle2D.Float getOriginalPoints() { return new Rectangle2D.Float(p1x, p1y, p2x, p2y); } /** * <p>Converts the Cartesian representation of the Rectangle into Rectangle in * the Java2D coordinate space.</p> * * @return rectangle in the Java2D coordinate space. */ public Rectangle2D.Float toJava2dCoordinates() { return new Rectangle2D.Float(x, y - height, width, height); } /** * Converts a rectangle defined in user page in Java2D coordinates back * to PDF space and in the vector for of the rectangle. * * @param rect user space rectangle in Java2D coordinates space. * @return vector notation of rectangle in PDF space. */ public static List getPRectangleVector(Rectangle2D rect) { // convert the rectangle back to PDF space. rect = new Rectangle2D.Double(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight()); ArrayList<Number> coords = new ArrayList<Number>(4); coords.add(rect.getMinX()); coords.add(rect.getMinY()); coords.add(rect.getMaxX()); coords.add(rect.getMaxY()); return coords; } /** * Normalizes the given coordinates so that the rectangle is created with the * proper dimensions. * * @param x1 x value of coordinate 1 * @param y1 y value of coordinate 1 * @param x2 x value of coordinate 2 * @param y2 y value of coordinate 2 */ private void normalizeCoordinates(float x1, float y1, float x2, float y2) { float x = x1, y = y1, w = Math.abs(x2 - x1), h = Math.abs(y2 - y1); // get smallest x if (x1 > x2) { x = x2; } // get largest y if (y1 < y2) { y = y2; } setRect(x, y, w, h); } }