/*******************************************************************************
* Mission Control Technologies, Copyright (c) 2009-2012, United States Government
* as represented by the Administrator of the National Aeronautics and Space
* Administration. All rights reserved.
*
* The MCT platform is 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.
*
* MCT includes source code licensed under additional open source licenses. See
* the MCT Open Source Licenses file included with this distribution or the About
* MCT Licenses dialog available at runtime from the MCT Help menu for additional
* information.
*******************************************************************************/
/**
*
*/
package plotter;
import java.awt.geom.Line2D;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import junit.framework.Assert;
import junit.framework.AssertionFailedError;
/**
* Used to verify that lines drawn match expectations.
* Endpoints of individual line segments may be switched (e.g. the lines (0,0)-(1,1) and (1,1)-(0,0) are equivalent),
* and lines may be drawn in any order.
* Example usage:
* <pre>
* {@link CountingGraphics} g = new CountingGraphics(...);
* // draw on g
* LineChecker c = new LineChecker();
* c.require(19, 180, 39, 160);
* c.require(159, 40, 179, 20);
* c.check(g.getLines());
* </pre>
* @author Adam Crume
*/
public class LineChecker {
/** Maximum allowable distance between two points that count as a match. */
private double error = .00001;
/** Required line segments. */
private List<Line2D> required = new ArrayList<Line2D>();
/** Allowed but not required line segments. */
private List<Line2D> allowed = new ArrayList<Line2D>();
/**
* Adds a required line segment.
* @param x1 X coordinate of end 1
* @param y1 Y coordinate of end 1
* @param x2 X coordinate of end 2
* @param y2 Y coordinate of end 2
*/
public void require(double x1, double y1, double x2, double y2) {
required.add(new Line2D.Double(x1, y1, x2, y2));
}
/**
* Adds an allowed but not required line segment.
* @param x1 X coordinate of end 1
* @param y1 Y coordinate of end 1
* @param x2 X coordinate of end 2
* @param y2 Y coordinate of end 2
*/
public void allow(double x1, double y1, double x2, double y2) {
allowed.add(new Line2D.Double(x1, y1, x2, y2));
}
/**
* Verifies that the argument matches the requirements.
* In other words, all required lines must be present, and no extra lines may be present.
* @param lines lines to check
* @throws AssertionFailedError if the lines do not match the requirements
*/
public void check(List<Line2D> lines) {
lines=new ArrayList<Line2D>(lines);
List<Line2D> required=new ArrayList<Line2D>(this.required);
for(Iterator<Line2D> reqItr = required.iterator(); reqItr.hasNext();) {
Line2D requiredLine=reqItr.next();
for(Iterator<Line2D> itr = lines.iterator(); itr.hasNext();) {
Line2D line = itr.next();
if(linesMatch(requiredLine, line)) {
itr.remove();
reqItr.remove();
break;
}
}
}
for(Line2D allowedLine : allowed) {
for(Iterator<Line2D> itr = lines.iterator(); itr.hasNext();) {
Line2D line = itr.next();
if(linesMatch(allowedLine, line)) {
itr.remove();
break;
}
}
}
if(!required.isEmpty() || !lines.isEmpty()) {
StringBuffer msg = new StringBuffer();
msg.append("Missing lines:\n");
formatLines(msg, required);
msg.append("Extra lines:\n");
formatLines(msg, lines);
Assert.fail(msg.toString());
}
}
private void formatLines(StringBuffer msg, List<Line2D> lines) {
for(Line2D line : lines) {
msg.append("(");
msg.append(line.getX1());
msg.append(", ");
msg.append(line.getY1());
msg.append(") - (");
msg.append(line.getX2());
msg.append(", ");
msg.append(line.getY2());
msg.append(")\n");
}
}
private boolean pointsMatch(double x1, double y1, double x2, double y2) {
return Math.abs(x1 - x2) < error && Math.abs(y1 - y2) < error;
}
private boolean linesMatch(Line2D requiredLine, Line2D line) {
double x1 = requiredLine.getX1();
double y1 = requiredLine.getY1();
double x2 = requiredLine.getX2();
double y2 = requiredLine.getY2();
double lineX1 = line.getX1();
double lineY1 = line.getY1();
double lineX2 = line.getX2();
double lineY2 = line.getY2();
// Check forward and backward
if(pointsMatch(lineX1, lineY1, x1, y1) && pointsMatch(lineX2, lineY2, x2, y2)) {
return true;
}
if(pointsMatch(lineX1, lineY1, x2, y2) && pointsMatch(lineX2, lineY2, x1, y1)) {
return true;
}
return false;
}
}