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