001/*
002 * Renderer 9. The MIT License.
003 * Copyright (c) 2022 rlkraft@pnw.edu
004 * See LICENSE for details.
005*/
006
007package renderer.scene;
008
009/**
010   A {@code Vector} object holds four doubles, which makes it a vector
011   in 4-dimensional space.
012<p>
013   In computer graphics, we use 4-dimensional homogeneous coordinates
014   to represent vectors (and points) in 3-dimensional space.
015<p>
016   Unlike a homogeneous {@link Vertex}, a homogeneous {@code Vector} usually
017   has its fourth coordinate set to 0.
018*/
019public final class Vector
020{
021   public final double x, y, z, w; // a vector in homogenous coordinates
022
023   /**
024      Construct a new {@code Vector} using the given x, y, and z coordinates.
025
026      @param x  x-coordinate of the new {@code Vector}
027      @param y  y-coordinate of the new {@code Vector}
028      @param z  z-coordinate of the new {@code Vector}
029   */
030   public Vector(final double x, final double y, final double z)
031   {
032      this(x, y, z, 0.0);
033   }
034
035
036   /**
037      Construct a new {@code Vector} using the given x, y, z, and w coordinates.
038      <p>
039      This constructor is used to create the column vectors in a 4-by-4
040      homogeneous {@link Matrix}.
041
042      @param x  x-coordinate of the new {@code Vector}
043      @param y  y-coordinate of the new {@code Vector}
044      @param z  z-coordinate of the new {@code Vector}
045      @param w  w-coordinate of the new {@code Vector}
046   */
047   public Vector(final double x, final double y, final double z, final double w)
048   {
049      this.x = x;
050      this.y = y;
051      this.z = z;
052      this.w = w;
053   }
054
055
056   /**
057      Construct a new {@code Vector} from a {@link Vertex}.
058
059      @param v  {@link Vertex} object to convert into a {@code Vector}
060   */
061   public Vector(final Vertex v)
062   {
063      this(v.x, v.y, v.z, v.w);
064   }
065
066
067   /**
068      The dot-product of two {@code Vector}s returns a scalar.
069
070      @param v  {@code Vector} object to multiply with this {@code Vector}
071      @return a double that is the dot-product of this {@code Vector} and {@code v}
072   */
073   public double dotProduct(final Vector v)
074   {
075      return (x * v.x) + (y * v.y) + (z * v.z);
076   }
077
078
079   /**
080      The cross-product of two {@code Vector}s returns a (new) {@code Vector}.
081
082      @param v  {@code Vector} object to multiply with this {@code Vector}
083      @return a new {@code Vector} object that is the cross-product of this {@code Vector} and {@code v}
084   */
085   public Vector crossProduct(final Vector v)
086   {
087      return new Vector(y*v.z - z*v.y, z*v.x - x*v.z, x*v.y - y*v.x);
088   }
089
090
091   /**
092      A scalar times a {@code Vector} returns a (new) {@code Vector}.
093
094      @param s  number to multiply this {@code Vector} by
095      @return a new {@code Vector} object that is the scalar times this {@code Vector}
096   */
097   public Vector times(final double s) // return s * this
098   {
099      return new Vector(s*x, s*y, s*z, s*w);
100   }
101
102
103   /**
104      A {@code Vector} plus a {@code Vector} returns a (new) {@code Vector}.
105
106      @param v  {@code Vector} object to add to this {@code Vector}
107      @return a new {@code Vector} object that is the sum of this {@code Vector} and {@code v}
108   */
109   public Vector plus(final Vector v) // return this + v
110   {
111      return new Vector(x + v.x, y + v.y, z + v.z, w + v.w);
112   }
113
114
115   /**
116      A {@code Vector} minus a {@code Vector} returns a (new) {@code Vector}.
117
118      @param v  {@code Vector} object to subtract from this {@code Vector}
119      @return a new {@code Vector} object that is this {@code Vector} minus {@code v}
120   */
121   public Vector minus(final Vector v) // return this - v
122   {
123      return new Vector(x - v.x, y - v.y, z - v.z, w - v.w);
124   }
125
126
127   /**
128      Return the normalized version of this {@code Vector}.
129      <p>
130      That is, return the {@code Vector} with length 1 that
131      points in the same direction as this {@code Vector}.
132
133      @return a new {@code Vector} that has length one and has the same direction as this {@code Vector}
134   */
135   public Vector normalize() // return this / |this|
136   {
137      final double norm = Math.sqrt( x*x + y*y + z*z );
138      return new Vector(x/norm, y/norm, z/norm);
139   }
140
141
142   /**
143      A {@code Vector} plus a {@link Vertex} returns a (new) {@link Vertex}.
144      <p>
145      The vector translates the vertex to a new location.
146
147      @param v  {@link Vertex} object to add to this {@code Vector}
148      @return a new {@link Vertex} object that is the translation of {@code v} by this {@code Vector}
149   */
150   public Vertex plus(final Vertex v)
151   {
152      return new Vertex(x + v.x, y + v.y, z + v.z);
153   }
154
155
156   /**
157      For debugging.
158
159      @return {@link String} representation of this {@code Vector} object
160   */
161   @Override
162   public String toString()
163   {
164      final int precision = 5;  // the default precision for the format string
165      return toString(precision);
166   }
167
168
169   /**
170      For debugging.
171      <p>
172      Allow the precision of the formatted output to be specified.
173
174      @param precision  precision value for the format string
175      @return {@link String} representation of this {@code Vector} object
176   */
177   public String toString(final int precision)
178   {
179      final int iWidth = 3; // default width of integer part of the format string
180      return toString(precision, iWidth);
181   }
182
183
184   /**
185      For debugging.
186      <p>
187      Allow the precision and width of the formatted output to be specified.
188      By width, we mean the width of the integer part of each number.
189
190      @param precision  precision value for the format string
191      @param iWidth     width of the integer part of the format string
192      @return {@link String} representation of this {@code Vector} object
193   */
194   public String toString(final int precision, final int iWidth)
195   {
196      // Here is one way to get programmable precision and width.
197      final int p = precision;      // the precision for the following format string
198      final int t = p + iWidth + 2; // the width for the following format string
199      final String format = "[x,y,z,w] = [% "+t+"."+p+"f  % "+t+"."+p+"f  % "+t+"."+p+"f  % "+t+"."+p+"f]";
200      return String.format(format, x, y, z, w);
201   }
202}