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