コード例 #1
0
 public boolean contains(int x, int y) {
   // If the button has changed size,
   // make a new shape object.
   if (shape == null || !shape.getBounds().equals(getBounds())) {
     shape = new Ellipse2D.Float(0, 0, getWidth(), getHeight());
   }
   return shape.contains(x, y);
 }
コード例 #2
0
ファイル: Tile.java プロジェクト: kreativekorp/powerpaint
 @Override
 public void clear(int x, int y, int width, int height, Shape clip) {
   if (clip == null || clip.contains(x, y, width, height)) {
     this.clear(x, y, width, height);
   } else {
     int[] oldRGB = new int[width * height];
     this.getRGB(x, y, width, height, oldRGB, 0, width);
     for (int oy = 0, ay = y, iy = 0; iy < height; oy += width, ay++, iy++) {
       for (int ox = oy, ax = x, ix = 0; ix < width; ox++, ax++, ix++) {
         if (clip.contains(ax, ay)) oldRGB[ox] = matte;
       }
     }
     this.setRGB(x, y, width, height, oldRGB, 0, width);
   }
 }
コード例 #3
0
ファイル: JImageObject.java プロジェクト: hashrock/JDrafter
 @Override
 public int hitByPoint(JEnvironment env, JRequest req, Point2D point) {
   if (isLocked() || !isVisible()) return JRequest.HIT_NON;
   Shape s = getShape();
   if (s.contains(point)) {
     req.hitObjects.add(this);
     return (req.hitResult = JRequest.HIT_OBJECT);
   }
   double radius = JEnvironment.PATH_SELECTOR_SIZE / 2 / env.getToScreenRatio();
   Rectangle2D.Double sr = new Rectangle2D.Double(0, 0, radius * 2, radius * 2);
   PathIterator path = s.getPathIterator(null);
   double[] coords = new double[6];
   while (!path.isDone()) {
     int type = path.currentSegment(coords);
     if (type == path.SEG_LINETO || type == path.SEG_MOVETO) {
       sr.x = coords[0] - radius;
       sr.y = coords[1] - radius;
       if (sr.contains(point)) {
         req.hitObjects.add(this);
         return (req.hitResult = JRequest.HIT_OBJECT);
       }
     }
     path.next();
   }
   return JRequest.HIT_NON;
 }
コード例 #4
0
ファイル: MergeBlockades.java プロジェクト: jpollo/rcrss
 // Morteza2011*****************************************************************
 private static void removeExtraEdges(ArrayList<Edge> edges, Shape shape) {
   for (short i = 0; i < edges.size(); i++) {
     if (shape.contains(edges.get(i).getMidPoint().getX(), edges.get(i).getMidPoint().getY())) {
       edges.remove(i--);
     }
   }
 }
コード例 #5
0
 @Override
 public boolean contains(int x, int y) {
   if (shape == null || !shape.getBounds().equals(getBounds())) {
     shape = new Area(makeStarDesign(5, new Point(50, 50), 50, 30));
   }
   return shape.contains(x, y);
 }
コード例 #6
0
ファイル: TextViewHybrid.java プロジェクト: zukov/Jpicedt
  /**
   * This implementation calls <code>super.hitTest</code> and returns the result if non-null (this
   * should be a HitInfo.Point), then returns a HitInfo.Interior if the mouse-click occured inside
   * the text bound (as defined by text layout)
   *
   * @return a HitInfo corresponding to the given mouse-event
   */
  public HitInfo hitTest(PEMouseEvent e) {

    // from Bitmap:
    if (image != null) {
      if (getBounds().contains(e.getPicPoint())) {
        return new HitInfo.Interior((PicText) element, e);
      }
      return null;
    }

    // from TextLayout:
    if (!getBounds().contains(e.getPicPoint())) return null;

    PicText te = (PicText) element;
    // recompute textlayout b-box, but store it in a temporary field !
    Rectangle2D tb = textLayout.getBounds();
    Shape text_bounds = text2ModelTr.createTransformedShape(tb);
    if (text_bounds.contains(e.getPicPoint())) {
      // [SR:pending] for the hitInfo to be reliable, getPicPoint() should first be transformed by
      //              inverse text2ModelTr ! (especially when rotationAngle != 0)
      TextHitInfo thi =
          textLayout.hitTestChar(
              (float) (e.getPicPoint().x - strx),
              (float) (e.getPicPoint().y - stry)); // guaranteed to return a non-null thi
      return new HitInfo.Text((PicText) element, thi, e);
    }
    // test hit on textlayout's bounding rectangle :
    // else if (bounds.contains(e.getPicPoint())) return new HitInfo.Interior(element,e);
    return null;
  }
