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