`   1:      /// <summary>`
`   2:      /// A Bezier Object represented by a set of BezierPatch objects, each containing 16 control points`
`   3:      /// </summary>`
`   4:      public class BezierObject : BaseObject`
`   5:      {`
`   6:          /// <summary>`
`   7:          /// The minimum division size to recurse to`
`   8:          /// </summary>`
`   9:          private static double DIV_SIZE = 0.005;`
`  10:   `
`  11:          /// <summary>`
`  12:          /// A Bezier Patch, made up of 16 control points`
`  13:          /// </summary>`
`  14:          public class BezierPatch`
`  15:          {`
`  16:              /// <summary>`
`  17:              /// The 4x4 array of control points`
`  18:              /// </summary>`
`  19:              public Vector[,] idx = new Vector[4,4];`
`  20:              /// <summary>`
`  21:              /// A public indexer to the array of control points`
`  22:              /// </summary>`
`  23:              public Vector this[int i, int j]`
`  24:              {`
`  25:                  get`
`  26:                  {`
`  27:                      return idx[i,j];`
`  28:                  }`
`  29:                  set`
`  30:                  {`
`  31:                      idx[i,j] = value;`
`  32:                  }`
`  33:              }`
`  34:              /// <summary>`
`  35:              /// A linear indexer to the array of control points`
`  36:              /// </summary>`
`  37:              public Vector this[int i]`
`  38:              {`
`  39:                  get`
`  40:                  {`
`  41:                      return this[i >> 2, i & 0x3];`
`  42:                  }`
`  43:                  set`
`  44:                  {`
`  45:                      this[i >> 2, i & 0x3] = value;`
`  46:                  }`
`  47:              }`
`  48:   `
`  49:              /// <summary>`
`  50:              /// Creates a copy of this bezier patch`
`  51:              /// </summary>`
`  52:              /// <returns>A clone of this patch</returns>`
`  53:              public BezierPatch Clone()`
`  54:              {`
`  55:                  BezierPatch ret = new BezierPatch();`
`  56:                  for (int i = 0; i < 4; i++)`
`  57:                      for (int j = 0; j < 4; j++)`
`  58:                          ret.idx[i,j] = idx[i,j];`
`  59:                  return ret;`
`  60:              }`
`  61:   `
`  62:              /// <summary>`
`  63:              /// Evaluates the Bezier Patch at the specified location`
`  64:              /// </summary>`
`  65:              /// <param name="s">The s parameter, from 0 to 1</param>`
`  66:              /// <param name="t">The t parameter, from 0 to 1</param>`
`  67:              /// <returns>A Vector containing the 3D world space location of the desired point</returns>`
`  68:              public Vector Evaluate(double s, double t)`
`  69:              {`
`  70:                  // Copy our vectors into a temporary array`
`  71:                  Vector[,] tmp = new Vector[4,4];`
`  72:                  for (int i = 0; i < 4; i++)`
`  73:                      for (int j = 0; j < 4; j++)`
`  74:                          tmp[i,j] = this[i,j];`
`  75:   `
`  76:                  // Take our 16 points, condense them into 9 points`
`  77:                  // Condense the 9 points into 4`
`  78:                  // Condense the 4 points into 1`
`  79:                  for (int size = 3; size > 0; size--)`
`  80:                      for (int i = 0; i < size; i++)`
`  81:                          for (int j = 0; j < size; j++)`
`  82:                          {`
`  83:                              // Replace the Pij with the average of the 3 'next' points`
`  84:                              // i,j+1 - i+1,j+1 `
`  85:                              //  |         |    `
`  86:                              //  |         |    `
`  87:                              // i,j ---- i+1,j  `
`  88:                              // First bisect along the top and bottom lines`
`  89:                              Vector vi1 = tmp[i+1,j] - tmp[i,j];`
`  90:                              Vector vi2 = tmp[i+1,j+1] - tmp[i,j+1];`
`  91:                              // Then bisect through the line connecting those two points`
`  92:                              Vector itemp1 = tmp[i,j] + vi1 * t;`
`  93:                              Vector itemp2 = tmp[i,j+1] + vi2 * t;`
`  94:                              Vector vj = itemp2 - itemp1;`
`  95:                              tmp[i,j] = itemp1 + vj * s;`
`  96:                          }`
`  97:   `
`  98:                  // After that loop, tmp[0,0] will contain the requested point`
`  99:                  return tmp[0,0];`
` 100:              }`
` 101:   `
` 102:              /// <summary>`
` 103:              /// Splits this Bezier Patch in the t direction`
` 104:              /// </summary>`
` 105:              /// <param name="t">The 't' parameter to split at, from 0 to 1</param>`
` 106:              /// <param name="a">Will contain the first half of the split</param>`
` 107:              /// <param name="b">Will contain the second half of the split</param>`
` 108:              public void Split_t(double t, out BezierPatch a, out BezierPatch b)`
` 109:              {`
` 110:                  // Check for degenerate case`
` 111:                  if (t < 0.0 || t > 1.0)`
` 112:                  {`
` 113:                      a = b = null;`
` 114:                      return;`
` 115:                  }`
` 116:   `
` 117:                  a = new BezierPatch();`
` 118:                  b = new BezierPatch();`
` 119:   `
` 120:                  // We're going to be splitting this bezier patch into two pieces,`
` 121:                  // effectively doubling the number of 'i' values`
` 122:   `
` 123:                  // Treat each row of 4 points as a single bezier curve`
` 124:                  for (int j = 0; j < 4; j++)`
` 125:                  {`
` 126:                      // For each row, calculate the new points`
` 127:                      Vector i1_1 = this[0,j] + t * (this[1,j] - this[0,j]);`
` 128:                      Vector i1_2 = this[1,j] + t * (this[2,j] - this[1,j]);`
` 129:                      Vector i1_3 = this[2,j] + t * (this[3,j] - this[2,j]);`
` 130:                      Vector i2_1 = i1_1 + t * (i1_2 - i1_1);`
` 131:                      Vector i2_2 = i1_2 + t * (i1_3 - i1_2);`
` 132:                      Vector i3_1 = i2_1 + t * (i2_2 - i2_1);`
` 133:                      // Points idx[0,j], i1_1, i2_1, and i3_1 make up curve A`
` 134:                      a.idx[0,j] = this[0,j];`
` 135:                      a.idx[1,j] = i1_1;`
` 136:                      a.idx[2,j] = i2_1;`
` 137:                      a.idx[3,j] = i3_1;`
` 138:                      // Points i3_1, i2_2, i1_3, and idx[3,j] make up curve B`
` 139:                      b.idx[0,j] = i3_1;`
` 140:                      b.idx[1,j] = i2_2;`
` 141:                      b.idx[2,j] = i1_3;`
` 142:                      b.idx[3,j] = this[3,j];`
` 143:                  }`
` 144:                  // Once all four curves are split, we're done`
` 145:              }`
` 146:   `
` 147:              /// <summary>`
` 148:              /// Splits this Bezier Patch in the s direction`
` 149:              /// </summary>`
` 150:              /// <param name="s">The 's' parameter to split at, from 0 to 1</param>`
` 151:              /// <param name="a">Will contain the first half of the split</param>`
` 152:              /// <param name="b">Will contain the second half of the split</param>`
` 153:              public void Split_s(double s, out BezierPatch a, out BezierPatch b)`
` 154:              {`
` 155:                  if (s < 0.0 || s > 1.0)`
` 156:                  {`
` 157:                      a = b = null;`
` 158:                      return;`
` 159:                  }`
` 160:   `
` 161:                  a = new BezierPatch();`
` 162:                  b = new BezierPatch();`
` 163:   `
` 164:                  // We're going to be splitting this bezier patch into two pieces,`
` 165:                  // effectively doubling the number of 'j' values`
` 166:   `
` 167:                  // Treat each row of 4 points as a single bezier curve`
` 168:                  for (int i = 0; i < 4; i++)`
` 169:                  {`
` 170:                      // For each row, calculate the new points`
` 171:                      Vector j1_1 = this[i,0] + s * (this[i,1] - this[i,0]);`
` 172:                      Vector j1_2 = this[i,1] + s * (this[i,2] - this[i,1]);`
` 173:                      Vector j1_3 = this[i,2] + s * (this[i,3] - this[i,2]);`
` 174:                      Vector j2_1 = j1_1 + s * (j1_2 - j1_1);`
` 175:                      Vector j2_2 = j1_2 + s * (j1_3 - j1_2);`
` 176:                      Vector j3_1 = j2_1 + s * (j2_2 - j2_1);`
` 177:                      // Points this[i,0], j1_1, j2_1, and j3_1 make up curve A`
` 178:                      a.idx[i,0] = this[i,0];`
` 179:                      a.idx[i,1] = j1_1;`
` 180:                      a.idx[i,2] = j2_1;`
` 181:                      a.idx[i,3] = j3_1;`
` 182:                      // Points j3_1, j2_2, j1_3, and this[i,3] make up curve B`
` 183:                      b.idx[i,0] = j3_1;`
` 184:                      b.idx[i,1] = j2_2;`
` 185:                      b.idx[i,2] = j1_3;`
` 186:                      b.idx[i,3] = this[i,3];`
` 187:                  }`
` 188:                  // Once all four curves are split, we're done`
` 189:              }`
` 190:   `
` 191:              /// <summary>`
` 192:              /// Clips this bezier patch in the t direction`
` 193:              /// </summary>`
` 194:              /// <param name="t0">The first location to split at</param>`
` 195:              /// <param name="t1">The second location to split at</param>`
` 196:              /// <param name="a">The Bezier Patch representing the original Bezier Patch from parameter t0 to t1</param>`
` 197:              public void Clip_t(double t0, double t1, out BezierPatch a)`
` 198:              {`
` 199:                  BezierPatch split_trash, split_a;`
` 200:                  // First split at t0`
` 201:                  Split_t(t0, out split_trash, out split_a);`
` 202:                  // split_trash contains the bezier curve from 0 to t0, so we can ignore it`
` 203:                  // split_a contains the curve from t0 to 1, so split it at the location `
` 204:                  // where t1 would be on that curve`
` 205:                  double t1n = (t1 - t0)/(1.0 - t0);`
` 206:                  // Keep the first part (t0 to t1), and throw out the second (t1 to 1)`
` 207:                  split_a.Split_t(t1n, out a, out split_trash);`
` 208:                  // Voila!`
` 209:              }`
` 210:   `
` 211:              /// <summary>`
` 212:              /// Clips this bezier patch in the s direction`
` 213:              /// </summary>`
` 214:              /// <param name="s0">The first location to split at</param>`
` 215:              /// <param name="s1">The second location to split at</param>`
` 216:              /// <param name="a">The Bezier Patch representing the original Bezier Patch from parameter s0 to s1</param>`
` 217:              public void Clip_s(double s0, double s1, out BezierPatch a)`
` 218:              {`
` 219:                  BezierPatch split_trash, split_a;`
` 220:                  // First split at s0`
` 221:                  Split_s(s0, out split_trash, out split_a);`
` 222:                  // split_trash contains the bezier curve from 0 to s0, so we can ignore it`
` 223:                  // split_a contains the curve from s0 to 1, so split it at the location `
` 224:                  // where s1 would be on that curve`
` 225:                  double s1n = (s1 - s0)/(1.0 - s0);`
` 226:                  // Keep the first part (s0 to s1), and throw out the second (s1 to 1)`
` 227:                  split_a.Split_s(s1n, out a, out split_trash);`
` 228:                  // Voila!`
` 229:              }`
` 230:   `
` 231:              /// <summary>`
` 232:              /// Creates a Hit object that intersects a given ray`
` 233:              /// </summary>`
` 234:              /// <param name="r">A Ray to intersect with this object</param>`
` 235:              /// <returns>The correct Hit object for the given ray</returns>`
` 236:              private Hit GenerateHit(Ray r)`
` 237:              {`
` 238:                  Hit h = new Hit();`
` 239:                  Vector ploc = Evaluate(0.5,0.5);`
` 240:                  double dist = Vector.Length(ploc - r.o);`
` 241:                  if (Vector.Dot(ploc - r.o, r.d) < 0)`
` 242:                      dist = -dist;`
` 243:                  h.n = Vector.Unitize(Vector.Cross(this[3,0] - this[0,0],this[0,3] - this[0,0]));`
` 244:                  h.r = r;`
` 245:                  if (Vector.Dot(h.n, r.d) > 0)`
` 246:                      h.n = -1 * h.n;`
` 247:                  h.t = dist;`
` 248:                  h.x = r.o + r.d * dist;`
` 249:                  return h;`
` 250:              }`
` 251:   `
` 252:              /// <summary>`
` 253:              /// Called by the scene to determine whether a given ray intersects this Bezier Patch`
` 254:              /// </summary>`
` 255:              /// <param name="r">The Ray to test for intersection</param>`
` 256:              /// <param name="divSize">The minimum size to recurse down to</param>`
` 257:              /// <param name="depth">The current depth of recursion</param>`
` 258:              /// <param name="dir">The direction to split in, 0 == t, 1 == s</param>`
` 259:              /// <returns>A new Hit object if the Ray intersects this patch, null if it does not</returns>`
` 260:              public Hit Intersect(Ray r, double divSize, int depth, int dir)`
` 261:              {`
` 262:                  // ---------------------`
` 263:                  // 1. Convert ray into intersection of two planes`
` 264:                  Plane xp = new Plane();`
` 265:                  xp.p = r.o + r.d;`
` 266:                  xp.n = Vector.Unitize(Vector.Cross(new Vector(0,1,0),r.d));`
` 267:                  Plane yp = new Plane();`
` 268:                  yp.p = r.o + r.d;`
` 269:                  yp.n = Vector.Unitize(Vector.Cross(r.d,xp.n));`
` 270:                  // ---------------------`
` 271:                  // 2. Flatten bezier patch onto these two new axes`
` 272:                  bool transpose = false;`
` 273:                  if (dir == 1)`
` 274:                      transpose = true;`
` 275:   `
` 276:                  double i_dist = Vector.Length(this[3,0] - this[0,0]);`
` 277:                  double j_dist = Vector.Length(this[0,3] - this[0,0]);`
` 278:   `
` 279:                  double[,,] Dij = new double[4,4,2];`
` 280:                  for (int i = 0; i < 4; i++)`
` 281:                  {`
` 282:                      for (int j = 0; j < 4; j++)`
` 283:                      {`
` 284:                          // If we're going to split along the 's' direction, then`
` 285:                          // transpose the control points of Dij`
` 286:                          if (transpose)`
` 287:                          {`
` 288:                              Dij[i,j,0] = xp.Dist(this[j,i]);`
` 289:                              Dij[i,j,1] = yp.Dist(this[j,i]);`
` 290:                          }`
` 291:                          else`
` 292:                          {`
` 293:                              Dij[i,j,0] = xp.Dist(this[i,j]);`
` 294:                              Dij[i,j,1] = yp.Dist(this[i,j]);`
` 295:                          }`
` 296:                      }`
` 297:                  }`
` 298:                  // ---------------------`
` 299:                  // 3. Choose a direction to split on, create a line through that direction, `
` 300:                  //    roughly parallel to the control points`
` 301:                  Vector Di1 = new Vector(Dij[3,0,0],Dij[3,0,1],0) - new Vector(Dij[0,0,0],Dij[0,0,1],0);`
` 302:                  Vector Di2 = new Vector(Dij[3,3,0],Dij[3,3,1],0) - new Vector(Dij[0,3,0],Dij[0,3,1],0);`
` 303:                  Vector Di = Vector.Unitize(Di1 + Di2);`
` 304:                  // Check for degenerate cases`
` 305:                  if (Di[0] == 0.0 && Di[1] == 0.0)`
` 306:                  {`
` 307:                      Di = Di1;`
` 308:                  }`
` 309:                  Vector l = Vector.Cross(Di,new Vector(0,0,1));`
` 310:                  // ---------------------`
` 311:                  // 4. Create a height map based on distance from that line`
` 312:                  double[,,] dij = new double[4,4,2];`
` 313:                  for (int i = 0; i < 4; i++)`
` 314:                  {`
` 315:                      for (int j = 0; j < 4; j++)`
` 316:                      {`
` 317:                          dij[i,j,0] = i / 3.0;`
` 318:                          dij[i,j,1] = l[0] * Dij[i,j,0] + l[1] * Dij[i,j,1];`
` 319:                      }`
` 320:                  }`
` 321:                  `
` 322:                  // Check whether the points actually cross the axis`
` 323:                  bool pos = false;`
` 324:                  bool changed = false;`
` 325:                  if (dij[0,0,1] >= 0.0)`
` 326:                      pos = true;`
` 327:                  for (int i = 0; i < 4; i++)`
` 328:                  {`
` 329:                      for (int j = 0; j < 4; j++)`
` 330:                      {`
` 331:                          if (dij[i,j,1] >= 0.0 && !pos)`
` 332:                              changed = true;`
` 333:                          if (dij[i,j,1] < 0.0 && pos)`
` 334:                              changed = true;`
` 335:                      }`
` 336:                  }`
` 337:                  // If they don't, then the ray doesn't hit this patch`
` 338:                  if (!changed)`
` 339:                      return null;`
` 340:                  `
` 341:                  // Check to see if we're done yet`
` 342:                  if (i_dist <= divSize && j_dist <= divSize)`
` 343:                      return GenerateHit(r);`
` 344:   `
` 345:                  // Check whether the currently selected axis is already small enough`
` 346:                  // If so, recurse in the other direction`
` 347:                  if (i_dist < divSize && !transpose)`
` 348:                      return Intersect(r, divSize, depth + 1, (transpose ? 0 : 1));`
` 349:                  else if (j_dist < divSize && transpose)`
` 350:                      return Intersect(r, divSize, depth + 1, (transpose ? 0 : 1));`
` 351:   `
` 352:                  // ---------------------`
` 353:                  // 5. Find the convex hull of the height map`
` 354:   `
` 355:                  // We only need the lowest and highest values at each interval`
` 356:                  double[,,] bounds = new double[4,2,2];`
` 357:                  for (int i = 0; i < 4; i++)`
` 358:                  {`
` 359:                      double minval = double.MaxValue;`
` 360:                      double maxval = double.MinValue;`
` 361:                      bounds[i,0,0] = dij[i,0,0];`
` 362:                      bounds[i,1,0] = dij[i,0,0];`
` 363:                      for (int j = 0; j < 4; j++)`
` 364:                      {`
` 365:                          if (dij[i,j,1] < minval)`
` 366:                              minval = dij[i,j,1];`
` 367:                          if (dij[i,j,1] > maxval)`
` 368:                              maxval = dij[i,j,1];`
` 369:                      }`
` 370:                      bounds[i,0,1] = minval;`
` 371:                      bounds[i,1,1] = maxval;`
` 372:                  }`
` 373:   `
` 374:                  // Determine location where the convex hull passes 'sea-level'`
` 375:                  double min_hull = double.MaxValue;`
` 376:                  double max_hull = double.MinValue;`
` 377:                  bool success = false;`
` 378:                  for (int a_i = 0; a_i < 4; a_i++)`
` 379:                      for (int a_j = 0; a_j < 2; a_j++)`
` 380:                          for (int b_i = 0; b_i < 4; b_i++)`
` 381:                              for (int b_j = 0; b_j < 2; b_j++)`
` 382:                              {`
` 383:                                  double t;`
` 384:                                  if (HitsAxis(bounds[a_i,a_j,0], bounds[a_i,a_j,1], bounds[b_i,b_j,0], bounds[b_i,b_j,1], out t))`
` 385:                                  {`
` 386:                                      if (t < min_hull)`
` 387:                                          min_hull = t;`
` 388:                                      if (t > max_hull)`
` 389:                                          max_hull = t;`
` 390:                                      success = true;`
` 391:                                  }`
` 392:                              }`
` 393:   `
` 394:                  if (!success)`
` 395:                      return null;`
` 396:   `
` 397:                  // ---------------------`
` 398:                  // 6-8. Check for max - min > 0.8, subdivide, or clip the bezier patch and recurse`
` 399:   `
` 400:                  // If our hull contains more than 80% of the axis line...`
` 401:                  if (max_hull - min_hull > 0.8)`
` 402:                  {`
` 403:                      // .. Split the bezier patch and call on each half`
` 404:                      BezierPatch a, b, temp;`
` 405:                      if (transpose)`
` 406:                      {`
` 407:                          Clip_s(min_hull, max_hull, out temp);`
` 408:                          Split_s(0.5, out a, out b);`
` 409:                      }`
` 410:                      else`
` 411:                      {`
` 412:                          Clip_t(min_hull, max_hull, out temp);`
` 413:                          Split_t(0.5, out a, out b);`
` 414:                      }`
` 415:                      Hit ha = a.Intersect(r, divSize, depth + 1, (transpose ? 0 : 1));`
` 416:                      Hit hb = b.Intersect(r, divSize, depth + 1, (transpose ? 0 : 1));`
` 417:                      if (ha != null && hb != null)`
` 418:                      {`
` 419:                          if (ha.t <= hb.t)`
` 420:                          {`
` 421:                              ha.next = hb;`
` 422:                              return ha;`
` 423:                          }`
` 424:                          else`
` 425:                          {`
` 426:                              hb.next = ha;`
` 427:                              return hb;`
` 428:                          }`
` 429:                      }`
` 430:                      else if (ha != null)`
` 431:                          return ha;`
` 432:                      else if (hb != null)`
` 433:                          return hb;`
` 434:                      else`
` 435:                          return null;`
` 436:                  }`
` 437:                  else`
` 438:                  {`
` 439:                      // Otherwise, just clip the bezier patch`
` 440:                      BezierPatch nbp;`
` 441:                      if (transpose)`
` 442:                          Clip_s(min_hull,max_hull,out nbp);`
` 443:                      else`
` 444:                          Clip_t(min_hull,max_hull,out nbp);`
` 445:                      return nbp.Intersect(r,divSize,depth + 1,(transpose ? 0 : 1));`
` 446:                  }`
` 447:              }`
` 448:          }`
` 449:   `
` 450:          /// <summary>`
` 451:          /// A private method which tests whether a line from (x1,y1) to (x2,y2) crosses the y axis`
` 452:          /// </summary>`
` 453:          /// <param name="x1">The x parameter of the first point</param>`
` 454:          /// <param name="y1">The y parameter of the first point</param>`
` 455:          /// <param name="x2">The x parameter of the second point</param>`
` 456:          /// <param name="y2">The y parameter of the second point</param>`
` 457:          /// <param name="i">The x value at which this line would pass the y axis</param>`
` 458:          /// <returns>True if this line actually crosses the y axis somewhere between x1 and x2</returns>`
` 459:          private static bool HitsAxis(double x1, double y1, double x2, double y2, out double i)`
` 460:          {`
` 461:              i = 0;`
` 462:   `
` 463:              double inv_m = (x2 - x1) / (y2 - y1);`
` 464:              if (double.IsNaN(inv_m) || double.IsInfinity(inv_m))`
` 465:              {`
` 466:                  // There's no rise, so this cannot cross the axis`
` 467:                  return false;`
` 468:              }`
` 469:              if (inv_m == 0.0)`
` 470:              {`
` 471:                  if (y1 < 0.0 && y2 < 0.0)`
` 472:                      return false;`
` 473:                  if (y2 > 0.0 && y2 > 0.0)`
` 474:                      return false;`
` 475:              }`
` 476:   `
` 477:              i = (-y1) * inv_m + x1;`
` 478:              if (x1 < x2)`
` 479:              {`
` 480:                  if (i < x1)`
` 481:                      return false;`
` 482:                  if (i > x2)`
` 483:                      return false;`
` 484:              }`
` 485:              else`
` 486:              {`
` 487:                  if (i > x1)`
` 488:                      return false;`
` 489:                  if (i < x2)`
` 490:                      return false;`
` 491:              }`
` 492:   `
` 493:              return true;`
` 494:          }`
` 495:   `
` 496:          /// <summary>`
` 497:          /// The list of patches which make up this Bezier Object`
` 498:          /// </summary>`
` 499:          public System.Collections.ArrayList patchList;`
` 500:   `
` 501:          /// <summary>`
` 502:          /// Loads a Bezier Object from a .bez file`
` 503:          /// </summary>`
` 504:          /// <param name="fs">An input stream to an open .bez file</param>`
` 505:          /// <returns>A new BezierObject if successful, null otherwise</returns>`
` 506:          public static BezierObject FromFile(System.IO.FileStream fs)`
` 507:          {`
` 508:              if (fs == null || !fs.CanRead)`
` 509:                  return null;`
` 510:   `
` 511:              BezierObject ret = new BezierObject();`
` 512:              System.Collections.ArrayList pointList = new System.Collections.ArrayList();`
` 513:              ret.patchList = new System.Collections.ArrayList();`
` 514:          `
` 515:              // Loop through the scene file and parse each line`
` 516:              String line;`
` 517:              while ((line = Util.GetLine(fs)) != null)`
` 518:              {`
` 519:                  // Break the string up into tokens`
` 520:                  line = Regex.Replace(line,@"((^[\s\t]+)|([s\t]+\$))","");`
` 521:                  String[] mc = Regex.Split(line,@"[\s\t]+");`
` 522:                  `
` 523:                  if (mc.Length == 4)            // 4 numbers == control point`
` 524:                  {`
` 525:                      Vector newPoint = new Vector(Double.Parse(mc[1]),Double.Parse(mc[2]),Double.Parse(mc[3]));`
` 526:                      pointList.Add(newPoint);`
` 527:                  }`
` 528:                  else if (mc.Length == 16)    // 16 numbers == patch`
` 529:                  {`
` 530:                      BezierPatch newPatch = new BezierPatch();`
` 531:                      newPatch[0] = (Vector)pointList[(-Int16.Parse(mc[0])) - 1];`
` 532:                      for (int i = 1; i < 16; i++)`
` 533:                          newPatch[i] = (Vector)pointList[(Int16.Parse(mc[i]) - 1)];`
` 534:                      ret.patchList.Add(newPatch);`
` 535:                  }`
` 536:              }`
` 537:   `
` 538:              return ret;`
` 539:          }`
` 540:   `
` 541:          /// <summary>`
` 542:          /// Converts a Bezier Object to triangles, and inserts these triangles into a given Scene`
` 543:          /// </summary>`
` 544:          /// <param name="scn">The Scene to insert the triangles into</param>`
` 545:          /// <param name="divisions">How many times to subdivide the Bezier Patch</param>`
` 546:          /// <remarks>`
` 547:          /// This should probably not be used, except for testing purposes, as rendering the Bezier Patch`
` 548:          /// directly is much faster and produces a much cleaner image.`
` 549:          /// </remarks>`
` 550:          public void ConvToTriangles(Scene scn, int divisions)`
` 551:          {`
` 552:              // Converts each patch to triangles and adds them to the scene`
` 553:              for (int i = 0; i < patchList.Count; i++)`
` 554:              {`
` 555:                  BezierPatch bp = (BezierPatch)patchList[i];`
` 556:   `
` 557:                  double div_size = 1.0 / (double)divisions;`
` 558:   `
` 559:                  for (int s_i = 0; s_i < divisions; s_i++)`
` 560:                      for (int t_i = 0; t_i < divisions; t_i++)`
` 561:                      {`
` 562:                          Double s = s_i * div_size;`
` 563:                          Double t = t_i * div_size;`
` 564:   `
` 565:                          // Evaluate the bezierpatch at four points to create triangles`
` 566:                          Vector va = bp.Evaluate(s,t);`
` 567:                          Vector vb = bp.Evaluate(s + div_size, t);`
` 568:                          Vector vc = bp.Evaluate(s + div_size, t + div_size);`
` 569:                          Vector vd = bp.Evaluate(s, t + div_size);`
` 570:                          TriangleObject t1 = new TriangleObject(va,vd,vb);`
` 571:                          TriangleObject t2 = new TriangleObject(vb,vd,vc);`
` 572:                          t1.mat = t2.mat = mat;`
` 573:                          scn.AddObject(t1);`
` 574:                          scn.AddObject(t2);`
` 575:                      }`
` 576:              }`
` 577:          }`
` 578:   `
` 579:          /// <summary>`
` 580:          /// The material for this BezierObject`
` 581:          /// </summary>`
` 582:          public BaseMaterial mat;`
` 583:   `
` 584:          /// <summary>`
` 585:          /// A necessary function to return the material at a given point`
` 586:          /// </summary>`
` 587:          /// <param name="x">The location to get a material at</param>`
` 588:          /// <returns>This object's material</returns>`
` 589:          public override BaseMaterial GetMaterialAt(Vector x)`
` 590:          {`
` 591:              return mat;`
` 592:          }`
` 593:          /// <summary>`
` 594:          /// Since it's impossible to say whether one is inside or outside of a Bezier Patch, this always returns false`
` 595:          /// </summary>`
` 596:          /// <param name="v">Location to test</param>`
` 597:          /// <returns>False</returns>`
` 598:          public override bool IsIn(Vector v)`
` 599:          {`
` 600:              return false;`
` 601:          }`
` 602:   `
` 603:          /// <summary>`
` 604:          /// A simple helper class to represent a Plane`
` 605:          /// </summary>`
` 606:          private class Plane`
` 607:          {`
` 608:              /// <summary>`
` 609:              /// A point on the plane`
` 610:              /// </summary>`
` 611:              public Vector p;`
` 612:              /// <summary>`
` 613:              /// The normal of the plane`
` 614:              /// </summary>`
` 615:              public Vector n;`
` 616:   `
` 617:              /// <summary>`
` 618:              /// Distance from a point to this plane`
` 619:              /// </summary>`
` 620:              /// <param name="x">A point</param>`
` 621:              /// <returns>The distance from 'x' to this plane</returns>`
` 622:              public double Dist(Vector x)`
` 623:              {`
` 624:                  return Vector.Dot(n,x - p);`
` 625:              }`
` 626:          }`
` 627:          `
` 628:          /// <summary>`
` 629:          /// Tests for an intersection between a given Ray and this Bezier Object`
` 630:          /// </summary>`
` 631:          /// <param name="r">The Ray to test</param>`
` 632:          /// <returns>The closest hit out of all of the patches in this object</returns>`
` 633:          public override Hit Intersect(Ray r)`
` 634:          {`
` 635:              Hit closest = null;`
` 636:              // Find the closest hit out of all of the bezier patches in this object`
` 637:              for (int patchnum = 0; patchnum < patchList.Count; patchnum++)`
` 638:              {`
` 639:                  BezierPatch bp = ((BezierPatch)patchList[patchnum]);`
` 640:                  Hit h = bp.Intersect(r,DIV_SIZE,0,0);`
` 641:                  if (h != null)`
` 642:                  {`
` 643:                      Hit ch = h;`
` 644:                      while (ch != null)`
` 645:                      {`
` 646:                          if (ch.t > 0)`
` 647:                          {`
` 648:                              ch.obj = this;`
` 649:                              if (closest == null)`
` 650:                                  closest = ch;`
` 651:                              else if (ch.t < closest.t)`
` 652:                                  closest = ch;`
` 653:                          }`
` 654:                          ch = ch.next;`
` 655:                      }`
` 656:                  }`
` 657:              }`
` 658:              return closest;`
` 659:          }`
` 660:      }`