コード例 #7
0
  @Override
  public boolean contains(Point2D position) {
    double flatness = 0.01;
    boolean intersect = false;
    PathIterator pit = path.getPathIterator(null, flatness);
    double[] coords = new double[6];
    double lastX = 0, lastY = 0;
    while (!intersect && !pit.isDone()) {
      int type = pit.currentSegment(coords);
      switch (type) {
        case PathIterator.SEG_MOVETO:
          lastX = coords[0];
          lastY = coords[1];
          break;
        case PathIterator.SEG_LINETO:
          BasicStroke stroke = new BasicStroke(10.0f);
          Line2D.Double line = new Line2D.Double(lastX, lastY, coords[0], coords[1]);
          Shape shape = stroke.createStrokedShape(line);
          if (shape.contains(position)) {
            intersect = true;
          }

          lastX = coords[0];
          lastY = coords[1];
      }
      pit.next();
    }
    return intersect;
  }
コード例 #8
0
ファイル: Tile.java プロジェクト: kreativekorp/powerpaint
 @Override
 public void setRGB(
     int x, int y, int width, int height, int[] rgb, int offset, int rowCount, Shape clip) {
   if (clip == null || clip.contains(x, y, width, height)) {
     this.setRGB(x, y, width, height, rgb, offset, rowCount);
   } else {
     int[] oldRGB = new int[width * height];
     this.getRGB(x, y, width, height, oldRGB, 0, width);
     for (int oy = 0, ny = offset, ay = y, iy = 0;
         iy < height;
         oy += width, ny += rowCount, ay++, iy++) {
       for (int ox = oy, nx = ny, ax = x, ix = 0; ix < width; ox++, nx++, ax++, ix++) {
         if (clip.contains(ax, ay)) oldRGB[ox] = rgb[nx];
       }
     }
     this.setRGB(x, y, width, height, oldRGB, 0, width);
   }
 }
コード例 #9
0
  /**
   * Check if teleporting from a location is allowed.
   *
   * @param x x coordinate
   * @param y y coordinate
   * @return <code>true</code> if teleporting to the point is allowed, <code>false</code> otherwise
   */
  public boolean isOutAllowed(int x, int y) {
    for (Shape r : leavingBarriers) {
      if (r.contains(x, y)) {
        return false;
      }
    }

    return true;
  }
コード例 #10
0
 public void selectAllWithin(BaseObject boundary) {
   BaseObject[] list = list();
   for (int i = 0; i < list.length; i++) {
     java.awt.Shape s1 = boundary.getShape();
     java.awt.Shape s2 = list[i].getShape();
     if (s1.contains(s2.getBounds2D())) {
       grab(list[i]);
     }
   }
 }
コード例 #11
0
ファイル: ShapePickSupport.java プロジェクト: RomaKoks/jung
  /**
   * Returns the vertex, if any, whose shape contains (x, y). If (x,y) is contained in more than one
   * vertex's shape, returns the vertex whose center is closest to the pick point.
   *
   * @param layout the layout instance that records the positions for all vertices
   * @param x the x coordinate of the pick point
   * @param y the y coordinate of the pick point
   * @return the vertex whose shape contains (x,y), and whose center is closest to the pick point
   */
  public V getVertex(Layout<V, E> layout, double x, double y) {

    V closest = null;
    double minDistance = Double.MAX_VALUE;
    Point2D ip =
        vv.getRenderContext()
            .getMultiLayerTransformer()
            .inverseTransform(Layer.VIEW, new Point2D.Double(x, y));
    x = ip.getX();
    y = ip.getY();

    while (true) {
      try {
        for (V v : getFilteredVertices(layout)) {

          Shape shape = vv.getRenderContext().getVertexShapeTransformer().apply(v);
          // get the vertex location
          Point2D p = layout.apply(v);
          if (p == null) continue;
          // transform the vertex location to screen coords
          p = vv.getRenderContext().getMultiLayerTransformer().transform(Layer.LAYOUT, p);

          double ox = x - p.getX();
          double oy = y - p.getY();

          if (shape.contains(ox, oy)) {

            if (style == Style.LOWEST) {
              // return the first match
              return v;
            } else if (style == Style.HIGHEST) {
              // will return the last match
              closest = v;
            } else {

              // return the vertex closest to the
              // center of a vertex shape
              Rectangle2D bounds = shape.getBounds2D();
              double dx = bounds.getCenterX() - ox;
              double dy = bounds.getCenterY() - oy;
              double dist = dx * dx + dy * dy;
              if (dist < minDistance) {
                minDistance = dist;
                closest = v;
              }
            }
          }
        }
        break;
      } catch (ConcurrentModificationException cme) {
      }
    }
    return closest;
  }
