package org.lemsml.jlems.viz.plot; public final class Geom { private Geom() { } public static boolean pointIsInside(double[] xb, double[] yb, int x, int y) { return pointIsInside(xb, yb, (double)x, (double)y); } public static boolean pointIsInside(double[] xb, double[] yb, double x, double y) { int n = xb.length; int iwn = 0; for (int i = 0; i < n; i++) { int idir = 0; int p = (i + 1) % n; if (yb[i] <= y && yb[p] > y) { idir = 1; } if (yb[i] > y && yb[p] <= y) { idir = -1; } if (idir != 0) { double f = (y - yb[i]) / (yb[p] - yb[i]); double xc = f * xb[p] + (1. - f) * xb[i]; int isid = (xc > x ? 1 : -1); iwn += isid * idir; } } return (iwn != 0); } public static double[][] makeLineBoundary(double[] xpts, double[] ypts) { int np = xpts.length; double[][] ret = new double[2][4 + 3 * (np - 2)]; double[] xret = ret[0]; double[] yret = ret[1]; int nr = xret.length - 1; int ic = 0; int iac = 0; double f = 0.15; for (int i = 0; i < np; i++) { int ifa = i - 1; if (ifa < 0) { ifa = 0; } int ifb = i + 1; if (ifb >= np - 1) { ifb = np - 1; } double dxa = xpts[ifa] - xpts[ifa + 1]; double dya = ypts[ifa] - ypts[ifa + 1]; double dxb = xpts[ifb] - xpts[ifb - 1]; double dyb = ypts[ifb] - ypts[ifb - 1]; double la = Math.sqrt(dxa * dxa + dya * dya) + 1.e-8; double lb = Math.sqrt(dxb * dxb + dyb * dyb) + 2.e-8; // ADHOC double vxa = dxa / la; double vya = dya / la; double vxb = dxb / lb; double vyb = dyb / lb; double cosTheta = vxa * vxb + vya * vyb; double sinHalfTheta = Math.sqrt((1. - cosTheta) / 2.); double vecp = vxa * vyb - vxb * vya; double vxo = vya - vyb; double vyo = -vxa + vxb; double lo = Math.sqrt(vxo * vxo + vyo * vyo); vxo /= lo; vyo /= lo; double fe = 1 / (sinHalfTheta); fe *= f; double xc = xpts[i]; double yc = ypts[i]; if (i == 0 || i == np - 1) { xret[ic] = xc + fe * vxo; yret[ic] = yc + fe * vyo; ic += 1; xret[nr - iac] = xc - fe * vxo; yret[nr - iac] = yc - fe * vyo; iac += 1; } else if (vecp < 0) { xret[ic] = xc + fe * vxo; yret[ic] = yc + fe * vyo; ic += 1; xret[nr - iac] =xc - f * vya; yret[nr - iac] = yc + f * vxa; iac += 1; xret[nr - iac] = xc + f * vyb; yret[nr - iac] = yc - f * vxb; iac += 1; } else { xret[ic] = xc + f * vya; yret[ic] = yc - f * vxa; ic += 1; xret[ic] = xc - f * vyb; yret[ic] = yc + f * vxb; ic += 1; xret[nr - iac] = xc - fe * vxo; yret[nr - iac] = yc - fe * vyo; iac += 1; } } return ret; } public static Position centerOfGravity(double[] xpts, double[] ypts) { int np = xpts.length; double xc = 0.; double yc = 0; for (int i = 0; i < np; i++) { xc += xpts[i]; yc += ypts[i]; } xc /= np; yc /= np; return new Position(xc, yc); } public static double distanceBetween(Position a, Position b) { double dx = b.getX() - a.getX(); double dy = b.getY() - a.getY(); double ret = Math.sqrt(dx*dx + dy*dy); return ret; } // TODO - smarter (eg pickable region code) public static double[][] innerPolygon(double[] x, double[] y) { int n = x.length; double[][] ret = new double[2][n]; double cx = 0.; double cy = 0.; for (int i = 0; i < n; i++) { cx += x[i]; cy += y[i]; } cx /= n; cy /= n; for (int i = 0; i < n; i++) { ret[0][i] = cx + 0.9 * (x[i] - cx); ret[1][i] = cy + 0.9 * (y[i] - cy); } return ret; } }