コード例 #1
0
  private void doMovement() {
    Point2D actualPosition = new Point2D.Double(getX(), getY());

    if (nextPosition == null) nextPosition = actualPosition;

    if (corner) {
      goToCorner();
      out.println("corner");
    } else if (nextPosition == null
        || nextPosition.equals(actualPosition)
        || nextPosition.distance(actualPosition) < 15) {
      try {
        // PositionFinder f = new PositionFinder(enemies, this);
        // nextPosition = f.generateRandomPoint();
        // nextPosition = f.findBestPointInRangeWithRandomOffset(500);
        gotoPointandSmooth();
      } catch (Exception e) {
        System.out.println(e);
      }

    } else {
      gotoPointandSmooth();
    }
    lastPosition = actualPosition;
  }
コード例 #2
0
  /**
   * Constructs a <code>LinearGradientPaint</code>.
   *
   * @param start the gradient axis start <code>Point</code> in user space
   * @param end the gradient axis end <code>Point</code> in user space
   * @param fractions numbers ranging from 0.0 to 1.0 specifying the distribution of colors along
   *     the gradient
   * @param colors array of colors corresponding to each fractional value
   * @param cycleMethod either NO_CYCLE, REFLECT, or REPEAT
   * @param colorSpace which colorspace to use for interpolation, either SRGB or LINEAR_RGB
   * @param gradientTransform transform to apply to the gradient
   * @throws NullPointerException if one of the points is null, or gradientTransform is null
   * @throws IllegalArgumentException if start and end points are the same points, or if
   *     fractions.length != colors.length, or if colors is less than 2 in size.
   */
  public LinearGradientPaint(
      Point2D start,
      Point2D end,
      float[] fractions,
      Color[] colors,
      CycleMethodEnum cycleMethod,
      ColorSpaceEnum colorSpace,
      AffineTransform gradientTransform) {
    super(fractions, colors, cycleMethod, colorSpace, gradientTransform);

    //
    // Check input parameters
    //
    if (start == null || end == null) {
      throw new NullPointerException("Start and end points must be" + "non-null");
    }

    if (start.equals(end)) {
      throw new IllegalArgumentException("Start point cannot equal" + "endpoint");
    }

    // copy the points...
    this.start = (Point2D) start.clone();

    this.end = (Point2D) end.clone();
  }
コード例 #3
0
  /**
   * Set the data for a 2D position conversion.
   *
   * @param pos the position, either in local cartesian coordinates or longitude/latitude
   * @param outputLonLat <code>true</code> if the coordinates should be converted to
   *     latitude/longitude
   */
  public void setPositionToConvert(Point2D pos, boolean outputLonLat) {
    if (destLonLat != outputLonLat || roadmapPos != null || pos.equals(cartesianPos)) setObsolete();

    cartesianPos = pos;
    srcLonLat = !outputLonLat;
    roadmapPos = null;
    destLonLat = outputLonLat;
  }
コード例 #4
0
ファイル: Polygon2D.java プロジェクト: 4ment/beast-mcmc
  public boolean bordersPoint2D(Point2D Point2D) {
    boolean borders = false;

    Iterator<Point2D> it = point2Ds.iterator();
    for (int i = 0; i < length; i++) {
      Point2D point = it.next();
      if (point.equals(Point2D)) {
        borders = true;
      }
    }
    return borders;
  }
コード例 #5
0
ファイル: Polygon2D.java プロジェクト: 4ment/beast-mcmc
 public void addPoint2D(Point2D point2D) {
   if (point2Ds.size() == 0) point2Ds.add(point2D);
   else if (point2Ds.size() == 1) {
     point2Ds.add(point2D);
     point2Ds.add(point2Ds.get(0));
   } else {
     Point2D last = point2Ds.remove(point2Ds.size() - 1);
     point2Ds.add(point2D);
     if (!last.equals(point2D)) point2Ds.add(last);
   }
   convertPointsToArrays();
   length = point2Ds.size() - 1;
 }
