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 an arc from a circle in 015 the xy-plane centered at the origin. 016 017 @see DiskSector 018 @see RingSector 019 @see ConeSector 020 @see CylinderSector 021 @see SphereSector 022 @see TorusSector 023*/ 024public class CircleSector extends Model implements MeshMaker 025{ 026 public final double r; 027 public final double theta1; 028 public final double theta2; 029 public final int n; 030 031 /** 032 Create half of a circle in the xy-plane with radius 1 and 033 with 8 line segments around the circumference. 034 */ 035 public CircleSector( ) 036 { 037 this(1, 0, Math.PI, 8); 038 } 039 040 041 /** 042 Create half of a circle in the xy-plane with radius {@code r} 043 and with 8 line segments around the circumference. 044 045 @param r radius of the circle 046 */ 047 public CircleSector(final double r) 048 { 049 this(r, 0, Math.PI, 8); 050 } 051 052 053 /** 054 Create an arc (a sector) of a circle in the xy-plane with 055 radius {@code r}, starting angle {@code theta1}, ending 056 angle {@code theta2}, and with {@code n} line segments 057 around the circumference. 058 <p> 059 The arc is drawn counterclockwise starting at angle 060 {@code theta1} and ending at angle {@code theta2}. Notice 061 that this means that if {@code theta1 <= theta2}, then we are 062 drawing the arc between the angles, but if {@code theta1 > theta2}, 063 then we are removing the arc between the angles. 064 <p> 065 Notice that any two angles define two arcs from a circle. 066 We want a definition for this method that unambiguously 067 determines, for any two angles, which of the two arcs to 068 draw. 069 070 @param r radius of the circle 071 @param theta1 beginning angle of the sector (in radians) 072 @param theta2 ending angle of the sector (in radians) 073 @param n number of line segments in the circle's circumference 074 @throws IllegalArgumentException if {@code n} is less than 3 075 */ 076 public CircleSector(final double r, 077 double theta1, double theta2, 078 final int n) 079 { 080 super(String.format("CircleSector(%.2f,%.2f,%.2f,%d)", 081 r, theta1, theta2, n)); 082 083 if (n < 4) 084 throw new IllegalArgumentException("n must be greater than 3"); 085 086 theta1 = theta1 % (2*Math.PI); 087 theta2 = theta2 % (2*Math.PI); 088 if (theta1 < 0) theta1 = 2*Math.PI + theta1; 089 if (theta2 < 0) theta2 = 2*Math.PI + theta2; 090 if (theta2 <= theta1) theta2 = theta2 + 2*Math.PI; 091 092 this.r = r; 093 this.theta1 = theta1; 094 this.theta2 = theta2; 095 this.n = n; 096 097 // Create the arc's geometry. 098 final double deltaTheta = (theta2 - theta1) / (n - 1); 099 100 // Create all the vertices. 101 for (int i = 0; i < n; ++i) 102 { 103 final double c = Math.cos(theta1 + i * deltaTheta), 104 s = Math.sin(theta1 + i * deltaTheta); 105 addVertex( new Vertex(r * c, r * s, 0) ); 106 } 107 108 // Create the line segments around the arc. 109 for (int i = 0; i < n - 1; ++i) 110 { 111 addPrimitive(new LineSegment(i, i+1)); 112 } 113 } 114 115 116 117 // Implement the MeshMaker interface (three methods). 118 @Override public int getHorzCount() {return n;} 119 120 @Override public int getVertCount() {return n;} 121 122 @Override 123 public CircleSector remake(final int n, final int k) 124 { 125 final int newN; 126 if (n != this.n) 127 newN = n; 128 else 129 newN = k;; 130 131 return new CircleSector(this.r, 132 this.theta1, this.theta2, 133 newN); 134 } 135}//CircleSector