org.piccolo2d.nodes.PArea Maven / Gradle / Ivy
The newest version!
/*
* Copyright (c) 2008-2019, Piccolo2D project, http://piccolo2d.org
* Copyright (c) 1998-2008, University of Maryland
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided
* that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list of conditions
* and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions
* and the following disclaimer in the documentation and/or other materials provided with the
* distribution.
*
* None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
* contributors may be used to endorse or promote products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.piccolo2d.nodes;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
/**
* Area node.
*/
public final class PArea extends PShape {
/** Area for this area node. */
private final transient Area area;
/**
* Create a new area node with an empty area.
*/
public PArea() {
area = new Area();
}
/**
* Create a new area node with an empty area and the specified stroke.
*
* @param stroke stroke
*/
public PArea(final Stroke stroke) {
area = new Area();
setStroke(stroke);
}
/**
* Create a new area node with the specified shape.
*
* @param shape shape, must not be null
*/
public PArea(final Shape shape) {
if (shape == null) {
throw new NullPointerException("shape must not be null");
}
this.area = new Area(shape);
}
/**
* Create a new area node with the specified shape and stroke.
*
* @param shape shape, must not be null
* @param stroke stroke
*/
public PArea(final Shape shape, final Stroke stroke) {
if (shape == null) {
throw new NullPointerException("shape must not be null");
}
this.area = new Area(shape);
setStroke(stroke);
}
/**
* Create a new area node with the specified area.
*
* @param area area, must not be null
*/
public PArea(final Area area) {
if (area == null) {
throw new NullPointerException("area must not be null");
}
this.area = new Area();
this.area.add(area);
}
/**
* Create a new area node with the specified area and stroke.
*
* @param area area, must not be null
* @param stroke stroke
*/
public PArea(final Area area, final Stroke stroke) {
if (area == null) {
throw new NullPointerException("area must not be null");
}
this.area = new Area();
this.area.add(area);
setStroke(stroke);
}
/**
* Return a copy of the area backing this area node.
*
* @return a copy of the area backing this area node
*/
public Area getArea() {
return (Area) area.clone();
}
/**
* Return the area backing this node. The returned area must not be
* modified or the bounds of this node may no longer be valid and any
* area
property change listeners will not be notified.
*
* @return the area backing this area node
*/
public Area getAreaReference() {
return area;
}
/**
* Add the shape of the specified area to the shape of this area node.
* The resulting shape of this area node will include the union of both shapes,
* or all areas that were contained in either this or the specified area.
*
* @param area area to add, must not be null
* @throws NullPointerException if area is null
*/
public void add(final Area area) {
Area oldArea = (Area) this.area.clone();
this.area.add(area);
updateBoundsFromShape();
firePropertyChange(-1, "area", oldArea, getArea());
}
/**
* Set the shape of this area node to be the combined area of its current
* shape and the shape of the specified area, minus their intersection. The
* resulting shape of this area node will include only areas that were contained
* in either this area node or in the specified area, but not in both.
*
* @param area area to exclusive or, must not be null
* @throws NullPointerException if area is null
*/
public void exclusiveOr(final Area area) {
Area oldArea = (Area) this.area.clone();
this.area.exclusiveOr(area);
updateBoundsFromShape();
firePropertyChange(-1, "area", oldArea, getArea());
}
/**
* Set the shape of this area node to the intersection of its current shape
* and the shape of the specified area. The resulting shape of this area node
* will include only areas that were contained in both this area node and also
* in the specified area.
*
* @param area area to intersect, must not be null
* @throws NullPointerException if area is null
*/
public void intersect(final Area area) {
Area oldArea = (Area) this.area.clone();
this.area.intersect(area);
updateBoundsFromShape();
firePropertyChange(-1, "area", oldArea, getArea());
}
/**
* Subtract the shape of the specified area from the shape of this area node.
* The resulting shape of this area node will include areas that were contained
* only in this area node and not in the specified area.
*
* @param area area to subtract, must not be null
* @throws NullPointerException if area is null
*/
public void subtract(final Area area) {
Area oldArea = (Area) this.area.clone();
this.area.subtract(area);
updateBoundsFromShape();
firePropertyChange(-1, "area", oldArea, getArea());
}
/**
* Removes all of the geometry from this area node and restores it to an empty area.
*/
public void reset() {
Area oldArea = (Area) area.clone();
area.reset();
updateBoundsFromShape();
firePropertyChange(-1, "area", oldArea, getArea());
}
/**
* Return true if this area node represents an empty area.
*
* @return true if this area node represents an empty area
*/
public boolean isEmpty() {
return area.isEmpty();
}
/**
* Return true if this area node consists entirely of straight-edged polygonal geometry.
*
* @return true if this area node consists entirely of straight-edged polygonal geometry
*/
public boolean isPolygonal() {
return area.isPolygonal();
}
/**
* Return true if this area node is rectangular in shape.
*
* @return true if this area node is rectangular in shape
*/
public boolean isRectangular() {
return area.isRectangular();
}
/**
* Return true if this area node is comprised of a single closed subpath. This
* method returns true if the path contains 0 or 1 subpaths, or false if the path
* contains more than 1 subpath. The subpaths are counted by the number of
* SEG_MOVETO
segments that appear in the path.
*
* @return true if this area node is comprised of a single closed subpath
*/
public boolean isSingular() {
return area.isSingular();
}
// todo:
// should modifiers return this to allow chaining, e.g. add(area0).intersect(area1)
// test serialization, may have to add custom code to serialize areas
/** {@inheritDoc} */
protected Shape getShape() {
return area;
}
/** {@inheritDoc} */
protected void transform(final AffineTransform transform) {
area.transform(transform);
}
}