コード例 #6
0
  @Override
  public Paint createCustomLcdBackgroundPaint(final Color[] LCD_COLORS) {
    final Point2D FOREGROUND_START = new Point2D.Double(0.0, 1.0);
    final Point2D FOREGROUND_STOP = new Point2D.Double(0.0, getHeight() - 1);
    if (FOREGROUND_START.equals(FOREGROUND_STOP)) {
      FOREGROUND_STOP.setLocation(0.0, FOREGROUND_START.getY() + 1);
    }

    final float[] FOREGROUND_FRACTIONS = {0.0f, 0.03f, 0.49f, 0.5f, 1.0f};

    final Color[] FOREGROUND_COLORS = {
      LCD_COLORS[0], LCD_COLORS[1], LCD_COLORS[2], LCD_COLORS[3], LCD_COLORS[4]
    };

    return new LinearGradientPaint(
        FOREGROUND_START, FOREGROUND_STOP, FOREGROUND_FRACTIONS, FOREGROUND_COLORS);
  }
コード例 #7
0
  public OMGraphicList prepare() {
    if (layer != null) {
      // setBuffer(null);
      Projection proj = layer.getProjection();
      if (layer.isProjectionOK(proj)) {
        // set the offsets depending on how much the image moves
        Point2D ul = proj.getUpperLeft();
        if (oldUL != null
            && !oldUL.equals(ul)
            && oldScale == proj.getScale()
            && proj.getClass().equals(oldProjType)) {
          Point2D currentPoint = proj.forward(ul);
          Point2D oldPoint = proj.forward(oldUL);

          offset.setLocation(
              oldPoint.getX() - currentPoint.getX(), oldPoint.getY() - currentPoint.getY());

          layer.repaint();
        }

        oldUL = ul;
        oldProjType = ((Proj) proj).getClass();
        oldScale = proj.getScale();

        OMGraphicList list = layer.prepare();
        setBuffer(createAndPaintImageBuffer(list));

        return list;
      } else {
        logger.warning("NULL projection, can't do anything.");
      }
    } else {
      logger.warning("NULL layer, can't do anything.");
    }
    return null;
  }
コード例 #8
0
  public static ArrayList<Point2D> computeHull(ArrayList<Point2D> points, boolean colinear) {
    HashSet<Point2D> onHull = new HashSet<Point2D>();
    // sort points based on x, then y
    Collections.sort(points, new JarvisMarch.XComparator());

    ArrayList<Point2D> chull = new ArrayList<Point2D>();
    chull.add(points.get(0));
    onHull.add(points.get(0));

    boolean completeHull = false;
    ArrayList<Point2D> previousAdded = new ArrayList<Point2D>(),
        beforePreviouslyAdded = new ArrayList<Point2D>();
    previousAdded.add(points.get(0));
    while (!completeHull) {
      Point2D cp = chull.get(chull.size() - 1);

      double lastAngle = Math.PI / 2;
      // if we have a previous point, computer the previous angle
      if (chull.size() > 1) lastAngle = angle(chull.get(chull.size() - 2), cp);
      if (lastAngle == Math.PI) lastAngle = 0;

      ArrayList<Point2D> smallest = new ArrayList<Point2D>();
      double smallestAngle = Double.POSITIVE_INFINITY;
      for (Point2D p : points) {
        if (p.equals(cp)) continue;
        boolean inline = false;
        // if it's an about face turn, skip it
        for (Point2D pre : beforePreviouslyAdded) if (p.equals(pre)) inline = true;
        if (inline) continue;

        double angle = angle(cp, p) - lastAngle;

        // if it's an about face turn, skip it
        if (angle == -Math.PI || angle == Math.PI) continue;
        if (angle > Math.PI) angle -= 2 * Math.PI;
        if (angle < -Math.PI) angle += 2 * Math.PI;
        angle = -angle;

        if (angle < smallestAngle) {
          smallest.clear();
          smallest.add(p);
          smallestAngle = angle;
        } else if (angle == smallestAngle) {
          smallest.add(p);
        }
      }

      // sort smallest based on distance to cp
      Collections.sort(points, new JarvisMarch.DistanceComparator(cp));

      beforePreviouslyAdded = previousAdded;
      previousAdded = new ArrayList<Point2D>();
      if (colinear) {
        for (Point2D p : smallest) {
          if (onHull.contains(p)) {
            completeHull = true;
            break;
          } else {
            previousAdded.add(p);
            onHull.add(p);
            chull.add(p);
          }
        }
      } else {
        Point2D p = smallest.get(smallest.size() - 1);
        if (onHull.contains(p)) {
          completeHull = true;
        } else {
          previousAdded.add(p);
          onHull.add(p);
          chull.add(p);
        }
      }
    }
    return chull;
  }
