001/* =========================================================== 002 * Orson Charts : a 3D chart library for the Java(tm) platform 003 * =========================================================== 004 * 005 * (C)opyright 2013-2022, by David Gilbert. All rights reserved. 006 * 007 * https://github.com/jfree/orson-charts 008 * 009 * This program is free software: you can redistribute it and/or modify 010 * it under the terms of the GNU General Public License as published by 011 * the Free Software Foundation, either version 3 of the License, or 012 * (at your option) any later version. 013 * 014 * This program is distributed in the hope that it will be useful, 015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 017 * GNU General Public License for more details. 018 * 019 * You should have received a copy of the GNU General Public License 020 * along with this program. If not, see <http://www.gnu.org/licenses/>. 021 * 022 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 023 * Other names may be trademarks of their respective owners.] 024 * 025 * If you do not wish to be bound by the terms of the GPL, an alternative 026 * commercial license can be purchased. For details, please see visit the 027 * Orson Charts home page: 028 * 029 * http://www.object-refinery.com/orsoncharts/index.html 030 * 031 */ 032 033package org.jfree.chart3d.graphics2d; 034 035import java.awt.geom.Point2D; 036import java.awt.geom.Rectangle2D; 037import java.io.Serializable; 038import org.jfree.chart3d.TitleAnchor; 039import org.jfree.chart3d.graphics3d.Offset2D; 040import org.jfree.chart3d.internal.Args; 041import org.jfree.chart3d.legend.LegendAnchor; 042 043/** 044 * Represents an anchor point for a chart title and/or legend. The anchor 045 * point is defined relative to a reference rectangle, the dimensions of which 046 * are not known in advance (typically the reference rectangle is the bounding 047 * rectangle of a chart that is being drawn). Some predefined anchor points 048 * are provided in the {@link TitleAnchor} and {@link LegendAnchor} classes. 049 * <br><br> 050 * Instances of this class are immutable. 051 * <br><br> 052 * NOTE: This class is serializable, but the serialization format is subject 053 * to change in future releases and should not be relied upon for persisting 054 * instances of this class. 055 */ 056@SuppressWarnings("serial") 057public final class Anchor2D implements Serializable { 058 059 /** 060 * An anchor point at the top left with zero offset from the target 061 * rectangle bounds. 062 * 063 * @since 1.1 064 */ 065 public static final Anchor2D TOP_LEFT = new Anchor2D(RefPt2D.TOP_LEFT, 066 Offset2D.ZERO_OFFSET); 067 068 /** 069 * An anchor point at the top center with zero offset from the target 070 * rectangle bounds. 071 * 072 * @since 1.1 073 */ 074 public static final Anchor2D TOP_CENTER = new Anchor2D(RefPt2D.TOP_CENTER, 075 Offset2D.ZERO_OFFSET); 076 077 /** 078 * An anchor point at the top right with zero offset from the target 079 * rectangle bounds. 080 * 081 * @since 1.1 082 */ 083 public static final Anchor2D TOP_RIGHT = new Anchor2D(RefPt2D.TOP_RIGHT, 084 Offset2D.ZERO_OFFSET); 085 086 /** 087 * An anchor point at the center left with zero offset from the target 088 * rectangle bounds. 089 * 090 * @since 1.1 091 */ 092 public static final Anchor2D CENTER_LEFT = new Anchor2D(RefPt2D.CENTER_LEFT, 093 Offset2D.ZERO_OFFSET); 094 095 /** 096 * An anchor point at the center of the target rectangle. 097 * 098 * @since 1.1 099 */ 100 public static final Anchor2D CENTER = new Anchor2D(RefPt2D.CENTER, 101 Offset2D.ZERO_OFFSET); 102 103 /** 104 * An anchor point at the center right with zero offset from the target 105 * rectangle bounds. 106 * 107 * @since 1.1 108 */ 109 public static final Anchor2D CENTER_RIGHT 110 = new Anchor2D(RefPt2D.CENTER_RIGHT, Offset2D.ZERO_OFFSET); 111 112 /** 113 * An anchor point at the bottom left with zero offset from the target 114 * rectangle bounds. 115 * 116 * @since 1.1 117 */ 118 public static final Anchor2D BOTTOM_LEFT = new Anchor2D(RefPt2D.BOTTOM_LEFT, 119 Offset2D.ZERO_OFFSET); 120 121 /** 122 * An anchor point at the bottom center with zero offset from the target 123 * rectangle bounds. 124 * 125 * @since 1.1 126 */ 127 public static final Anchor2D BOTTOM_CENTER 128 = new Anchor2D(RefPt2D.BOTTOM_CENTER, Offset2D.ZERO_OFFSET); 129 130 /** 131 * An anchor point at the bottom right with zero offset from the target 132 * rectangle bounds. 133 * 134 * @since 1.1 135 */ 136 public static final Anchor2D BOTTOM_RIGHT 137 = new Anchor2D(RefPt2D.BOTTOM_RIGHT, Offset2D.ZERO_OFFSET); 138 139 /** 140 * The reference point relative to some bounding rectangle, normally the 141 * bounds of the chart (never {@code null}). 142 */ 143 private final RefPt2D refPt; 144 145 /** 146 * The offsets to apply (never {@code null}). 147 */ 148 private final Offset2D offset; 149 150 /** 151 * Creates a default instance. 152 */ 153 public Anchor2D() { 154 this(RefPt2D.TOP_LEFT); 155 } 156 157 /** 158 * Creates a new {@code Anchor2D} instance with the specified 159 * reference point and offsets of {@code (4.0, 4.0)}. 160 * 161 * @param refPt the reference point ({@code null} not permitted). 162 */ 163 public Anchor2D(RefPt2D refPt) { 164 this(refPt, new Offset2D(4.0, 4.0)); 165 } 166 167 /** 168 * Creates a new anchor. 169 * 170 * @param refPt the reference point ({@code null} not permitted). 171 * @param offset the offset ({@code null} not permitted). 172 */ 173 public Anchor2D(RefPt2D refPt, Offset2D offset) { 174 Args.nullNotPermitted(refPt, "refPt"); 175 Args.nullNotPermitted(offset, "offset"); 176 this.refPt = refPt; 177 this.offset = offset; 178 } 179 180 /** 181 * Returns the reference point. 182 * 183 * @return The reference point (never {@code null}). 184 */ 185 public RefPt2D getRefPt() { 186 return this.refPt; 187 } 188 189 /** 190 * Returns the offsets. 191 * 192 * @return The offsets (never {@code null}). 193 */ 194 public Offset2D getOffset() { 195 return this.offset; 196 } 197 198 /** 199 * Returns the anchor point for the given rectangle. 200 * 201 * @param rect the reference rectangle ({@code null} not permitted). 202 * 203 * @return The anchor point. 204 */ 205 public Point2D getAnchorPoint(Rectangle2D rect) { 206 Args.nullNotPermitted(rect, "rect"); 207 double x = 0.0; 208 double y = 0.0; 209 if (this.refPt.isLeft()) { 210 x = rect.getX() + this.offset.getDX(); 211 } else if (this.refPt.isHorizontalCenter()) { 212 x = rect.getCenterX(); 213 } else if (this.refPt.isRight()) { 214 x = rect.getMaxX() - this.offset.getDX(); 215 } 216 if (this.refPt.isTop()) { 217 y = rect.getMinY() + this.offset.getDY(); 218 } else if (this.refPt.isVerticalCenter()) { 219 y = rect.getCenterY(); 220 } else if (this.refPt.isBottom()) { 221 y = rect.getMaxY() - this.offset.getDY(); 222 } 223 return new Point2D.Double(x, y); 224 } 225 226 /** 227 * Resolves the anchor to a specific point relative to a rectangle defined 228 * by the points (startX, startY) and (endX, endY). 229 * 230 * @param startX the x-coordinate for the bottom left corner of the target 231 * rect. 232 * @param startY the y-coordinate for the bottom left corner of the target 233 * rect. 234 * @param endX the x-coordinate for the top right corner of the target 235 * rect. 236 * @param endY the y-coordinate for the top right corner of the target 237 * rect. 238 * 239 * @return The resolved point. 240 * 241 * @since 1.2 242 */ 243 public Point2D resolveAnchorWithPercentOffset(double startX, double startY, 244 double endX, double endY) { 245 double x = 0.0; 246 double y = 0.0; 247 if (this.refPt.isLeft()) { 248 x = startX + this.offset.getDX() * (endX - startX); 249 } else if (this.refPt.isHorizontalCenter()) { 250 x = (startX + endX) / 2.0; 251 } else if (this.refPt.isRight()) { 252 x = endX - this.offset.getDX() * (endX - startX); 253 } 254 if (this.refPt.isTop()) { 255 y = endY - this.offset.getDY() * (endY - startY); 256 } else if (this.refPt.isVerticalCenter()) { 257 y = (startY + endY) / 2.0; 258 } else if (this.refPt.isBottom()) { 259 y = startY + this.offset.getDY() * (endY - startY); 260 } 261 return new Point2D.Double(x, y); 262 } 263 264 /** 265 * Tests this instance for equality with an arbitrary object. 266 * 267 * @param obj the object ({@code null} not permitted). 268 * 269 * @return A boolean. 270 */ 271 @Override 272 public boolean equals(Object obj) { 273 if (obj == this) { 274 return true; 275 } 276 if (!(obj instanceof Anchor2D)) { 277 return false; 278 } 279 Anchor2D that = (Anchor2D) obj; 280 if (!this.refPt.equals(that.refPt)) { 281 return false; 282 } 283 if (!this.offset.equals(that.offset)) { 284 return false; 285 } 286 return true; 287 } 288}