001/*
002 * Renderer 4. The MIT License.
003 * Copyright (c) 2022 rlkraft@pnw.edu
004 * See LICENSE for details.
005*/
006
007package renderer.scene;
008
009import renderer.scene.primitives.*;
010
011import java.util.List;
012import java.util.ArrayList;
013import java.awt.Color;
014
015/**
016   A {@code Model} object represents a distinct geometric object in a
017   {@link Scene}. A {@code Model} data structure is mainly a {@link List}
018   of {@link Vertex} objects, a {@link List} of {@link Primitive} objects,
019   and a list of {@link Color} objects.
020<p>
021   Each {@link Vertex} object contains the xyz-coordinates, in the
022   {@code Model}'s own coordinate system, for one point from the
023   {@code Model}.
024<p>
025   Each {@link Color} object represents a color associated to one
026   (or more) {@link Vertex} objects.
027<p>
028   The {@link Vertex} objects represents points from the geometric object
029   that we are modeling. In the real world, a geometric object has an infinite
030   number of points. In 3D graphics, we "approximate" a geometric object by
031   listing just enough points to adequately describe the object. For example,
032   in the real world, a rectangle contains an infinite number of points, but
033   it can be adequately modeled by just its four corner points. (Think about
034   a circle. How many points does it take to adequately model a circle? Look
035   at the {@link renderer.models_L.Circle} model.)
036<p>
037   Each {@link Primitive} object is either a {@link LineSegment} or a
038   {@link Point}.
039<p>
040   Each {@link LineSegment} object contains four integers, two integers that
041   are the indices of two {@link Vertex} objects from the {@code Model}'s
042   vertex list, and two integers that are indices of two {@link Color}
043   objects from the {@link Model}'s color list. The two vertices are the
044   line segment's two endpoints, and each of the two colors is associated
045   with one of the two endpoints.
046<p>
047   Each {@link Point} object contains two integers, one integer index of
048   a {@link Vertex} from the {@code Model}'s vertex list, and one integer
049   index of a {@link Color} from the {@code Model}'s color list.
050<p>
051   We use {@link LineSegment} objects to represent the space between the
052   model's vertices. For example, while a rectangle can be approximated by
053   its four corner points, those same four points could also represent two
054   parallel line segments, or they could represent two lines that cross each
055   other. By using four line segments that connect around the four points,
056   we get a good, unambiguous representation of a rectangle.
057<p>
058   If we modeled a circle using just points, we would probably need to use
059   hundreds of points. But if we connect every two adjacent points with a
060   short line segment, we can get a good model of a circle with just a few
061   dozen points.
062<p>
063   Our {@code Model}'s represent geometric objects as a "wire-frame" of line
064   segments, that is, a geometric object is drawn as a collection of "edges".
065   This is a fairly simplistic way of doing 3D graphics and we will improve
066   this in later renderers.
067<p>
068   See
069<br> <a href="https://en.wikipedia.org/wiki/Wire-frame_model" target="_top">
070              https://en.wikipedia.org/wiki/Wire-frame_model</a>
071<br>or
072<br> <a href="https://www.google.com/search?q=computer+graphics+wireframe&tbm=isch" target="_top">
073              https://www.google.com/search?q=computer+graphics+wireframe&tbm=isch</a>
074*/
075public class Model
076{
077   public final List<Vertex> vertexList;
078   public final List<Primitive> primitiveList;
079   public final List<Color> colorList;
080   public final String name;
081
082   public boolean visible;
083
084   /**
085      Construct an empty {@code Model} object.
086   */
087   public Model()
088   {
089      this(new ArrayList<>(),  // vertexList
090           new ArrayList<>(),  // primitiveList
091           new ArrayList<>(),  // colorList
092           "",                 // name
093           true);              // visible
094   }
095
096
097   /**
098      Construct an empty {@code Model} object with the given
099      {link String} name.
100
101      @param name  a {link String} that is a name for this {@code Model}
102      @throws NullPointerException if {@code name} is {@code null}
103   */
104   public Model(final String name)
105   {
106      this(new ArrayList<>(),  // vertexList
107           new ArrayList<>(),  // primitiveList
108           new ArrayList<>(),  // colorList
109           name,               // name
110           true);              // visible
111   }
112
113
114   /**
115      Construct a {@code Model} object with all the given data.
116
117      @param vertexList     a {@link Vertex} {link List} for this {@code Model}
118      @param primitiveList  a {@link Primitive} {link List} for this {@code Model}
119      @param colorList      a {@link Color} {link List} for this {@code Model}
120      @param name           a {link String} that is a name for this {@code Model}
121      @param visible        a {@code boolean} that determines this {@code Model}'s visibility
122      @throws NullPointerException if {@code vertexList} is {@code null}
123      @throws NullPointerException if {@code primitiveList} is {@code null}
124      @throws NullPointerException if {@code colorList} is {@code null}
125      @throws NullPointerException if {@code name} is {@code null}
126   */
127   public Model(final List<Vertex> vertexList,
128                final List<Primitive> primitiveList,
129                final List<Color> colorList,
130                final String name,
131                final boolean visible)
132   {
133      if (null == vertexList)
134         throw new NullPointerException("vertexList must not be null");
135      if (null == primitiveList)
136         throw new NullPointerException("primitiveList must not be null");
137      if (null == colorList)
138         throw new NullPointerException("colorList must not be null");
139      if (null == name)
140         throw new NullPointerException("name must not be null");
141
142      this.vertexList = vertexList;
143      this.primitiveList = primitiveList;
144      this.colorList = colorList;
145      this.name = name;
146      this.visible = visible;
147   }
148
149
150   /**
151      Add a {@link Vertex} (or vertices) to this {@code Model}'s
152      {@link List} of vertices.
153
154      @param vArray  array of {@link Vertex} objects to add to this {@code Model}
155      @throws NullPointerException if any {@link Vertex} is {@code null}
156   */
157   public final void addVertex(final Vertex... vArray)
158   {
159      for (final Vertex v : vArray)
160      {
161         if (null == v)
162            throw new NullPointerException("Vertex must not be null");
163
164         vertexList.add( v );
165      }
166   }
167
168
169   /**
170      Get a {@link Primitive} from this {@code Model}'s
171      {@link List} of primitives.
172
173      @param index  integer index of a {@link Primitive} from this {@code Model}
174      @return the {@link Primitive} object at the given index
175   */
176   public final Primitive getPrimitive(final int index)
177   {
178      return primitiveList.get(index);
179   }
180
181
182   /**
183      Add a {@link Primitive} (or Primitives) to this {@code Model}'s
184      {@link List} of primitives.
185      <p>
186      NOTE: This method does not add any vertices to the {@code Model}'s
187      {@link Vertex} list. This method assumes that the appropriate vertices
188      have been added to the {@code Model}'s {@link Vertex} list.
189
190      @param pArray  array of {@link Primitive} objects to add to this {@code Model}
191      @throws NullPointerException if any {@link Primitive} is {@code null}
192   */
193   public final void addPrimitive(final Primitive... pArray)
194   {
195      for (final Primitive p : pArray)
196      {
197         if (null == p)
198            throw new NullPointerException("Primitive must not be null");
199
200         primitiveList.add(p);
201      }
202   }
203
204
205   /**
206      Add a {@link Color} (or colors) to this {@code Model}'s
207      {@link List} of colors.
208
209      @param cArray  array of {@link Color} objects to add to this {@code Model}
210      @throws NullPointerException if any {@link Color} is {@code null}
211   */
212   public final void addColor(final Color... cArray)
213   {
214      for (final Color c : cArray)
215      {
216         if (null == c)
217            throw new NullPointerException("Color must not be null");
218
219         this.colorList.add(c);
220      }
221   }
222
223
224   /**
225      For debugging.
226
227      @return {@link String} representation of this {@code Model} object
228   */
229   @Override
230   public String toString()
231   {
232      String result = "";
233      result += "Model: " + name + "\n";
234      result += "This Model's visibility is: " + visible + "\n";
235      result += "Model has " + vertexList.size() + " vertices.\n";
236      result += "Model has " + colorList.size() + " colors.\n";
237      result += "Model has " + primitiveList.size() + " primitives.\n";
238      int i = 0;
239      for (final Vertex v : this.vertexList)
240      {
241         result += i + ": " + v.toString() + "\n";
242         ++i;
243      }
244      i = 0;
245      for (final Color c : this.colorList)
246      {
247         result += i + ": " + c.toString() + "\n";
248         ++i;
249      }
250      i = 0;
251      for (final Primitive p : this.primitiveList)
252      {
253         result += i + ": " + p.toString() + "\n";
254         ++i;
255      }
256      return result;
257   }
258}