CircleShape.java

  1. package org.opentrafficsim.base.geometry;

  2. import java.util.Iterator;
  3. import java.util.NoSuchElementException;

  4. import org.djutils.draw.line.Polygon2d;
  5. import org.djutils.draw.point.Point2d;
  6. import org.djutils.exceptions.Throw;

  7. /**
  8.  * Shape defined by a circle.
  9.  * <p>
  10.  * Copyright (c) 2024-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
  11.  * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
  12.  * </p>
  13.  * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
  14.  */
  15. public class CircleShape implements OtsShape
  16. {

  17.     /** Radius. */
  18.     private final double radius;

  19.     /** Number of line segments in polygon representation. */
  20.     private final int polygonSegments;

  21.     /** Polygon representation. */
  22.     private Polygon2d polygon;

  23.     /**
  24.      * Constructor.
  25.      * @param radius radius.
  26.      */
  27.     public CircleShape(final double radius)
  28.     {
  29.         this(radius, DEFAULT_POLYGON_SEGMENTS);
  30.     }

  31.     /**
  32.      * Constructor.
  33.      * @param radius radius.
  34.      * @param polygonSegments number of segments in polygon representation.
  35.      */
  36.     public CircleShape(final double radius, final int polygonSegments)
  37.     {
  38.         Throw.whenNull(radius, "Radius must not be null.");
  39.         Throw.when(radius <= 0.0, IllegalArgumentException.class, "Radius must be above 0.0.");
  40.         this.radius = radius;
  41.         this.polygonSegments = polygonSegments;
  42.     }

  43.     @Override
  44.     public double getMinX()
  45.     {
  46.         return -this.radius;
  47.     }

  48.     @Override
  49.     public double getMaxX()
  50.     {
  51.         return this.radius;
  52.     }

  53.     @Override
  54.     public double getMinY()
  55.     {
  56.         return -this.radius;
  57.     }

  58.     @Override
  59.     public double getMaxY()
  60.     {
  61.         return this.radius;
  62.     }

  63.     @Override
  64.     public boolean contains(final Point2d point) throws NullPointerException
  65.     {
  66.         return CENTER.distance(point) < this.radius;
  67.     }

  68.     @Override
  69.     public boolean contains(final double x, final double y)
  70.     {
  71.         return contains(new Point2d(x, y));
  72.     }

  73.     @Override
  74.     public double signedDistance(final Point2d point)
  75.     {
  76.         return CENTER.distance(point) - this.radius;
  77.     }

  78.     @Override
  79.     public Polygon2d asPolygon()
  80.     {
  81.         if (this.polygon == null)
  82.         {
  83.             if (this.radius == 0.0)
  84.             {
  85.                 this.polygon = new Polygon2d(false, new Point2d(0.0, 0.0));
  86.             }
  87.             else
  88.             {
  89.                 this.polygon = new Polygon2d(new Iterator<Point2d>()
  90.                 {
  91.                     /** Step. */
  92.                     private int step = 0;

  93.                     @Override
  94.                     public boolean hasNext()
  95.                     {
  96.                         return this.step <= CircleShape.this.polygonSegments;
  97.                     }

  98.                     @Override
  99.                     public Point2d next()
  100.                     {
  101.                         Throw.when(!hasNext(), NoSuchElementException.class, "Iterator has no more elements.");
  102.                         // at full circle (this.step == polygonSegments), make sure end point is exactly the same as the start
  103.                         // point
  104.                         double ang = this.step == CircleShape.this.polygonSegments ? 0.0
  105.                                 : (2.0 * Math.PI * this.step) / CircleShape.this.polygonSegments;
  106.                         this.step++;
  107.                         return new Point2d(Math.cos(ang) * CircleShape.this.radius, Math.sin(ang) * CircleShape.this.radius);
  108.                     }
  109.                 });
  110.             }
  111.         }
  112.         return this.polygon;
  113.     }

  114.     @Override
  115.     public String toString()
  116.     {
  117.         return "CircleShape [radius=" + this.radius + "]";
  118.     }

  119. }