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 right circular cylinder 015 with its axis along the y-axis. 016<p> 017 See <a href="https://en.wikipedia.org/wiki/Cylinder" target="_top"> 018 https://en.wikipedia.org/wiki/Cylinder</a> 019<p> 020 This model can also be used to create right k-sided polygonal prisms. 021<p> 022 See <a href="https://en.wikipedia.org/wiki/Prism_(geometry)" target="_top"> 023 https://en.wikipedia.org/wiki/Prism_(geometry)</a> 024 025 @see CylinderSector 026*/ 027public class Cylinder extends Model implements MeshMaker 028{ 029 public final double r; 030 public final double h; 031 public final int n; 032 public final int k; 033 034 /** 035 Create a right circular cylinder with radius 1 and its 036 axis along the y-axis from {@code y = 1} to {@code y = -1}. 037 */ 038 public Cylinder( ) 039 { 040 this(1, 1, 15, 16); 041 } 042 043 044 /** 045 Create a right circular cylinder with radius {@code r} and 046 its axis along the y-axis from {@code y = h} to {@code y = -h}. 047 048 @param r radius of the cylinder 049 @param h height of the cylinder (from h to -h along the y-axis) 050 */ 051 public Cylinder(final double r, final double h) 052 { 053 this(r, h, 15, 16); 054 } 055 056 057 /** 058 Create a right circular cylinder with radius {@code r} and 059 its axis along the y-axis from {@code y = h} to {@code y = -h}. 060 <p> 061 The last two parameters determine the number of lines of longitude 062 and the number of circles of latitude in the model. 063 <p> 064 If there are {@code n} circles of latitude in the model (including 065 the top and bottom edges), then each line of longitude will have 066 {@code n+1} line segments. If there are {@code k} lines of longitude, 067 then each circle of latitude will have {@code k} line segments. 068 <p> 069 There must be at least three lines of longitude and at least 070 two circles of latitude. 071 <p> 072 By setting {@code k} to be a small integer, this model can also be 073 used to create k-sided polygonal prisms. 074 075 @param r radius of the cylinder 076 @param h height of the cylinder (from h to -h along the y-axis) 077 @param n number of circles of latitude around the cylinder 078 @param k number of lines of longitude 079 @throws IllegalArgumentException if {@code n} is less than 2 080 @throws IllegalArgumentException if {@code k} is less than 4 081 */ 082 public Cylinder(final double r, final double h, final int n, final int k) 083 { 084 super(String.format("Cylinder(%.2f,%.2f,%d,%d)", r, h, n, k)); 085 086 if (n < 2) 087 throw new IllegalArgumentException("n must be greater than 1"); 088 if (k < 4) 089 throw new IllegalArgumentException("k must be greater than 3"); 090 091 this.r = r; 092 this.h = h; 093 this.n = n; 094 this.k = k; 095 096 // Create the cylinder's geometry. 097 098 final double deltaH = (2.0 * h) / (n - 1), 099 deltaTheta = (2.0 * Math.PI) / (k - 1); 100 101 // An array of vertices to be used to create line segments. 102 final Vertex[][] v = new Vertex[n][k]; 103 104 // Create all the vertices (from the top down). 105 for (int j = 0; j < k; ++j) // choose an angle of longitude 106 { 107 final double c = Math.cos(j * deltaTheta), 108 s = Math.sin(j * deltaTheta); 109 for (int i = 0; i < n; ++i) // choose a circle of latitude 110 { 111 v[i][j] = new Vertex( r * c, 112 h - i * deltaH, 113 -r * s ); 114 } 115 } 116 final Vertex topCenter = new Vertex(0, h, 0), 117 bottomCenter = new Vertex(0, -h, 0); 118 119 // Add all of the vertices to this model. 120 for (int i = 0; i < n; ++i) 121 { 122 for (int j = 0; j < k; ++j) 123 { 124 addVertex( v[i][j] ); 125 } 126 } 127 addVertex(topCenter, 128 bottomCenter); 129 final int topCenterIndex = n * k, 130 bottomCenterIndex = n * k + 1; 131 132 // Create all the horizontal circles of latitude around the cylinder. 133 for (int i = 0; i < n; ++i) // choose a circle of latitude 134 { 135 for (int j = 0; j < k - 1; ++j) 136 { // v[i][j] v[i][j+1] 137 addPrimitive(new LineSegment( (i * k) + j, (i * k) + (j+1) )); 138 } 139 } 140 141 // Create the lines of longitude from the top to the bottom. 142 for (int j = 0; j < k; ++j) // choose a line of longitude 143 { // v[0][j] 144 addPrimitive(new LineSegment( topCenterIndex, (0 * k) + j )); 145 for (int i = 0; i < n - 1; ++i) 146 { // v[i][j] v[i+1][j] 147 addPrimitive(new LineSegment( (i * k) + j, ((i+1) * k) + j )); 148 } 149 addPrimitive(new LineSegment( ((n-1) * k) + j, bottomCenterIndex )); 150 // v[n-1][j] 151 } 152 } 153 154 155 156 // Implement the MeshMaker interface (three methods). 157 @Override public int getHorzCount() {return n;} 158 159 @Override public int getVertCount() {return k;} 160 161 @Override 162 public Cylinder remake(final int n, final int k) 163 { 164 return new Cylinder(this.r, this.h, n, k); 165 } 166}//Cylinder