コード例 #12
0
ファイル: graphPanel.java プロジェクト: TUDelftNAS/graphGEAR
 /**
  * Finds whether a point is within a node
  *
  * @param p point
  * @return node id that the point is in, or -1 if no node contains the point
  */
 public int findNodeClicked(Point p) {
   double xs = (double) (this.getWidth() - b - (nodes.get(0).r * nodeScaling));
   double ys = (double) (this.getHeight() - b - (nodes.get(0).r * nodeScaling) - noticeBorder);
   for (drawNode N : nodes.values()) {
     Shape S = new Ellipse2D.Double(N.x * xs, N.y * ys, N.r * nodeScaling, N.r * nodeScaling);
     if (S.contains(p)) {
       return N.id;
     }
   }
   return -1;
 }
コード例 #13
0
ファイル: Manager.java プロジェクト: Tadimsky/vooga
 /**
  * Selects all the entities in provided rectangle. Allows a user to drag around the desired
  * entities.
  *
  * @param area The area to select the entities in.
  */
 public void select(Shape area) {
   deselectAll();
   boolean multi = myMultiSelect;
   setMultiSelect(true);
   for (InteractiveEntity ie : myEntities) {
     if (area.intersects(ie.getBounds()) || area.contains(ie.getBounds())) {
       select(ie);
     }
   }
   setMultiSelect(multi);
 }
コード例 #14
0
 /*
  * The magnetic potential of an atom is always zero, because magnetic force does not do any work. But for a dipole
  * moment, it is not zero.
  *
  * FIXME: I didn't find a closed-form solution for an electric dipole's magnetic potential.
  */
 double getPotential(Particle p, float time) {
   if (bounds != null && !bounds.contains(p.getRx(), p.getRy())) return 0;
   double poten = 0.0;
   if (p instanceof GayBerneParticle) {
     GayBerneParticle gb = (GayBerneParticle) p;
     if (Math.abs(gb.dipoleMoment) > 0) {
       double temp = Math.sin(gb.theta) * gb.vx - Math.cos(gb.theta) * gb.vy;
       if (o == OUTWARD) temp = -temp;
       poten = gb.dipoleMoment * b * temp;
     }
   }
   return poten;
 }
コード例 #15
0
 void dyn(Particle p) {
   if (bounds != null && !bounds.contains(p.getRx(), p.getRy())) return;
   double temp = Math.abs(b) * p.charge * MDModel.GF_CONVERSION_CONSTANT / p.getMass();
   if (o == OUTWARD) temp = -temp;
   p.fx += temp * p.vy;
   p.fy -= temp * p.vx;
   if (p instanceof GayBerneParticle) {
     GayBerneParticle gb = (GayBerneParticle) p;
     if (Math.abs(gb.dipoleMoment) > 0) {
       temp = Math.cos(gb.theta) * gb.vx + Math.sin(gb.theta) * gb.vy;
       if (o == OUTWARD) temp = -temp;
       gb.tau -= gb.dipoleMoment * temp * b / gb.inertia * MDModel.GF_CONVERSION_CONSTANT;
     }
   }
 }