コード例 #9
0
  // <editor-fold defaultstate="collapsed" desc="Image related">
  private BufferedImage create_LCD_Image(final int WIDTH, final int HEIGHT) {
    if (WIDTH <= 0 || HEIGHT <= 0) {
      return null;
    }

    final BufferedImage IMAGE = UTIL.createImage(WIDTH, HEIGHT, Transparency.TRANSLUCENT);
    final Graphics2D G2 = IMAGE.createGraphics();
    G2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    G2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE);
    G2.setRenderingHint(
        RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
    final int IMAGE_WIDTH = IMAGE.getWidth();
    final int IMAGE_HEIGHT = IMAGE.getHeight();

    // Background rectangle
    final Point2D BACKGROUND_START = new Point2D.Double(0.0, 0.0);
    final Point2D BACKGROUND_STOP = new Point2D.Double(0.0, IMAGE_HEIGHT);
    if (BACKGROUND_START.equals(BACKGROUND_STOP)) {
      BACKGROUND_STOP.setLocation(0.0, BACKGROUND_START.getY() + 1);
    }

    final float[] BACKGROUND_FRACTIONS = {0.0f, 0.08f, 0.92f, 1.0f};

    final Color[] BACKGROUND_COLORS = {
      new Color(0.4f, 0.4f, 0.4f, 1.0f),
      new Color(0.5f, 0.5f, 0.5f, 1.0f),
      new Color(0.5f, 0.5f, 0.5f, 1.0f),
      new Color(0.9f, 0.9f, 0.9f, 1.0f)
    };

    final LinearGradientPaint BACKGROUND_GRADIENT =
        new LinearGradientPaint(
            BACKGROUND_START, BACKGROUND_STOP, BACKGROUND_FRACTIONS, BACKGROUND_COLORS);
    // final double BACKGROUND_CORNER_RADIUS = WIDTH * 0.09375;
    final double BACKGROUND_CORNER_RADIUS = WIDTH > HEIGHT ? (HEIGHT * 0.095) : (WIDTH * 0.095);
    final java.awt.geom.RoundRectangle2D BACKGROUND =
        new java.awt.geom.RoundRectangle2D.Double(
            0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, BACKGROUND_CORNER_RADIUS, BACKGROUND_CORNER_RADIUS);
    G2.setPaint(BACKGROUND_GRADIENT);
    G2.fill(BACKGROUND);

    // Foreground rectangle
    final Point2D FOREGROUND_START = new Point2D.Double(0.0, 1.0);
    final Point2D FOREGROUND_STOP = new Point2D.Double(0.0, IMAGE_HEIGHT - 1);
    if (FOREGROUND_START.equals(FOREGROUND_STOP)) {
      FOREGROUND_STOP.setLocation(0.0, FOREGROUND_START.getY() + 1);
    }

    final float[] FOREGROUND_FRACTIONS = {0.0f, 0.03f, 0.49f, 0.5f, 1.0f};

    final Color[] FOREGROUND_COLORS = {
      lcdColor.GRADIENT_START_COLOR,
      lcdColor.GRADIENT_FRACTION1_COLOR,
      lcdColor.GRADIENT_FRACTION2_COLOR,
      lcdColor.GRADIENT_FRACTION3_COLOR,
      lcdColor.GRADIENT_STOP_COLOR
    };

    if (lcdColor == LcdColor.CUSTOM) {
      G2.setPaint(customLcdBackground);
    } else {
      final LinearGradientPaint FOREGROUND_GRADIENT =
          new LinearGradientPaint(
              FOREGROUND_START, FOREGROUND_STOP, FOREGROUND_FRACTIONS, FOREGROUND_COLORS);
      G2.setPaint(FOREGROUND_GRADIENT);
    }
    final double FOREGROUND_CORNER_RADIUS = BACKGROUND.getArcWidth() - 1;
    final java.awt.geom.RoundRectangle2D FOREGROUND =
        new java.awt.geom.RoundRectangle2D.Double(
            1,
            1,
            IMAGE_WIDTH - 2,
            IMAGE_HEIGHT - 2,
            FOREGROUND_CORNER_RADIUS,
            FOREGROUND_CORNER_RADIUS);
    G2.fill(FOREGROUND);

    G2.dispose();

    return IMAGE;
  }
