001/*
002 * Renderer Models. The MIT License.
003 * Copyright (c) 2022 rlkraft@pnw.edu
004 * See LICENSE for details.
005*/
006
007package renderer.models_L;
008
009import renderer.scene.*;
010import renderer.scene.primitives.*;
011import renderer.scene.util.MeshMaker;
012
013/**
014   Create a wireframe model of an arc from a circle in
015   the xy-plane centered at the origin.
016
017   @see DiskSector
018   @see RingSector
019   @see ConeSector
020   @see CylinderSector
021   @see SphereSector
022   @see TorusSector
023*/
024public class CircleSector extends Model implements MeshMaker
025{
026   public final double r;
027   public final double theta1;
028   public final double theta2;
029   public final int n;
030
031   /**
032      Create half of a circle in the xy-plane with radius 1 and
033      with 8 line segments around the circumference.
034   */
035   public CircleSector( )
036   {
037      this(1, 0, Math.PI, 8);
038   }
039
040
041   /**
042      Create half of a circle in the xy-plane with radius {@code r}
043      and with 8 line segments around the circumference.
044
045      @param r  radius of the circle
046   */
047   public CircleSector(final double r)
048   {
049      this(r, 0, Math.PI, 8);
050   }
051
052
053   /**
054      Create an arc (a sector) of a circle in the xy-plane with
055      radius {@code r}, starting angle {@code theta1}, ending
056      angle {@code theta2}, and with {@code n} line segments
057      around the circumference.
058   <p>
059      The arc is drawn counterclockwise starting at angle
060      {@code theta1} and ending at angle {@code theta2}. Notice
061      that this means that if {@code theta1 <= theta2}, then we are
062      drawing the arc between the angles, but if {@code theta1 > theta2},
063      then we are removing the arc between the angles.
064   <p>
065      Notice that any two angles define two arcs from a circle.
066      We want a definition for this method that unambiguously
067      determines, for any two angles, which of the two arcs to
068      draw.
069
070      @param r       radius of the circle
071      @param theta1  beginning angle of the sector (in radians)
072      @param theta2  ending angle of the sector (in radians)
073      @param n       number of line segments in the circle's circumference
074      @throws IllegalArgumentException if {@code n} is less than 3
075   */
076   public CircleSector(final double r,
077                       double theta1, double theta2,
078                       final int n)
079   {
080      super(String.format("CircleSector(%.2f,%.2f,%.2f,%d)",
081                                        r, theta1, theta2, n));
082
083      if (n < 4)
084         throw new IllegalArgumentException("n must be greater than 3");
085
086      theta1 = theta1 % (2*Math.PI);
087      theta2 = theta2 % (2*Math.PI);
088      if (theta1 < 0) theta1 = 2*Math.PI + theta1;
089      if (theta2 < 0) theta2 = 2*Math.PI + theta2;
090      if (theta2 <= theta1) theta2 = theta2 + 2*Math.PI;
091
092      this.r = r;
093      this.theta1 = theta1;
094      this.theta2 = theta2;
095      this.n = n;
096
097      // Create the arc's geometry.
098      final double deltaTheta = (theta2 - theta1) / (n - 1);
099
100      // Create all the vertices.
101      for (int i = 0; i < n; ++i)
102      {
103         final double c = Math.cos(theta1 + i * deltaTheta),
104                      s = Math.sin(theta1 + i * deltaTheta);
105         addVertex( new Vertex(r * c, r * s, 0) );
106      }
107
108      // Create the line segments around the arc.
109      for (int i = 0; i < n - 1; ++i)
110      {
111         addPrimitive(new LineSegment(i, i+1));
112      }
113   }
114
115
116
117   // Implement the MeshMaker interface (three methods).
118   @Override public int getHorzCount() {return n;}
119
120   @Override public int getVertCount() {return n;}
121
122   @Override
123   public CircleSector remake(final int n, final int k)
124   {
125      final int newN;
126      if (n != this.n)
127         newN = n;
128      else
129         newN = k;;
130
131      return new CircleSector(this.r,
132                              this.theta1, this.theta2,
133                              newN);
134   }
135}//CircleSector