コード例 #16
0
  @Override
  public void draw(
      Graphics2D g2d,
      ComponentState componentState,
      boolean outlineMode,
      Project project,
      IDrawingObserver drawingObserver) {
    Shape clip = g2d.getClip();
    if (checkPointsClipped(clip)
        && !clip.contains(firstPoint.x, secondPoint.y)
        && !clip.contains(secondPoint.x, firstPoint.y)) {
      return;
    }
    super.draw(g2d, componentState, outlineMode, project, drawingObserver);
    if (componentState != ComponentState.DRAGGING) {
      if (alpha < MAX_ALPHA) {
        g2d.setComposite(
            AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f * alpha / MAX_ALPHA));
      }
      Point p = new Point(firstPoint);
      int diameter = getClosestOdd((int) PAD_SIZE.convertToPixels());
      int holeDiameter = getClosestOdd((int) HOLE_SIZE.convertToPixels());
      int spacing = (int) this.spacing.convertToPixels();

      while (p.y < secondPoint.y - spacing) {
        p.x = firstPoint.x;
        p.y += spacing;
        while (p.x < secondPoint.x - spacing - diameter) {
          p.x += spacing;
          g2d.setColor(padColor);
          g2d.fillOval(p.x - diameter / 2, p.y - diameter / 2, diameter, diameter);
          g2d.setColor(padColor.darker());
          g2d.drawOval(p.x - diameter / 2, p.y - diameter / 2, diameter, diameter);
          g2d.setColor(Constants.CANVAS_COLOR);
          g2d.fillOval(p.x - holeDiameter / 2, p.y - holeDiameter / 2, holeDiameter, holeDiameter);
          g2d.setColor(padColor.darker());
          g2d.drawOval(p.x - holeDiameter / 2, p.y - holeDiameter / 2, holeDiameter, holeDiameter);
        }
      }
      super.drawCoordinates(g2d, spacing);
    }
  }
コード例 #17
0
ファイル: MoveShapeTool.java プロジェクト: imagej/envisaje
 public void mousePressed(MouseEvent e) {
   if (e.isPopupTrigger()) {
     showPopup(e);
     return;
   }
   if (stack == null && layer != null) stack = layer.getLookup().lookup(ShapeStack.class);
   List<Primitive> l = stack.getPrimitives();
   Rectangle2D.Double scratch = new Rectangle2D.Double(0, 0, 0, 0);
   Point point = mousePressPoint = e.getPoint();
   if (shape != null) {
     ControlPoint[] p = new ControlPointFactory().getControlPoints((Adjustable) shape, this);
     for (int i = 0; i < p.length; i++) {
       ControlPoint pt = p[i];
       if (pt.hit(point.x, point.y)) {
         setSelectedControlPoint(pt);
         return;
       }
     }
   }
   boolean found = false;
   for (Primitive p : l) {
     if (p instanceof Vector) {
       Vector vector = (Vector) p;
       Shape shape = vector.toShape();
       if (shape.contains(point.x, point.y)) {
         setSelectedShape(p);
         found = true;
       }
     } else if (p instanceof Volume) {
       Volume volume = (Volume) p;
       volume.getBounds(scratch);
       System.err.println(p);
       if (scratch.contains(point.x, point.y)) {
         setSelectedShape(p);
         found = true;
       }
     }
   }
   if (!found) {
     setSelectedShape(null);
   }
 }
 @Override
 public AffineTransform getArrowTransform(
     RenderContext<String, String> rc, Shape edgeShape, Shape vertexShape) {
   GeneralPath path = new GeneralPath(edgeShape);
   float[] seg = new float[6];
   Point2D p1 = null;
   Point2D p2 = null;
   AffineTransform at = new AffineTransform();
   AffineTransform firstAt = new AffineTransform();
   // when the PathIterator is done, switch to the line-subdivide
   // method to get the arrowhead closer.
   boolean out = false;
   boolean found = false;
   boolean firstFound = false;
   for (PathIterator i = path.getPathIterator(null, 1); !i.isDone(); i.next()) {
     int ret = i.currentSegment(seg);
     if (ret == PathIterator.SEG_MOVETO) {
       p2 = new Point2D.Float(seg[0], seg[1]);
     } else if (ret == PathIterator.SEG_LINETO) {
       p1 = p2;
       p2 = new Point2D.Float(seg[0], seg[1]);
       if (vertexShape.contains(p2)) {
         if (out) {
           at = getArrowTransform(rc, new Line2D.Float(p1, p2), vertexShape);
           found = true;
           break;
         } else if (!firstFound) {
           firstAt = getArrowTransform(rc, new Line2D.Float(p1, p2), vertexShape);
           firstFound = true;
         }
       } else {
         out = true;
       }
     }
   }
   if (found) {
     return at;
   } else {
     return firstAt;
   }
 }
