Java tutorial
/* * Copyright Jordan Schalm 2015 * This program is distributed under the terms of the GNU General Public License. * * This file is part of Ko. * * Ko 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. * * Ko 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 Ko. If not, see <http://www.gnu.org/licenses/>. */ import java.util.Set; import java.util.TreeSet; import org.opencv.core.Point; /** * @author Jordan Schalm * * KoTrendline represents a trendline in the set of detected stones along * the x or y axis. */ public class KoTrendline implements Comparable<KoTrendline> { public static final int X_ORIENTATION = 1; public static final int Y_ORIENTATION = 0; private Set<KoCircle> constituents; private int orientation; /** * Creates a new trendline with the given orientation and the given set of constituent stones. * @param constituents * a set of KoCircle objects that are members of this trendline. * @param orientation * orientation of the new trendline, must be either X_ORIENTATION (1) or Y_ORIENTATION (0) */ public KoTrendline(Set<KoCircle> constituents, int orientation) { if (orientation != X_ORIENTATION && orientation != Y_ORIENTATION) { System.out.println( "Illegal value for orientation in Trendline initializer. Must be X_ORIENTATION (1) or Y_ORIENTATION (0)."); throw new IllegalArgumentException(); } this.orientation = orientation; this.constituents = constituents; // TODO: consider creating a copy here to prevent rep exposure } /** * Creates a new, empty trendline with the given orientation. * @param orientation * orientation of the new trendline, must be either X_ORIENTATION (1) or Y_ORIENTATION (0) */ public KoTrendline(int orientation) { if (orientation != X_ORIENTATION && orientation != Y_ORIENTATION) { System.out.println("Illegal value for direction in Trendline initializer. Must be 'x' or 'y'."); throw new IllegalArgumentException(); } this.orientation = orientation; this.constituents = new TreeSet<KoCircle>(); } /** * Returns this stone's orientation. * @return either */ public int getOrientation() { return this.orientation; } /** * Adds a stone to this trendline, if it doesn't already exist. * @param stone * The stone to add. * @return * true if the stone was successfully added (ie. was not already * in the trendline) and false otherwise. */ public boolean addStone(KoCircle stone) { if (constituents.add(stone)) { return true; } return false; } /** * Removes a stone from this trendline, if it exists. * @param stone * The stone to remove. * @return * true if the stone was successfully removed (ie. initially existed * in the trendline) false otherwise. */ public boolean removeStone(KoCircle stone) { if (constituents.remove(stone)) { return true; } return false; } /** * @return the set of all DetectedCircle objects contained in this trendline */ public Set<KoCircle> getConstituents() { return new TreeSet<KoCircle>(this.constituents); } /** * @return the average x (if orientation == Y) or y (if orientation == X) * coordinate of all stones in this trendline. */ public double getOrigin() { double sum = 0; for (KoCircle current : this.constituents) { if (orientation == X_ORIENTATION) sum += current.getImgY(); else sum += current.getImgX(); } return sum / this.constituents.size(); } /** * @return a Point containing the coordinates of the bottom-most (or leftmost) * stone in this trendline. */ public Point getBottomPoint() { double origin = getOrigin(); double max = 0; for (KoCircle current : this.constituents) { if (orientation == X_ORIENTATION) { if (current.getImgX() > max) { max = current.getImgX(); } } if (orientation == Y_ORIENTATION) { if (current.getImgY() > max) { max = current.getImgY(); } } } if (orientation == X_ORIENTATION) { return new Point(max, origin); } else { return new Point(origin, max); } } /** * @return a Point containing the coordinates of the topmost (or rightmost) * stone in this trendline. */ public Point getTopPoint() { double origin = getOrigin(); double min = Double.MAX_VALUE; for (KoCircle current : this.constituents) { if (orientation == X_ORIENTATION) { if (current.getImgX() < min) { min = current.getImgX(); } } if (orientation == Y_ORIENTATION) { if (current.getImgY() < min) { min = current.getImgY(); } } } if (orientation == X_ORIENTATION) { return new Point(min, origin); } else { return new Point(origin, min); } } /** * @return the slope of this trendline using least squares method */ public double calculateSlope() { double xSum = 0, ySum = 0; for (KoCircle current : this.constituents) { xSum += current.getImgX(); ySum += current.getImgY(); } double xBar = xSum / this.constituents.size(); double yBar = ySum / this.constituents.size(); double numerator = 0, denominator = 0; for (KoCircle current : this.constituents) { numerator += (current.getImgX() - xBar) * (current.getImgY() - yBar); denominator += (current.getImgX() - xBar) * (current.getImgX() - xBar); } return numerator / denominator; } @Override public int compareTo(KoTrendline other) { if (other.getOrientation() != this.orientation) { throw new IllegalArgumentException(); // TODO BAD! } else { return (int) (this.getOrigin() - other.getOrigin()); } } }