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