コード例 #19
0
ファイル: MoveShapeTool.java プロジェクト: imagej/envisaje
 private void showPopup(MouseEvent e) {
   Point point = e.getPoint();
   List<Primitive> l = stack.getPrimitives();
   Rectangle2D.Double scratch = new Rectangle2D.Double(0, 0, 0, 0);
   List<Primitive> shapes = new ArrayList<Primitive>();
   List<Vector> vectors = new ArrayList<Vector>();
   Primitive topMost = null;
   for (Primitive p : l) {
     if (p instanceof Vector) {
       Vector vector = (Vector) p;
       Shape shape = vector.toShape();
       System.err.println(shape);
       if (shape.contains(point.x, point.y)) {
         topMost = vector;
         shapes.add(vector);
         vectors.add(vector);
       }
     } else if (p instanceof Volume) {
       Volume volume = (Volume) p;
       volume.getBounds(scratch);
       System.err.println(p);
       if (scratch.contains(point.x, point.y)) {
         topMost = volume;
         shapes.add(volume);
       }
     }
   }
   if (!shapes.isEmpty()) {
     assert topMost != null;
     JPopupMenu menu = new JPopupMenu();
     menu.add(new FrontBackAction(true, topMost, stack));
     menu.add(new FrontBackAction(false, topMost, stack));
     menu.add(new CSGAction(UNION, vectors, stack));
     menu.add(new CSGAction(INTERSECTION, vectors, stack));
     menu.add(new CSGAction(SUBTRACTION, vectors, stack));
     menu.add(new CSGAction(XOR, vectors, stack));
     menu.show(repainter.getDialogParent(), point.x, point.y);
   }
 }
コード例 #20
0
ファイル: TestRoute.java プロジェクト: DanVanAtta/triplea
  @Test
  public void testCorrectParameterHandling() {
    // Should not throw any exception - should do nothing
    spyRouteDrawer.drawRoute(null, null, null, null, null);
    final MapPanel mockedMapPanel = mock(MapPanel.class);
    when(mockedMapPanel.getXOffset()).thenReturn(0);
    when(mockedMapPanel.getYOffset()).thenReturn(0);
    when(mockedMapPanel.getScale()).thenReturn(0.0);
    final Shape mockShape = mock(Shape.class);
    final Graphics2D mockGraphics = mock(Graphics2D.class);
    when(mockShape.contains(any(Point2D.class))).thenReturn(true);
    when(mockGraphics.getClip()).thenReturn(mockShape);
    spyRouteDrawer.drawRoute(
        mockGraphics, dummyRouteDescription, mockedMapPanel, dummyMapData, "2");
    verify(mockGraphics, atLeastOnce()).draw(any(Line2D.class));
    verify(mockedMapPanel).getXOffset(); // Those methods are needed
    verify(mockedMapPanel).getYOffset();
    verify(mockedMapPanel).getScale();

    verify(dummyRouteDescription, times(2)).getRoute();
    verify(dummyRouteDescription.getRoute(), atLeastOnce()).getAllTerritories();
  }
コード例 #21
0
ファイル: ShapePickSupport.java プロジェクト: RomaKoks/jung
  /**
   * Returns the vertices whose layout coordinates are contained in <code>Shape</code>. The shape is
   * in screen coordinates, and the graph vertices are transformed to screen coordinates before they
   * are tested for inclusion.
   *
   * @return the <code>Collection</code> of vertices whose <code>layout</code> coordinates are
   *     contained in <code>shape</code>.
   */
  public Collection<V> getVertices(Layout<V, E> layout, Shape shape) {
    Set<V> pickedVertices = new HashSet<V>();

    // remove the view transform from the rectangle
    shape = vv.getRenderContext().getMultiLayerTransformer().inverseTransform(Layer.VIEW, shape);

    while (true) {
      try {
        for (V v : getFilteredVertices(layout)) {
          Point2D p = layout.apply(v);
          if (p == null) continue;

          p = vv.getRenderContext().getMultiLayerTransformer().transform(Layer.LAYOUT, p);
          if (shape.contains(p)) {
            pickedVertices.add(v);
          }
        }
        break;
      } catch (ConcurrentModificationException cme) {
      }
    }
    return pickedVertices;
  }
