/*-
*******************************************************************************
* Copyright (c) 2011, 2014 Diamond Light Source Ltd.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Peter Chang - initial API and implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.dawnsci.analysis.dataset.roi;
import java.io.Serializable;
import java.util.Set;
import org.eclipse.dawnsci.analysis.api.roi.IPolylineROI;
/**
* Class for a polygonal ROI is a closed form of a polyline ROI (end point is implicitly the start point)
*/
public class PolygonalROI extends PolylineROI implements Serializable {
public PolygonalROI() {
super();
}
public PolygonalROI(IPolylineROI poly) {
PolylineROI c = poly instanceof PolylineROI ? ((PolylineROI) poly).copy() : new PolylineROI(poly);
name = c.name;
spt = c.spt;
plot = c.plot;
pts = c.pts;
}
public PolygonalROI(double[] start) {
super(start);
}
/**
* @return number of sides (or points)
*/
@Override
public int getSides() {
return super.getNumberOfPoints();
}
@Override
public PolygonalROI copy() {
PolygonalROI c = new PolygonalROI(spt.clone());
for (int i = 1, imax = pts.size(); i < imax; i++)
c.insertPoint(pts.get(i).copy());
c.name = name;
c.plot = plot;
return c;
}
@Override
public boolean containsPoint(double x, double y) {
if (super.containsPoint(x, y))
return true;
// after Eric Haines' non-division version of Stuart MacMartin's strategy
int imax = pts.size();
double[] pa = pts.get(imax - 1).getPointRef();
boolean fya = pa[1] >= y; // segment crossing flag
boolean f = false; // inside flag
for (int i = 0; i < imax; i++) {
double[] pb = pts.get(i).getPointRef();
boolean fyb = pb[1] >= y;
if (fya != fyb) { // test if in y-range of segment
boolean fi = (pb[1] - y) * (pa[0] - pb[0]) >= (pb[0] - x) * (pa[1] - pb[1]);
if (fi == fyb) { // test if intersect
f = !f;
}
}
pa = pb;
fya = fyb;
}
return f;
}
@Override
public boolean isNearOutline(double x, double y, double distance) {
if (super.isNearOutline(x, y, distance))
return true;
int imax = pts.size();
if (imax < 2)
return true;
// test last segment that completes circuit
double[] p = pts.get(imax - 1).getPointRef();
double ox = p[0];
double oy = p[1];
p = pts.get(0).getPointRef();
return ROIUtils.isNearSegment(p[0] - ox, p[1] - oy, x - ox, y - oy, distance);
}
@Override
public double[] findHorizontalIntersections(double y) {
if (!intersectHorizontal(y))
return null;
int n = pts.size() - 1;
if (n == 0) {
return pts.get(0).findHorizontalIntersections(y);
}
Set<Double> values = calculateHorizontalIntersections(y);
double[] xi;
double[] pta = pts.get(n).getPointRef();
double[] ptb = spt;
xi = ROIUtils.findYIntersection(pta, ptb, y);
if (xi != null) {
for (double x : xi)
values.add(x);
}
xi = new double[values.size()];
int i = 0;
for (Double d : values) {
xi[i++] = d;
}
return xi;
}
}