コード例 #10
0
ファイル: ChangePad.java プロジェクト: BioTapestry/Production
    /**
     * ************************************************************************* * * Do the
     * relocation
     */
    private DialogAndInProcessCmd stepRelocateModuleSource() {
      String currentOverlay = rcxT_.oso.getCurrentOverlay();

      //
      // Go and find if we intersect anything.
      //

      Intersection intersected =
          appState_
              .getGenomePresentation()
              .intersectANetModuleElement(
                  x, y, rcxT_, GenomePresentation.NetModuleIntersect.NET_MODULE_LINK_PAD);
      //
      // If we don't intersect anything, or the correct thing, we need to bag it.
      //

      if (intersected == null) {
        return (new DialogAndInProcessCmd(ServerControlFlowHarness.ClickResult.REJECT, this));
      }
      String id = intersected.getObjectID();
      NetOverlayOwner owner =
          rcxT_.getGenomeSource().getOverlayOwnerFromGenomeKey(rcxT_.getGenomeID());
      NetworkOverlay novr = owner.getNetworkOverlay(currentOverlay);
      NetModule nm = novr.getModule(id);
      if (nm == null) {
        return (new DialogAndInProcessCmd(ServerControlFlowHarness.ClickResult.REJECT, this));
      }

      NetModuleFree.IntersectionExtraInfo ei =
          (NetModuleFree.IntersectionExtraInfo) intersected.getSubID();
      if (ei == null) {
        return (new DialogAndInProcessCmd(ServerControlFlowHarness.ClickResult.REJECT, this));
      }
      if (ei.type != NetModuleFree.IntersectionExtraInfo.IS_PAD) {
        return (new DialogAndInProcessCmd(ServerControlFlowHarness.ClickResult.REJECT, this));
      }

      // New point:

      Point2D padPt = (Point2D) ei.intersectPt.clone();
      UiUtil.forceToGrid(padPt, UiUtil.GRID_SIZE);
      Vector2D toSide = ei.padNorm.scaled(-1.0);

      String treeID = intersect.getObjectID();
      NetModuleLinkageProperties nmlp =
          rcxT_
              .getLayout()
              .getNetOverlayProperties(currentOverlay)
              .getNetModuleLinkagePropertiesFromTreeID(treeID);

      LinkSegmentID[] linkIDs = intersect.segmentIDsFromIntersect();
      Set<String> throughSeg = nmlp.resolveLinkagesThroughSegment(linkIDs[0]);
      int totalLinks = nmlp.getLinkageList().size();
      if (throughSeg.size() != totalLinks) {
        return (new DialogAndInProcessCmd(ServerControlFlowHarness.ClickResult.REJECT, this));
      }
      String myLinkId = throughSeg.iterator().next();
      NetModuleLinkage myLink = novr.getLinkage(myLinkId);
      if (!myLink.getSource().equals(id)) {
        return (new DialogAndInProcessCmd(ServerControlFlowHarness.ClickResult.REJECT, this));
      }

      //
      // Pretty lax about links in and out of modules.  Only restriction is that
      // link cannot end on the same pad as it starts (avoids zero-length links!)
      //

      Iterator<String> tsit = throughSeg.iterator();
      while (tsit.hasNext()) {
        String linkID = tsit.next();
        if (!novr.linkIsFeedback(linkID)) {
          continue;
        }
        Point2D targPt = nmlp.getTargetEnd(linkID, 0.0);
        if (padPt.equals(targPt)) {
          return (new DialogAndInProcessCmd(ServerControlFlowHarness.ClickResult.REJECT, this));
        }
      }

      //
      // Undo/Redo support
      //

      UndoSupport support = new UndoSupport(appState_, "undo.changeModuleLinkSource");

      //
      // We reject unless the target we are intersecting matches the
      // link we are trying to relocate.
      //

      Layout.PropChange lpc =
          rcxT_.getLayout().changeNetModuleSource(currentOverlay, treeID, padPt, toSide, rcxT_);
      if (lpc != null) {
        PropChangeCmd mov = new PropChangeCmd(appState_, rcxT_, lpc);
        support.addEdit(mov);
        support.addEvent(
            new LayoutChangeEvent(rcxT_.getLayoutID(), LayoutChangeEvent.UNSPECIFIED_CHANGE));
        support.finish();
        return (new DialogAndInProcessCmd(ServerControlFlowHarness.ClickResult.ACCEPT, this));
      } else {
        return (new DialogAndInProcessCmd(ServerControlFlowHarness.ClickResult.REJECT, this));
      }
    }