コード例 #22
0
ファイル: GamePlayComponent.java プロジェクト: sebrockm/sy
  private void drawHighlightedArea(Shape areaOnImage, Graphics2D g2) {
    Color lastColor = g2.getColor();

    Shape areaOnScreen = fromImageToOuterTransform().createTransformedShape(areaOnImage);
    Rectangle2D bounds = areaOnScreen.getBounds2D();

    AffineTransform at = fromOuterToImageTransform();

    for (int y = 0; y < bounds.getHeight(); ++y) {
      for (int x = 0; x < bounds.getWidth(); ++x) {
        Point2D screenP = new Point2D.Double(bounds.getMinX() + x, bounds.getMinY() + y);
        if (!areaOnScreen.contains(screenP)) continue;

        Point2D imageP = at.transform(screenP, null);
        Color pixelColor =
            new Color(mapImage.getRGB((int) imageP.getX(), (int) imageP.getY()), true).brighter();
        g2.setColor(pixelColor);
        g2.draw(new Rectangle((int) screenP.getX(), (int) screenP.getY(), 1, 1));
      }
    }

    g2.setColor(lastColor);
  }
コード例 #23
0
 /*
  * Creates a line of width EDGE_SELECT_WIDTH for each edge
  * and tests if mouse click was in that Shape's boundary.
  * Returns the edge if one was selected, null otherwise.
  */
 public TreeEdge testEdgeShapes(MouseEvent event) {
   if (argument == null || argument.getTree() == null) return null;
   double x = event.getX();
   double y = event.getY();
   BasicStroke edgeWidth = new BasicStroke(EDGE_SELECT_WIDTH);
   if (argument.getBreadthFirstTraversal() == null) return null;
   Enumeration nodeList = argument.getBreadthFirstTraversal().elements();
   while (nodeList.hasMoreElements()) {
     TreeVertex vertex = (TreeVertex) nodeList.nextElement();
     if (argument.isMultiRoots() && vertex.getLayer() == 0) continue;
     Enumeration edges = vertex.getEdgeList().elements();
     while (edges.hasMoreElements()) {
       TreeEdge edge = (TreeEdge) edges.nextElement();
       Shape shape = edge.getShape(this);
       Shape wideEdge = edgeWidth.createStrokedShape(shape);
       TreeVertex child = edge.getDestVertex();
       if (wideEdge.contains(x, y)) {
         edge.setSelected(!edge.isSelected());
         return edge;
       }
     }
   }
   return null;
 }
コード例 #24
0
ファイル: Tile.java プロジェクト: kreativekorp/powerpaint
 @Override
 public void setRGB(int x, int y, int rgb, Shape clip) {
   if (clip == null || clip.contains(x, y)) {
     this.setRGB(x, y, rgb);
   }
 }
コード例 #25
0
ファイル: Fan.java プロジェクト: aalmiray/jsilhouette-geom
 public boolean contains(Point2D p) {
   return fan.contains(p);
 }
コード例 #26
0
ファイル: FillShapePainter.java プロジェクト: srnsw/xena
  /** Returns true if pt is in the area painted by this shape painter */
  public boolean inPaintedArea(Point2D pt) {
    if ((paint == null) || (shape == null)) return false;

    return shape.contains(pt);
  }
コード例 #27
0
ファイル: FillShapePainter.java プロジェクト: srnsw/xena
 /** Returns true if pt is in the area painted by this shape painter */
 public boolean inSensitiveArea(Point2D pt) {
   if (shape == null) return false;
   return shape.contains(pt);
 }
コード例 #28
0
ファイル: BoardFrame.java プロジェクト: jjchee/mancala
 /**
  * Checks if mouse click is inside the controller
  *
  * @param point mouse location
  * @return does the pit shape contain mouse location
  */
 public boolean contains(Point2D point) {
   return pitShape.contains(point);
   // somehow magically make this work for mouse listener..
 }
コード例 #29
0
ファイル: Fan.java プロジェクト: aalmiray/jsilhouette-geom
 public boolean contains(Rectangle2D r) {
   return fan.contains(r);
 }
コード例 #30
0
ファイル: ShapedPanel.java プロジェクト: bmod/baseonejlib
  public boolean inside(int x, int y) {
    if (x < 0 || y < 0 || x >= getWidth() || y >= getHeight()) return false;

    Shape shape = getShape();
    return shape == null ? super.inside(x, y) : shape.contains(x, y);
  }