001package ball.util; 002/*- 003 * ########################################################################## 004 * Utilities 005 * %% 006 * Copyright (C) 2008 - 2022 Allen D. Ball 007 * %% 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 * ########################################################################## 020 */ 021import java.awt.Point; 022import java.awt.geom.Point2D; 023import java.beans.ConstructorProperties; 024import java.io.Serializable; 025import java.util.Arrays; 026import java.util.Comparator; 027import java.util.Objects; 028import java.util.SortedSet; 029import java.util.TreeSet; 030 031/** 032 * X-Y coordinate representation. 033 * 034 * {@bean.info} 035 * 036 * @author {@link.uri mailto:ball@hcf.dev Allen D. Ball} 037 */ 038public class Coordinate implements Comparable<Coordinate>, Serializable { 039 private static final long serialVersionUID = -4428900365914120909L; 040 041 private static final Comparator<? super Coordinate> COMPARATOR = 042 Comparator 043 .comparingInt(Coordinate::getY) 044 .thenComparingInt(Coordinate::getX); 045 046 /** @serial */ private final int y; 047 /** @serial */ private final int x; 048 049 /** 050 * @param y The Y-coordinate. 051 * @param x The X-coordinate. 052 */ 053 @ConstructorProperties({ "y", "x" }) 054 public Coordinate(Number y, Number x) { this(y.intValue(), x.intValue()); } 055 056 private Coordinate(int y, int x) { 057 this.y = y; 058 this.x = x; 059 } 060 061 public int getY() { return y; } 062 063 public int getX() { return x; } 064 065 /** 066 * Method to get the {@link Coordinate} relative to {@link.this} 067 * {@link Coordinate}. 068 * 069 * @param dy The change in Y-coordinate. 070 * @param dx The change in X-coordinate. 071 * 072 * @return The relative {@link Coordinate}. 073 */ 074 public Coordinate translate(Number dy, Number dx) { 075 return new Coordinate(getY() + dy.intValue(), getX() + dx.intValue()); 076 } 077 078 /** 079 * Method to getthe {@link Coordinate} relative to {@link.this} 080 * {@link Coordinate}. 081 * 082 * @param ds The {@link Coordinate} describing the change. 083 * 084 * @return The relative {@link Coordinate}. 085 */ 086 public Coordinate translate(Coordinate ds) { 087 return translate(ds.getY(), ds.getX()); 088 } 089 090 /** 091 * Method to determine if {@link.this} {@link Coordinate} is within the 092 * area described by the argument {@link Coordinate}s. 093 * 094 * @param min The minimum {@link Coordinate}. 095 * @param max The maximum {@link Coordinate}. 096 * 097 * @return {@code true} if within the area; {@code false} otherwise. 098 */ 099 public boolean within(Coordinate min, Coordinate max) { 100 return ((min.getY() <= getY() && getY() < max.getY()) && (min.getX() <= getX() && getX() < max.getX())); 101 } 102 103 /** 104 * Method to translate this {@link Coordinate} to a {@link Point2D}. 105 * 106 * @return The {@link Point}. 107 */ 108 public Point2D asPoint() { return new Point(getX(), getY()); } 109 110 @Override 111 public int compareTo(Coordinate that) { 112 return Objects.compare(this, that, COMPARATOR); 113 } 114 115 @Override 116 public boolean equals(Object object) { 117 return ((object instanceof Coordinate) ? (this.compareTo((Coordinate) object) == 0) : super.equals(object)); 118 } 119 120 @Override 121 public int hashCode() { return Arrays.asList(y, x).hashCode(); } 122 123 @Override 124 public String toString() { return Arrays.asList(y, x).toString(); } 125 126 /** 127 * Static method to return a {@link SortedSet} of {@link Coordinate}s 128 * specified by the parameters. 129 * 130 * @param min {@code [y0, x0]} 131 * @param max {@code [yN, xN]} 132 * 133 * @return The {@link SortedSet} of {@link Coordinate}s. 134 */ 135 public static SortedSet<Coordinate> range(Coordinate min, Coordinate max) { 136 return range(Math.min(min.getY(), max.getY()), Math.min(min.getX(), max.getX()), 137 Math.max(min.getY(), max.getY()), Math.max(min.getX(), max.getX())); 138 } 139 140 /** 141 * Static method to return a {@link SortedSet} of {@link Coordinate}s 142 * specified by the parameters. 143 * 144 * @param y0 {@code MIN(y)} 145 * @param x0 {@code MIN(x)} 146 * @param yN {@code MAX(y) + 1} 147 * @param xN {@code MAX(x) + 1} 148 * 149 * @return The {@link SortedSet} of {@link Coordinate}s. 150 */ 151 public static SortedSet<Coordinate> range(int y0, int x0, int yN, int xN) { 152 TreeSet<Coordinate> set = new TreeSet<>(); 153 154 for (int y = y0; y < yN; y += 1) { 155 for (int x = x0; x < xN; x += 1) { 156 set.add(new Coordinate(y, x)); 157 } 158 } 159 160 return set; 161 } 162}