コード例 #11
0
 @Override
 public boolean equals(Object other) {
   if (this == other) return true;
   if (!(other instanceof Vertex)) return false;
   return myLocation.equals(((Vertex) other).myLocation);
 }
コード例 #12
0
ファイル: DangerFinder.java プロジェクト: benbardin/isnork
  public Direction findSafestDirection(
      Point2D myPosition,
      Point2D myPreviousPosition,
      Set<Observation> whatYouSee,
      Direction preferredDirection,
      boolean shouldReturnToBoat) {
    updateCoordinates(myPosition, myPreviousPosition, whatYouSee);
    findDanger();

    // if we are at boat, reset the tracked helper state
    if (myPosition.equals(new Point2D.Double(0, 0))) {
      backtrackLocations.clear();
    }

    // logger.debug("in find safest direction");
    double minDanger = Integer.MAX_VALUE;

    ArrayList<DirectionAndDanger> directionsSafeToDangerous = new ArrayList<DirectionAndDanger>();
    ArrayList<Direction> safestDirections = new ArrayList<Direction>();

    // First, find the minimum danger. Create an equivalence class of directions sharing this value.
    for (Direction d : Direction.values()) {
      double curDanger;
      if (directionDanger.containsKey(d)) {
        curDanger = Math.abs(directionDanger.get(d));
        // logger.trace("directionDanger.get("+d+") = "+curDanger);
      } else {
        curDanger = 0;
      }

      Point2D nextPosition =
          new Point2D.Double(myPosition.getX() + d.getDx(), myPosition.getY() + d.getDy());
      // Do not consider directions that take us too close to the walls
      if (ourBoard.isNearBoundary(
          nextPosition, Math.max(WALL_MAX_DISTANCE, (double) r / Math.sqrt(2.0) - 1.0))) {
        continue;
      }

      // Do not consider directions that put us in backtracked locations
      // i.e. we are trying to go around danger, so don't go backwards
      if (backtrackLocations.contains(nextPosition)) {
        continue;
      }

      //			logger.debug("current danger in direction " + d + ":" + curDanger);

      if (curDanger < minDanger) {
        safestDirections.clear();
        safestDirections.add(d);
        // logger.debug("Min Danger so far in Direction: " + d);

        minDanger = curDanger;
      } else if (curDanger == minDanger) {
        safestDirections.add(d);
      }

      directionsSafeToDangerous.add(new DirectionAndDanger(d, curDanger));
    }

    // Sort from least dangerous to most dangerous
    Collections.sort(directionsSafeToDangerous);

    mySafestDirection = null;
    if (shouldReturnToBoat) {
      // If returning to boat, always head in preferredDirection if it is among the safest
      if (preferredDirection == null) {
        mySafestDirection = null;
      } else if (safestDirections.contains(preferredDirection)) {
        mySafestDirection = preferredDirection;
      } else {
        // Prioritize the directions closer to the safest
        // And de-prioritize the previous location
        Direction previousDirection = OurBoard.getDirectionTowards(myPosition, myPreviousPosition);
        for (Direction d : DirectionUtil.getClosestDirections(preferredDirection)) {
          if (safestDirections.contains(d) && !d.equals(previousDirection)) {
            mySafestDirection = d;
            break;
          }
        }
        // We excluded previous direction in above loop.
        // If mySafestDirection == null, that means safest is previous direction.
        if (mySafestDirection == null) {
          if (!directionsSafeToDangerous.isEmpty()) {
            mySafestDirection = directionsSafeToDangerous.get(0).getDirection();
          } else {
            // just go back towards boat...
            mySafestDirection = OurBoard.getDirectionTowards(myPosition, new Point2D.Double(0, 0));
          }
        }

        // we did not pick preferredDirection, so next time make sure we don't come back
        backtrackLocations.add(myPreviousPosition);
      }
    } else {
      // 80% of the time, continue in preferredDirection if it is among the safest

      if (preferredDirection != null
          && safestDirections.contains(preferredDirection)
          && random.nextDouble() <= 0.80) {

        mySafestDirection = preferredDirection;
      } else {
        List<Direction> closestDirections = DirectionUtil.getClosestDirections(preferredDirection);
        // Try to pick the safest direction out of [forward-left, forward-right, left, right]
        List<Direction> firstTwo = closestDirections.subList(0, 2);
        List<Direction> nextTwo = closestDirections.subList(2, 4);
        // Look at the top 3 safest directions
        if (directionsSafeToDangerous.size() >= 3) {
          for (DirectionAndDanger dad : directionsSafeToDangerous.subList(0, 3)) {
            // skip the one going backwards
            if (dad.equals(OurBoard.getDirectionTowards(myPosition, myPreviousPosition))) {
              continue;
            }
            if (firstTwo.contains(dad.getDirection())) {
              mySafestDirection = dad.getDirection();
              break;
            } else if (nextTwo.contains(dad.getDirection())) {
              mySafestDirection = dad.getDirection();
              break;
            }
          }
        }
        if (mySafestDirection == null) {
          if (!safestDirections.isEmpty()) {
            Collections.shuffle(safestDirections);
            mySafestDirection = safestDirections.get(0);
          } else {
            // no safe directions?? return to boat then...
            mySafestDirection = OurBoard.getDirectionTowards(myPosition, new Point2D.Double(0, 0));
          }
        }

        // we did not pick preferredDirection, so next time make sure we don't come back
        backtrackLocations.add(myPreviousPosition);
      }
    }

    // if we end up going in preferredDirection, no need to avoid backtrack areas anymore
    backtrackLocations.clear();

    // logger.debug("Safest direction: " + mySafestDirection + " (from among " +
    // safestDirections.toString() + ")");
    return mySafestDirection;
  }
