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 a sector of a ring (an annulus)
015   in the xy-plane centered at the origin.
016<p>
017   See <a href="https://en.wikipedia.org/wiki/Annulus_(mathematics)" target="_top">
018                https://en.wikipedia.org/wiki/Annulus_(mathematics)</a>
019<p>
020   See <a href="https://en.wikipedia.org/wiki/Circular_sector" target="_top">
021                https://en.wikipedia.org/wiki/Circular_sector</a>
022
023   @see Ring
024*/
025public class RingSector extends Model implements MeshMaker
026{
027   public final double r1;
028   public final double r2;
029   public final double theta1;
030   public final double theta2;
031   public final int n;
032   public final int k;
033
034   /**
035      Create half a ring (annulus) in the xy-plane
036      with outer radius 1, inner radius 0.33, with 7
037      spokes coming out of the center, and with 5
038      concentric circles.
039   */
040   public RingSector( )
041   {
042      this(1.0, 0.33, 0, Math.PI, 5, 7);
043   }
044
045
046   /**
047      Create a sector of a ring (annulus) in the xy-plane
048      with outer radius {@code r1}, inner radius {@code r2},
049      starting angle {@code theta1}, ending angle {@code theta2},
050      with {@code k} spokes coming out of the center, and
051      with {@code n} concentric circles.
052   <p>
053      If there are {@code k} spokes, then each (partial) circle
054      around the center will have {@code k-1} line segments.
055      If there are {@code n} concentric circles around the center,
056      then each spoke will have {@code n-1} line segments.
057   <p>
058      There must be at least four spokes and at least two concentric circle.
059
060      @param r1      outer radius of the ring
061      @param r2      inner radius of the ring
062      @param theta1  beginning angle of the sector (in radians)
063      @param theta2  ending angle of the sector (in radians)
064      @param n       number of concentric circles
065      @param k       number of spokes in the ring
066      @throws IllegalArgumentException if {@code n} is less than 2
067      @throws IllegalArgumentException if {@code k} is less than 4
068   */
069   public RingSector(final double r1, final double r2,
070                     double theta1, double theta2,
071                     final int n, final int k)
072   {
073      super(String.format("Ring Sector(%.2f,%.2f,%.2f,%.2f,%d,%d)",
074                                       r1, r2, theta1, theta2, n, k));
075
076      if (n < 2)
077         throw new IllegalArgumentException("n must be greater than 1");
078      if (k < 4)
079         throw new IllegalArgumentException("k must be greater than 3");
080
081      theta1 = theta1 % (2*Math.PI);
082      theta2 = theta2 % (2*Math.PI);
083      if (theta1 < 0) theta1 = 2*Math.PI + theta1;
084      if (theta2 < 0) theta2 = 2*Math.PI + theta2;
085      if (theta2 <= theta1) theta2 = theta2 + 2*Math.PI;
086
087      this.r1 = r1;
088      this.r2 = r2;
089      this.theta1 = theta1;
090      this.theta2 = theta2;
091      this.n = n;
092      this.k = k;
093
094      // Create the rings's geometry.
095
096      final double deltaR = (r1 - r2) / (n - 1),
097                   deltaTheta = (theta2 - theta1) / (k - 1);
098
099      // An array of vertices to be used to create line segments.
100      final Vertex[][] v = new Vertex[n][k];
101
102      // Create all the vertices.
103      for (int j = 0; j < k; ++j) // choose a spoke (an angle)
104      {
105         final double c = Math.cos(theta1 + j * deltaTheta),
106                      s = Math.sin(theta1 + j * deltaTheta);
107         for (int i = 0; i < n; ++i) // move along the spoke
108         {
109            final double ri = r2 + i * deltaR;
110            v[i][j] = new Vertex(ri * c,
111                                 ri * s,
112                                 0);
113         }
114      }
115
116      // Add all of the vertices to this model.
117      for (int i = 0; i < n; ++i)
118      {
119         for (int j = 0; j < k; ++j)
120         {
121            addVertex( v[i][j] );
122         }
123      }
124
125      // Create line segments around each concentric ring.
126      for (int i = 0; i < n; ++i)  // choose a ring
127      {
128         for (int j = 0; j < k - 1; ++j)
129         {  //                               v[i][j]       v[i][j+1]
130            addPrimitive(new LineSegment( (i * k) + j, (i * k) + (j+1) ));
131         }
132      }
133
134      // Create the spokes.connecting the inner circle to the outer circle.
135      for (int j = 0; j < k; ++j) // choose a spoke
136      {
137         for (int i = 0; i < n - 1; ++i)
138         {  //                                v[i][j]      v[i+1][j]
139            addPrimitive(new LineSegment( (i * k) + j, ((i+1) * k) + j ));
140         }
141      }
142   }
143
144
145
146   // Implement the MeshMaker interface (thre methods).
147   @Override public int getHorzCount() {return n;}
148
149   @Override public int getVertCount() {return k;}
150
151   @Override
152   public RingSector remake(final int n, final int k)
153   {
154      return new RingSector(this.r1, this.r2,
155                            this.theta1, this.theta2,
156                            n, k);
157   }
158}//RingSector