001package conexp.fx.core.collections;
002
003/*
004 * #%L
005 * Concept Explorer FX
006 * %%
007 * Copyright (C) 2010 - 2023 Francesco Kriegel
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
011 * published by the Free Software Foundation, either version 3 of the
012 * License, or (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
020 * License along with this program.  If not, see
021 * <http://www.gnu.org/licenses/gpl-3.0.html>.
022 * #L%
023 */
024
025import java.util.Comparator;
026
027public class IntPair extends Pair<Integer, Integer> implements Cloneable {
028
029  public static final IntPair valueOf(final int x, final int y) {
030    return new IntPair(x, y);
031  }
032
033  public static final IntPair zero() {
034    return new IntPair();
035  }
036
037  public static final Comparator<IntPair> CANTORIAN_COMPARATOR          = new Comparator<IntPair>() {
038
039                                                                          @Override
040                                                                          public int compare(IntPair o1, IntPair o2) {
041                                                                            if (o1.equals(o2))
042                                                                              return 0;
043                                                                            if (cantorianSum(
044                                                                                o1.x,
045                                                                                o1.y) < cantorianSum(o2.x, o2.y))
046                                                                              return -1;
047                                                                            return 1;
048                                                                          }
049                                                                        };
050  public static final Comparator<IntPair> POSITIVE_CANTORIAN_COMPARATOR = new Comparator<IntPair>() {
051
052                                                                          @Override
053                                                                          public int compare(IntPair o1, IntPair o2) {
054                                                                            if (o1.equals(o2))
055                                                                              return 0;
056                                                                            if (positiveCantorianSum(
057                                                                                o1.x,
058                                                                                o1.y) < positiveCantorianSum(
059                                                                                    o2.x,
060                                                                                    o2.y))
061                                                                              return -1;
062                                                                            return 1;
063                                                                          }
064                                                                        };
065
066  public static final int cantorianSum(final int m, final int n) {
067    int shift = 0;
068    if (m < 0)
069      shift++;
070    if (n < 0)
071      shift += 2;
072    // shift is 0 iff both are positive
073    // shift is 1 iff only n is positive
074    // shift is 2 iff only m is positive
075    // shift is 3 iff none is positive
076    return 4 * positiveCantorianSum(Math.abs(m), Math.abs(n)) + shift;
077  }
078
079  /**
080   * cantorianSum is a bijection between positive integers and pairs of positive integers
081   */
082  public static final int positiveCantorianSum(final int m, final int n) {
083    if (m < 0 || n < 0)
084      throw new RuntimeException("positive cantorian sum can only be calculated for positive integers!");
085    return m + ((m + n + 1) * (m + n + 2)) / 2;
086//    int cantorianSum = m;
087//    for (int i = 1; i < m + n + 1; i++)
088//      cantorianSum += i;
089//    return cantorianSum;
090  }
091
092  public static final IntPair findPositiveCantorianSum(final int sum) {
093    int m = sum;
094    for (int n = 0; n < Integer.MAX_VALUE; n++)
095      if (positiveCantorianSum(m, n) == sum)
096        return IntPair.valueOf(m, n);
097    return null;
098  }
099
100  public IntPair(final int x, final int y) {
101    super(Integer.valueOf(x), Integer.valueOf(y));
102  }
103
104  public IntPair() {
105    super(Integer.valueOf(0), Integer.valueOf(0));
106  }
107
108  @Override
109  public boolean equals(Object object) {
110    if (object == null)
111      return false;
112    if (!(object instanceof IntPair))
113      return false;
114    final IntPair other = (IntPair) object;
115    return other.x() == this.x() && other.y() == this.y();
116  }
117
118  @Override
119  public int hashCode() {
120    return cantorianSum(x(), y());
121  }
122
123//  public final int x() {
124//    return x.intValue();
125//  }
126//
127//  public final int y() {
128//    return y.intValue();
129//  }
130
131  @Override
132  public final IntPair clone() {
133    return new IntPair(x(), y());
134  }
135
136  public final void setX(final int x) {
137    this.x = Integer.valueOf(x);
138  }
139
140  public final void setY(final int y) {
141    this.y = Integer.valueOf(y);
142  }
143
144  public final void set(final int x, final int y) {
145    setX(x);
146    setY(y);
147  }
148
149  public final void set(final IntPair coordinates) {
150    set(coordinates.x(), coordinates.y());
151  }
152
153  public final IntPair negate() {
154    setX(-x());
155    setY(-y());
156    return this;
157  }
158
159  public final IntPair add(final int x, final int y) {
160    this.x += Integer.valueOf(x);
161    this.y += Integer.valueOf(y);
162    return this;
163  }
164
165  public final IntPair add(final IntPair coordinates) {
166    add(coordinates.x(), coordinates.y());
167    return this;
168  }
169
170  public final IntPair subtract(final int x, final int y) {
171    this.x -= Integer.valueOf(x);
172    this.y -= Integer.valueOf(y);
173    return this;
174  }
175
176  public final IntPair subtract(final IntPair coordinates) {
177    subtract(coordinates.x(), coordinates.y());
178    return this;
179  }
180
181  public final IntPair delta(final int x, final int y) {
182    return new IntPair(x, y).minus(this);
183  }
184
185  public final IntPair delta(final IntPair coordinates) {
186    return coordinates.clone().minus(this);
187  }
188
189  public final IntPair plus(final int x, final int y) {
190    return clone().add(x, y);
191  }
192
193  public final IntPair plus(final IntPair coordinates) {
194    return clone().add(coordinates);
195  }
196
197  public final IntPair minus(final int x, final int y) {
198    return clone().subtract(x, y);
199  }
200
201  public final IntPair minus(final IntPair coordinates) {
202    return clone().subtract(coordinates);
203  }
204
205  public final IntPair negative() {
206    return clone().negate();
207  }
208}