コード例 #13
0
 /**
  * Gets a list of Point2D objects that lie within pixels in a rectangle and along a line.
  *
  * @param searchRect the rectangle
  * @param x0 the x-component of a point on the line
  * @param y0 the y-component of a point on the line
  * @param slope the slope of the line
  * @return a list of Point2D
  */
 public ArrayList<Point2D> getSearchPoints(
     Rectangle searchRect, double x0, double y0, double theta) {
   double slope = -Math.tan(theta);
   // create line to search along
   Line2D line = new Line2D.Double();
   if (slope > LARGE_NUMBER) {
     line.setLine(x0, y0, x0, y0 + 1);
   } else if (slope < 1 / LARGE_NUMBER) {
     line.setLine(x0, y0, x0 + 1, y0);
   } else {
     line.setLine(x0, y0, x0 + 1, y0 + slope);
   }
   // create intersection points (to set line ends)
   Point2D p1 = new Point2D.Double();
   Point2D p2 = new Point2D.Double(Double.NaN, Double.NaN);
   Point2D p = p1;
   boolean foundBoth = false;
   double d = searchRect.x;
   Object[] data = getDistanceAndPointAtX(line, d);
   if (data != null) {
     p.setLocation((Point2D) data[1]);
     if (p.getY() >= searchRect.y && p.getY() <= searchRect.y + searchRect.height) {
       // line end is left edge
       p = p2;
     }
   }
   d += searchRect.width;
   data = getDistanceAndPointAtX(line, d);
   if (data != null) {
     p.setLocation((Point2D) data[1]);
     if (p.getY() >= searchRect.y && p.getY() <= searchRect.y + searchRect.height) {
       // line end is right edge
       if (p == p1) p = p2;
       else foundBoth = true;
     }
   }
   if (!foundBoth) {
     d = searchRect.y;
     data = getDistanceAndPointAtY(line, d);
     if (data != null) {
       p.setLocation((Point2D) data[1]);
       if (p.getX() >= searchRect.x && p.getX() <= searchRect.x + searchRect.width) {
         // line end is top edge
         if (p == p1) p = p2;
         else if (!p1.equals(p2)) foundBoth = true;
       }
     }
   }
   if (!foundBoth) {
     d += searchRect.height;
     data = getDistanceAndPointAtY(line, d);
     if (data != null) {
       p.setLocation((Point2D) data[1]);
       if (p.getX() >= searchRect.x && p.getX() <= searchRect.x + searchRect.width) {
         // line end is bottom edge
         if (p == p2 && !p1.equals(p2)) foundBoth = true;
       }
     }
   }
   // if both line ends have been found, use line to find pixels to search
   if (foundBoth) {
     // set line ends to intersections
     line.setLine(p1, p2);
     if (p1.getX() > p2.getX()) {
       line.setLine(p2, p1);
     }
     // find pixel intersections that fall along the line
     int xMin = (int) Math.ceil(Math.min(p1.getX(), p2.getX()));
     int xMax = (int) Math.floor(Math.max(p1.getX(), p2.getX()));
     int yMin = (int) Math.ceil(Math.min(p1.getY(), p2.getY()));
     int yMax = (int) Math.floor(Math.max(p1.getY(), p2.getY()));
     // collect intersections in TreeMap sorted by position along line
     TreeMap<Double, Point2D> intersections = new TreeMap<Double, Point2D>();
     for (int x = xMin; x <= xMax; x++) {
       Object[] next = getDistanceAndPointAtX(line, x);
       intersections.put((Double) next[0], (Point2D) next[1]);
     }
     for (int y = yMin; y <= yMax; y++) {
       Object[] next = getDistanceAndPointAtY(line, y);
       intersections.put((Double) next[0], (Point2D) next[1]);
     }
     p = null;
     // create array of search points that are midway between intersections
     ArrayList<Point2D> searchPts = new ArrayList<Point2D>();
     for (Double key : intersections.keySet()) {
       Point2D next = intersections.get(key);
       if (p != null) {
         double x = (p.getX() + next.getX()) / 2 - searchRect.x;
         double y = (p.getY() + next.getY()) / 2 - searchRect.y;
         p.setLocation(x, y);
         searchPts.add(p);
       }
       p = next;
     }
     return searchPts;
   }
   return null;
 }