BRL-CAD
brep.cpp
Go to the documentation of this file.
1 /* B R E P . C P P
2  * BRL-CAD
3  *
4  * Copyright (c) 2007-2014 United States Government as represented by
5  * the U.S. Army Research Laboratory.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * version 2.1 as published by the Free Software Foundation.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this file; see the file named COPYING for more
18  * information.
19  */
20 /** @addtogroup g_ */
21 /** @{ */
22 /** @file brep.cpp
23  *
24  * Implementation of a generalized Boundary Representation (BREP)
25  * primitive using the openNURBS library.
26  *
27  */
28 
29 #include "common.h"
30 
31 #include <vector>
32 #include <list>
33 #include <map>
34 #include <stack>
35 #include <iostream>
36 #include <algorithm>
37 #include <set>
38 #include <utility>
39 
40 #include "poly2tri/poly2tri.h"
41 
42 #include "assert.h"
43 
44 #include "vmath.h"
45 
46 #include "bu/cv.h"
47 #include "bu/time.h"
48 #include "brep.h"
49 #include "dvec.h"
50 
51 #include "raytrace.h"
52 #include "rtgeom.h"
53 
54 #include "./brep_local.h"
55 #include "./brep_debug.h"
56 
57 /* undefine "min" and "max" macros, if they exist, to prevent
58  * name conflicts with functions "std::min" and "std::max".
59  */
60 #ifdef max
61 #undef max
62 #endif
63 
64 #ifdef min
65 #undef min
66 #endif
67 
68 #define BN_VMATH_PREFIX_INDICES 1
69 #define ROOT_TOL 1.E-7
70 
71 /* uncomment to enable debug plotting */
72 /* #define PLOTTING 1 */
73 
74 #ifdef __cplusplus
75 extern "C" {
76 #endif
77 int rt_brep_bbox(struct rt_db_internal* ip, point_t *min, point_t *max);
78 int rt_brep_prep(struct soltab *stp, struct rt_db_internal* ip, struct rt_i* rtip);
79 void rt_brep_print(register const struct soltab *stp);
80 int rt_brep_shot(struct soltab *stp, register struct xray *rp, struct application *ap, struct seg *seghead);
81 void rt_brep_norm(register struct hit *hitp, struct soltab *stp, register struct xray *rp);
82 void rt_brep_curve(register struct curvature *cvp, register struct hit *hitp, struct soltab *stp);
83 int rt_brep_class(const struct soltab *stp, const fastf_t *min, const fastf_t *max, const struct bn_tol *tol);
84 void rt_brep_uv(struct application *ap, struct soltab *stp, register struct hit *hitp, register struct uvcoord *uvp);
85 void rt_brep_free(register struct soltab *stp);
86 int rt_brep_adaptive_plot(struct rt_db_internal *ip, const struct rt_view_info *info);
87 int rt_brep_plot(struct bu_list *vhead, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol, const struct rt_view_info *UNUSED(info));
88 int rt_brep_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol);
89 int rt_brep_get(struct bu_vls *logstr, const struct rt_db_internal *intern, const char *attr);
90 int rt_brep_adjust(struct bu_vls *logstr, const struct rt_db_internal *intern, int argc, const char **argv);
91 int rt_brep_export5(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip);
92 int rt_brep_import5(struct rt_db_internal *ip, const struct bu_external *ep, register const fastf_t *mat, const struct db_i *dbip);
93 void rt_brep_ifree(struct rt_db_internal *ip);
94 int rt_brep_describe(struct bu_vls *str, const struct rt_db_internal *ip, int verbose, double mm2local);
95 int rt_brep_tclget(Tcl_Interp *interp, const struct rt_db_internal *intern, const char *attr);
96 int rt_brep_tcladjust(Tcl_Interp *interp, struct rt_db_internal *intern, int argc, const char **argv);
97 int rt_brep_params(struct pc_pc_set *, const struct rt_db_internal *ip);
98 RT_EXPORT extern int rt_brep_boolean(struct rt_db_internal *out, const struct rt_db_internal *ip1, const struct rt_db_internal *ip2, db_op_t operation);
99 struct rt_selection_set *rt_brep_find_selections(const struct rt_db_internal *ip, const struct rt_selection_query *query);
100 int rt_brep_process_selection(struct rt_db_internal *ip, const struct rt_selection *selection, const struct rt_selection_operation *op);
101 #ifdef __cplusplus
102 }
103 #endif
104 
105 
106 /* FIXME: fugly */
107 static int hit_count = 0;
108 
109 
110 /********************************************************************************
111  * Auxiliary functions
112  ********************************************************************************/
113 
114 
115 using namespace brlcad;
116 
117 ON_Ray toXRay(struct xray* rp)
118 {
119  ON_3dPoint pt(rp->r_pt);
120  ON_3dVector dir(rp->r_dir);
121  return ON_Ray(pt, dir);
122 }
123 
124 
125 //--------------------------------------------------------------------------------
126 // specific
127 struct brep_specific*
129 {
130  return (struct brep_specific*)bu_calloc(1, sizeof(struct brep_specific), "brep_specific_new");
131 }
132 
133 
134 void
136 {
137  if (bs != NULL) {
138  delete bs->bvh;
139  bu_free(bs, "brep_specific_delete");
140  }
141 }
142 
143 
144 //--------------------------------------------------------------------------------
145 // prep
146 
147 bool
148 brep_pt_trimmed(pt2d_t pt, const ON_BrepFace& face)
149 {
150  bool retVal = false;
151  TRACE1("brep_pt_trimmed: " << PT2(pt));
152 
153  // for each loop
154  const ON_Surface* surf = face.SurfaceOf();
155  double umin, umax;
156  ON_2dPoint from(0.0, 0.0);
157  ON_2dPoint to(0.0, 0.0);
158 
159  from.x = pt[0];
160  from.y = to.y = pt[1];
161  surf->GetDomain(0, &umin, &umax);
162  to.x = umax + 1;
163  ON_Line ray(from, to);
164 
165  // int intersections = 0;
166  // for (int i = 0; i < face.LoopCount(); i++) {
167  // ON_BrepLoop* loop = face.Loop(i);
168  // for each trim
169  // for (int j = 0; j < loop->m_ti.Count(); j++) {
170  // ON_BrepTrim& trim = face.Brep()->m_T[loop->m_ti[j]];
171  // const ON_Curve* trimCurve = trim.TrimCurveOf();
172  // intersections += brep_count_intersections(ray, trimCurve);
173  // ray.IntersectCurve(trimCurve, intersections, 0.0001);
174  // intersections += trimCurve->NumIntersectionsWith(ray);
175  // }
176  // }
177 
178  /* If we base trimming on the number of intersections with, rhino
179  * generated curves won't raytrace. In fact, we need to ignore
180  * trimming for the time being, just return false.
181  *
182  * FIXME: figure out what this code does, and fix it for rhino
183  * generated geometries. djg 4/16/08
184  */
185 
186  // the point is trimmed if the # of intersections is even and non-zero
187  // retVal= (intersections > 0 && (intersections % 2) == 0);
188 
189  return retVal;
190 }
191 
192 
193 double
194 getVerticalTangent(const ON_Curve *curve, double min, double max)
195 {
196  double mid;
197  ON_3dVector tangent;
198  bool tanmin;
199 
200  tangent = curve->TangentAt(min);
201  tanmin = (tangent[X] < 0.0);
202  while ((max - min) > 0.00001) {
203  mid = (max + min) / 2.0;
204  tangent = curve->TangentAt(mid);
205  if (NEAR_ZERO(tangent[X], 0.00001)) {
206  return mid;
207  }
208  if ((tangent[X] < 0.0) == tanmin) {
209  min = mid;
210  } else {
211  max = mid;
212  }
213  }
214  return min;
215 }
216 
217 
218 double
219 getHorizontalTangent(const ON_Curve *curve, double min, double max)
220 {
221  double mid;
222  ON_3dVector tangent;
223  bool tanmin;
224 
225  tangent = curve->TangentAt(min);
226  tanmin = (tangent[Y] < 0.0);
227  while ((max - min) > 0.00001) {
228  mid = (max + min) / 2.0;
229  tangent = curve->TangentAt(mid);
230  if (NEAR_ZERO(tangent[Y], 0.00001)) {
231  return mid;
232  }
233  if ((tangent[Y] < 0.0) == tanmin) {
234  min = mid;
235  } else {
236  max = mid;
237  }
238  }
239  return min;
240 }
241 
242 
243 bool
244 split_trims_hv_tangent(const ON_Curve* curve, ON_Interval& t, std::list<double>& list)
245 {
246  bool tanx1, tanx2, tanx_changed;
247  bool tany1, tany2, tany_changed;
248  bool tan_changed;
249  ON_3dVector tangent1(0.0, 0.0, 0.0);
250  ON_3dVector tangent2(0.0, 0.0, 0.0);
251  ON_3dPoint p1(0.0, 0.0, 0.0);
252  ON_3dPoint p2(0.0, 0.0, 0.0);
253 
254  tangent1 = curve->TangentAt(t[0]);
255  tangent2 = curve->TangentAt(t[1]);
256 
257  tanx1 = (tangent1[X] < 0.0);
258  tanx2 = (tangent2[X] < 0.0);
259  tany1 = (tangent1[Y] < 0.0);
260  tany2 = (tangent2[Y] < 0.0);
261 
262  tanx_changed = (tanx1 != tanx2);
263  tany_changed = (tany1 != tany2);
264 
265  tan_changed = tanx_changed || tany_changed;
266 
267  if (tan_changed) {
268  if (tanx_changed && tany_changed) {//horz & vert simply split
269  double midpoint = (t[1] + t[0]) / 2.0;
270  ON_Interval left(t[0], midpoint);
271  ON_Interval right(midpoint, t[1]);
272  split_trims_hv_tangent(curve, left, list);
273  split_trims_hv_tangent(curve, right, list);
274  return true;
275  } else if (tanx_changed) {//find horz
276  double x = getVerticalTangent(curve, t[0], t[1]);
277  list.push_back(x);
279  } else { //find vert
280  double x = getHorizontalTangent(curve, t[0], t[1]);
281  list.push_back(x);
283  }
284  } else { // check point slope for change
285  bool slopex, slopex_changed;
286  bool slopey, slopey_changed;
287  bool slope_changed;
288 
289  p1 = curve->PointAt(t[0]);
290  p2 = curve->PointAt(t[1]);
291 
292  slopex = ((p2[X] - p1[X]) < 0.0);
293  slopey = ((p2[Y] - p1[Y]) < 0.0);
294 
295  slopex_changed = (slopex != tanx1);
296  slopey_changed = (slopey != tany1);
297 
298  slope_changed = slopex_changed || slopey_changed;
299 
300  if (slope_changed) { //2 horz or 2 vert changes simply split
301  double midpoint = (t[1] + t[0]) / 2.0;
302  ON_Interval left(t[0], midpoint);
303  ON_Interval right(midpoint, t[1]);
304  split_trims_hv_tangent(curve, left, list);
305  split_trims_hv_tangent(curve, right, list);
306  return true;
307  } else {
309  }
310  }
311  //plot color coded segment
312  plottrim(*curve, t[0], t[1]);
313 
314  return true;
315 }
316 
317 
319  struct brep_specific *bs;
320  SurfaceTree**faces;
321 };
322 
323 static void
324 brep_build_bvh_surface_tree(int cpu, void *data)
325 {
326  struct brep_build_bvh_parallel *bbbp = (struct brep_build_bvh_parallel *)data;
327  int index;
328  ON_BrepFaceArray& faces = bbbp->bs->brep->m_F;
329  size_t faceCount = faces.Count();
330 
331  do {
332  index = -1;
333 
334  /* figure out which face to work on next */
336  for (size_t i = 0; i < faceCount; i++) {
337  if (bbbp->faces[i] == NULL) {
338  index = i;
339  bbbp->faces[i] = (SurfaceTree*)(intptr_t)(cpu+1); /* claim this one */
340  break;
341  }
342  }
344 
345  if (index != -1) {
346  bu_log("thread %d: preparing face %d of %d\n", cpu, index+1, faceCount);
347  SurfaceTree* st = new SurfaceTree(&faces[index], true, 8);
348  bbbp->faces[index] = st;
349  }
350 
351  /* iterate until there is no more work left */
352  } while (index != -1);
353 }
354 
355 
356 int
358 {
359  // First, run the openNURBS validity check on the brep in question
360  ON_TextLog tl(stderr);
361  ON_Brep* brep = bs->brep;
362  int64_t start;
363 
364  if (brep == NULL) {
365  bu_log("NULL Brep");
366  return -1;
367  } else {
368  start = bu_gettime();
369  if (!brep->IsValid(&tl)) bu_log("brep is NOT valid\n");
370  bu_log("!!! BREP ISVALID: %.2f sec\n", (bu_gettime() - start) / 1000000.0);
371  }
372 
373  /* Initialize the top level Bounding Box node for the entire
374  * surface tree. The purpose of this node is to provide a parent
375  * node for the trees to be built on each BREP component surface.
376  * This takes no time.
377  */
378  bs->bvh = new BBNode(brep->BoundingBox());
379 
380  ON_BrepFaceArray& faces = brep->m_F;
381  size_t faceCount = faces.Count();
382 
383  struct brep_build_bvh_parallel bbbp;
384  bbbp.bs = bs;
385  bbbp.faces = (SurfaceTree**)bu_calloc(faceCount, sizeof(SurfaceTree*), "alloc face array");
386 
387  /* For each face in the brep, build its surface tree and add the
388  * root node of that tree as a child of the bvh master node
389  * defined above. We do this in parallel in order to divy up work
390  * for objects comprised of many faces.
391  *
392  * A possible future refinement of this approach would be to build
393  * a tree structure on top of the collection of surface trees
394  * based on their 3D bounding volumes, as opposed to the current
395  * approach of simply having all surfaces be child nodes of the
396  * master node. This would allow a ray intersection to avoid
397  * checking every surface tree bounding box, but should probably
398  * be undertaken only if this step proves to be a bottleneck for
399  * raytracing.
400  */
401 
402  start = bu_gettime();
403  bu_parallel(brep_build_bvh_surface_tree, 0, &bbbp);
404 
405  for (int i = 0; (size_t)i < faceCount; i++) {
406  ON_BrepFace& face = faces[i];
407  face.m_face_user.p = bbbp.faces[i];
408  bs->bvh->addChild(bbbp.faces[i]->getRootNode());
409  }
410  bu_log("!!! PREP FACES: %.2f sec\n", (bu_gettime() - start) / 1000000.0);
411 
412  bu_free(bbbp.faces, "free face array");
413 
414  bs->bvh->BuildBBox();
415  return 0;
416 }
417 
418 
419 /********************************************************************************
420  * BRL-CAD Primitive interface
421  ********************************************************************************/
422 
423 /**
424  * Calculate a bounding RPP around a BREP. Unlike the prep
425  * routine, which makes use of the full bounding volume hierarchy,
426  * this routine just calls the openNURBS function.
427  */
428 int
429 rt_brep_bbox(struct rt_db_internal *ip, point_t *min, point_t *max)
430 {
431  struct rt_brep_internal* bi;
432  ON_3dPoint dmin(0.0, 0.0, 0.0);
433  ON_3dPoint dmax(0.0, 0.0, 0.0);
434 
435  RT_CK_DB_INTERNAL(ip);
436  bi = (struct rt_brep_internal*)ip->idb_ptr;
437  RT_BREP_CK_MAGIC(bi);
438 
439  bi->brep->GetBBox(dmin, dmax);
440  VMOVE(*min, dmin);
441  VMOVE(*max, dmax);
442 
443  return 0;
444 }
445 
446 
447 /**
448  * Given a pointer of a GED database record, and a transformation
449  * matrix, determine if this is a valid NURB, and if so, prepare the
450  * surface so the intersections will work.
451  */
452 int
453 rt_brep_prep(struct soltab *stp, struct rt_db_internal* ip, struct rt_i* rtip)
454 {
455  int64_t start;
456 
457  TRACE1("rt_brep_prep");
458  /* This prepares the NURBS specific data structures to be used
459  * during intersection... i.e. acceleration data structures and
460  * whatever else is needed.
461  */
462  struct rt_brep_internal* bi;
463  struct brep_specific* bs;
464  const struct bn_tol *tol = &rtip->rti_tol;
465 
466  RT_CK_DB_INTERNAL(ip);
467  bi = (struct rt_brep_internal*)ip->idb_ptr;
468  RT_BREP_CK_MAGIC(bi);
469 
470  if ((bs = (struct brep_specific*)stp->st_specific) == NULL) {
471  BU_ALLOC(bs, struct brep_specific);
472  bs->brep = bi->brep;
473  bi->brep = NULL;
474  stp->st_specific = (void *)bs;
475  }
476 
477  /* The workhorse routines of BREP prep are called by brep_build_bvh
478  */
479  start = bu_gettime();
480  if (brep_build_bvh(bs) < 0) {
481  return -1;
482  }
483  bu_log("!!! BUILD BVH: %.2f sec\n", (bu_gettime() - start) / 1000000.0);
484 
485  /* Once a proper SurfaceTree is built, finalize the bounding
486  * volumes. This takes no time. */
487  bs->bvh->GetBBox(stp->st_min, stp->st_max);
488 
489  // expand outer bounding box just a little bit
490  point_t adjust;
491  VSETALL(adjust, tol->dist < SMALL_FASTF ? SMALL_FASTF : tol->dist);
492  VSUB2(stp->st_min, stp->st_min, adjust);
493  VADD2(stp->st_max, stp->st_max, adjust);
494 
495  VADD2SCALE(stp->st_center, stp->st_min, stp->st_max, 0.5);
496  vect_t work;
497  VSUB2SCALE(work, stp->st_max, stp->st_min, 0.5);
498  fastf_t f = work[X];
499  V_MAX(f, work[Y]);
500  V_MAX(f, work[Z]);
501  stp->st_aradius = f;
502  stp->st_bradius = MAGNITUDE(work);
503 
504  return 0;
505 }
506 
507 
508 void
509 rt_brep_print(const struct soltab *stp)
510 {
511  struct brep_specific* bs;
512 
513  if (!stp)
514  return;
515  RT_CK_SOLTAB(stp);
516  bs = (struct brep_specific*)stp->st_specific;
517  if (!bs)
518  return;
519 }
520 
521 
522 //================================================================================
523 // shot support
524 
525 
526 class brep_hit
527 {
528 public:
529 
530  enum hit_type {
535  CRACK_HIT //applied to first point of two near_miss points with same normal direction, second point removed
536  };
539  LEAVING
540  };
541 
542  const ON_BrepFace& face;
544  point_t origin;
545  point_t point;
546  vect_t normal;
547  pt2d_t uv;
548  bool trimmed;
550  bool oob;
551  enum hit_type hit;
552  enum hit_direction direction;
554  // XXX - calculate the dot of the dir with the normal here!
555  BBNode const * sbv;
556 
557  brep_hit(const ON_BrepFace& f, const ON_Ray& ray, const point_t p, const vect_t n, const pt2d_t _uv)
558  : face(f), trimmed(false), closeToEdge(false), oob(false), hit(CLEAN_HIT), direction(ENTERING), m_adj_face_index(0), sbv(NULL)
559  {
560  vect_t dir;
561  VMOVE(origin, ray.m_origin);
562  VMOVE(point, p);
563  VMOVE(normal, n);
564  VSUB2(dir, point, origin);
565  dist = VDOT(ray.m_dir, dir);
566  move(uv, _uv);
567  }
568 
569  brep_hit(const ON_BrepFace& f, fastf_t d, const ON_Ray& ray, const point_t p, const vect_t n, const pt2d_t _uv)
570  : face(f), dist(d), trimmed(false), closeToEdge(false), oob(false), hit(CLEAN_HIT), direction(ENTERING), m_adj_face_index(0), sbv(NULL)
571  {
572  VMOVE(origin, ray.m_origin);
573  VMOVE(point, p);
574  VMOVE(normal, n);
575  move(uv, _uv);
576  }
577 
578  brep_hit(const brep_hit& h)
579  : face(h.face), dist(h.dist), trimmed(h.trimmed), closeToEdge(h.closeToEdge), oob(h.oob), hit(h.hit), direction(h.direction), m_adj_face_index(h.m_adj_face_index), sbv(h.sbv)
580  {
581  VMOVE(origin, h.origin);
582  VMOVE(point, h.point);
583  VMOVE(normal, h.normal);
584  move(uv, h.uv);
585 
586  }
587 
589  {
590  const_cast<ON_BrepFace&>(face) = h.face;
591  dist = h.dist;
592  VMOVE(origin, h.origin);
593  VMOVE(point, h.point);
594  VMOVE(normal, h.normal);
595  move(uv, h.uv);
596  trimmed = h.trimmed;
597  closeToEdge = h.closeToEdge;
598  oob = h.oob;
599  sbv = h.sbv;
600  hit = h.hit;
601  direction = h.direction;
602  m_adj_face_index = h.m_adj_face_index;
603 
604  return *this;
605  }
606 
607  bool operator==(const brep_hit& h) const
608  {
609  return NEAR_ZERO(dist - h.dist, BREP_SAME_POINT_TOLERANCE);
610  }
611 
612  bool operator<(const brep_hit& h) const
613  {
614  return dist < h.dist;
615  }
616 };
617 
618 
619 typedef std::list<brep_hit> HitList;
620 
621 
622 typedef enum {
631 
632 
633 HIDDEN const char*
635 {
636  static const char *reason[] = {
637  "grazed to the right of the edge",
638  "missed the edge altogether (outside tolerance)",
639  "hit root iteration limit",
640  "root diverged",
641  "out of subsurface bounds",
642  "trimmed",
643  "found",
644  "UNKNOWN"
645  };
646 
647  return reason[index + 5];
648 }
649 
650 
651 void
652 utah_F(const ON_3dPoint &S, const ON_3dVector &p1, const double p1d, const ON_3dVector &p2, const double p2d, double &f1, double &f2)
653 {
654  f1 = (S * p1) + p1d;
655  f2 = (S * p2) + p2d;
656 }
657 
658 
659 void
660 utah_Fu(const ON_3dVector &Su, const ON_3dVector &p1, const ON_3dVector &p2, double &d0, double &d1)
661 {
662  d0 = Su * p1;
663  d1 = Su * p2;
664 }
665 
666 
667 void
668 utah_Fv(const ON_3dVector &Sv, const ON_3dVector &p1, const ON_3dVector &p2, double &d0, double &d1)
669 {
670  d0 = Sv * p1;
671  d1 = Sv * p2;
672 }
673 
674 
675 double
676 utah_calc_t(const ON_Ray &r, ON_3dPoint &S)
677 {
678  ON_3dVector d(r.m_dir);
679  ON_3dVector oS(S - r.m_origin);
680 
681  return (d * oS) / (d * d);
682 }
683 
684 
685 void
686 utah_pushBack(const ON_Surface* surf, ON_2dPoint &uv)
687 {
688  double t0, t1;
689 
690  surf->GetDomain(0, &t0, &t1);
691  if (t1 < t0) {
692  double tmp = t0;
693  t0 = t1;
694  t1 = tmp;
695  }
696 
697  if (uv.x < t0) {
698  uv.x = t0;
699  } else if (uv.x > t1) {
700  uv.x = t1;
701  }
702 
703  surf->GetDomain(1, &t0, &t1);
704  if (t1 < t0) {
705  double tmp = t0;
706  t0 = t1;
707  t1 = tmp;
708  }
709  if (uv.y < t0) {
710  uv.y = t0;
711  } else if (uv.y > t1) {
712  uv.y = t1;
713  }
714 }
715 
716 
717 void
718 utah_pushBack(const BBNode* sbv, ON_2dPoint &uv)
719 {
720  double t0, t1;
721  int i = sbv->m_u.m_t[0] < sbv->m_u.m_t[1] ? 0 : 1;
722 
723  t0 = sbv->m_u.m_t[i];
724  t1 = sbv->m_u.m_t[1 - i];
725  if (uv.x < t0) {
726  uv.x = t0;
727  } else if (uv.x > t1) {
728  uv.x = t1;
729  }
730  i = sbv->m_v.m_t[0] < sbv->m_v.m_t[1] ? 0 : 1;
731  t0 = sbv->m_v.m_t[i];
732  t1 = sbv->m_v.m_t[1 - i];
733  if (uv.y < t0) {
734  uv.y = t0;
735  } else if (uv.y > t1) {
736  uv.y = t1;
737  }
738 }
739 
740 
741 int
742 utah_newton_solver(const BBNode* sbv, const ON_Surface* surf, const ON_Ray& r, ON_2dPoint* ouv, double* t, ON_3dVector* N, bool& converged, ON_2dPoint* suv, const int count, const int iu, const int iv)
743 {
744  int i = 0;
745  int intersects = 0;
746  double j11 = 0.0;
747  double j12 = 0.0;
748  double j21 = 0.0;
749  double j22 = 0.0;
750  double f = 0.0;
751  double g = 0.0;
752  double rootdist = 0.0;
753  double oldrootdist = 0.0;
754  double J = 0.0;
755  double invdetJ = 0.0;
756  double du = 0.0;
757  double dv = 0.0;
758  double cdu = 0.0;
759  double cdv = 0.0;
760 
761  ON_3dVector p1, p2;
762  double p1d = 0.0, p2d = 0.0;
763  int errantcount = 0;
764  utah_ray_planes(r, p1, p1d, p2, p2d);
765 
766  ON_3dPoint S(0.0, 0.0, 0.0);
767  ON_3dVector Su(0.0, 0.0, 0.0);
768  ON_3dVector Sv(0.0, 0.0, 0.0);
769  //ON_3dVector Suu, Suv, Svv;
770 
771  ON_2dPoint uv(0.0, 0.0);
772  ON_2dPoint puv(0.0, 0.0);
773 
774  uv.x = suv->x;
775  uv.y = suv->y;
776 
777  ON_2dPoint uv0(uv);
778  surf->Ev1Der(uv.x, uv.y, S, Su, Sv);
779  //surf->Ev2Der( uv.x, uv.y, S, Su, Sv, Suu, Suv, Svv);
780 
781  utah_F(S, p1, p1d, p2, p2d, f, g);
782  rootdist = fabs(f) + fabs(g);
783 
784  for (i = 0; i < BREP_MAX_ITERATIONS; i++) {
785  utah_Fu(Su, p1, p2, j11, j21);
786  utah_Fv(Sv, p1, p2, j12, j22);
787 
788  J = (j11 * j22 - j12 * j21);
789 
791  // perform jittered perturbation in parametric domain....
792  uv.x = uv.x + .1 * drand48() * (uv0.x - uv.x);
793  uv.y = uv.y + .1 * drand48() * (uv0.y - uv.y);
794  continue;
795  }
796 
797  invdetJ = 1.0 / J;
798 
799  if ((iu != -1) && (iv != -1)) {
800  du = -invdetJ * (j22 * f - j12 * g);
801  dv = -invdetJ * (j11 * g - j21 * f);
802 
803  if (i == 0) {
804  if (((iu == 0) && (du < 0.0)) || ((iu == 1) && (du > 0.0)))
805  return intersects; //head out of U bounds
806  if (((iv == 0) && (dv < 0.0)) || ((iv == 1) && (dv > 0.0)))
807  return intersects; //head out of V bounds
808  }
809  }
810 
811  du = invdetJ * (j22 * f - j12 * g);
812  dv = invdetJ * (j11 * g - j21 * f);
813 
814 
815  if (i == 0) {
816  cdu = du;
817  cdv = dv;
818  } else {
819  int sgnd = (du > 0) - (du < 0);
820  int sgncd = (cdu > 0) - (cdu < 0);
821  if ((sgnd != sgncd) && (fabs(du) > fabs(cdu))) {
822  du = sgnd * 0.75 * fabs(cdu);
823  }
824  sgnd = (dv > 0) - (dv < 0);
825  sgncd = (cdv > 0) - (cdv < 0);
826  if ((sgnd != sgncd) && (fabs(dv) > fabs(cdv))) {
827  dv = sgnd * 0.75 * fabs(cdv);
828  }
829  cdu = du;
830  cdv = dv;
831  }
832  puv.x = uv.x;
833  puv.y = uv.y;
834 
835  uv.x -= du;
836  uv.y -= dv;
837 
838  utah_pushBack(sbv, uv);
839 
840  surf->Ev1Der(uv.x, uv.y, S, Su, Sv);
841  utah_F(S, p1, p1d, p2, p2d, f, g);
842  oldrootdist = rootdist;
843  rootdist = fabs(f) + fabs(g);
844  int halve_count = 0;
845 
846  /* FIXME: all constants should be documented, why this
847  * value? what's the sensitivity/impact?
848  */
849  while ((halve_count++ < 3) && (oldrootdist < rootdist)) {
850  // divide current UV step
851  uv.x = (puv.x + uv.x) / 2.0;
852  uv.y = (puv.y + uv.y) / 2.0;
853 
854  utah_pushBack(sbv, uv);
855 
856  surf->Ev1Der(uv.x, uv.y, S, Su, Sv);
857  utah_F(S, p1, p1d, p2, p2d, f, g);
858  rootdist = fabs(f) + fabs(g);
859  }
860 
861  if (oldrootdist <= rootdist) {
862 
863  /* FIXME: all constants should be documented. why this
864  * value? must it coincide with the constant in the
865  * preceding loop?
866  */
867  if (errantcount > 3) {
868  return intersects;
869  } else {
870  errantcount++;
871  }
872  }
873 
874  if (rootdist < ROOT_TOL) {
875  int ulow = (sbv->m_u.m_t[0] <= sbv->m_u.m_t[1]) ? 0 : 1;
876  int vlow = (sbv->m_v.m_t[0] <= sbv->m_v.m_t[1]) ? 0 : 1;
877  if ((sbv->m_u.m_t[ulow] - VUNITIZE_TOL < uv.x && uv.x < sbv->m_u.m_t[1 - ulow] + VUNITIZE_TOL) &&
878  (sbv->m_v.m_t[vlow] - VUNITIZE_TOL < uv.y && uv.y < sbv->m_v.m_t[1 - vlow] + VUNITIZE_TOL)) {
879  bool new_point = true;
880  for (int j = 0; j < count; j++) {
881  if (NEAR_EQUAL(uv.x, ouv[j].x, VUNITIZE_TOL) && NEAR_EQUAL(uv.y, ouv[j].y, VUNITIZE_TOL)) {
882  new_point = false;
883  }
884  }
885  if (new_point) {
886  //bu_log("New Hit Point:(%f %f %f) uv(%f, %f)\n", S.x, S.y, S.z, uv.x, uv.y);
887  t[count] = utah_calc_t(r, S);
888  N[count] = ON_CrossProduct(Su, Sv);
889  N[count].Unitize();
890  ouv[count].x = uv.x;
891  ouv[count].y = uv.y;
892  intersects++;
893  converged = true;
894  }
895  }
896  return intersects;
897  }
898  }
899  return intersects;
900 }
901 
902 
903 int
904 utah_newton_4corner_solver(const BBNode* sbv, const ON_Surface* surf, const ON_Ray& r, ON_2dPoint* ouv, double* t, ON_3dVector* N, bool& converged, int docorners)
905 {
906  int intersects = 0;
907  converged = false;
908  if (docorners) {
909  for (int iu = 0; iu < 2; iu++) {
910  for (int iv = 0; iv < 2; iv++) {
911  ON_2dPoint uv;
912  uv.x = sbv->m_u[iu];
913  uv.y = sbv->m_v[iv];
914  intersects += utah_newton_solver(sbv, surf, r, ouv, t, N, converged, &uv, intersects, iu, iv);
915  }
916  }
917  }
918 
919  ON_2dPoint uv;
920  uv.x = sbv->m_u.Mid();
921  uv.y = sbv->m_v.Mid();
922  intersects += utah_newton_solver(sbv, surf, r, ouv, t, N, converged, &uv, intersects, -1, -1);
923  return intersects;
924 }
925 
926 
927 bool
928 utah_isTrimmed(ON_2dPoint uv, const ON_BrepFace *face)
929 {
930  static bool approximationsInit = false;
931  static const int MAX_CURVES = 10000;
932  static const int MAX_NUMBEROFPOINTS = 1000;
933 
934  static bool curveApproximated[MAX_CURVES];
935  static ON_3dPoint curveApproximations[MAX_CURVES][MAX_NUMBEROFPOINTS];
936 
937  ON_wString curveinfo;
938  ON_TextLog log(curveinfo);
939 
940  if (!approximationsInit) {
941  approximationsInit = true;
942  for (int i = 0; i < MAX_CURVES; i++) {
943  curveApproximated[i] = false;
944  }
945  }
946 
947  if (face == NULL) {
948  return false;
949  }
950  const ON_Surface* surf = face->SurfaceOf();
951  if (surf == NULL) {
952  return false;
953  }
954  TRACE1("utah_isTrimmed: " << uv);
955  // for each loop
956  for (int li = 0; li < face->LoopCount(); li++) {
957  ON_BrepLoop* loop = face->Loop(li);
958  if (loop == 0) {
959  continue;
960  }
961 
962  // for each trim
963  ON_3dPoint closestPoint(0.0, 0.0, 0.0);
964  ON_3dVector tangent(0.0, 0.0, 0.0);
965  ON_3dVector kappa(0.0, 0.0, 0.0);
966  double currentDistance = -10000.0;
967  ON_3dPoint hitPoint(uv.x, uv.y, 0.0);
968 
969  for (int lti = 0; lti < loop->TrimCount(); lti++) {
970  const ON_BrepTrim* trim = loop->Trim(lti);
971  if (0 == trim)
972  continue;
973  const ON_Curve* trimCurve = face->Brep()->m_C2[trim->m_c2i];
974  if (trimCurve == 0) {
975  continue;
976  }
977 
978  // Uncomment the following to get a look at the summary report
979  // of a given trimming curve
980  /* trimCurve->Dump(log);
981  ON_String cinfo = ON_String(curveinfo);
982  const char *info = cinfo.Array();
983  bu_log("%s\n", info);
984  */
985 
986  double closestT;
987  bool gotClosest = trimCurve->GetClosestPoint(hitPoint, &closestT);
988  if (!gotClosest) {
989  // Someone needs to work on GetClosestPoint not to fail
990  // It is failing on nurbs curves that aren't rational
991  // For now if it fails we will use the approx. approach
992  double shortestDistance;
993  double t;
994  ON_Interval domain = trimCurve->Domain();
995  double step = (domain.m_t[1] - domain.m_t[0]) / (double) MAX_NUMBEROFPOINTS;
996  if (!curveApproximated[trim->m_c2i]) {
997  curveApproximated[trim->m_c2i] = true;
998  t = domain.m_t[0];
999  for (int i = 0; i < MAX_NUMBEROFPOINTS; i++) {
1000  curveApproximations[trim->m_c2i][i] = trimCurve->PointAt(t);
1001  t += step;
1002  }
1003  }
1004  closestT = t = domain.m_t[0];
1005  closestPoint = curveApproximations[trim->m_c2i][0];
1006  currentDistance = shortestDistance = closestPoint.DistanceTo(hitPoint);
1007  for (int i = 0; i < MAX_NUMBEROFPOINTS; i++) {
1008  closestPoint = curveApproximations[trim->m_c2i][i];
1009  currentDistance = closestPoint.DistanceTo(hitPoint);
1010  if (currentDistance < shortestDistance) {
1011  closestT = t;
1012  shortestDistance = currentDistance;
1013  }
1014  t += step;
1015  }
1016  }
1017  ON_3dPoint testClosestPoint;
1018  ON_3dVector testTangent, testKappa;
1019  double testDistance;
1020  trimCurve->EvCurvature(closestT, testClosestPoint, testTangent, testKappa);
1021  testDistance = testClosestPoint.DistanceTo(hitPoint);
1022  if ((currentDistance < 0.0) || (testDistance < currentDistance)) {
1023  closestPoint = testClosestPoint;
1024  tangent = testTangent;
1025  kappa = testKappa;
1026  currentDistance = testDistance;
1027  }
1028  }
1029  if (currentDistance >= 0.0) {
1030  ON_3dVector hitDirection(hitPoint.x - closestPoint.x, hitPoint.y - closestPoint.y, hitPoint.z - closestPoint.z);
1031  double dot = (hitDirection * kappa);
1032  //printf("closestT=%lf dot=%lf closestPoint=(%lf, %lf, %lf) hitPoint=(%lf, %lf, %lf) tangent=(%lf, %lf, %lf) kappa=(%lf, %lf, %lf) normal=(%lf, %lf, %lf) hitDirection=(%lf, %lf, %lf)\n", closestT, dot, closestPoint.x, closestPoint.y, closestPoint.z, hitPoint.x, hitPoint.y, hitPoint.z, tangent.x, tangent.y, tangent.z, kappa.x, kappa.y, kappa.z, normal.x, normal.y, normal.z, hitDirection.x, hitDirection.y, hitDirection.z);
1033  if (((li == 0) && (dot < 0.0)) ||
1034  ((li > 0) && (dot > 0.0))) {
1035  return true;
1036  }
1037  }
1038  }
1039  return false;
1040 }
1041 
1042 
1043 #define MAX_BREP_SUBDIVISION_INTERSECTS 5
1044 int
1045 utah_brep_intersect(const BBNode* sbv, const ON_BrepFace* face, const ON_Surface* surf, pt2d_t& uv, ON_Ray& ray, HitList& hits)
1046 {
1047  ON_3dVector N[MAX_BREP_SUBDIVISION_INTERSECTS];
1049  ON_2dPoint ouv[MAX_BREP_SUBDIVISION_INTERSECTS];
1050  int found = BREP_INTERSECT_ROOT_DIVERGED;
1051  bool converged = false;
1052  int numhits;
1053 
1054  double grazing_float = sbv->m_normal * ray.m_dir;
1055 
1056  if (fabs(grazing_float) < 0.2) {
1057  numhits = utah_newton_4corner_solver(sbv, surf, ray, ouv, t, N, converged, 1);
1058  } else {
1059  numhits = utah_newton_4corner_solver(sbv, surf, ray, ouv, t, N, converged, 0);
1060  }
1061 
1062  if (converged) {
1063  for (int i = 0; i < numhits; i++) {
1064  double closesttrim;
1065  BRNode* trimBR = NULL;
1066  int trim_status = sbv->isTrimmed(ouv[i], &trimBR, closesttrim,BREP_EDGE_MISS_TOLERANCE);
1067  if (trim_status != 1) {
1068  ON_3dPoint _pt;
1069  ON_3dVector _norm(N[i]);
1070  vect_t vpt;
1071  vect_t vnorm;
1072  _pt = ray.m_origin + (ray.m_dir * t[i]);
1073  VMOVE(vpt, _pt);
1074  if (face->m_bRev) {
1075  //bu_log("Reversing normal for Face:%d\n", face->m_face_index);
1076  _norm.Reverse();
1077  }
1078  VMOVE(vnorm, _norm);
1079  hit_count += 1;
1080  uv[0] = ouv[i].x;
1081  uv[1] = ouv[i].y;
1082  brep_hit bh(*face, t[i], ray, vpt, vnorm, uv);
1083  bh.trimmed = false;
1084  if (trimBR != NULL) {
1085  bh.m_adj_face_index = trimBR->m_adj_face_index;
1086  } else {
1087  bh.m_adj_face_index = -99;
1088  }
1089  if (fabs(closesttrim) < BREP_EDGE_MISS_TOLERANCE) {
1090  bh.closeToEdge = true;
1091  bh.hit = brep_hit::NEAR_HIT;
1092  } else {
1093  bh.closeToEdge = false;
1094  bh.hit = brep_hit::CLEAN_HIT;
1095  }
1096  if (VDOT(ray.m_dir, vnorm) < 0.0)
1098  else
1100  bh.sbv = sbv;
1101  hits.push_back(bh);
1102  found = BREP_INTERSECT_FOUND;
1103  } else if (fabs(closesttrim) < BREP_EDGE_MISS_TOLERANCE) {
1104  ON_3dPoint _pt;
1105  ON_3dVector _norm(N[i]);
1106  vect_t vpt;
1107  vect_t vnorm;
1108  _pt = ray.m_origin + (ray.m_dir * t[i]);
1109  VMOVE(vpt, _pt);
1110  if (face->m_bRev) {
1111  //bu_log("Reversing normal for Face:%d\n", face->m_face_index);
1112  _norm.Reverse();
1113  }
1114  VMOVE(vnorm, _norm);
1115  hit_count += 1;
1116  uv[0] = ouv[i].x;
1117  uv[1] = ouv[i].y;
1118  brep_hit bh(*face, t[i], ray, vpt, vnorm, uv);
1119  bh.trimmed = true;
1120  bh.closeToEdge = true;
1121  if (trimBR != NULL) {
1122  bh.m_adj_face_index = trimBR->m_adj_face_index;
1123  } else {
1124  bh.m_adj_face_index = -99;
1125  }
1126  bh.hit = brep_hit::NEAR_MISS;
1127  if (VDOT(ray.m_dir, vnorm) < 0.0)
1129  else
1131  bh.sbv = sbv;
1132  hits.push_back(bh);
1133  found = BREP_INTERSECT_FOUND;
1134  }
1135  }
1136  }
1137  return found;
1138 }
1139 
1140 
1141 typedef std::pair<int, int> ip_t;
1142 typedef std::list<ip_t> MissList;
1143 
1144 HIDDEN int
1145 sign(double val)
1146 {
1147  return (val >= 0.0) ? 1 : -1;
1148 }
1149 
1150 
1151 bool
1152 containsNearMiss(HitList *hits)
1153 {
1154  for (HitList::iterator i = hits->begin(); i != hits->end(); ++i) {
1155  brep_hit&out = *i;
1156  if (out.hit == brep_hit::NEAR_MISS) {
1157  return true;
1158  }
1159  }
1160  return false;
1161 }
1162 
1163 
1164 bool
1165 containsNearHit(HitList *hits)
1166 {
1167  for (HitList::iterator i = hits->begin(); i != hits->end(); ++i) {
1168  brep_hit&out = *i;
1169  if (out.hit == brep_hit::NEAR_HIT) {
1170  return true;
1171  }
1172  }
1173  return false;
1174 }
1175 
1176 
1177 /**
1178  * Intersect a ray with a brep. If an intersection occurs, a struct
1179  * seg will be acquired and filled in.
1180  *
1181  * Returns -
1182  * 0 MISS
1183  * >0 HIT
1184  */
1185 int
1186 rt_brep_shot(struct soltab *stp, register struct xray *rp, struct application *ap, struct seg *seghead)
1187 {
1188  struct brep_specific* bs;
1189 
1190  if (!stp)
1191  return 0;
1192  RT_CK_SOLTAB(stp);
1193  bs = (struct brep_specific*)stp->st_specific;
1194  if (!bs)
1195  return 0;
1196 
1197  /* First, test for intersections between the Surface Tree
1198  * hierarchy and the ray - if one or more leaf nodes are
1199  * intersected, there is potentially a hit and more evaluation is
1200  * needed. Otherwise, return a miss.
1201  */
1202  std::list<BBNode*> inters;
1203  ON_Ray r = toXRay(rp);
1204  bs->bvh->intersectsHierarchy(r, inters);
1205  if (inters.size() == 0) return 0; // MISS
1206 
1207  // find all the hits (XXX very inefficient right now!)
1208  HitList all_hits; // record all hits
1209  MissList misses;
1210  int s = 0;
1211  hit_count = 0;
1212  for (std::list<BBNode*>::iterator i = inters.begin(); i != inters.end(); i++) {
1213  const BBNode* sbv = (*i);
1214  const ON_BrepFace* f = sbv->m_face;
1215  const ON_Surface* surf = f->SurfaceOf();
1216  pt2d_t uv = {sbv->m_u.Mid(), sbv->m_v.Mid()};
1217  utah_brep_intersect(sbv, f, surf, uv, r, all_hits);
1218  s++;
1219  }
1220 
1221 #ifdef KDEBUGMISS
1222  //(void)fclose(_plot_file());
1223  // plot = NULL;
1224 #endif
1225  HitList hits = all_hits;
1226 
1227  // sort the hits
1228  hits.sort();
1229  HitList orig = hits;
1230 ////////////////////////
1231  if ((hits.size() > 1) && containsNearMiss(&hits)) { //&& ((hits.size() % 2) != 0)) {
1232  /*
1233  bu_log("**** Before Pass1 Hits: %d\n", hits.size());
1234 
1235  for (HitList::iterator i = hits.begin(); i != hits.end(); ++i) {
1236  point_t prev;
1237 
1238  brep_hit &out = *i;
1239 
1240  if (i != hits.begin()) {
1241  bu_log("<%g>", DIST_PT_PT(out.point, prev));
1242  }
1243  bu_log("(");
1244  if (out.hit == brep_hit::CLEAN_HIT) bu_log("-CH-(%d)", out.face.m_face_index);
1245  if (out.hit == brep_hit::NEAR_HIT) bu_log("_NH_(%d)", out.face.m_face_index);
1246  if (out.hit == brep_hit::NEAR_MISS) bu_log("_NM_(%d)", out.face.m_face_index);
1247  if (out.direction == brep_hit::ENTERING) bu_log("+");
1248  if (out.direction == brep_hit::LEAVING) bu_log("-");
1249  VMOVE(prev, out.point);
1250  bu_log(")");
1251  }
1252  */
1253  HitList::iterator prev;
1254  HitList::iterator next;
1255  HitList::iterator curr = hits.begin();
1256  while (curr != hits.end()) {
1257  brep_hit &curr_hit = *curr;
1258  if (curr_hit.hit == brep_hit::NEAR_MISS) {
1259  if (curr != hits.begin()) {
1260  prev = curr;
1261  prev--;
1262  brep_hit &prev_hit = (*prev);
1263  if ((prev_hit.hit != brep_hit::NEAR_MISS) && (prev_hit.direction == curr_hit.direction)) {
1264  //remove current miss
1265  curr = hits.erase(curr);
1266  curr = hits.begin(); //rewind and start again
1267  continue;
1268  }
1269  }
1270  next = curr;
1271  next++;
1272  if (next != hits.end()) {
1273  brep_hit &next_hit = (*next);
1274  if ((next_hit.hit != brep_hit::NEAR_MISS) && (next_hit.direction == curr_hit.direction)) {
1275  //remove current miss
1276  curr = hits.erase(curr);
1277  curr = hits.begin(); //rewind and start again
1278  continue;
1279  }
1280  }
1281  }
1282  curr++;
1283  }
1284 
1285  // check for crack hits between adjacent faces
1286  curr = hits.begin();
1287  while (curr != hits.end()) {
1288  brep_hit &curr_hit = *curr;
1289  if (curr != hits.begin()) {
1290  if (curr_hit.hit == brep_hit::NEAR_MISS) {
1291  prev = curr;
1292  prev--;
1293  brep_hit &prev_hit = (*prev);
1294  if (prev_hit.hit == brep_hit::NEAR_MISS) { // two near misses in a row
1295  if (prev_hit.m_adj_face_index == curr_hit.face.m_face_index) {
1296  if (prev_hit.direction == curr_hit.direction) {
1297  //remove current miss
1298  prev_hit.hit = brep_hit::CRACK_HIT;
1299  curr = hits.erase(curr);
1300  continue;
1301  } else {
1302  //remove both edge near misses
1303  (void)hits.erase(prev);
1304  curr = hits.erase(curr);
1305  continue;
1306  }
1307  } else {
1308  // not adjacent faces so remove first miss
1309  (void)hits.erase(prev);
1310  }
1311  }
1312  }
1313  }
1314  curr++;
1315  }
1316  // check for CH double enter or double leave between adjacent faces(represents overlapping faces)
1317  curr = hits.begin();
1318  while (curr != hits.end()) {
1319  brep_hit &curr_hit = *curr;
1320  if (curr_hit.hit == brep_hit::CLEAN_HIT) {
1321  if (curr != hits.begin()) {
1322  prev = curr;
1323  prev--;
1324  brep_hit &prev_hit = (*prev);
1325  if ((prev_hit.hit == brep_hit::CLEAN_HIT) &&
1326  (prev_hit.direction == curr_hit.direction) &&
1327  (prev_hit.face.m_face_index == curr_hit.m_adj_face_index)) {
1328  // if "entering" remove first hit if "existing" remove second hit
1329  // until we get good solids with known normal directions assume
1330  // first hit direction is "entering" todo check solid status and normals
1331  HitList::iterator first = hits.begin();
1332  brep_hit &first_hit = *first;
1333  if (first_hit.direction == curr_hit.direction) { // assume "entering"
1334  curr = hits.erase(prev);
1335  } else { // assume "exiting"
1336  curr = hits.erase(curr);
1337  }
1338  continue;
1339  }
1340  }
1341  }
1342  curr++;
1343  }
1344 
1345  if ((hits.size() > 0) && ((hits.size() % 2) != 0)) {
1346  brep_hit &curr_hit = hits.back();
1347  if (curr_hit.hit == brep_hit::NEAR_MISS) {
1348  hits.pop_back();
1349  }
1350  }
1351 
1352  if ((hits.size() > 0) && ((hits.size() % 2) != 0)) {
1353  brep_hit &curr_hit = hits.front();
1354  if (curr_hit.hit == brep_hit::NEAR_MISS) {
1355  hits.pop_front();
1356  }
1357  }
1358  /*
1359  bu_log("**** After Pass3 Hits: %d\n", hits.size());
1360 
1361  for (HitList::iterator i = hits.begin(); i != hits.end(); ++i) {
1362  point_t prev;
1363 
1364  brep_hit &out = *i;
1365 
1366  if (i != hits.begin()) {
1367  bu_log("<%g>", DIST_PT_PT(out.point, prev));
1368  }
1369  bu_log("(");
1370  if (out.hit == brep_hit::CRACK_HIT) bu_log("_CRACK_(%d)", out.face.m_face_index);
1371  if (out.hit == brep_hit::CLEAN_HIT) bu_log("_CH_(%d)", out.face.m_face_index);
1372  if (out.hit == brep_hit::NEAR_HIT) bu_log("_NH_(%d)", out.face.m_face_index);
1373  if (out.hit == brep_hit::NEAR_MISS) bu_log("_NM_(%d)", out.face.m_face_index);
1374  if (out.direction == brep_hit::ENTERING) bu_log("+");
1375  if (out.direction == brep_hit::LEAVING) bu_log("-");
1376  VMOVE(prev, out.point);
1377  bu_log(")");
1378  }
1379 
1380  bu_log("\n**********************\n");
1381  */
1382  }
1383  ///////////// handle near hit
1384  if ((hits.size() > 1) && containsNearHit(&hits)) { //&& ((hits.size() % 2) != 0)) {
1385  HitList::iterator prev;
1386  HitList::iterator next;
1387  HitList::iterator curr = hits.begin();
1388  while (curr != hits.end()) {
1389  brep_hit &curr_hit = *curr;
1390  if (curr_hit.hit == brep_hit::NEAR_HIT) {
1391  if (curr != hits.begin()) {
1392  prev = curr;
1393  prev--;
1394  brep_hit &prev_hit = (*prev);
1395  if ((prev_hit.hit != brep_hit::NEAR_HIT) && (prev_hit.direction == curr_hit.direction)) {
1396  //remove current miss
1397  curr = hits.erase(curr);
1398  continue;
1399  }
1400  }
1401  next = curr;
1402  next++;
1403  if (next != hits.end()) {
1404  brep_hit &next_hit = (*next);
1405  if ((next_hit.hit != brep_hit::NEAR_HIT) && (next_hit.direction == curr_hit.direction)) {
1406  //remove current miss
1407  curr = hits.erase(curr);
1408  continue;
1409  }
1410  }
1411  }
1412  curr++;
1413  }
1414  curr = hits.begin();
1415  while (curr != hits.end()) {
1416  brep_hit &curr_hit = *curr;
1417  if (curr_hit.hit == brep_hit::NEAR_HIT) {
1418  if (curr != hits.begin()) {
1419  prev = curr;
1420  prev--;
1421  brep_hit &prev_hit = (*prev);
1422  if ((prev_hit.hit == brep_hit::NEAR_HIT) && (prev_hit.direction == curr_hit.direction)) {
1423  //remove current near hit
1424  prev_hit.hit = brep_hit::CRACK_HIT;
1425  curr = hits.erase(curr);
1426  continue;
1427  }
1428  }
1429  }
1430  curr++;
1431  }
1432  }
1433 
1434  all_hits.clear();
1435  all_hits = hits;
1436 
1437 
1438  if (hits.size() > 0) {
1439  // remove grazing hits with with normal to ray dot less than BREP_GRAZING_DOT_TOL (>= 89.999 degrees obliq)
1440  TRACE("-- Remove grazing hits --");
1441  int num = 0;
1442  for (HitList::iterator i = hits.begin(); i != hits.end(); ++i) {
1443  brep_hit &curr_hit = *i;
1444  if ((curr_hit.trimmed && !curr_hit.closeToEdge) || curr_hit.oob || NEAR_ZERO(VDOT(curr_hit.normal, rp->r_dir), BREP_GRAZING_DOT_TOL)) {
1445  // remove what we were removing earlier
1446  if (curr_hit.oob) {
1447  TRACE("\toob u: " << i->uv[0] << ", " << IVAL(i->sbv->m_u));
1448  TRACE("\toob v: " << i->uv[1] << ", " << IVAL(i->sbv->m_v));
1449  }
1450  i = hits.erase(i);
1451 
1452  if (i != hits.begin())
1453  --i;
1454 
1455  continue;
1456  }
1457  TRACE("hit " << num << ": " << PT(i->point) << " [" << VDOT(i->normal, rp->r_dir) << "]");
1458  ++num;
1459  }
1460  }
1461 
1462 
1463  if (hits.size() > 0) {
1464  // we should have "valid" points now, remove duplicates or grazes(same point with in/out sign change)
1465  HitList::iterator last = hits.begin();
1466  HitList::iterator i = hits.begin();
1467  ++i;
1468  while (i != hits.end()) {
1469  if ((*i) == (*last)) {
1470  double lastDot = VDOT(last->normal, rp->r_dir);
1471  double iDot = VDOT(i->normal, rp->r_dir);
1472 
1473  if (sign(lastDot) != sign(iDot)) {
1474  // delete them both
1475  i = hits.erase(last);
1476  i = hits.erase(i);
1477  last = i;
1478 
1479  if (i != hits.end())
1480  ++i;
1481  } else {
1482  // just delete the second
1483  i = hits.erase(i);
1484  }
1485  } else {
1486  last = i;
1487  ++i;
1488  }
1489  }
1490  }
1491 
1492  // remove multiple "INs" in a row assume last "IN" is the actual entering hit, for
1493  // multiple "OUTs" in a row assume first "OUT" is the actual exiting hit, remove unused
1494  // "INs/OUTs" from hit list.
1495  //if ((hits.size() > 0) && ((hits.size() % 2) != 0)) {
1496  if (hits.size() > 0) {
1497  // we should have "valid" points now, remove duplicates or grazes
1498  HitList::iterator last = hits.begin();
1499  HitList::iterator i = hits.begin();
1500  ++i;
1501  int entering = 1;
1502  while (i != hits.end()) {
1503  double lastDot = VDOT(last->normal, rp->r_dir);
1504  double iDot = VDOT(i->normal, rp->r_dir);
1505 
1506  if (i == hits.begin()) {
1507  //take this as the entering sign for now, should be checking solid for
1508  // inward or outward facing normals and make determination there but to
1509  // much unsolid geom right now.
1510  entering = sign(iDot);
1511  }
1512  if (sign(lastDot) == sign(iDot)) {
1513  if (sign(iDot) == entering) {
1514  i = hits.erase(last);
1515  last = i;
1516  if (i != hits.end())
1517  ++i;
1518  } else { //exiting
1519  i = hits.erase(i);
1520  }
1521 
1522  } else {
1523  last = i;
1524  ++i;
1525  }
1526  }
1527  }
1528 
1529  if ((hits.size() > 1) && ((hits.size() % 2) != 0)) {
1530  brep_hit &first_hit = hits.front();
1531  brep_hit &last_hit = hits.back();
1532  double firstDot = VDOT(first_hit.normal, rp->r_dir);
1533  double lastDot = VDOT(last_hit.normal, rp->r_dir);
1534  if (sign(firstDot) == sign(lastDot)) {
1535  hits.pop_back();
1536  }
1537  }
1538 
1539  bool hit = false;
1540  if (hits.size() > 1) {
1541 
1542 //#define KODDHIT
1543 #ifdef KODDHIT //ugly debugging hack to raytrace single surface and not worry about odd hits
1544  static fastf_t diststep = 0.0;
1545  bool hit_it = hits.size() > 0;
1546 #else
1547  bool hit_it = hits.size() % 2 == 0;
1548 #endif
1549  if (hit_it) {
1550  // take each pair as a segment
1551  for (HitList::iterator i = hits.begin(); i != hits.end(); ++i) {
1552  brep_hit& in = *i;
1553 #ifndef KODDHIT //ugly debugging hack to raytrace single surface and not worry about odd hits
1554  i++;
1555 #endif
1556  brep_hit& out = *i;
1557 
1558  register struct seg* segp;
1559  RT_GET_SEG(segp, ap->a_resource);
1560  segp->seg_stp = stp;
1561 
1562  VMOVE(segp->seg_in.hit_point, in.point);
1563  VMOVE(segp->seg_in.hit_normal, in.normal);
1564 #ifdef KODDHIT //ugly debugging hack to raytrace single surface and not worry about odd hits
1565  segp->seg_in.hit_dist = diststep + 1.0;
1566 #else
1567  segp->seg_in.hit_dist = in.dist;
1568 #endif
1569  segp->seg_in.hit_surfno = in.face.m_face_index;
1570  VSET(segp->seg_in.hit_vpriv, in.uv[0], in.uv[1], 0.0);
1571 
1572  VMOVE(segp->seg_out.hit_point, out.point);
1573  VMOVE(segp->seg_out.hit_normal, out.normal);
1574  segp->seg_out.hit_dist = out.dist;
1575  segp->seg_out.hit_surfno = out.face.m_face_index;
1576  VSET(segp->seg_out.hit_vpriv, out.uv[0], out.uv[1], 0.0);
1577 
1578  BU_LIST_INSERT(&(seghead->l), &(segp->l));
1579  }
1580  hit = true;
1581  } else {
1582  //TRACE2("screen xy: " << ap->a_x << ", " << ap->a_y);
1583  bu_log("**** ERROR odd number of hits: %lu\n", static_cast<unsigned long>(hits.size()));
1584  bu_log("xyz %g %g %g \n", rp->r_pt[0], rp->r_pt[1], rp->r_pt[2]);
1585  bu_log("dir %g %g %g \n", rp->r_dir[0], rp->r_dir[1], rp->r_dir[2]);
1586  bu_log("**** Current Hits: %lu\n", static_cast<unsigned long>(hits.size()));
1587 
1588  for (HitList::iterator i = hits.begin(); i != hits.end(); ++i) {
1589  point_t prev;
1590 
1591  brep_hit &out = *i;
1592  VMOVE(prev, out.point);
1593 
1594  if (i != hits.begin()) {
1595  bu_log("<%g>", DIST_PT_PT(out.point, prev));
1596  }
1597  bu_log("(");
1598  if (out.hit == brep_hit::CRACK_HIT) bu_log("_CRACK_(%d)", out.face.m_face_index);
1599  if (out.hit == brep_hit::CLEAN_HIT) bu_log("_CH_(%d)", out.face.m_face_index);
1600  if (out.hit == brep_hit::NEAR_HIT) bu_log("_NH_(%d)", out.face.m_face_index);
1601  if (out.hit == brep_hit::NEAR_MISS) bu_log("_NM_(%d)", out.face.m_face_index);
1602  if (out.direction == brep_hit::ENTERING) bu_log("+");
1603  if (out.direction == brep_hit::LEAVING) bu_log("-");
1604 
1605  bu_log(")");
1606  }
1607  bu_log("\n**** Orig Hits: %lu\n", static_cast<unsigned long>(orig.size()));
1608 
1609  for (HitList::iterator i = orig.begin(); i != orig.end(); ++i) {
1610  point_t prev;
1611 
1612  brep_hit &out = *i;
1613  VMOVE(prev, out.point);
1614 
1615  if (i != orig.begin()) {
1616  bu_log("<%g>", DIST_PT_PT(out.point, prev));
1617  }
1618  bu_log("(");
1619  if (out.hit == brep_hit::CRACK_HIT) bu_log("_CRACK_(%d)", out.face.m_face_index);
1620  if (out.hit == brep_hit::CLEAN_HIT) bu_log("_CH_(%d)", out.face.m_face_index);
1621  if (out.hit == brep_hit::NEAR_HIT) bu_log("_NH_(%d)", out.face.m_face_index);
1622  if (out.hit == brep_hit::NEAR_MISS) bu_log("_NM_(%d)", out.face.m_face_index);
1623  if (out.direction == brep_hit::ENTERING) bu_log("+");
1624  if (out.direction == brep_hit::LEAVING) bu_log("-");
1625  bu_log("<%d>", out.sbv->m_face->m_bRev);
1626 
1627  bu_log(")");
1628  }
1629 
1630  bu_log("\n**********************\n");
1631  }
1632  }
1633 
1634  return (hit) ? (int)hits.size() : 0; // MISS
1635 }
1636 
1637 
1638 /**
1639  * Given ONE ray distance, return the normal and entry/exit point.
1640  */
1641 void
1642 rt_brep_norm(struct hit *hitp, struct soltab *stp, struct xray *rp)
1643 {
1644  struct brep_specific* bs;
1645 
1646  if (!hitp || !stp || !rp)
1647  return;
1648  RT_CK_SOLTAB(stp);
1649  bs = (struct brep_specific*)stp->st_specific;
1650  if (!bs)
1651  return;
1652 
1653  /* XXX todo */
1654 }
1655 
1656 
1657 /**
1658  * Return the curvature of the nurb.
1659  */
1660 void
1661 rt_brep_curve(struct curvature *cvp, struct hit *hitp, struct soltab *stp)
1662 {
1663  struct brep_specific* bs;
1664 
1665  if (!cvp || !hitp || !stp)
1666  return;
1667  RT_CK_SOLTAB(stp);
1668  bs = (struct brep_specific*)stp->st_specific;
1669  if (!bs)
1670  return;
1671 
1672  /* XXX todo */
1673 }
1674 
1675 
1676 int
1677 rt_brep_class(const struct soltab *stp, const fastf_t *min, const fastf_t *max, const struct bn_tol *tol)
1678 {
1679  if (stp) RT_CK_SOLTAB(stp);
1680  if (tol) BN_CK_TOL(tol);
1681  if (!min) return 0;
1682  if (!max) return 0;
1683 
1684  return 0;
1685 }
1686 
1687 
1688 /**
1689  * For a hit on the surface of an nurb, return the (u, v) coordinates
1690  * of the hit point, 0 <= u, v <= 1
1691  * u = azimuth
1692  * v = elevation
1693  */
1694 void
1695 rt_brep_uv(struct application *ap, struct soltab *stp, register struct hit *hitp, register struct uvcoord *uvp)
1696 {
1697  struct brep_specific* bs;
1698 
1699  if (ap) RT_CK_APPLICATION(ap);
1700  if (!stp)
1701  return;
1702  RT_CK_SOLTAB(stp);
1703  bs = (struct brep_specific*)stp->st_specific;
1704  if (!bs)
1705  return;
1706 
1707  uvp->uv_u = hitp->hit_vpriv[0];
1708  uvp->uv_v = hitp->hit_vpriv[1];
1709 }
1710 
1711 
1712 void
1713 rt_brep_free(register struct soltab *stp)
1714 {
1715  TRACE1("rt_brep_free");
1716 
1717  struct brep_specific* bs;
1718 
1719  if (!stp)
1720  return;
1721  RT_CK_SOLTAB(stp);
1722  bs = (struct brep_specific*)stp->st_specific;
1723  if (!bs)
1724  return;
1725 
1727 }
1728 
1729 
1730 /**
1731  * Given surface tree bounding box information, plot the bounding box
1732  * as a wireframe in mged.
1733  */
1734 void
1735 plot_bbnode(BBNode* node, struct bu_list* vhead, int depth, int start, int limit)
1736 {
1737  BU_CK_LIST_HEAD(vhead);
1738 
1739  ON_3dPoint min = node->m_node.m_min;
1740  ON_3dPoint max = node->m_node.m_max;
1741  point_t verts[] = {{min[0], min[1], min[2]},
1742  {min[0], max[1], min[2]},
1743  {min[0], max[1], max[2]},
1744  {min[0], min[1], max[2]},
1745  {max[0], min[1], min[2]},
1746  {max[0], max[1], min[2]},
1747  {max[0], max[1], max[2]},
1748  {max[0], min[1], max[2]}};
1749 
1750  if (depth >= start && depth <= limit) {
1751  for (int i = 0; i <= 4; i++) {
1752  RT_ADD_VLIST(vhead, verts[i % 4], (i == 0) ? BN_VLIST_LINE_MOVE : BN_VLIST_LINE_DRAW);
1753  }
1754  for (int i = 0; i <= 4; i++) {
1755  RT_ADD_VLIST(vhead, verts[(i % 4) + 4], (i == 0) ? BN_VLIST_LINE_MOVE : BN_VLIST_LINE_DRAW);
1756  }
1757  for (int i = 0; i < 4; i++) {
1758  RT_ADD_VLIST(vhead, verts[i], BN_VLIST_LINE_MOVE);
1759  RT_ADD_VLIST(vhead, verts[i + 4], BN_VLIST_LINE_DRAW);
1760  }
1761 
1762  }
1763 
1764  for (size_t i = 0; i < node->m_children.size(); i++) {
1765  if (i < 1)
1766  plot_bbnode(node->m_children[i], vhead, depth + 1, start, limit);
1767  }
1768 }
1769 
1770 
1771 double
1772 find_next_point(const ON_Curve* crv, double startdomval, double increment, double tolerance, int stepcount)
1773 {
1774  double inc = increment;
1775  if (startdomval + increment > 1.0) inc = 1.0 - startdomval;
1776  ON_Interval dom = crv->Domain();
1777  ON_3dPoint prev_pt = crv->PointAt(dom.ParameterAt(startdomval));
1778  ON_3dPoint next_pt = crv->PointAt(dom.ParameterAt(startdomval + inc));
1779  if (prev_pt.DistanceTo(next_pt) > tolerance) {
1780  stepcount++;
1781  inc = inc / 2;
1782  return find_next_point(crv, startdomval, inc, tolerance, stepcount);
1783  } else {
1784  if (stepcount > 5) return 0.0;
1785  return startdomval + inc;
1786  }
1787 }
1788 
1789 
1790 double
1791 find_next_trimming_point(const ON_Curve* crv, const ON_Surface* s, double startdomval, double increment, double tolerance, int stepcount)
1792 {
1793  double inc = increment;
1794  if (startdomval + increment > 1.0) inc = 1.0 - startdomval;
1795  ON_Interval dom = crv->Domain();
1796  ON_3dPoint prev_pt = crv->PointAt(dom.ParameterAt(startdomval));
1797  ON_3dPoint next_pt = crv->PointAt(dom.ParameterAt(startdomval + inc));
1798  ON_3dPoint prev_3d_pt, next_3d_pt;
1799  s->EvPoint(prev_pt[0], prev_pt[1], prev_3d_pt, 0, 0);
1800  s->EvPoint(next_pt[0], next_pt[1], next_3d_pt, 0, 0);
1801  if (prev_3d_pt.DistanceTo(next_3d_pt) > tolerance) {
1802  stepcount++;
1803  inc = inc / 2;
1804  return find_next_trimming_point(crv, s, startdomval, inc, tolerance, stepcount);
1805  } else {
1806  if (stepcount > 5) return 0.0;
1807  return startdomval + inc;
1808  }
1809 }
1810 
1811 
1812 /* a binary predicate for std:list implemented as a function */
1813 bool
1814 near_equal(double first, double second)
1815 {
1816  /* FIXME: arbitrary nearness tolerance */
1817  return NEAR_EQUAL(first, second, 1e-6);
1818 }
1819 
1820 
1821 void
1822 plot_sum_surface(struct bu_list *vhead, const ON_Surface *surf, int isocurveres, int gridres)
1823 {
1824  point_t pt1 = VINIT_ZERO;
1825  point_t pt2 = VINIT_ZERO;
1826 
1827  ON_2dPoint from(0.0, 0.0);
1828  ON_2dPoint to(0.0, 0.0);
1829 
1830  ON_Interval udom = surf->Domain(0);
1831  ON_Interval vdom = surf->Domain(1);
1832 
1833  for (int u = 0; u <= gridres; u++) {
1834  for (int v = 1; v <= isocurveres; v++) {
1835  double ut = (double)u / (double)gridres;
1836  double vt = (double)(v - 1) / (double)isocurveres;
1837  ON_3dPoint p = surf->PointAt(udom.ParameterAt(ut),
1838  vdom.ParameterAt(vt));
1839  VMOVE(pt1, p);
1840 
1841  ut = (double) u / (double) gridres;
1842  vt = (double) v / (double) isocurveres;
1843  p = surf->PointAt(udom.ParameterAt(ut),
1844  vdom.ParameterAt(vt));
1845  VMOVE(pt2, p);
1846  RT_ADD_VLIST(vhead, pt1, BN_VLIST_LINE_MOVE);
1847  RT_ADD_VLIST(vhead, pt2, BN_VLIST_LINE_DRAW);
1848  }
1849  }
1850 
1851  for (int v = 0; v <= gridres; v++) {
1852  for (int u = 1; u <= isocurveres; u++) {
1853  double ut = (double)(u - 1) / (double)isocurveres;
1854  double vt = (double)v / (double)gridres;
1855 
1856  ON_3dPoint p = surf->PointAt(
1857  udom.ParameterAt((double)(u - 1) / (double) isocurveres),
1858  vdom.ParameterAt((double) v / (double) gridres));
1859  VMOVE(pt1, p);
1860 
1861  ut = (double)u / (double)isocurveres;
1862  vt = (double)v / (double)gridres;
1863  p = surf->PointAt(udom.ParameterAt(ut), vdom.ParameterAt(vt));
1864  VMOVE(pt2, p);
1865 
1866  RT_ADD_VLIST(vhead, pt1, BN_VLIST_LINE_MOVE);
1867  RT_ADD_VLIST(vhead, pt2, BN_VLIST_LINE_DRAW);
1868  }
1869  }
1870  return;
1871 }
1872 
1873 
1874 void
1875 plotisoUCheckForTrim(struct bu_list *vhead, SurfaceTree* st, fastf_t from, fastf_t to, fastf_t v)
1876 {
1877  point_t pt1 = VINIT_ZERO;
1878  point_t pt2 = VINIT_ZERO;
1879  std::list<BRNode*> m_trims_right;
1880  std::list<double> trim_hits;
1881 
1882  const ON_Surface *surf = st->getSurface();
1883  CurveTree *ctree = st->ctree;
1884  double umin, umax;
1885 
1886  surf->GetDomain(0, &umin, &umax);
1887  m_trims_right.clear();
1888 
1889  fastf_t tol = 0.001;
1890  ON_2dPoint pt(0.0, 0.0);
1891 
1892  pt.x = umin;
1893  pt.y = v;
1894 
1895  if (ctree != NULL) {
1896  m_trims_right.clear();
1897  ctree->getLeavesRight(m_trims_right, pt, tol);
1898  }
1899 
1900  int cnt = 1;
1901 
1902  //bu_log("V - %f\n", pt.x);
1903  trim_hits.clear();
1904  std::list<BRNode *>::iterator i;
1905  for (i = m_trims_right.begin(); i != m_trims_right.end(); i++, cnt++) {
1906  BRNode* br = dynamic_cast<BRNode*>(*i);
1907 
1908  point_t bmin, bmax;
1909  if (!br->m_Horizontal) {
1910  br->GetBBox(bmin, bmax);
1911  if (((bmin[Y] - tol) <= pt[Y]) && (pt[Y] <= (bmax[Y] + tol))) { //if check trim and in BBox
1912  fastf_t u = br->getCurveEstimateOfU(pt[Y], tol);
1913  trim_hits.push_back(u);
1914  //bu_log("%d U %d - %f pt %f, %f bmin %f, %f bmax %f, %f\n", br->m_face->m_face_index, cnt, u, pt.x, pt.y, bmin[X], bmin[Y], bmax[X], bmax[Y]);
1915  }
1916  }
1917  }
1918 
1919  trim_hits.sort();
1920  trim_hits.unique(near_equal);
1921 
1922  int hit_cnt = trim_hits.size();
1923 
1924  cnt = 1;
1925  //bu_log("\tplotisoUCheckForTrim: hit_cnt %d from center %f %f 0.0 to center %f %f 0.0\n", hit_cnt, from, v , to, v);
1926 
1927  if ((hit_cnt > 0) && ((hit_cnt % 2) == 0)) {
1928  while (!trim_hits.empty()) {
1929  double start = trim_hits.front();
1930  if (start < from) {
1931  start = from;
1932  }
1933  trim_hits.pop_front();
1934 
1935  double end = trim_hits.front();
1936  if (end > to) {
1937  end = to;
1938  }
1939  trim_hits.pop_front();
1940 
1941  //bu_log("\tfrom - %f, to - %f\n", from, to);
1942  fastf_t deltax = (end - start) / 50.0;
1943  if (deltax > 0.001) {
1944  for (fastf_t x = start; x < end; x = x + deltax) {
1945  ON_3dPoint p = surf->PointAt(x, pt.y);
1946  VMOVE(pt1, p);
1947  if (x + deltax > end) {
1948  p = surf->PointAt(end, pt.y);
1949  } else {
1950  p = surf->PointAt(x + deltax, pt.y);
1951  }
1952  VMOVE(pt2, p);
1953 
1954  // bu_log(
1955  // "\t\t%d from center %f %f 0.0 to center %f %f 0.0\n",
1956  // cnt++, x, v, x + deltax, v);
1957 
1958  RT_ADD_VLIST(vhead, pt1, BN_VLIST_LINE_MOVE);
1959  RT_ADD_VLIST(vhead, pt2, BN_VLIST_LINE_DRAW);
1960  }
1961  }
1962  }
1963  }
1964 
1965  return;
1966 }
1967 
1968 
1969 void
1970 plotisoVCheckForTrim(struct bu_list *vhead, SurfaceTree* st, fastf_t from, fastf_t to, fastf_t u)
1971 {
1972  point_t pt1 = VINIT_ZERO;
1973  point_t pt2 = VINIT_ZERO;
1974  std::list<BRNode*> m_trims_above;
1975  std::list<double> trim_hits;
1976 
1977  const ON_Surface *surf = st->getSurface();
1978  CurveTree *ctree = st->ctree;
1979  double vmin, vmax;
1980  surf->GetDomain(1, &vmin, &vmax);
1981 
1982  m_trims_above.clear();
1983 
1984  fastf_t tol = 0.001;
1985  ON_2dPoint pt(0.0, 0.0);
1986 
1987  pt.x = u;
1988  pt.y = vmin;
1989 
1990  if (ctree != NULL) {
1991  m_trims_above.clear();
1992  ctree->getLeavesAbove(m_trims_above, pt, tol);
1993  }
1994 
1995  int cnt = 1;
1996  trim_hits.clear();
1997  for (std::list<BRNode*>::iterator i = m_trims_above.begin(); i
1998  != m_trims_above.end(); i++, cnt++) {
1999  BRNode* br = dynamic_cast<BRNode*>(*i);
2000 
2001  point_t bmin, bmax;
2002  if (!br->m_Vertical) {
2003  br->GetBBox(bmin, bmax);
2004 
2005  if (((bmin[X] - tol) <= pt[X]) && (pt[X] <= (bmax[X] + tol))) { //if check trim and in BBox
2006  fastf_t v = br->getCurveEstimateOfV(pt[X], tol);
2007  trim_hits.push_back(v);
2008  //bu_log("%d V %d - %f pt %f, %f bmin %f, %f bmax %f, %f\n", br->m_face->m_face_index, cnt, v, pt.x, pt.y, bmin[X], bmin[Y], bmax[X], bmax[Y]);
2009  }
2010  }
2011  }
2012  trim_hits.sort();
2013  trim_hits.unique(near_equal);
2014 
2015  size_t hit_cnt = trim_hits.size();
2016  cnt = 1;
2017 
2018  //bu_log("\tplotisoVCheckForTrim: hit_cnt %d from center %f %f 0.0 to center %f %f 0.0\n", hit_cnt, u, from, u, to);
2019 
2020  if ((hit_cnt > 0) && ((hit_cnt % 2) == 0)) {
2021  while (!trim_hits.empty()) {
2022  double start = trim_hits.front();
2023  trim_hits.pop_front();
2024  if (start < from) {
2025  start = from;
2026  }
2027  double end = trim_hits.front();
2028  trim_hits.pop_front();
2029  if (end > to) {
2030  end = to;
2031  }
2032  //bu_log("\tfrom - %f, to - %f\n", from, to);
2033  fastf_t deltay = (end - start) / 50.0;
2034  if (deltay > 0.001) {
2035  for (fastf_t y = start; y < end; y = y + deltay) {
2036  ON_3dPoint p = surf->PointAt(pt.x, y);
2037  VMOVE(pt1, p);
2038  if (y + deltay > end) {
2039  p = surf->PointAt(pt.x, end);
2040  } else {
2041  p = surf->PointAt(pt.x, y + deltay);
2042  }
2043  VMOVE(pt2, p);
2044 
2045  //bu_log("\t\t%d from center %f %f 0.0 to center %f %f 0.0\n",
2046  // cnt++, u, y, u, y + deltay);
2047 
2048  RT_ADD_VLIST(vhead, pt1, BN_VLIST_LINE_MOVE);
2049  RT_ADD_VLIST(vhead, pt2, BN_VLIST_LINE_DRAW);
2050  }
2051  }
2052  }
2053  }
2054  return;
2055 }
2056 
2057 
2058 void
2059 plotisoU(struct bu_list *vhead, SurfaceTree* st, fastf_t from, fastf_t to, fastf_t v, int curveres)
2060 {
2061  point_t pt1 = VINIT_ZERO;
2062  point_t pt2 = VINIT_ZERO;
2063  fastf_t deltau = (to - from) / curveres;
2064  const ON_Surface *surf = st->getSurface();
2065 
2066  for (fastf_t u = from; u < to; u = u + deltau) {
2067  ON_3dPoint p = surf->PointAt(u, v);
2068  //bu_log("p1 2d - %f, %f 3d - %f, %f, %f\n", pt.x, y, p.x, p.y, p.z);
2069  VMOVE(pt1, p);
2070  if (u + deltau > to) {
2071  p = surf->PointAt(to, v);
2072  } else {
2073  p = surf->PointAt(u + deltau, v);
2074  }
2075  //bu_log("p1 2d - %f, %f 3d - %f, %f, %f\n", pt.x, y+deltay, p.x, p.y, p.z);
2076  VMOVE(pt2, p);
2077  RT_ADD_VLIST(vhead, pt1, BN_VLIST_LINE_MOVE);
2078  RT_ADD_VLIST(vhead, pt2, BN_VLIST_LINE_DRAW);
2079  }
2080 }
2081 
2082 
2083 void
2084 plotisoV(struct bu_list *vhead, SurfaceTree* st, fastf_t from, fastf_t to, fastf_t u, int curveres)
2085 {
2086  point_t pt1 = VINIT_ZERO;
2087  point_t pt2 = VINIT_ZERO;
2088  fastf_t deltav = (to - from) / curveres;
2089  const ON_Surface *surf = st->getSurface();
2090 
2091  for (fastf_t v = from; v < to; v = v + deltav) {
2092  ON_3dPoint p = surf->PointAt(u, v);
2093  //bu_log("p1 2d - %f, %f 3d - %f, %f, %f\n", pt.x, y, p.x, p.y, p.z);
2094  VMOVE(pt1, p);
2095  if (v + deltav > to) {
2096  p = surf->PointAt(u, to);
2097  } else {
2098  p = surf->PointAt(u, v + deltav);
2099  }
2100  //bu_log("p1 2d - %f, %f 3d - %f, %f, %f\n", pt.x, y+deltay, p.x, p.y, p.z);
2101  VMOVE(pt2, p);
2102  RT_ADD_VLIST(vhead, pt1, BN_VLIST_LINE_MOVE);
2103  RT_ADD_VLIST(vhead, pt2, BN_VLIST_LINE_DRAW);
2104  }
2105 }
2106 
2107 
2108 void
2109 plot_BBNode(struct bu_list *vhead, SurfaceTree* st, BBNode * node, int isocurveres, int gridres)
2110 {
2111  if (node->isLeaf()) {
2112  //draw leaf
2113  if (node->m_trimmed) {
2114  return; // nothing to do node is trimmed
2115  } else if (node->m_checkTrim) { // node may contain trim check all corners
2116  fastf_t u = node->m_u[0];
2117  fastf_t v = node->m_v[0];
2118  fastf_t from = u;
2119  fastf_t to = node->m_u[1];
2120  //bu_log("drawBBNode: node %x uvmin center %f %f 0.0, uvmax center %f %f 0.0\n", node, node->m_u[0], node->m_v[0], node->m_u[1], node->m_v[1]);
2121 
2122  plotisoUCheckForTrim(vhead, st, from, to, v); //bottom
2123  v = node->m_v[1];
2124  plotisoUCheckForTrim(vhead, st, from, to, v); //top
2125  from = node->m_v[0];
2126  to = node->m_v[1];
2127  plotisoVCheckForTrim(vhead, st, from, to, u); //left
2128  u = node->m_u[1];
2129  plotisoVCheckForTrim(vhead, st, from, to, u); //right
2130  return;
2131  } else { // fully untrimmed just draw bottom and right edges
2132  fastf_t u = node->m_u[0];
2133  fastf_t v = node->m_v[0];
2134  fastf_t from = u;
2135  fastf_t to = node->m_u[1];
2136  plotisoU(vhead, st, from, to, v, isocurveres); //bottom
2137 
2138  from = v;
2139  to = node->m_v[1];
2140  plotisoV(vhead, st, from, to, u, isocurveres); //right
2141  return;
2142  }
2143  } else {
2144  if (node->m_children.size() > 0) {
2145  for (std::vector<BBNode*>::iterator childnode =
2146  node->m_children.begin(); childnode
2147  != node->m_children.end(); childnode++) {
2148  plot_BBNode(vhead, st, *childnode, isocurveres, gridres);
2149  }
2150  }
2151  }
2152 }
2153 
2154 
2155 void
2156 plot_face_from_surface_tree(struct bu_list *vhead, SurfaceTree* st, int isocurveres, int gridres)
2157 {
2158  BBNode *root = st->getRootNode();
2159  plot_BBNode(vhead, st, root, isocurveres, gridres);
2160 }
2161 
2162 
2163 void
2164 getEdgePoints(const ON_BrepTrim &trim,
2165  fastf_t t1,
2166  ON_3dPoint &start_2d,
2167  ON_3dVector &start_tang,
2168  ON_3dPoint &start_3d,
2169  ON_3dVector &start_norm,
2170  fastf_t t2,
2171  ON_3dPoint &end_2d,
2172  ON_3dVector &end_tang,
2173  ON_3dPoint &end_3d,
2174  ON_3dVector &end_norm,
2175  fastf_t min_dist,
2176  fastf_t max_dist,
2177  fastf_t within_dist,
2178  fastf_t cos_within_ang,
2179  std::map<double, ON_3dPoint *> &param_points)
2180 {
2181  const ON_Surface *s = trim.SurfaceOf();
2182  ON_Interval range = trim.Domain();
2183  ON_3dPoint mid_2d = ON_3dPoint::UnsetPoint;
2184  ON_3dPoint mid_3d = ON_3dPoint::UnsetPoint;
2185  ON_3dVector mid_norm = ON_3dVector::UnsetVector;
2186  ON_3dVector mid_tang = ON_3dVector::UnsetVector;
2187  fastf_t t = (t1 + t2) / 2.0;
2188 
2189  if (trim.EvTangent(t, mid_2d, mid_tang)
2190  && surface_EvNormal(s, mid_2d.x, mid_2d.y, mid_3d, mid_norm)) {
2191  ON_Line line3d(start_3d, end_3d);
2192  double dist3d;
2193 
2194  if ((line3d.Length() > max_dist)
2195  || ((dist3d = mid_3d.DistanceTo(line3d.ClosestPointTo(mid_3d)))
2196  > within_dist + ON_ZERO_TOLERANCE)
2197  || ((((start_tang * end_tang)
2198  < cos_within_ang - ON_ZERO_TOLERANCE)
2199  || ((start_norm * end_norm)
2200  < cos_within_ang - ON_ZERO_TOLERANCE))
2201  && (dist3d > min_dist + ON_ZERO_TOLERANCE))) {
2202  getEdgePoints(trim, t1, start_2d, start_tang, start_3d, start_norm,
2203  t, mid_2d, mid_tang, mid_3d, mid_norm, min_dist, max_dist,
2204  within_dist, cos_within_ang, param_points);
2205  param_points[(t - range.m_t[0]) / (range.m_t[1] - range.m_t[0])] =
2206  new ON_3dPoint(mid_3d);
2207  getEdgePoints(trim, t, mid_2d, mid_tang, mid_3d, mid_norm, t2,
2208  end_2d, end_tang, end_3d, end_norm, min_dist, max_dist,
2209  within_dist, cos_within_ang, param_points);
2210  } else {
2211  int udir = 0;
2212  int vdir = 0;
2213  ON_2dPoint start = start_2d;
2214  ON_2dPoint end = end_2d;
2215  if (ConsecutivePointsCrossClosedSeam(s, start, end, udir, vdir,
2216  BREP_SAME_POINT_TOLERANCE))
2217  {
2218  double seam_t;
2219  ON_2dPoint from = ON_2dPoint::UnsetPoint;
2220  ON_2dPoint to = ON_2dPoint::UnsetPoint;
2221  if (FindTrimSeamCrossing(trim, t1, t2, seam_t, from, to,
2222  BREP_SAME_POINT_TOLERANCE))
2223  {
2224  ON_2dPoint seam_2d = trim.PointAt(seam_t);
2225  ON_3dPoint seam_3d = s->PointAt(seam_2d.x, seam_2d.y);
2226  double tpercent = (seam_t - range.m_t[0]) / (range.m_t[1] - range.m_t[0]);
2227  if (param_points.find(tpercent) == param_points.end()) {
2228  param_points[tpercent] = new ON_3dPoint(seam_3d);
2229  }
2230  }
2231  }
2232  }
2233  } else {
2234  int udir = 0;
2235  int vdir = 0;
2236  ON_2dPoint start = start_2d;
2237  ON_2dPoint end = end_2d;
2238  if (ConsecutivePointsCrossClosedSeam(s, start, end, udir, vdir, BREP_SAME_POINT_TOLERANCE)) {
2239  double seam_t;
2240  ON_2dPoint from = ON_2dPoint::UnsetPoint;
2241  ON_2dPoint to = ON_2dPoint::UnsetPoint;
2242  if (FindTrimSeamCrossing(trim, t1, t2, seam_t, from, to, BREP_SAME_POINT_TOLERANCE)) {
2243  ON_2dPoint seam_2d = trim.PointAt(seam_t);
2244  ON_3dPoint seam_3d = s->PointAt(seam_2d.x, seam_2d.y);
2245  double tpercent = (seam_t - range.m_t[0]) / (range.m_t[1] - range.m_t[0]);
2246  if (param_points.find(tpercent) == param_points.end()) {
2247  param_points[tpercent] = new ON_3dPoint(seam_3d);
2248  }
2249  }
2250  }
2251  }
2252 }
2253 
2254 std::map<double, ON_3dPoint *> *
2255 getEdgePoints(ON_BrepTrim &trim,
2256  fastf_t max_dist,
2257  const struct rt_tess_tol *ttol,
2258  const struct bn_tol *tol,
2259  const struct rt_view_info *UNUSED(info))
2260 {
2261  std::map<double, ON_3dPoint *> *param_points = NULL;
2262  fastf_t min_dist, within_dist, cos_within_ang;
2263 
2264  double dist = 1000.0;
2265 
2266  const ON_Surface *s = trim.SurfaceOf();
2267 
2268  bool bGrowBox = false;
2269  ON_3dPoint min, max;
2270  if (trim.GetBoundingBox(min, max, bGrowBox)) {
2271  dist = DIST_PT_PT(min, max);
2272  }
2273 
2274  if (ttol->abs < tol->dist + ON_ZERO_TOLERANCE) {
2275  min_dist = tol->dist;
2276  } else {
2277  min_dist = ttol->abs;
2278  }
2279 
2280  double rel = 0.0;
2281  if (ttol->rel > 0.0 + ON_ZERO_TOLERANCE) {
2282  rel = ttol->rel * dist;
2283  if (max_dist < rel * 10.0) {
2284  max_dist = rel * 10.0;
2285  }
2286  within_dist = rel < min_dist ? min_dist : rel;
2287  } else if (ttol->abs > 0.0 + ON_ZERO_TOLERANCE) {
2288  within_dist = min_dist;
2289  } else {
2290  within_dist = 0.01 * dist; // default to 1% minimum surface distance
2291  }
2292 
2293  if (ttol->norm > 0.0 + ON_ZERO_TOLERANCE) {
2294  cos_within_ang = cos(ttol->norm);
2295  } else {
2296  cos_within_ang = cos(ON_PI / 2.0);
2297  }
2298 
2299  if (trim.m_trim_user.p == NULL) {
2300  param_points = new std::map<double, ON_3dPoint *>();
2301  trim.m_trim_user.p = (void *) param_points;
2302  ON_Interval range = trim.Domain();
2303  if (s->IsClosed(0) || s->IsClosed(1)) {
2304  ON_BoundingBox trim_bbox = ON_BoundingBox::EmptyBoundingBox;
2305  trim.GetBoundingBox(trim_bbox, false);
2306  }
2307 
2308  if (trim.IsClosed()) {
2309  double mid_range = (range.m_t[0] + range.m_t[1]) / 2.0;
2310  ON_3dPoint start_2d(0.0, 0.0, 0.0);
2311  ON_3dPoint start_3d(0.0, 0.0, 0.0);
2312  ON_3dVector start_tang(0.0, 0.0, 0.0);
2313  ON_3dVector start_norm(0.0, 0.0, 0.0);
2314  ON_3dPoint mid_2d(0.0, 0.0, 0.0);
2315  ON_3dPoint mid_3d(0.0, 0.0, 0.0);
2316  ON_3dVector mid_tang(0.0, 0.0, 0.0);
2317  ON_3dVector mid_norm(0.0, 0.0, 0.0);
2318  ON_3dPoint end_2d(0.0, 0.0, 0.0);
2319  ON_3dPoint end_3d(0.0, 0.0, 0.0);
2320  ON_3dVector end_tang(0.0, 0.0, 0.0);
2321  ON_3dVector end_norm(0.0, 0.0, 0.0);
2322 
2323  if (trim.EvTangent(range.m_t[0], start_2d, start_tang)
2324  && trim.EvTangent(mid_range, mid_2d, mid_tang)
2325  && trim.EvTangent(range.m_t[1], end_2d, end_tang)
2326  && surface_EvNormal(s, mid_2d.x, mid_2d.y, mid_3d, mid_norm)
2327  && surface_EvNormal(s, start_2d.x, start_2d.y, start_3d, start_norm)
2328  && surface_EvNormal(s, end_2d.x, end_2d.y, end_3d, end_norm))
2329  {
2330  (*param_points)[0.0] = new ON_3dPoint(
2331  s->PointAt(trim.PointAt(range.m_t[0]).x,
2332  trim.PointAt(range.m_t[0]).y));
2333  getEdgePoints(trim, range.m_t[0], start_2d, start_tang,
2334  start_3d, start_norm, mid_range, mid_2d, mid_tang,
2335  mid_3d, mid_norm, min_dist, max_dist, within_dist,
2336  cos_within_ang, *param_points);
2337  (*param_points)[0.5] = new ON_3dPoint(
2338  s->PointAt(trim.PointAt(mid_range).x,
2339  trim.PointAt(mid_range).y));
2340  getEdgePoints(trim, mid_range, mid_2d, mid_tang, mid_3d,
2341  mid_norm, range.m_t[1], end_2d, end_tang, end_3d,
2342  end_norm, min_dist, max_dist, within_dist,
2343  cos_within_ang, *param_points);
2344  (*param_points)[1.0] = new ON_3dPoint(
2345  s->PointAt(trim.PointAt(range.m_t[1]).x,
2346  trim.PointAt(range.m_t[1]).y));
2347  } else {
2348  start_2d = trim.PointAt(range.m_t[0]);
2349  end_2d = trim.PointAt(range.m_t[1]);
2350  start_3d = s->PointAt(start_2d.x,start_2d.y);
2351  end_3d = s->PointAt(end_2d.x,end_2d.y);
2352  mid_2d = trim.PointAt(mid_range);
2353  mid_3d = s->PointAt(mid_2d.x, mid_2d.y);
2354  (*param_points)[0.0] = new ON_3dPoint(
2355  s->PointAt(trim.PointAt(range.m_t[0]).x,
2356  trim.PointAt(range.m_t[0]).y));
2357  getEdgePoints(trim, range.m_t[0], start_2d, start_tang,
2358  start_3d, start_norm, mid_range, mid_2d, mid_tang,
2359  mid_3d, mid_norm, min_dist, max_dist, within_dist,
2360  cos_within_ang, *param_points);
2361  (*param_points)[0.5] = new ON_3dPoint(
2362  s->PointAt(trim.PointAt(mid_range).x,
2363  trim.PointAt(mid_range).y));
2364  getEdgePoints(trim, mid_range, mid_2d, mid_tang, mid_3d,
2365  mid_norm, range.m_t[1], end_2d, end_tang, end_3d,
2366  end_norm, min_dist, max_dist, within_dist,
2367  cos_within_ang, *param_points);
2368  (*param_points)[1.0] = new ON_3dPoint(
2369  s->PointAt(trim.PointAt(range.m_t[1]).x,
2370  trim.PointAt(range.m_t[1]).y));
2371  }
2372  } else {
2373  ON_3dPoint start_2d(0.0, 0.0, 0.0);
2374  ON_3dPoint start_3d(0.0, 0.0, 0.0);
2375  ON_3dVector start_tang(0.0, 0.0, 0.0);
2376  ON_3dVector start_norm(0.0, 0.0, 0.0);
2377  ON_3dPoint end_2d(0.0, 0.0, 0.0);
2378  ON_3dPoint end_3d(0.0, 0.0, 0.0);
2379  ON_3dVector end_tang(0.0, 0.0, 0.0);
2380  ON_3dVector end_norm(0.0, 0.0, 0.0);
2381 
2382  if (trim.EvTangent(range.m_t[0], start_2d, start_tang)
2383  && trim.EvTangent(range.m_t[1], end_2d, end_tang)
2384  && surface_EvNormal(s, start_2d.x, start_2d.y, start_3d, start_norm)
2385  && surface_EvNormal(s, end_2d.x, end_2d.y, end_3d, end_norm)) {
2386  (*param_points)[0.0] = new ON_3dPoint(start_3d);
2387  getEdgePoints(trim, range.m_t[0], start_2d, start_tang,
2388  start_3d, start_norm, range.m_t[1], end_2d, end_tang,
2389  end_3d, end_norm, min_dist, max_dist, within_dist,
2390  cos_within_ang, *param_points);
2391  (*param_points)[1.0] = new ON_3dPoint(end_3d);
2392  } else {
2393  start_2d = trim.PointAt(range.m_t[0]);
2394  end_2d = trim.PointAt(range.m_t[1]);
2395  start_3d = s->PointAt(start_2d.x,start_2d.y);
2396  end_3d = s->PointAt(end_2d.x,end_2d.y);
2397  (*param_points)[0.0] = new ON_3dPoint(start_3d);
2398  getEdgePoints(trim, range.m_t[0], start_2d, start_tang,
2399  start_3d, start_norm, range.m_t[1], end_2d, end_tang,
2400  end_3d, end_norm, min_dist, max_dist, within_dist,
2401  cos_within_ang, *param_points);
2402  (*param_points)[1.0] = new ON_3dPoint(end_3d);
2403  }
2404  }
2405  } else {
2406  param_points = (std::map<double, ON_3dPoint *> *) trim.m_trim_user.p;
2407  }
2408 
2409  return param_points;
2410 }
2411 
2412 void
2413 getSurfacePoints(const ON_Surface *s,
2414  fastf_t u1,
2415  fastf_t u2,
2416  fastf_t v1,
2417  fastf_t v2,
2418  fastf_t min_dist,
2419  fastf_t within_dist,
2420  fastf_t cos_within_ang,
2421  ON_2dPointArray &on_surf_points,
2422  bool left,
2423  bool below)
2424 {
2425  double ldfactor = 2.0;
2426  ON_2dPoint p2d(0.0, 0.0);
2427  ON_3dPoint p[4] = {ON_3dPoint(), ON_3dPoint(), ON_3dPoint(), ON_3dPoint()};
2428  ON_3dVector norm[4] = {ON_3dVector(), ON_3dVector(), ON_3dVector(), ON_3dVector()};
2429  ON_3dPoint mid(0.0, 0.0, 0.0);
2430  ON_3dVector norm_mid(0.0, 0.0, 0.0);
2431  fastf_t u = (u1 + u2) / 2.0;
2432  fastf_t v = (v1 + v2) / 2.0;
2433  fastf_t udist = u2 - u1;
2434  fastf_t vdist = v2 - v1;
2435 
2436  if ((udist < min_dist + ON_ZERO_TOLERANCE)
2437  || (vdist < min_dist + ON_ZERO_TOLERANCE)) {
2438  return;
2439  }
2440 
2441  if (udist > ldfactor * vdist) {
2442  int isteps = (int)(udist / vdist);
2443  isteps = (int)(udist / vdist / ldfactor * 2.0);
2444  fastf_t step = udist / (fastf_t) isteps;
2445 
2446  fastf_t step_u;
2447  for (int i = 1; i <= isteps; i++) {
2448  step_u = u1 + i * step;
2449  if ((below) && (i < isteps)) {
2450  p2d.Set(step_u, v1);
2451  on_surf_points.Append(p2d);
2452  }
2453  if (i == 1) {
2454  getSurfacePoints(s, u1, u1 + step, v1, v2, min_dist,
2455  within_dist, cos_within_ang, on_surf_points, left,
2456  below);
2457  } else if (i == isteps) {
2458  getSurfacePoints(s, u2 - step, u2, v1, v2, min_dist,
2459  within_dist, cos_within_ang, on_surf_points, left,
2460  below);
2461  } else {
2462  getSurfacePoints(s, step_u - step, step_u, v1, v2, min_dist, within_dist,
2463  cos_within_ang, on_surf_points, left, below);
2464  }
2465  left = false;
2466 
2467  if (i < isteps) {
2468  //top
2469  p2d.Set(step_u, v2);
2470  on_surf_points.Append(p2d);
2471  }
2472  }
2473  } else if (vdist > ldfactor * udist) {
2474  int isteps = (int)(vdist / udist);
2475  isteps = (int)(vdist / udist / ldfactor * 2.0);
2476  fastf_t step = vdist / (fastf_t) isteps;
2477  fastf_t step_v;
2478  for (int i = 1; i <= isteps; i++) {
2479  step_v = v1 + i * step;
2480  if ((left) && (i < isteps)) {
2481  p2d.Set(u1, step_v);
2482  on_surf_points.Append(p2d);
2483  }
2484 
2485  if (i == 1) {
2486  getSurfacePoints(s, u1, u2, v1, v1 + step, min_dist,
2487  within_dist, cos_within_ang, on_surf_points, left,
2488  below);
2489  } else if (i == isteps) {
2490  getSurfacePoints(s, u1, u2, v2 - step, v2, min_dist,
2491  within_dist, cos_within_ang, on_surf_points, left,
2492  below);
2493  } else {
2494  getSurfacePoints(s, u1, u2, step_v - step, step_v, min_dist, within_dist,
2495  cos_within_ang, on_surf_points, left, below);
2496  }
2497 
2498  below = false;
2499 
2500  if (i < isteps) {
2501  //right
2502  p2d.Set(u2, step_v);
2503  on_surf_points.Append(p2d);
2504  }
2505  }
2506  } else if ((surface_EvNormal(s, u1, v1, p[0], norm[0]))
2507  && (surface_EvNormal(s, u2, v1, p[1], norm[1])) // for u
2508  && (surface_EvNormal(s, u2, v2, p[2], norm[2]))
2509  && (surface_EvNormal(s, u1, v2, p[3], norm[3]))
2510  && (surface_EvNormal(s, u, v, mid, norm_mid))) {
2511  double udot;
2512  double vdot;
2513  ON_Line line1(p[0], p[2]);
2514  ON_Line line2(p[1], p[3]);
2515  double dist = mid.DistanceTo(line1.ClosestPointTo(mid));
2516  V_MAX(dist, mid.DistanceTo(line2.ClosestPointTo(mid)));
2517 
2518  if (dist < min_dist + ON_ZERO_TOLERANCE) {
2519  return;
2520  }
2521 
2522  if (VNEAR_EQUAL(norm[0], norm[1], ON_ZERO_TOLERANCE)) {
2523  udot = 1.0;
2524  } else {
2525  udot = norm[0] * norm[1];
2526  }
2527  if (VNEAR_EQUAL(norm[0], norm[3], ON_ZERO_TOLERANCE)) {
2528  vdot = 1.0;
2529  } else {
2530  vdot = norm[0] * norm[3];
2531  }
2532  if ((udot < cos_within_ang - ON_ZERO_TOLERANCE)
2533  && (vdot < cos_within_ang - ON_ZERO_TOLERANCE)) {
2534  if (left) {
2535  p2d.Set(u1, v);
2536  on_surf_points.Append(p2d);
2537  }
2538  if (below) {
2539  p2d.Set(u, v1);
2540  on_surf_points.Append(p2d);
2541  }
2542  //center
2543  p2d.Set(u, v);
2544  on_surf_points.Append(p2d);
2545  //right
2546  p2d.Set(u2, v);
2547  on_surf_points.Append(p2d);
2548  //top
2549  p2d.Set(u, v2);
2550  on_surf_points.Append(p2d);
2551 
2552  getSurfacePoints(s, u1, u, v1, v, min_dist, within_dist,
2553  cos_within_ang, on_surf_points, left, below);
2554  getSurfacePoints(s, u1, u, v, v2, min_dist, within_dist,
2555  cos_within_ang, on_surf_points, left, false);
2556  getSurfacePoints(s, u, u2, v1, v, min_dist, within_dist,
2557  cos_within_ang, on_surf_points, false, below);
2558  getSurfacePoints(s, u, u2, v, v2, min_dist, within_dist,
2559  cos_within_ang, on_surf_points, false, false);
2560  } else if (udot < cos_within_ang - ON_ZERO_TOLERANCE) {
2561  if (below) {
2562  p2d.Set(u, v1);
2563  on_surf_points.Append(p2d);
2564  }
2565  //top
2566  p2d.Set(u, v2);
2567  on_surf_points.Append(p2d);
2568  getSurfacePoints(s, u1, u, v1, v2, min_dist, within_dist,
2569  cos_within_ang, on_surf_points, left, below);
2570  getSurfacePoints(s, u, u2, v1, v2, min_dist, within_dist,
2571  cos_within_ang, on_surf_points, false, below);
2572  } else if (vdot < cos_within_ang - ON_ZERO_TOLERANCE) {
2573  if (left) {
2574  p2d.Set(u1, v);
2575  on_surf_points.Append(p2d);
2576  }
2577  //right
2578  p2d.Set(u2, v);
2579  on_surf_points.Append(p2d);
2580 
2581  getSurfacePoints(s, u1, u2, v1, v, min_dist, within_dist,
2582  cos_within_ang, on_surf_points, left, below);
2583  getSurfacePoints(s, u1, u2, v, v2, min_dist, within_dist,
2584  cos_within_ang, on_surf_points, left, false);
2585  } else {
2586  if (left) {
2587  p2d.Set(u1, v);
2588  on_surf_points.Append(p2d);
2589  }
2590  if (below) {
2591  p2d.Set(u, v1);
2592  on_surf_points.Append(p2d);
2593  }
2594  //center
2595  p2d.Set(u, v);
2596  on_surf_points.Append(p2d);
2597  //right
2598  p2d.Set(u2, v);
2599  on_surf_points.Append(p2d);
2600  //top
2601  p2d.Set(u, v2);
2602  on_surf_points.Append(p2d);
2603 
2604  if (dist > within_dist + ON_ZERO_TOLERANCE) {
2605 
2606  getSurfacePoints(s, u1, u, v1, v, min_dist, within_dist,
2607  cos_within_ang, on_surf_points, left, below);
2608  getSurfacePoints(s, u1, u, v, v2, min_dist, within_dist,
2609  cos_within_ang, on_surf_points, left, false);
2610  getSurfacePoints(s, u, u2, v1, v, min_dist, within_dist,
2611  cos_within_ang, on_surf_points, false, below);
2612  getSurfacePoints(s, u, u2, v, v2, min_dist, within_dist,
2613  cos_within_ang, on_surf_points, false, false);
2614  }
2615  }
2616  }
2617 }
2618 
2619 
2620 void
2621 getSurfacePoints(ON_BrepFace &face,
2622  const struct rt_tess_tol *ttol,
2623  const struct bn_tol *tol,
2624  const struct rt_view_info *UNUSED(info),
2625  ON_2dPointArray &on_surf_points)
2626 {
2627  double surface_width, surface_height;
2628  const ON_Surface *s = face.SurfaceOf();
2629  ON_Brep *brep = face.Brep();
2630 
2631  if (s->GetSurfaceSize(&surface_width, &surface_height)) {
2632  double dist = 0.0;
2633  double min_dist = 0.0;
2634  double within_dist = 0.0;
2635  double cos_within_ang = 0.0;
2636 
2637  if ((surface_width < tol->dist) || (surface_height < tol->dist)) {
2638  return;
2639  }
2640 
2641  // may be a smaller trimmed subset of surface so worth getting
2642  // face boundary
2643  bool bGrowBox = false;
2644  ON_3dPoint min, max;
2645  for (int li = 0; li < face.LoopCount(); li++) {
2646  for (int ti = 0; ti < face.Loop(li)->TrimCount(); ti++) {
2647  ON_BrepTrim *trim = face.Loop(li)->Trim(ti);
2648  trim->GetBoundingBox(min, max, bGrowBox);
2649  bGrowBox = true;
2650  }
2651  }
2652 
2653  ON_BoundingBox tight_bbox;
2654  if (brep->GetTightBoundingBox(tight_bbox)) {
2655  dist = DIST_PT_PT(tight_bbox.m_min, tight_bbox.m_max);
2656  }
2657 
2658  if (ttol->abs < tol->dist + ON_ZERO_TOLERANCE) {
2659  min_dist = tol->dist;
2660  } else {
2661  min_dist = ttol->abs;
2662  }
2663 
2664  double rel = 0.0;
2665  if (ttol->rel > 0.0 + ON_ZERO_TOLERANCE) {
2666  rel = ttol->rel * dist;
2667  within_dist = rel < min_dist ? min_dist : rel;
2668  //if (ttol->abs < tol->dist + ON_ZERO_TOLERANCE) {
2669  // min_dist = within_dist;
2670  //}
2671  } else if ((ttol->abs > 0.0 + ON_ZERO_TOLERANCE)
2672  && (ttol->norm < 0.0 + ON_ZERO_TOLERANCE)) {
2673  within_dist = min_dist;
2674  } else if ((ttol->abs > 0.0 + ON_ZERO_TOLERANCE)
2675  || (ttol->norm > 0.0 + ON_ZERO_TOLERANCE)) {
2676  within_dist = dist;
2677  } else {
2678  within_dist = 0.01 * dist; // default to 1% minimum surface distance
2679  }
2680 
2681  if (ttol->norm > 0.0 + ON_ZERO_TOLERANCE) {
2682  cos_within_ang = cos(ttol->norm);
2683  } else {
2684  cos_within_ang = cos(ON_PI / 2.0);
2685  }
2686  ON_BOOL32 uclosed = s->IsClosed(0);
2687  ON_BOOL32 vclosed = s->IsClosed(1);
2688  if (uclosed && vclosed) {
2689  ON_2dPoint p(0.0, 0.0);
2690  double midx = (min.x + max.x) / 2.0;
2691  double midy = (min.y + max.y) / 2.0;
2692 
2693  //bottom left
2694  p.Set(min.x, min.y);
2695  on_surf_points.Append(p);
2696 
2697  //midy left
2698  p.Set(min.x, midy);
2699  on_surf_points.Append(p);
2700 
2701  getSurfacePoints(s, min.x, midx, min.y, midy, min_dist, within_dist,
2702  cos_within_ang, on_surf_points, true, true);
2703 
2704  //bottom midx
2705  p.Set(midx, min.y);
2706  on_surf_points.Append(p);
2707 
2708  //midx midy
2709  p.Set(midx, midy);
2710  on_surf_points.Append(p);
2711 
2712  getSurfacePoints(s, midx, max.x, min.y, midy, min_dist, within_dist,
2713  cos_within_ang, on_surf_points, false, true);
2714 
2715  //bottom right
2716  p.Set(max.x, min.y);
2717  on_surf_points.Append(p);
2718 
2719  //right midy
2720  p.Set(max.x, midy);
2721  on_surf_points.Append(p);
2722 
2723  //top left
2724  p.Set(min.x, max.y);
2725  on_surf_points.Append(p);
2726 
2727  getSurfacePoints(s, min.x, midx, midy, max.y, min_dist, within_dist,
2728  cos_within_ang, on_surf_points, true, false);
2729 
2730  //top midx
2731  p.Set(midx, max.y);
2732  on_surf_points.Append(p);
2733 
2734  getSurfacePoints(s, midx, max.x, midy, max.y, min_dist, within_dist,
2735  cos_within_ang, on_surf_points, false, false);
2736 
2737  //top left
2738  p.Set(max.x, max.y);
2739  on_surf_points.Append(p);
2740  } else if (uclosed) {
2741  ON_2dPoint p(0.0, 0.0);
2742  double midx = (min.x + max.x) / 2.0;
2743 
2744  //bottom left
2745  p.Set(min.x, min.y);
2746  on_surf_points.Append(p);
2747 
2748  //top left
2749  p.Set(min.x, max.y);
2750  on_surf_points.Append(p);
2751 
2752  getSurfacePoints(s, min.x, midx, min.y, max.y, min_dist,
2753  within_dist, cos_within_ang, on_surf_points, true, true);
2754 
2755  //bottom midx
2756  p.Set(midx, min.y);
2757  on_surf_points.Append(p);
2758 
2759  //top midx
2760  p.Set(midx, max.y);
2761  on_surf_points.Append(p);
2762 
2763  getSurfacePoints(s, midx, max.x, min.y, max.y, min_dist,
2764  within_dist, cos_within_ang, on_surf_points, false, true);
2765 
2766  //bottom right
2767  p.Set(max.x, min.y);
2768  on_surf_points.Append(p);
2769 
2770  //top right
2771  p.Set(max.x, max.y);
2772  on_surf_points.Append(p);
2773  } else if (vclosed) {
2774  ON_2dPoint p(0.0, 0.0);
2775  double midy = (min.y + max.y) / 2.0;
2776 
2777  //bottom left
2778  p.Set(min.x, min.y);
2779  on_surf_points.Append(p);
2780 
2781  //left midy
2782  p.Set(min.x, midy);
2783  on_surf_points.Append(p);
2784 
2785  getSurfacePoints(s, min.x, max.x, min.y, midy, min_dist,
2786  within_dist, cos_within_ang, on_surf_points, true, true);
2787 
2788  //bottom right
2789  p.Set(max.x, min.y);
2790  on_surf_points.Append(p);
2791 
2792  //right midy
2793  p.Set(max.x, midy);
2794  on_surf_points.Append(p);
2795 
2796  getSurfacePoints(s, min.x, max.x, midy, max.y, min_dist,
2797  within_dist, cos_within_ang, on_surf_points, true, false);
2798 
2799  // top left
2800  p.Set(min.x, max.y);
2801  on_surf_points.Append(p);
2802 
2803  //top right
2804  p.Set(max.x, max.y);
2805  on_surf_points.Append(p);
2806  } else {
2807  ON_2dPoint p(0.0, 0.0);
2808 
2809  //bottom left
2810  p.Set(min.x, min.y);
2811  on_surf_points.Append(p);
2812 
2813  //top left
2814  p.Set(min.x, max.y);
2815  on_surf_points.Append(p);
2816 
2817  getSurfacePoints(s, min.x, max.x, min.y, max.y, min_dist,
2818  within_dist, cos_within_ang, on_surf_points, true, true);
2819 
2820  //bottom right
2821  p.Set(max.x, min.y);
2822  on_surf_points.Append(p);
2823 
2824  //top right
2825  p.Set(max.x, max.y);
2826  on_surf_points.Append(p);
2827  }
2828  }
2829 }
2830 
2831 
2832 void
2833 getUVCurveSamples(const ON_Surface *s,
2834  const ON_Curve *curve,
2835  fastf_t t1,
2836  ON_3dPoint &start_2d,
2837  ON_3dVector &start_tang,
2838  ON_3dPoint &start_3d,
2839  ON_3dVector &start_norm,
2840  fastf_t t2,
2841  ON_3dPoint &end_2d,
2842  ON_3dVector &end_tang,
2843  ON_3dPoint &end_3d,
2844  ON_3dVector &end_norm,
2845  fastf_t min_dist,
2846  fastf_t max_dist,
2847  fastf_t within_dist,
2848  fastf_t cos_within_ang,
2849  std::map<double, ON_3dPoint *> &param_points)
2850 {
2851  ON_Interval range = curve->Domain();
2852  ON_3dPoint mid_2d(0.0, 0.0, 0.0);
2853  ON_3dPoint mid_3d(0.0, 0.0, 0.0);
2854  ON_3dVector mid_norm(0.0, 0.0, 0.0);
2855  ON_3dVector mid_tang(0.0, 0.0, 0.0);
2856  fastf_t t = (t1 + t2) / 2.0;
2857 
2858  if (curve->EvTangent(t, mid_2d, mid_tang)
2859  && surface_EvNormal(s, mid_2d.x, mid_2d.y, mid_3d, mid_norm)) {
2860  ON_Line line3d(start_3d, end_3d);
2861  double dist3d;
2862 
2863  if ((line3d.Length() > max_dist)
2864  || ((dist3d = mid_3d.DistanceTo(line3d.ClosestPointTo(mid_3d)))
2865  > within_dist + ON_ZERO_TOLERANCE)
2866  || ((((start_tang * end_tang)
2867  < cos_within_ang - ON_ZERO_TOLERANCE)
2868  || ((start_norm * end_norm)
2869  < cos_within_ang - ON_ZERO_TOLERANCE))
2870  && (dist3d > min_dist + ON_ZERO_TOLERANCE))) {
2871  getUVCurveSamples(s, curve, t1, start_2d, start_tang, start_3d, start_norm,
2872  t, mid_2d, mid_tang, mid_3d, mid_norm, min_dist, max_dist,
2873  within_dist, cos_within_ang, param_points);
2874  param_points[(t - range.m_t[0]) / (range.m_t[1] - range.m_t[0])] =
2875  new ON_3dPoint(mid_3d);
2876  getUVCurveSamples(s, curve, t, mid_2d, mid_tang, mid_3d, mid_norm, t2,
2877  end_2d, end_tang, end_3d, end_norm, min_dist, max_dist,
2878  within_dist, cos_within_ang, param_points);
2879  }
2880  }
2881 }
2882 
2883 
2884 std::map<double, ON_3dPoint *> *
2885 getUVCurveSamples(const ON_Surface *surf,
2886  const ON_Curve *curve,
2887  fastf_t max_dist,
2888  const struct rt_tess_tol *ttol,
2889  const struct bn_tol *tol,
2890  const struct rt_view_info *UNUSED(info))
2891 {
2892  fastf_t min_dist, within_dist, cos_within_ang;
2893 
2894  double dist = 1000.0;
2895 
2896  bool bGrowBox = false;
2897  ON_3dPoint min, max;
2898  if (curve->GetBoundingBox(min, max, bGrowBox)) {
2899  dist = DIST_PT_PT(min, max);
2900  }
2901 
2902  if (ttol->abs < tol->dist + ON_ZERO_TOLERANCE) {
2903  min_dist = tol->dist;
2904  } else {
2905  min_dist = ttol->abs;
2906  }
2907 
2908  double rel = 0.0;
2909  if (ttol->rel > 0.0 + ON_ZERO_TOLERANCE) {
2910  rel = ttol->rel * dist;
2911  if (max_dist < rel * 10.0) {
2912  max_dist = rel * 10.0;
2913  }
2914  within_dist = rel < min_dist ? min_dist : rel;
2915  } else if (ttol->abs > 0.0 + ON_ZERO_TOLERANCE) {
2916  within_dist = min_dist;
2917  } else {
2918  within_dist = 0.01 * dist; // default to 1% minimum surface distance
2919  }
2920 
2921  if (ttol->norm > 0.0 + ON_ZERO_TOLERANCE) {
2922  cos_within_ang = cos(ttol->norm);
2923  } else {
2924  cos_within_ang = cos(ON_PI / 2.0);
2925  }
2926 
2927  std::map<double, ON_3dPoint *> *param_points = new std::map<double, ON_3dPoint *>();
2928  ON_Interval range = curve->Domain();
2929 
2930  if (curve->IsClosed()) {
2931  double mid_range = (range.m_t[0] + range.m_t[1]) / 2.0;
2932  ON_3dPoint start_2d(0.0, 0.0, 0.0);
2933  ON_3dPoint start_3d(0.0, 0.0, 0.0);
2934  ON_3dVector start_tang(0.0, 0.0, 0.0);
2935  ON_3dVector start_norm(0.0, 0.0, 0.0);
2936  ON_3dPoint mid_2d(0.0, 0.0, 0.0);
2937  ON_3dPoint mid_3d(0.0, 0.0, 0.0);
2938  ON_3dVector mid_tang(0.0, 0.0, 0.0);
2939  ON_3dVector mid_norm(0.0, 0.0, 0.0);
2940  ON_3dPoint end_2d(0.0, 0.0, 0.0);
2941  ON_3dPoint end_3d(0.0, 0.0, 0.0);
2942  ON_3dVector end_tang(0.0, 0.0, 0.0);
2943  ON_3dVector end_norm(0.0, 0.0, 0.0);
2944 
2945  if (curve->EvTangent(range.m_t[0], start_2d, start_tang)
2946  && curve->EvTangent(mid_range, mid_2d, mid_tang)
2947  && curve->EvTangent(range.m_t[1], end_2d, end_tang)
2948  && surface_EvNormal(surf, mid_2d.x, mid_2d.y, mid_3d, mid_norm)
2949  && surface_EvNormal(surf, start_2d.x, start_2d.y, start_3d, start_norm)
2950  && surface_EvNormal(surf, end_2d.x, end_2d.y, end_3d, end_norm))
2951  {
2952  (*param_points)[0.0] = new ON_3dPoint(
2953  surf->PointAt(curve->PointAt(range.m_t[0]).x,
2954  curve->PointAt(range.m_t[0]).y));
2955  getUVCurveSamples(surf, curve, range.m_t[0], start_2d, start_tang,
2956  start_3d, start_norm, mid_range, mid_2d, mid_tang,
2957  mid_3d, mid_norm, min_dist, max_dist, within_dist,
2958  cos_within_ang, *param_points);
2959  (*param_points)[0.5] = new ON_3dPoint(
2960  surf->PointAt(curve->PointAt(mid_range).x,
2961  curve->PointAt(mid_range).y));
2962  getUVCurveSamples(surf, curve, mid_range, mid_2d, mid_tang, mid_3d,
2963  mid_norm, range.m_t[1], end_2d, end_tang, end_3d,
2964  end_norm, min_dist, max_dist, within_dist,
2965  cos_within_ang, *param_points);
2966  (*param_points)[1.0] = new ON_3dPoint(
2967  surf->PointAt(curve->PointAt(range.m_t[1]).x,
2968  curve->PointAt(range.m_t[1]).y));
2969  }
2970  } else {
2971  ON_3dPoint start_2d(0.0, 0.0, 0.0);
2972  ON_3dPoint start_3d(0.0, 0.0, 0.0);
2973  ON_3dVector start_tang(0.0, 0.0, 0.0);
2974  ON_3dVector start_norm(0.0, 0.0, 0.0);
2975  ON_3dPoint end_2d(0.0, 0.0, 0.0);
2976  ON_3dPoint end_3d(0.0, 0.0, 0.0);
2977  ON_3dVector end_tang(0.0, 0.0, 0.0);
2978  ON_3dVector end_norm(0.0, 0.0, 0.0);
2979 
2980  if (curve->EvTangent(range.m_t[0], start_2d, start_tang)
2981  && curve->EvTangent(range.m_t[1], end_2d, end_tang)
2982  && surface_EvNormal(surf, start_2d.x, start_2d.y, start_3d, start_norm)
2983  && surface_EvNormal(surf, end_2d.x, end_2d.y, end_3d, end_norm))
2984  {
2985  (*param_points)[0.0] = new ON_3dPoint(start_3d);
2986  getUVCurveSamples(surf, curve, range.m_t[0], start_2d, start_tang,
2987  start_3d, start_norm, range.m_t[1], end_2d, end_tang,
2988  end_3d, end_norm, min_dist, max_dist, within_dist,
2989  cos_within_ang, *param_points);
2990  (*param_points)[1.0] = new ON_3dPoint(end_3d);
2991  }
2992  }
2993 
2994 
2995  return param_points;
2996 }
2997 
2998 
2999 /*
3000  * number_of_seam_crossings
3001  */
3002 int
3003 number_of_seam_crossings(const ON_Surface *surf, ON_SimpleArray<BrepTrimPoint> &brep_trim_points)
3004 {
3005  int rc = 0;
3006  ON_2dPoint *prev_non_seam_pt = NULL;
3007  for (int i = 0; i < brep_trim_points.Count(); i++) {
3008  ON_2dPoint *pt = &brep_trim_points[i].p2d;
3009  if (!IsAtSeam(surf, *pt, BREP_SAME_POINT_TOLERANCE)) {
3010  int udir = 0;
3011  int vdir = 0;
3012  if (prev_non_seam_pt != NULL) {
3013  if (ConsecutivePointsCrossClosedSeam(surf, *prev_non_seam_pt, *pt, udir, vdir, BREP_SAME_POINT_TOLERANCE)) {
3014  rc++;
3015  }
3016  }
3017  prev_non_seam_pt = pt;
3018  }
3019  }
3020 
3021  return rc;
3022 }
3023 
3024 
3025 bool
3026 LoopStraddlesDomain(const ON_Surface *surf, ON_SimpleArray<BrepTrimPoint> &brep_loop_points)
3027 {
3028  if (surf->IsClosed(0) || surf->IsClosed(1)) {
3029  int num_crossings = number_of_seam_crossings(surf, brep_loop_points);
3030  if (num_crossings == 1) {
3031  return true;
3032  }
3033  }
3034  return false;
3035 }
3036 
3037 
3038 /*
3039  * entering - 1
3040  * exiting - 2
3041  * contained - 0
3042  */
3043 int
3044 is_entering(const ON_Surface *surf, const ON_SimpleArray<BrepTrimPoint> &brep_loop_points)
3045 {
3046  int numpoints = brep_loop_points.Count();
3047  for (int i = 1; i < numpoints - 1; i++) {
3048  int seam = 0;
3049  ON_2dPoint p = brep_loop_points[i].p2d;
3050  if ((seam = IsAtSeam(surf, p, BREP_SAME_POINT_TOLERANCE)) > 0) {
3051  ON_2dPoint unwrapped = UnwrapUVPoint(surf, p, BREP_SAME_POINT_TOLERANCE);
3052  if (seam == 1) {
3053  bool right_seam = unwrapped.x > surf->Domain(0).Mid();
3054  bool decreasing = (brep_loop_points[numpoints - 1].p2d.x - brep_loop_points[0].p2d.x) < 0;
3055  if (right_seam != decreasing) { // basically XOR'ing here
3056  return 2;
3057  } else {
3058  return 1;
3059  }
3060  } else {
3061  bool top_seam = unwrapped.y > surf->Domain(1).Mid();
3062  bool decreasing = (brep_loop_points[numpoints - 1].p2d.y - brep_loop_points[0].p2d.y) < 0;
3063  if (top_seam != decreasing) { // basically XOR'ing here
3064  return 2;
3065  } else {
3066  return 1;
3067  }
3068  }
3069  }
3070  }
3071  return 0;
3072 }
3073 
3074 /*
3075  * shift_closed_curve_split_over_seam
3076  */
3077 bool
3078 shift_loop_straddled_over_seam(const ON_Surface *surf, ON_SimpleArray<BrepTrimPoint> &brep_loop_points, double same_point_tolerance)
3079 {
3080  if (surf->IsClosed(0) || surf->IsClosed(1)) {
3081  ON_Interval dom[2];
3082  int entering = is_entering(surf, brep_loop_points);
3083 
3084  dom[0] = surf->Domain(0);
3085  dom[1] = surf->Domain(1);
3086 
3087  int seam = 0;
3088  int i;
3089  ON_2dPoint *prev_pt = NULL;
3090  BrepTrimPoint btp;
3091  BrepTrimPoint end_btp;
3092  ON_SimpleArray<BrepTrimPoint> part1;
3093  ON_SimpleArray<BrepTrimPoint> part2;
3094 
3095  end_btp.p2d = ON_2dPoint::UnsetPoint;
3096  int numpoints = brep_loop_points.Count();
3097  bool first_seam_pt = true;
3098  for (i = 0; i < numpoints; i++) {
3099  btp = brep_loop_points[i];
3100  if ((seam = IsAtSeam(surf, btp.p2d, same_point_tolerance)) > 0) {
3101  if (first_seam_pt) {
3102  part1.Append(btp);
3103  first_seam_pt = false;
3104  }
3105  end_btp = btp;
3106  SwapUVSeamPoint(surf, end_btp.p2d);
3107  part2.Append(end_btp);
3108  } else {
3109  if (dom[0].Includes(btp.p2d.x, false) && dom[1].Includes(btp.p2d.y, false)) {
3110  part1.Append(brep_loop_points[i]);
3111  } else {
3112  btp = brep_loop_points[i];
3113  btp.p2d = UnwrapUVPoint(surf, brep_loop_points[i].p2d, same_point_tolerance);
3114  part2.Append(btp);
3115  }
3116  }
3117  prev_pt = &brep_loop_points[i].p2d;
3118  }
3119 
3120  brep_loop_points.Empty();
3121  if (entering == 1) {
3122  brep_loop_points.Append(part1.Count() - 1, part1.Array());
3123  brep_loop_points.Append(part2.Count(), part2.Array());
3124  } else {
3125  brep_loop_points.Append(part2.Count() - 1, part2.Array());
3126  brep_loop_points.Append(part1.Count(), part1.Array());
3127  }
3128  }
3129  return true;
3130 }
3131 
3132 
3133 /*
3134  * extend_over_seam_crossings
3135  */
3136 bool
3137 extend_over_seam_crossings(const ON_Surface *surf, ON_SimpleArray<BrepTrimPoint> &brep_loop_points)
3138 {
3139  int num_points = brep_loop_points.Count();
3140  double ulength = surf->Domain(0).Length();
3141  double vlength = surf->Domain(1).Length();
3142  for (int i = 1; i < num_points; i++) {
3143  if (surf->IsClosed(0)) {
3144  double delta = brep_loop_points[i].p2d.x - brep_loop_points[i - 1].p2d.x;
3145  while (fabs(delta) > ulength / 2.0) {
3146  if (delta < 0.0) {
3147  brep_loop_points[i].p2d.x += ulength; // east bound
3148  } else {
3149  brep_loop_points[i].p2d.x -= ulength;; // west bound
3150  }
3151  delta = brep_loop_points[i].p2d.x - brep_loop_points[i - 1].p2d.x;
3152  }
3153  }
3154  if (surf->IsClosed(1)) {
3155  double delta = brep_loop_points[i].p2d.y - brep_loop_points[i - 1].p2d.y;
3156  while (fabs(delta) > vlength / 2.0) {
3157  if (delta < 0.0) {
3158  brep_loop_points[i].p2d.y += vlength; // north bound
3159  } else {
3160  brep_loop_points[i].p2d.y -= vlength;; // south bound
3161  }
3162  delta = brep_loop_points[i].p2d.y - brep_loop_points[i - 1].p2d.y;
3163  }
3164  }
3165  }
3166 
3167  return true;
3168 }
3169 
3170 static void
3171 get_loop_sample_points(
3172  ON_SimpleArray<BrepTrimPoint> *points,
3173  const ON_BrepFace &face,
3174  const ON_BrepLoop *loop,
3175  fastf_t max_dist,
3176  const struct rt_tess_tol *ttol,
3177  const struct bn_tol *tol,
3178  const struct rt_view_info *info)
3179 {
3180  int trim_count = loop->TrimCount();
3181 
3182  for (int lti = 0; lti < trim_count; lti++) {
3183  ON_BrepTrim *trim = loop->Trim(lti);
3184  //ON_BrepEdge *edge = trim->Edge();
3185 
3186  if (trim->m_type == ON_BrepTrim::singular) {
3187  BrepTrimPoint btp;
3188  ON_BrepVertex& v1 = face.Brep()->m_V[trim->m_vi[0]];
3189  ON_3dPoint *p3d = new ON_3dPoint(v1.Point());
3190  //ON_2dPoint p2d_begin = trim->PointAt(trim->Domain().m_t[0]);
3191  //ON_2dPoint p2d_end = trim->PointAt(trim->Domain().m_t[1]);
3192  double delta = trim->Domain().Length() / 10.0;
3193  ON_Interval trim_dom = trim->Domain();
3194 
3195  for (int i = 1; i <= 10; i++) {
3196  btp.p3d = p3d;
3197  btp.p2d = v1.Point();
3198  btp.t = trim->Domain().m_t[0] + (i - 1) * delta;
3199  btp.p2d = trim->PointAt(btp.t);
3200  btp.e = ON_UNSET_VALUE;
3201  points->Append(btp);
3202  }
3203  // skip last point of trim if not last trim
3204  if (lti < trim_count - 1)
3205  continue;
3206 
3207  ON_BrepVertex& v2 = face.Brep()->m_V[trim->m_vi[1]];
3208  btp.p3d = p3d;
3209  btp.p2d = v2.Point();
3210  btp.t = trim->Domain().m_t[1];
3211  btp.p2d = trim->PointAt(btp.t);
3212  btp.e = ON_UNSET_VALUE;
3213  points->Append(btp);
3214 
3215  continue;
3216  }
3217 
3218  if (!trim->m_trim_user.p) {
3219  (void) getEdgePoints(*trim, max_dist, ttol, tol, info);
3220  }
3221  if (trim->m_trim_user.p) {
3222  std::map<double, ON_3dPoint *> *param_points3d = (std::map<double, ON_3dPoint *> *) trim->m_trim_user.p;
3223 
3224  ON_3dPoint boxmin;
3225  ON_3dPoint boxmax;
3226 
3227  if (trim->GetBoundingBox(boxmin, boxmax, false)) {
3228  double t0, t1;
3229 
3230  std::map<double, ON_3dPoint*>::const_iterator i;
3231 
3232  trim->GetDomain(&t0, &t1);
3233  for (i = param_points3d->begin();
3234  i != param_points3d->end();) {
3235  BrepTrimPoint btp;
3236  btp.t = (*i).first;
3237  btp.p3d = (*i).second;
3238 
3239  // skip last point of trim if not last trim
3240  if ((++i == param_points3d->end()) && (lti < trim_count - 1))
3241  continue;
3242 
3243  btp.p2d = trim->PointAt(t0 + (t1 - t0) * btp.t);
3244  btp.e = ON_UNSET_VALUE;
3245  points->Append(btp);
3246  }
3247  }
3248  }
3249  }
3250 }
3251 
3252 
3253 /* force near seam points to seam */
3254 static void
3255 ForceNearSeamPointsToSeam(
3256  const ON_Surface *s,
3257  const ON_BrepFace &face,
3258  ON_SimpleArray<BrepTrimPoint> *brep_loop_points,
3259  double same_point_tolerance)
3260 {
3261  int loop_cnt = face.LoopCount();
3262  for (int li = 0; li < loop_cnt; li++) {
3263  int num_loop_points = brep_loop_points[li].Count();
3264  if (num_loop_points > 1) {
3265  for (int i = 0; i < num_loop_points; i++) {
3266  ON_2dPoint &p = brep_loop_points[li][i].p2d;
3267  if (IsAtSeam(s, p, same_point_tolerance)) {
3268  ForceToClosestSeam(s, p, same_point_tolerance);
3269  }
3270  }
3271  }
3272  }
3273 }
3274 
3275 
3276 static void
3277 ExtendPointsOverClosedSeam(
3278  const ON_Surface *s,
3279  const ON_BrepFace &face,
3280  ON_SimpleArray<BrepTrimPoint> *brep_loop_points)
3281 {
3282  int loop_cnt = face.LoopCount();
3283  // extend loop points over seam if needed.
3284  for (int li = 0; li < loop_cnt; li++) {
3285  int num_loop_points = brep_loop_points[li].Count();
3286  if (num_loop_points > 1) {
3287  if (!extend_over_seam_crossings(s, brep_loop_points[li])) {
3288  std::cerr << "Error: Face(" << face.m_face_index << ") cannot extend loops over closed seams." << std::endl;
3289  }
3290  }
3291  }
3292 }
3293 
3294 
3295 // process through loops checking for straddle condition.
3296 static void
3297 ShiftLoopsThatStraddleSeam(
3298  const ON_Surface *s,
3299  const ON_BrepFace &face,
3300  ON_SimpleArray<BrepTrimPoint> *brep_loop_points,
3301  double same_point_tolerance)
3302 {
3303  int loop_cnt = face.LoopCount();
3304  for (int li = 0; li < loop_cnt; li++) {
3305  int num_loop_points = brep_loop_points[li].Count();
3306  if (num_loop_points > 1) {
3307  ON_2dPoint brep_loop_begin = brep_loop_points[li][0].p2d;
3308  ON_2dPoint brep_loop_end = brep_loop_points[li][num_loop_points - 1].p2d;
3309 
3310  if (!V2NEAR_EQUAL(brep_loop_begin, brep_loop_end, same_point_tolerance)) {
3311  if (LoopStraddlesDomain(s, brep_loop_points[li])) {
3312  // reorder loop points
3313  shift_loop_straddled_over_seam(s, brep_loop_points[li], same_point_tolerance);
3314  }
3315  }
3316  }
3317  }
3318 }
3319 
3320 
3321 // process through closing open loops that begin and end on closed seam
3322 static void
3323 CloseOpenLoops(
3324  const ON_Surface *s,
3325  const ON_BrepFace &face,
3326  const struct rt_tess_tol *ttol,
3327  const struct bn_tol *tol,
3328  const struct rt_view_info *info,
3329  ON_SimpleArray<BrepTrimPoint> *brep_loop_points,
3330  double same_point_tolerance)
3331 {
3332  std::list<std::map<double, ON_3dPoint *> *> bridgePoints;
3333  int loop_cnt = face.LoopCount();
3334  for (int li = 0; li < loop_cnt; li++) {
3335  int num_loop_points = brep_loop_points[li].Count();
3336  if (num_loop_points > 1) {
3337  ON_2dPoint brep_loop_begin = brep_loop_points[li][0].p2d;
3338  ON_2dPoint brep_loop_end = brep_loop_points[li][num_loop_points - 1].p2d;
3339  ON_3dPoint brep_loop_begin3d = s->PointAt(brep_loop_begin.x, brep_loop_begin.y);
3340  ON_3dPoint brep_loop_end3d = s->PointAt(brep_loop_end.x, brep_loop_end.y);
3341 
3342  if (!V2NEAR_EQUAL(brep_loop_begin, brep_loop_end, same_point_tolerance) &&
3343  VNEAR_EQUAL(brep_loop_begin3d, brep_loop_end3d, same_point_tolerance)) {
3344  int seam_begin = 0;
3345  int seam_end = 0;
3346  if ((seam_begin = IsAtSeam(s, brep_loop_begin, same_point_tolerance)) &&
3347  (seam_end = IsAtSeam(s, brep_loop_end, same_point_tolerance))) {
3348  bool loop_not_closed = true;
3349  if ((li + 1) < loop_cnt) {
3350  // close using remaining loops
3351  for (int rli = li + 1; rli < loop_cnt; rli++) {
3352  int rnum_loop_points = brep_loop_points[rli].Count();
3353  ON_2dPoint rbrep_loop_begin = brep_loop_points[rli][0].p2d;
3354  ON_2dPoint rbrep_loop_end = brep_loop_points[rli][rnum_loop_points - 1].p2d;
3355  if (!V2NEAR_EQUAL(rbrep_loop_begin, rbrep_loop_end, same_point_tolerance)) {
3356  if (IsAtSeam(s, rbrep_loop_begin, same_point_tolerance) && IsAtSeam(s, rbrep_loop_end, same_point_tolerance)) {
3357  double t0, t1;
3358  ON_LineCurve line1(brep_loop_end, rbrep_loop_begin);
3359  std::map<double, ON_3dPoint *> *linepoints3d = getUVCurveSamples(s, &line1, 1000.0, ttol, tol, info);
3360  bridgePoints.push_back(linepoints3d);
3361  line1.GetDomain(&t0, &t1);
3362  std::map<double, ON_3dPoint*>::const_iterator i;
3363  for (i = linepoints3d->begin();
3364  i != linepoints3d->end(); i++) {
3365  BrepTrimPoint btp;
3366 
3367  // skips first point
3368  if (i == linepoints3d->begin())
3369  continue;
3370 
3371  btp.t = (*i).first;
3372  btp.p3d = (*i).second;
3373  btp.p2d = line1.PointAt(t0 + (t1 - t0) * btp.t);
3374  btp.e = ON_UNSET_VALUE;
3375  brep_loop_points[li].Append(btp);
3376  }
3377  //brep_loop_points[li].Append(brep_loop_points[rli].Count(),brep_loop_points[rli].Array());
3378  for (int j = 1; j < rnum_loop_points; j++) {
3379  brep_loop_points[li].Append(brep_loop_points[rli][j]);
3380  }
3381  ON_LineCurve line2(rbrep_loop_end, brep_loop_begin);
3382  linepoints3d = getUVCurveSamples(s, &line2, 1000.0, ttol, tol, info);
3383  bridgePoints.push_back(linepoints3d);
3384  line2.GetDomain(&t0, &t1);
3385 
3386  for (i = linepoints3d->begin();
3387  i != linepoints3d->end(); i++) {
3388  BrepTrimPoint btp;
3389  // skips first point
3390  if (i == linepoints3d->begin())
3391  continue;
3392 
3393  btp.t = (*i).first;
3394  btp.p3d = (*i).second;
3395  btp.p2d = line2.PointAt(t0 + (t1 - t0) * btp.t);
3396  btp.e = ON_UNSET_VALUE;
3397  brep_loop_points[li].Append(btp);
3398  }
3399  brep_loop_points[rli].Empty();
3400  loop_not_closed = false;
3401  }
3402  }
3403  }
3404  }
3405  if (loop_not_closed) {
3406  // no matching loops found that would close so use domain boundary
3407  ON_Interval u = s->Domain(0);
3408  ON_Interval v = s->Domain(1);
3409  if (seam_end == 1) {
3410  if (NEAR_EQUAL(brep_loop_end.x, u.m_t[0], same_point_tolerance)) {
3411  // low end so decreasing
3412 
3413  // now where do we have to close to
3414  if (seam_begin == 1) {
3415  // has to be on opposite seam
3416  double t0, t1;
3417  ON_2dPoint p = brep_loop_end;
3418  p.y = v.m_t[0];
3419  ON_LineCurve line1(brep_loop_end, p);
3420  std::map<double, ON_3dPoint *> *linepoints3d = getUVCurveSamples(s, &line1, 1000.0, ttol, tol, info);
3421  bridgePoints.push_back(linepoints3d);
3422  line1.GetDomain(&t0, &t1);
3423  std::map<double, ON_3dPoint*>::const_iterator i;
3424  for (i = linepoints3d->begin();
3425  i != linepoints3d->end(); i++) {
3426  BrepTrimPoint btp;
3427 
3428  // skips first point
3429  if (i == linepoints3d->begin())
3430  continue;
3431 
3432  btp.t = (*i).first;
3433  btp.p3d = (*i).second;
3434  btp.p2d = line1.PointAt(t0 + (t1 - t0) * btp.t);
3435  btp.e = ON_UNSET_VALUE;
3436  brep_loop_points[li].Append(btp);
3437  }
3438  line1.SetStartPoint(p);
3439  p.x = u.m_t[1];
3440  line1.SetEndPoint(p);
3441  linepoints3d = getUVCurveSamples(s, &line1, 1000.0, ttol, tol, info);
3442  bridgePoints.push_back(linepoints3d);
3443  line1.GetDomain(&t0, &t1);
3444  for (i = linepoints3d->begin();
3445  i != linepoints3d->end(); i++) {
3446  BrepTrimPoint btp;
3447 
3448  // skips first point
3449  if (i == linepoints3d->begin())
3450  continue;
3451 
3452  btp.t = (*i).first;
3453  btp.p3d = (*i).second;
3454  btp.p2d = line1.PointAt(t0 + (t1 - t0) * btp.t);
3455  btp.e = ON_UNSET_VALUE;
3456  brep_loop_points[li].Append(btp);
3457  }
3458  line1.SetStartPoint(p);
3459  line1.SetEndPoint(brep_loop_begin);
3460  linepoints3d = getUVCurveSamples(s, &line1, 1000.0, ttol, tol, info);
3461  bridgePoints.push_back(linepoints3d);
3462  line1.GetDomain(&t0, &t1);
3463  for (i = linepoints3d->begin();
3464  i != linepoints3d->end(); i++) {
3465  BrepTrimPoint btp;
3466 
3467  // skips first point
3468  if (i == linepoints3d->begin())
3469  continue;
3470 
3471  btp.t = (*i).first;
3472  btp.p3d = (*i).second;
3473  btp.p2d = line1.PointAt(t0 + (t1 - t0) * btp.t);
3474  btp.e = ON_UNSET_VALUE;
3475  brep_loop_points[li].Append(btp);
3476  }
3477 
3478  } else if (seam_begin == 2) {
3479 
3480  } else {
3481  //both needed
3482  }
3483 
3484  } else { //assume on other end
3485  // high end so increasing
3486  // now where do we have to close to
3487  if (seam_begin == 1) {
3488  // has to be on opposite seam
3489  double t0, t1;
3490  ON_2dPoint p = brep_loop_end;
3491  p.y = v.m_t[1];
3492  ON_LineCurve line1(brep_loop_end, p);
3493  std::map<double, ON_3dPoint *> *linepoints3d = getUVCurveSamples(s, &line1, 1000.0, ttol, tol, info);
3494  bridgePoints.push_back(linepoints3d);
3495  line1.GetDomain(&t0, &t1);
3496  std::map<double, ON_3dPoint*>::const_iterator i;
3497  for (i = linepoints3d->begin();
3498  i != linepoints3d->end(); i++) {
3499  BrepTrimPoint btp;
3500 
3501  // skips first point
3502  if (i == linepoints3d->begin())
3503  continue;
3504 
3505  btp.t = (*i).first;
3506  btp.p3d = (*i).second;
3507  btp.p2d = line1.PointAt(t0 + (t1 - t0) * btp.t);
3508  btp.e = ON_UNSET_VALUE;
3509  brep_loop_points[li].Append(btp);
3510  }
3511  line1.SetStartPoint(p);
3512  p.x = u.m_t[0];
3513  line1.SetEndPoint(p);
3514  linepoints3d = getUVCurveSamples(s, &line1, 1000.0, ttol, tol, info);
3515  bridgePoints.push_back(linepoints3d);
3516  line1.GetDomain(&t0, &t1);
3517  for (i = linepoints3d->begin();
3518  i != linepoints3d->end(); i++) {
3519  BrepTrimPoint btp;
3520 
3521  // skips first point
3522  if (i == linepoints3d->begin())
3523  continue;
3524 
3525  btp.t = (*i).first;
3526  btp.p3d = (*i).second;
3527  btp.p2d = line1.PointAt(t0 + (t1 - t0) * btp.t);
3528  btp.e = ON_UNSET_VALUE;
3529  brep_loop_points[li].Append(btp);
3530  }
3531  line1.SetStartPoint(p);
3532  line1.SetEndPoint(brep_loop_begin);
3533  linepoints3d = getUVCurveSamples(s, &line1, 1000.0, ttol, tol, info);
3534  bridgePoints.push_back(linepoints3d);
3535  line1.GetDomain(&t0, &t1);
3536  for (i = linepoints3d->begin();
3537  i != linepoints3d->end(); i++) {
3538  BrepTrimPoint btp;
3539 
3540  // skips first point
3541  if (i == linepoints3d->begin())
3542  continue;
3543 
3544  btp.t = (*i).first;
3545  btp.p3d = (*i).second;
3546  btp.p2d = line1.PointAt(t0 + (t1 - t0) * btp.t);
3547  btp.e = ON_UNSET_VALUE;
3548  brep_loop_points[li].Append(btp);
3549  }
3550  } else if (seam_begin == 2) {
3551 
3552  } else {
3553  //both
3554  }
3555  }
3556  } else if (seam_end == 2) {
3557  if (NEAR_EQUAL(brep_loop_end.y, v.m_t[0], same_point_tolerance)) {
3558 
3559  } else { //assume on other end
3560 
3561  }
3562  } else {
3563  //both
3564  }
3565  }
3566  }
3567  }
3568  }
3569  }
3570 }
3571 
3572 
3573 /*
3574  * lifted from Clipper private function and rework for brep_loop_points
3575  */
3576 static bool
3577 PointInPolygon(ON_2dPoint &pt, ON_SimpleArray<BrepTrimPoint> &brep_loop_points)
3578 {
3579  bool result = false;
3580 
3581  for( int i = 0; i < brep_loop_points.Count(); i++){
3582  ON_2dPoint curr_pt = brep_loop_points[i].p2d;
3583  ON_2dPoint prev_pt = ON_2dPoint::UnsetPoint;
3584  if (i == 0) {
3585  prev_pt = brep_loop_points[brep_loop_points.Count()-1].p2d;
3586  } else {
3587  prev_pt = brep_loop_points[i-1].p2d;
3588  }
3589  if ((((curr_pt.y <= pt.y) && (pt.y < prev_pt.y)) ||
3590  ((prev_pt.y <= pt.y) && (pt.y < curr_pt.y))) &&
3591  (pt.x < (prev_pt.x - curr_pt.x) * (pt.y - curr_pt.y) /
3592  (prev_pt.y - curr_pt.y) + curr_pt.x ))
3593  result = !result;
3594  }
3595  return result;
3596 }
3597 
3598 
3599 static void
3600 ShiftPoints(ON_SimpleArray<BrepTrimPoint> &brep_loop_points, double ushift, double vshift)
3601 {
3602  for( int i = 0; i < brep_loop_points.Count(); i++){
3603  brep_loop_points[i].p2d.x += ushift;
3604  brep_loop_points[i].p2d.y += vshift;
3605  }
3606 }
3607 
3608 
3609 // process through to make sure inner hole loops are actually inside of outer polygon
3610 // need to make sure that any hole polygons are properly shifted over correct closed seams
3611 // going to try and do an inside test on hole vertex
3612 static void
3613 ShiftInnerLoops(
3614  const ON_Surface *s,
3615  const ON_BrepFace &face,
3616  ON_SimpleArray<BrepTrimPoint> *brep_loop_points)
3617 {
3618  int loop_cnt = face.LoopCount();
3619  if (loop_cnt > 1) { // has inner loops or holes
3620  for( int li = 1; li < loop_cnt; li++) {
3621  ON_2dPoint p2d((brep_loop_points[li])[0].p2d.x, (brep_loop_points[li])[0].p2d.y);
3622  if (!PointInPolygon(p2d, brep_loop_points[0])) {
3623  double ulength = s->Domain(0).Length();
3624  double vlength = s->Domain(1).Length();
3625  ON_2dPoint sftd_pt = p2d;
3626 
3627  //do shift until inside
3628  if (s->IsClosed(0) && s->IsClosed(1)) {
3629  // First just U
3630  for(int iu = 0; iu < 2; iu++) {
3631  double ushift = 0.0;
3632  if (iu == 0) {
3633  ushift = -ulength;
3634  } else {
3635  ushift = ulength;
3636  }
3637  sftd_pt.x = p2d.x + ushift;
3638  if (PointInPolygon(sftd_pt, brep_loop_points[0])) {
3639  // shift all U accordingly
3640  ShiftPoints(brep_loop_points[li], ushift, 0.0);
3641  break;
3642  }
3643  }
3644  // Second just V
3645  for(int iv = 0; iv < 2; iv++) {
3646  double vshift = 0.0;
3647  if (iv == 0) {
3648  vshift = -vlength;
3649  } else {
3650  vshift = vlength;
3651  }
3652  sftd_pt.y = p2d.y + vshift;
3653  if (PointInPolygon(sftd_pt, brep_loop_points[0])) {
3654  // shift all V accordingly
3655  ShiftPoints(brep_loop_points[li], 0.0, vshift);
3656  break;
3657  }
3658  }
3659  // Third both U & V
3660  for(int iu = 0; iu < 2; iu++) {
3661  double ushift = 0.0;
3662  if (iu == 0) {
3663  ushift = -ulength;
3664  } else {
3665  ushift = ulength;
3666  }
3667  sftd_pt.x = p2d.x + ushift;
3668  for(int iv = 0; iv < 2; iv++) {
3669  double vshift = 0.0;
3670  if (iv == 0) {
3671  vshift = -vlength;
3672  } else {
3673  vshift = vlength;
3674  }
3675  sftd_pt.y = p2d.y + vshift;
3676  if (PointInPolygon(sftd_pt, brep_loop_points[0])) {
3677  // shift all U & V accordingly
3678  ShiftPoints(brep_loop_points[li], ushift, vshift);
3679  break;
3680  }
3681  }
3682  }
3683  } else if (s->IsClosed(0)) {
3684  // just U
3685  for(int iu = 0; iu < 2; iu++) {
3686  double ushift = 0.0;
3687  if (iu == 0) {
3688  ushift = -ulength;
3689  } else {
3690  ushift = ulength;
3691  }
3692  sftd_pt.x = p2d.x + ushift;
3693  if (PointInPolygon(sftd_pt, brep_loop_points[0])) {
3694  // shift all U accordingly
3695  ShiftPoints(brep_loop_points[li], ushift, 0.0);
3696  break;
3697  }
3698  }
3699  } else if (s->IsClosed(1)) {
3700  // just V
3701  for(int iv = 0; iv < 2; iv++) {
3702  double vshift = 0.0;
3703  if (iv == 0) {
3704  vshift = -vlength;
3705  } else {
3706  vshift = vlength;
3707  }
3708  sftd_pt.y = p2d.y + vshift;
3709  if (PointInPolygon(sftd_pt, brep_loop_points[0])) {
3710  // shift all V accordingly
3711  ShiftPoints(brep_loop_points[li], 0.0, vshift);
3712  break;
3713  }
3714  }
3715  }
3716  }
3717  }
3718  }
3719 }
3720 
3721 
3722 static void
3723 PerformClosedSurfaceChecks(
3724  const ON_Surface *s,
3725  const ON_BrepFace &face,
3726  const struct rt_tess_tol *ttol,
3727  const struct bn_tol *tol,
3728  const struct rt_view_info *info,
3729  ON_SimpleArray<BrepTrimPoint> *brep_loop_points,
3730  double same_point_tolerance)
3731 {
3732  // force near seam points to seam.
3733  ForceNearSeamPointsToSeam(s, face, brep_loop_points, same_point_tolerance);
3734 
3735  // extend loop points over closed seam if needed.
3736  ExtendPointsOverClosedSeam(s, face, brep_loop_points);
3737 
3738  // shift open loops that straddle a closed seam with the intent of closure at the surface boundary.
3739  ShiftLoopsThatStraddleSeam(s, face, brep_loop_points, same_point_tolerance);
3740 
3741  // process through closing open loops that begin and end on closed seam
3742  CloseOpenLoops(s, face, ttol, tol, info, brep_loop_points, same_point_tolerance);
3743 
3744  // process through to make sure inner hole loops are actually inside of outer polygon
3745  // need to make sure that any hole polygons are properly shifted over correct closed seams
3746  ShiftInnerLoops(s, face, brep_loop_points);
3747 }
3748 
3749 
3750 void
3751 poly2tri_CDT(struct bu_list *vhead,
3752  ON_BrepFace &face,
3753  const struct rt_tess_tol *ttol,
3754  const struct bn_tol *tol,
3755  const struct rt_view_info *info,
3756  bool watertight = false,
3757  int plottype = 0,
3758  int num_points = -1.0)
3759 {
3760  ON_RTree rt_trims, rt_points;
3761  ON_2dPointArray on_surf_points;
3762  const ON_Surface *s = face.SurfaceOf();
3763  double surface_width, surface_height;
3764  std::vector<ON_3dPoint *> singularity_points;
3765  p2t::CDT* cdt = NULL;
3766  ON_BoundingBox loop_bb;
3767  int fi = face.m_face_index;
3768 
3769  fastf_t max_dist = 0.0;
3770  if (s->GetSurfaceSize(&surface_width, &surface_height)) {
3771  if ((surface_width < tol->dist) || (surface_height < tol->dist)) {
3772  return;
3773  }
3774  max_dist = sqrt(surface_width * surface_width + surface_height *
3775  surface_height) / 10.0;
3776  }
3777 
3778  std::map<p2t::Point *, ON_3dPoint *> *pointmap = new std::map<p2t::Point *, ON_3dPoint *>();
3779 
3780  int loop_cnt = face.LoopCount();
3781  //ON_2dPoint loop_start = ON_2dVector::UnsetVector;
3782  //ON_2dPoint loop_end = ON_2dVector::UnsetVector;
3783  ON_2dPointArray on_loop_points;
3784  ON_SimpleArray<BrepTrimPoint> *brep_loop_points = new ON_SimpleArray<BrepTrimPoint>[loop_cnt];
3785  std::vector<p2t::Point*> polyline;
3786 
3787  // first simply load loop point samples
3788  for (int li = 0; li < loop_cnt; li++) {
3789  ON_BrepLoop *loop = face.Loop(li);
3790  get_loop_sample_points(&brep_loop_points[li], face, loop, max_dist, ttol, tol, info);
3791  }
3792 
3793  std::list<std::map<double, ON_3dPoint *> *> bridgePoints;
3794  if (s->IsClosed(0) || s->IsClosed(1)) {
3795  PerformClosedSurfaceChecks(s, face, ttol, tol, info, brep_loop_points, BREP_SAME_POINT_TOLERANCE);
3796 
3797  }
3798  // process through loops building polygons.
3799  bool outer = true;
3800  for (int li = 0; li < loop_cnt; li++) {
3801  int num_loop_points = brep_loop_points[li].Count();
3802  if (num_loop_points > 2) {
3803  for (int i = 1; i < num_loop_points; i++) {
3804  // map point to last entry to 3d point
3805  p2t::Point *p = new p2t::Point((brep_loop_points[li])[i].p2d.x, (brep_loop_points[li])[i].p2d.y);
3806  polyline.push_back(p);
3807  (*pointmap)[p] = (brep_loop_points[li])[i].p3d;
3808  }
3809  for (int i = 1; i < brep_loop_points[li].Count(); i++) {
3810  // map point to last entry to 3d point
3811  ON_Line *line = new ON_Line((brep_loop_points[li])[i - 1].p2d, (brep_loop_points[li])[i].p2d);
3812  ON_BoundingBox bb = line->BoundingBox();
3813 
3814  bb.m_max.x = bb.m_max.x + ON_ZERO_TOLERANCE;
3815  bb.m_max.y = bb.m_max.y + ON_ZERO_TOLERANCE;
3816  bb.m_max.z = bb.m_max.z + ON_ZERO_TOLERANCE;
3817  bb.m_min.x = bb.m_min.x - ON_ZERO_TOLERANCE;
3818  bb.m_min.y = bb.m_min.y - ON_ZERO_TOLERANCE;
3819  bb.m_min.z = bb.m_min.z - ON_ZERO_TOLERANCE;
3820 
3821  rt_trims.Insert2d(bb.Min(), bb.Max(), line);
3822  }
3823  if (outer) {
3824  cdt = new p2t::CDT(polyline);
3825  outer = false;
3826  } else {
3827  cdt->AddHole(polyline);
3828  }
3829  polyline.clear();
3830  }
3831  }
3832 
3833  delete [] brep_loop_points;
3834 
3835  if (outer) {
3836  std::cerr << "Error: Face(" << fi << ") cannot evaluate its outer loop and will not be facetized." << std::endl;
3837  return;
3838  }
3839 
3840  getSurfacePoints(face, ttol, tol, info, on_surf_points);
3841 
3842  for (int i = 0; i < on_surf_points.Count(); i++) {
3843  ON_SimpleArray<void*> results;
3844  ON_2dPoint *p = on_surf_points.At(i);
3845 
3846  rt_trims.Search2d((const double *) p, (const double *) p, results);
3847 
3848  if (results.Count() > 0) {
3849  bool on_edge = false;
3850  for (int ri = 0; ri < results.Count(); ri++) {
3851  double dist;
3852  ON_Line *l = (ON_Line *) *results.At(ri);
3853  dist = l->MinimumDistanceTo(*p);
3854  if (NEAR_ZERO(dist, tol->dist)) {
3855  on_edge = true;
3856  break;
3857  }
3858  }
3859  if (!on_edge) {
3860  cdt->AddPoint(new p2t::Point(p->x, p->y));
3861  }
3862  } else {
3863  cdt->AddPoint(new p2t::Point(p->x, p->y));
3864  }
3865  }
3866 
3867  ON_SimpleArray<void*> results;
3868  ON_BoundingBox bb = rt_trims.BoundingBox();
3869 
3870  rt_trims.Search2d((const double *) bb.m_min, (const double *) bb.m_max,
3871  results);
3872 
3873  if (results.Count() > 0) {
3874  for (int ri = 0; ri < results.Count(); ri++) {
3875  ON_Line *l = (ON_Line *) *results.At(ri);
3876  delete l;
3877  }
3878  }
3879  rt_trims.RemoveAll();
3880 
3881  if ((plottype < 3)) {
3882  cdt->Triangulate(true, num_points);
3883  } else {
3884  cdt->Triangulate(false, num_points);
3885  }
3886 
3887  if (plottype < 3) {
3888  std::vector<p2t::Triangle*> tris = cdt->GetTriangles();
3889  if (plottype == 0) { // shaded tris 3d
3890  ON_3dPoint pnt[3] = {ON_3dPoint(), ON_3dPoint(), ON_3dPoint()};
3891  ON_3dVector norm[3] = {ON_3dVector(), ON_3dVector(), ON_3dVector()};
3892  point_t pt[3] = {VINIT_ZERO, VINIT_ZERO, VINIT_ZERO};
3893  vect_t nv[3] = {VINIT_ZERO, VINIT_ZERO, VINIT_ZERO};
3894 
3895  for (size_t i = 0; i < tris.size(); i++) {
3896  p2t::Triangle *t = tris[i];
3897  p2t::Point *p = NULL;
3898  for (size_t j = 0; j < 3; j++) {
3899  p = t->GetPoint(j);
3900  if (surface_EvNormal(s, p->x, p->y, pnt[j], norm[j])) {
3901  if (watertight) {
3902  std::map<p2t::Point *, ON_3dPoint *>::iterator ii =
3903  pointmap->find(p);
3904  if (ii != pointmap->end()) {
3905  pnt[j] = *((*ii).second);
3906  }
3907  }
3908  if (face.m_bRev) {
3909  norm[j] = norm[j] * -1.0;
3910  }
3911  VMOVE(pt[j], pnt[j]);
3912  VMOVE(nv[j], norm[j]);
3913  }
3914  }
3915  //tri one
3916  RT_ADD_VLIST(vhead, nv[0], BN_VLIST_TRI_START);
3917  RT_ADD_VLIST(vhead, nv[0], BN_VLIST_TRI_VERTNORM);
3918  RT_ADD_VLIST(vhead, pt[0], BN_VLIST_TRI_MOVE);
3919  RT_ADD_VLIST(vhead, nv[1], BN_VLIST_TRI_VERTNORM);
3920  RT_ADD_VLIST(vhead, pt[1], BN_VLIST_TRI_DRAW);
3921  RT_ADD_VLIST(vhead, nv[2], BN_VLIST_TRI_VERTNORM);
3922  RT_ADD_VLIST(vhead, pt[2], BN_VLIST_TRI_DRAW);
3923  RT_ADD_VLIST(vhead, pt[0], BN_VLIST_TRI_END);
3924  }
3925  } else if (plottype == 1) { // tris 3d wire
3926  ON_3dPoint pnt[3] = {ON_3dPoint(), ON_3dPoint(), ON_3dPoint()};;
3927  ON_3dVector norm[3] = {ON_3dVector(), ON_3dVector(), ON_3dVector()};;
3928  point_t pt[3] = {VINIT_ZERO, VINIT_ZERO, VINIT_ZERO};
3929 
3930  for (size_t i = 0; i < tris.size(); i++) {
3931  p2t::Triangle *t = tris[i];
3932  p2t::Point *p = NULL;
3933  for (size_t j = 0; j < 3; j++) {
3934  p = t->GetPoint(j);
3935  if (surface_EvNormal(s, p->x, p->y, pnt[j], norm[j])) {
3936  if (watertight) {
3937  std::map<p2t::Point *, ON_3dPoint *>::iterator ii =
3938  pointmap->find(p);
3939  if (ii != pointmap->end()) {
3940  pnt[j] = *((*ii).second);
3941  }
3942  }
3943  if (face.m_bRev) {
3944  norm[j] = norm[j] * -1.0;
3945  }
3946  VMOVE(pt[j], pnt[j]);
3947  }
3948  }
3949  //tri one
3950  RT_ADD_VLIST(vhead, pt[0], BN_VLIST_LINE_MOVE);
3951  RT_ADD_VLIST(vhead, pt[1], BN_VLIST_LINE_DRAW);
3952  RT_ADD_VLIST(vhead, pt[2], BN_VLIST_LINE_DRAW);
3953  RT_ADD_VLIST(vhead, pt[0], BN_VLIST_LINE_DRAW);
3954 
3955  }
3956  } else if (plottype == 2) { // tris 2d
3957  point_t pt1 = VINIT_ZERO;
3958  point_t pt2 = VINIT_ZERO;
3959 
3960  for (size_t i = 0; i < tris.size(); i++) {
3961  p2t::Triangle *t = tris[i];
3962  p2t::Point *p = NULL;
3963 
3964  for (size_t j = 0; j < 3; j++) {
3965  if (j == 0) {
3966  p = t->GetPoint(2);
3967  } else {
3968  p = t->GetPoint(j - 1);
3969  }
3970  pt1[0] = p->x;
3971  pt1[1] = p->y;
3972  pt1[2] = 0.0;
3973  p = t->GetPoint(j);
3974  pt2[0] = p->x;
3975  pt2[1] = p->y;
3976  pt2[2] = 0.0;
3977  RT_ADD_VLIST(vhead, pt1, BN_VLIST_LINE_MOVE);
3978  RT_ADD_VLIST(vhead, pt2, BN_VLIST_LINE_DRAW);
3979  }
3980  }
3981  }
3982  } else if (plottype == 3) {
3983  std::list<p2t::Triangle*> tris = cdt->GetMap();
3984  std::list<p2t::Triangle*>::iterator it;
3985  point_t pt1 = VINIT_ZERO;
3986  point_t pt2 = VINIT_ZERO;
3987 
3988  for (it = tris.begin(); it != tris.end(); it++) {
3989  p2t::Triangle* t = *it;
3990  p2t::Point *p = NULL;
3991  for (size_t j = 0; j < 3; j++) {
3992  if (j == 0) {
3993  p = t->GetPoint(2);
3994  } else {
3995  p = t->GetPoint(j - 1);
3996  }
3997  pt1[0] = p->x;
3998  pt1[1] = p->y;
3999  pt1[2] = 0.0;
4000  p = t->GetPoint(j);
4001  pt2[0] = p->x;
4002  pt2[1] = p->y;
4003  pt2[2] = 0.0;
4004  RT_ADD_VLIST(vhead, pt1, BN_VLIST_LINE_MOVE);
4005  RT_ADD_VLIST(vhead, pt2, BN_VLIST_LINE_DRAW);
4006  }
4007  }
4008  } else if (plottype == 4) {
4009  std::vector<p2t::Point*>& points = cdt->GetPoints();
4010  point_t pt = VINIT_ZERO;
4011 
4012  for (size_t i = 0; i < points.size(); i++) {
4013  p2t::Point *p = NULL;
4014  p = (p2t::Point *) points[i];
4015  pt[0] = p->x;
4016  pt[1] = p->y;
4017  pt[2] = 0.0;
4018  RT_ADD_VLIST(vhead, pt, BN_VLIST_POINT_DRAW);
4019  }
4020  }
4021 
4022  std::map<p2t::Point *, ON_3dPoint *>::iterator ii;
4023  for (ii = pointmap->begin(); ii != pointmap->end(); pointmap->erase(ii++))
4024  ;
4025  while (!singularity_points.empty()) {
4026  delete singularity_points.back();
4027  singularity_points.pop_back();
4028  }
4029  delete pointmap;
4030 
4031  std::list<std::map<double, ON_3dPoint *> *>::iterator bridgeIter = bridgePoints.begin();
4032  while (bridgeIter != bridgePoints.end()) {
4033  std::map<double, ON_3dPoint *> *map = (*bridgeIter);
4034  std::map<double, ON_3dPoint *>::iterator mapIter = map->begin();
4035  while (mapIter != map->end()) {
4036  ON_3dPoint *p = (*mapIter++).second;
4037  delete p;
4038  }
4039  map->clear();
4040  delete map;
4041  bridgeIter++;
4042  }
4043  bridgePoints.clear();
4044 
4045  for (int li = 0; li < face.LoopCount(); li++) {
4046  ON_BrepLoop *loop = face.Loop(li);
4047 
4048  for (int lti = 0; lti < loop->TrimCount(); lti++) {
4049  ON_BrepTrim *trim = loop->Trim(lti);
4050 
4051  if (trim->m_trim_user.p) {
4052  std::map<double, ON_3dPoint *> *points = (std::map < double,
4053  ON_3dPoint * > *) trim->m_trim_user.p;
4054  std::map<double, ON_3dPoint *>::iterator i;
4055  for (i = points->begin(); i != points->end(); i++) {
4056  ON_3dPoint *p = (*i).second;
4057  delete p;
4058  }
4059  points->clear();
4060  delete points;
4061  trim->m_trim_user.p = NULL;
4062  }
4063  }
4064  }
4065  if (cdt != NULL) {
4066  std::vector<p2t::Point*> v = cdt->GetPoints();
4067  while (!v.empty()) {
4068  delete v.back();
4069  v.pop_back();
4070  }
4071  if (plottype < 4)
4072  delete cdt;
4073  }
4074  return;
4075 }
4076 
4077 
4078 void
4079 plot_face_trim(struct bu_list *vhead, ON_BrepFace &face, int plotres, bool dim3d)
4080 {
4081  const ON_Surface* surf = face.SurfaceOf();
4082  double umin, umax;
4083  point_t pt1 = VINIT_ZERO;
4084  point_t pt2 = VINIT_ZERO;
4085  ON_2dPoint from(0.0, 0.0);
4086  ON_2dPoint to(0.0, 0.0);
4087 
4088  ON_TextLog tl(stderr);
4089 
4090  surf->GetDomain(0, &umin, &umax);
4091  for (int i = 0; i < face.LoopCount(); i++) {
4092  ON_BrepLoop* loop = face.Loop(i);
4093  // for each trim
4094  for (int j = 0; j < loop->m_ti.Count(); j++) {
4095  ON_BrepTrim& trim = face.Brep()->m_T[loop->m_ti[j]];
4096  const ON_Curve* trimCurve = trim.TrimCurveOf();
4097  //trimCurve->Dump(tl);
4098 
4099  ON_Interval dom = trimCurve->Domain();
4100  // XXX todo: dynamically sample the curve
4101  for (int k = 1; k <= plotres; k++) {
4102  ON_3dPoint p = trimCurve->PointAt(dom.ParameterAt((double)(k
4103  - 1) / (double) plotres));
4104  if (dim3d)
4105  p = surf->PointAt(p.x, p.y);
4106  VMOVE(pt1, p);
4107  p = trimCurve->PointAt(dom.ParameterAt((double) k
4108  / (double) plotres));
4109  if (dim3d)
4110  p = surf->PointAt(p.x, p.y);
4111  VMOVE(pt2, p);
4112  RT_ADD_VLIST(vhead, pt1, BN_VLIST_LINE_MOVE);
4113  RT_ADD_VLIST(vhead, pt2, BN_VLIST_LINE_DRAW);
4114  }
4115  }
4116  }
4117 
4118  return;
4119 }
4120 
4121 
4122 int
4123 rt_brep_adaptive_plot(struct rt_db_internal *ip, const struct rt_view_info *info)
4124 {
4125  TRACE1("rt_brep_adaptive_plot");
4126  struct rt_brep_internal* bi;
4127  point_t pt1 = VINIT_ZERO;
4128  point_t pt2 = VINIT_ZERO;
4129 
4130  BU_CK_LIST_HEAD(info->vhead);
4131  RT_CK_DB_INTERNAL(ip);
4132  bi = (struct rt_brep_internal*)ip->idb_ptr;
4133  RT_BREP_CK_MAGIC(bi);
4134 
4135  ON_Brep* brep = bi->brep;
4136  int gridres = 10;
4137  int isocurveres = 100;
4138 
4139  for (int index = 0; index < brep->m_F.Count(); index++) {
4140  ON_BrepFace& face = brep->m_F[index];
4141  const ON_Surface *surf = face.SurfaceOf();
4142 
4143  if (surf->IsClosed(0) || surf->IsClosed(1)) {
4144  ON_SumSurface *sumsurf = const_cast<ON_SumSurface *>(ON_SumSurface::Cast(surf));
4145  if (sumsurf != NULL) {
4146  SurfaceTree* st = new SurfaceTree(&face, true, 2);
4147 
4148  plot_face_from_surface_tree(info->vhead, st, isocurveres, gridres);
4149 
4150  delete st;
4151  } else {
4152  ON_RevSurface *revsurf = const_cast<ON_RevSurface *>(ON_RevSurface::Cast(surf));
4153 
4154  if (revsurf != NULL) {
4155  SurfaceTree* st = new SurfaceTree(&face, true, 0);
4156 
4157  plot_face_from_surface_tree(info->vhead, st, isocurveres, gridres);
4158 
4159  delete st;
4160  }
4161  }
4162  }
4163  }
4164 
4165  for (int index = 0; index < bi->brep->m_E.Count(); index++) {
4166  ON_BrepEdge& e = brep->m_E[index];
4167  const ON_Curve* crv = e.EdgeCurveOf();
4168 
4169  if (crv->IsLinear()) {
4170  ON_BrepVertex& v1 = brep->m_V[e.m_vi[0]];
4171  ON_BrepVertex& v2 = brep->m_V[e.m_vi[1]];
4172  VMOVE(pt1, v1.Point());
4173  VMOVE(pt2, v2.Point());
4174  RT_ADD_VLIST(info->vhead, pt1, BN_VLIST_LINE_MOVE);
4175  RT_ADD_VLIST(info->vhead, pt2, BN_VLIST_LINE_DRAW);
4176  } else {
4177  point_t endpt;
4178  ON_Interval dom = crv->Domain();
4179 
4180  ON_3dPoint p = crv->PointAt(dom.ParameterAt(1.0));
4181  VMOVE(endpt, p);
4182 
4183  int min_linear_seg_count = crv->Degree() + 1;
4184  double max_domain_step = 1.0 / min_linear_seg_count;
4185 
4186  // specify first tentative segment t1 to t2
4187  double t2 = max_domain_step;
4188  double t1 = 0.0;
4189  p = crv->PointAt(dom.ParameterAt(t1));
4190  VMOVE(pt1, p);
4191  RT_ADD_VLIST(info->vhead, pt1, BN_VLIST_LINE_MOVE);
4192 
4193  // add segments until the minimum segment count is
4194  // achieved and the distance between the end of the last
4195  // segment and the endpoint is within point spacing
4196  for (int nsegs = 0; (nsegs < min_linear_seg_count) ||
4197  (DIST_PT_PT(pt1, endpt) > info->point_spacing); ++nsegs) {
4198  p = crv->PointAt(dom.ParameterAt(t2));
4199  VMOVE(pt2, p);
4200 
4201  // bring t2 increasingly closer to t1 until target
4202  // point spacing is achieved
4203  double step = t2 - t1;
4204  while (DIST_PT_PT(pt1, pt2) > info->point_spacing) {
4205  step /= 2.0;
4206  t2 = t1 + step;
4207  p = crv->PointAt(dom.ParameterAt(t2));
4208  VMOVE(pt2, p);
4209  }
4210  RT_ADD_VLIST(info->vhead, pt2, BN_VLIST_LINE_DRAW);
4211 
4212  // advance to next segment
4213  t1 = t2;
4214  VMOVE(pt1, pt2);
4215 
4216  t2 += max_domain_step;
4217  if (t2 > 1.0) {
4218  t2 = 1.0;
4219  }
4220  }
4221  RT_ADD_VLIST(info->vhead, endpt, BN_VLIST_LINE_DRAW);
4222  }
4223  }
4224 
4225  return 0;
4226 }
4227 
4228 
4229 /**
4230  * There are several ways to visualize NURBS surfaces, depending on
4231  * the purpose. For "normal" wireframe viewing, the ideal approach is
4232  * to do a tessellation of the NURBS surface and show that wireframe.
4233  * The quicker and simpler approach is to visualize the edges,
4234  * although that can sometimes generate less than ideal/useful results
4235  * (for example, a revolved edge that forms a sphere will have a
4236  * wireframe consisting of a 2D arc in MGED when only edges are used.)
4237  * A third approach is to walk the uv space for each surface, find
4238  * 3space points at uv intervals, and draw lines between the results -
4239  * this is slightly more comprehensive when it comes to showing where
4240  * surfaces are in 3space but looks blocky and crude. For now,
4241  * edge-only wireframes are the default.
4242  *
4243  */
4244 int
4245 rt_brep_plot(struct bu_list *vhead, struct rt_db_internal *ip, const struct rt_tess_tol *UNUSED(ttol), const struct bn_tol *tol, const struct rt_view_info *UNUSED(info))
4246 {
4247  TRACE1("rt_brep_plot");
4248  struct rt_brep_internal* bi;
4249  int i;
4250 
4251  BU_CK_LIST_HEAD(vhead);
4252  RT_CK_DB_INTERNAL(ip);
4253  bi = (struct rt_brep_internal*)ip->idb_ptr;
4254  RT_BREP_CK_MAGIC(bi);
4255 
4256  ON_Brep* brep = bi->brep;
4257  int gridres = 10;
4258  int isocurveres = 100;
4259 
4260  for (int index = 0; index < brep->m_F.Count(); index++) {
4261  ON_BrepFace& face = brep->m_F[index];
4262  const ON_Surface *surf = face.SurfaceOf();
4263 
4264  if (surf != NULL) {
4265  if (surf->IsClosed(0) || surf->IsClosed(1)) {
4266  ON_SumSurface *sumsurf = const_cast<ON_SumSurface *>(ON_SumSurface::Cast(surf));
4267  if (sumsurf != NULL) {
4268  SurfaceTree* st = new SurfaceTree(&face, true, 2);
4269 
4270  plot_face_from_surface_tree(vhead, st, isocurveres, gridres);
4271 
4272  delete st;
4273  } else {
4274  ON_RevSurface *revsurf = const_cast<ON_RevSurface *>(ON_RevSurface::Cast(surf));
4275 
4276  if (revsurf != NULL) {
4277  SurfaceTree* st = new SurfaceTree(&face, true, 0);
4278 
4279  plot_face_from_surface_tree(vhead, st, isocurveres, gridres);
4280 
4281  delete st;
4282  }
4283  }
4284  }
4285  } else {
4286  bu_log("Surface index %d not defined.\n", index);
4287  }
4288  }
4289 
4290  {
4291 
4292  point_t pt1 = VINIT_ZERO;
4293  point_t pt2 = VINIT_ZERO;
4294 
4295  for (i = 0; i < bi->brep->m_E.Count(); i++) {
4296  ON_BrepEdge& e = brep->m_E[i];
4297  const ON_Curve* crv = e.EdgeCurveOf();
4298 
4299  if (crv->IsLinear()) {
4300  ON_BrepVertex& v1 = brep->m_V[e.m_vi[0]];
4301  ON_BrepVertex& v2 = brep->m_V[e.m_vi[1]];
4302  VMOVE(pt1, v1.Point());
4303  VMOVE(pt2, v2.Point());
4304  RT_ADD_VLIST(vhead, pt1, BN_VLIST_LINE_MOVE);
4305  RT_ADD_VLIST(vhead, pt2, BN_VLIST_LINE_DRAW);
4306  } else {
4307  ON_Interval dom = crv->Domain();
4308 
4309  double domainval = 0.0;
4310  double olddomainval = 1.0;
4311  int crudestep = 0;
4312  // Insert first point.
4313  ON_3dPoint p = crv->PointAt(dom.ParameterAt(domainval));
4314  VMOVE(pt1, p);
4315  RT_ADD_VLIST(vhead, pt1, BN_VLIST_LINE_MOVE);
4316 
4317  /* Dynamic sampling approach - start with an initial guess
4318  * for the next point of one tenth of the domain length
4319  * further down the domain from the previous value. Set a
4320  * maximum physical distance between points of 100 times
4321  * the model tolerance. Reduce the increment until the
4322  * tolerance is satisfied, then add the point and use it
4323  * as the starting point for the next calculation until
4324  * the whole domain is finished. Perhaps it would be more
4325  * ideal to base the tolerance on some fraction of the
4326  * curve bounding box dimensions?
4327  */
4328 
4329  while (domainval < 1.0 && crudestep <= 100) {
4330  olddomainval = domainval;
4331  if (crudestep == 0)
4332  domainval = find_next_point(crv, domainval, 0.1,
4333  tol->dist * 100, 0);
4334  if (crudestep >= 1 || ZERO(domainval)) {
4335  crudestep++;
4336  domainval = olddomainval + (1.0 - olddomainval)
4337  / 100 * crudestep;
4338  }
4339  p = crv->PointAt(dom.ParameterAt(domainval));
4340  VMOVE(pt1, p);
4341  RT_ADD_VLIST(vhead, pt1, BN_VLIST_LINE_DRAW);
4342  }
4343  }
4344  }
4345  }
4346 
4347  return 0;
4348 }
4349 
4350 int rt_brep_plot_poly(struct bu_list *vhead, const struct db_full_path *pathp, struct rt_db_internal *ip,
4351  const struct rt_tess_tol *ttol, const struct bn_tol *tol,
4352  const struct rt_view_info *info)
4353 {
4354  TRACE1("rt_brep_plot");
4355  struct rt_brep_internal* bi;
4356  const char *solid_name = DB_FULL_PATH_CUR_DIR(pathp)->d_namep;
4357  ON_wString wstr;
4358  ON_TextLog tl(wstr);
4359 
4360  BU_CK_LIST_HEAD(vhead);
4361  RT_CK_DB_INTERNAL(ip);
4362  bi = (struct rt_brep_internal*) ip->idb_ptr;
4363  RT_BREP_CK_MAGIC(bi);
4364 
4365  ON_Brep* brep = bi->brep;
4366  if (brep == NULL || !brep->IsValid(&tl)) {
4367  if (wstr.Length() > 0) {
4368  ON_String onstr = ON_String(wstr);
4369  const char *isvalidinfo = onstr.Array();
4370  bu_log("brep (%s) is NOT valid: %s\n", solid_name, isvalidinfo);
4371  } else {
4372  bu_log("brep (%s) is NOT valid.\n", solid_name);
4373  }
4374  //return 0; let's just try it for now, need to improve the not valid checks
4375  }
4376 
4377 #ifndef TESTIT
4378 #ifndef WATER_TIGHT
4379 #ifdef DRAW_FACE
4380  fastf_t max_dist = 0;
4381 #endif
4382  for (int index = 0; index < brep->m_F.Count(); index++) {
4383  ON_BrepFace *face = brep->Face(index);
4384  const ON_Surface *s = face->SurfaceOf();
4385  if (s) {
4386  double surface_width, surface_height;
4387  if (s->GetSurfaceSize(&surface_width, &surface_height)) {
4388  // reparameterization of the face's surface and transforms the "u"
4389  // and "v" coordinates of all the face's parameter space trimming
4390  // curves to minimize distortion in the map from parameter space to 3d..
4391  face->SetDomain(0, 0.0, surface_width);
4392  face->SetDomain(1, 0.0, surface_height);
4393 #ifdef DRAW_FACE
4394  max_dist = sqrt(surface_width * surface_width + surface_height * surface_height) / 10.0;
4395 #endif
4396  }
4397  }
4398  }
4399 #ifdef DRAW_FACE
4400  for (int index = 0; index < brep->m_E.Count(); index++) {
4401  ON_BrepEdge& edge = brep->m_E[index];
4402  if (edge.m_edge_user.p == NULL) {
4403  std::map<double, ON_3dPoint *> *points = getEdgePoints(edge, max_dist, ttol, tol, info);
4404  }
4405  }
4406 #endif
4407 #endif /* WATER_TIGHT */
4408  bool watertight = true;
4409  int plottype = 0;
4410  int numpoints = -1;
4411  for (int index = 0; index < brep->m_F.Count(); index++) {
4412  ON_BrepFace& face = brep->m_F[index];
4413  const ON_Surface *s = face.SurfaceOf();
4414 
4415  if (s) {
4416 
4417 #ifdef DRAW_FACE
4418  draw_face_CDT(vhead, face, ttol, tol, info, watertight, plottype, numpoints);
4419 #else
4420  poly2tri_CDT(vhead, face, ttol, tol, info, watertight, plottype, numpoints);
4421 #endif
4422  } else {
4423  bu_log("Error solid \"%s\" missing surface definition for Face(%d). Will skip this face when drawing.\n", solid_name, index);
4424  }
4425  }
4426 #else /* TESTIT */
4427  for (int index = 0; index < brep->m_F.Count(); index++) {
4428  ON_BrepFace& face = brep->m_F[index];
4429  SurfaceTree* st = new SurfaceTree(&face, true, 10);
4430 
4431  plot_poly_from_surface_tree(vhead, st, face.m_bRev);
4432 
4433  delete st;
4434  }
4435 #endif /* TESTIT */
4436 #ifdef WATERTIGHT
4437  for (int index = 0; index < brep->m_E.Count(); index++) {
4438  ON_BrepEdge& edge = brep->m_E[index];
4439  if (edge.m_edge_user.p != NULL) {
4440  std::map<double, ON_3dPoint *> *points = (std::map<double, ON_3dPoint *> *)edge.m_edge_user.p;
4441  std::map<double, ON_3dPoint *>::iterator i;
4442  for (i = points->begin(); i != points->end(); i++) {
4443  ON_3dPoint *p = (*i).second;
4444  delete p;
4445  }
4446  points->clear();
4447  delete points;
4448  edge.m_edge_user.p = NULL;
4449  }
4450  }
4451 #else
4452  for (int index = 0; index < brep->m_T.Count(); index++) {
4453  ON_BrepTrim& trim = brep->m_T[index];
4454  if (trim.m_trim_user.p != NULL) {
4455  std::map<double, ON_3dPoint *> *points = (std::map<double, ON_3dPoint *> *)trim.m_trim_user.p;
4456  std::map<double, ON_3dPoint *>::iterator i;
4457  for (i = points->begin(); i != points->end(); i++) {
4458  ON_3dPoint *p = (*i).second;
4459  delete p;
4460  }
4461  points->clear();
4462  delete points;
4463  trim.m_trim_user.p = NULL;
4464  }
4465  }
4466 #endif
4467 
4468  return 0;
4469 }
4470 
4471 int
4472 rt_brep_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
4473 {
4474  struct rt_brep_internal *bi;
4475 
4476  if (!r || !m || !ip || !ttol || !tol)
4477  return -1;
4478 
4479  RT_CK_DB_INTERNAL(ip);
4480  bi = (struct rt_brep_internal *)ip->idb_ptr;
4481  RT_BREP_CK_MAGIC(bi);
4482 
4483  /* XXX - implement me */
4484  return -1;
4485 }
4486 
4487 
4488 /**
4489  * XXX In order to facilitate exporting the ON_Brep object without a
4490  * whole lot of effort, we're going to (for now) extend the
4491  * ON_BinaryArchive to support an "in-memory" representation of a
4492  * binary archive. Currently, the openNURBS library only supports
4493  * file-based archiving operations. This implies the
4494  */
4495 class RT_MemoryArchive : public ON_BinaryArchive
4496 {
4497 public:
4498  RT_MemoryArchive();
4499  RT_MemoryArchive(void *memory, size_t len);
4500  virtual ~RT_MemoryArchive();
4501 
4502  // ON_BinaryArchive overrides
4503  size_t CurrentPosition() const;
4504  bool SeekFromCurrentPosition(int);
4505  bool SeekFromStart(size_t);
4506  bool AtEnd() const;
4507 
4508  size_t Size() const;
4509  /**
4510  * Generate a byte-array copy of this memory archive. Allocates
4511  * memory using bu_malloc, so must be freed with bu_free
4512  */
4513  uint8_t* CreateCopy() const;
4514 
4515 protected:
4516  size_t Read(size_t, void*);
4517  size_t Write(size_t, const void*);
4518  bool Flush();
4519 
4520 private:
4521  size_t pos;
4522  std::vector<char> m_buffer;
4523 };
4524 
4525 
4527  : ON_BinaryArchive(ON::write3dm), pos(0)
4528 {
4529 }
4530 
4531 
4532 RT_MemoryArchive::RT_MemoryArchive(void *memory, size_t len)
4533  : ON_BinaryArchive(ON::read3dm), pos(0)
4534 {
4535  m_buffer.reserve(len);
4536  for (size_t i = 0; i < len; i++) {
4537  m_buffer.push_back(((char*)memory)[i]);
4538  }
4539 }
4540 
4541 
4543 {
4544 }
4545 
4546 
4547 size_t
4549 {
4550  return pos;
4551 }
4552 
4553 
4554 bool
4556 {
4557  if (pos + seek_to > m_buffer.size()) return false;
4558  pos += seek_to;
4559  return true;
4560 }
4561 
4562 
4563 bool
4565 {
4566  if (seek_to > m_buffer.size()) return false;
4567  pos = seek_to;
4568  return true;
4569 }
4570 
4571 
4572 bool
4574 {
4575  return pos >= m_buffer.size();
4576 }
4577 
4578 
4579 size_t
4581 {
4582  return m_buffer.size();
4583 }
4584 
4585 
4586 uint8_t*
4588 {
4589  uint8_t *memory = (uint8_t *)bu_malloc(m_buffer.size() * sizeof(uint8_t), "rt_memoryarchive createcopy");
4590  const size_t size = m_buffer.size();
4591  for (size_t i = 0; i < size; i++) {
4592  memory[i] = m_buffer[i];
4593  }
4594  return memory;
4595 }
4596 
4597 
4598 size_t
4599 RT_MemoryArchive::Read(size_t amount, void* buf)
4600 {
4601  const size_t read_amount = (pos + amount > m_buffer.size()) ? m_buffer.size() - pos : amount;
4602  const size_t start = pos;
4603  for (; pos < (start + read_amount); pos++) {
4604  ((char*)buf)[pos - start] = m_buffer[pos];
4605  }
4606  return read_amount;
4607 }
4608 
4609 
4610 size_t
4611 RT_MemoryArchive::Write(const size_t amount, const void* buf)
4612 {
4613  // the write can come in at any position!
4614  const size_t start = pos;
4615  // resize if needed to support new data
4616  if (m_buffer.size() < (start + amount)) {
4617  m_buffer.resize(start + amount);
4618  }
4619  for (; pos < (start + amount); pos++) {
4620  m_buffer[pos] = ((char*)buf)[pos - start];
4621  }
4622  return amount;
4623 }
4624 
4625 
4626 bool
4628 {
4629  return true;
4630 }
4631 
4632 int
4633 rt_brep_get(struct bu_vls *logstr, const struct rt_db_internal *intern, const char *attr)
4634 {
4635  struct rt_brep_internal *bi = (struct rt_brep_internal *)intern->idb_ptr;
4636  RT_BREP_CK_MAGIC(bi);
4637 
4638  if (attr == (char *)NULL) {
4639  bu_vls_sprintf(logstr, "brep");
4640  /* Create the serialized version for encoding */
4641  RT_MemoryArchive archive;
4642  ONX_Model model;
4643  {
4644  ON_Layer default_layer;
4645  default_layer.SetLayerIndex(0);
4646  default_layer.SetLayerName("Default");
4647  model.m_layer_table.Reserve(1);
4648  model.m_layer_table.Append(default_layer);
4649  }
4650  ONX_Model_Object& mo = model.m_object_table.AppendNew();
4651  mo.m_object = bi->brep;
4652  mo.m_attributes.m_layer_index = 0;
4653  mo.m_attributes.m_name = "brep";
4654  mo.m_attributes.m_uuid = ON_opennurbs4_id;
4655  model.m_properties.m_RevisionHistory.NewRevision();
4656  model.m_properties.m_Application.m_application_name = "BRL-CAD B-Rep primitive";
4657  model.Polish();
4658  ON_TextLog err(stderr);
4659  bool ok = model.Write(archive, 4, "export5", &err);
4660  if (ok) {
4661  void *archive_cp = archive.CreateCopy();
4662  signed char *brep64 = bu_b64_encode_block((const signed char *)archive_cp, archive.Size());
4663  bu_vls_printf(logstr, " \"%s\"", brep64);
4664  bu_free(archive_cp, "free archive copy");
4665  bu_free(brep64, "free encoded brep string");
4666  return 0;
4667  }
4668  }
4669  return -1;
4670 }
4671 
4672 int
4673 rt_brep_adjust(struct bu_vls *logstr, const struct rt_db_internal *intern, int argc, const char **argv)
4674 {
4675  struct rt_brep_internal *bi = (struct rt_brep_internal *)intern->idb_ptr;
4676  signed char *decoded;
4677  ONX_Model model;
4678  if (argc == 1 && argv[0]) {
4679  int decoded_size = bu_b64_decode(&decoded, (const signed char *)argv[0]);
4680  RT_MemoryArchive archive(decoded, decoded_size);
4681  ON_wString wonstr;
4682  ON_TextLog dump(wonstr);
4683 
4684  RT_BREP_CK_MAGIC(bi);
4685  model.Read(archive, &dump);
4686  bu_vls_printf(logstr, "%s", ON_String(wonstr).Array());
4687  ONX_Model_Object mo = model.m_object_table[0];
4688  bi->brep = ON_Brep::New(*ON_Brep::Cast(mo.m_object));
4689  return 0;
4690  }
4691  return -1;
4692 }
4693 
4694 int
4695 rt_brep_export5(struct bu_external *ep, const struct rt_db_internal *ip, double UNUSED(local2mm), const struct db_i *dbip)
4696 {
4697  TRACE1("rt_brep_export5");
4698  struct rt_brep_internal* bi;
4699 
4700  if (dbip) RT_CK_DBI(dbip);
4701  RT_CK_DB_INTERNAL(ip);
4702  if (ip->idb_type != ID_BREP) return -1;
4703  bi = (struct rt_brep_internal*)ip->idb_ptr;
4704  RT_BREP_CK_MAGIC(bi);
4705 
4706  BU_EXTERNAL_INIT(ep);
4707 
4708  RT_MemoryArchive archive;
4709  /* XXX what to do about the version */
4710  ONX_Model model;
4711 
4712  {
4713  ON_Layer default_layer;
4714  default_layer.SetLayerIndex(0);
4715  default_layer.SetLayerName("Default");
4716  model.m_layer_table.Reserve(1);
4717  model.m_layer_table.Append(default_layer);
4718  }
4719 
4720  ONX_Model_Object& mo = model.m_object_table.AppendNew();
4721  mo.m_object = bi->brep;
4722  mo.m_attributes.m_layer_index = 0;
4723  mo.m_attributes.m_name = "brep";
4724  mo.m_attributes.m_uuid = ON_opennurbs4_id;
4725 
4726  model.m_properties.m_RevisionHistory.NewRevision();
4727  model.m_properties.m_Application.m_application_name = "BRL-CAD B-Rep primitive";
4728 
4729  model.Polish();
4730  ON_TextLog err(stderr);
4731  bool ok = model.Write(archive, 4, "export5", &err);
4732  if (ok) {
4733  ep->ext_nbytes = (long)archive.Size();
4734  ep->ext_buf = archive.CreateCopy();
4735  return 0;
4736  } else {
4737  return -1;
4738  }
4739 }
4740 
4741 
4742 int
4743 rt_brep_import5(struct rt_db_internal *ip, const struct bu_external *ep, const fastf_t *mat, const struct db_i *dbip)
4744 {
4745  ON::Begin();
4746  TRACE1("rt_brep_import5");
4747 
4748  struct rt_brep_internal* bi;
4749  if (dbip) RT_CK_DBI(dbip);
4750  BU_CK_EXTERNAL(ep);
4751  RT_CK_DB_INTERNAL(ip);
4752  ip->idb_major_type = DB5_MAJORTYPE_BRLCAD;
4753  ip->idb_type = ID_BREP;
4754  ip->idb_meth = &OBJ[ID_BREP];
4755  BU_ALLOC(ip->idb_ptr, struct rt_brep_internal);
4756 
4757  bi = (struct rt_brep_internal*)ip->idb_ptr;
4758  bi->magic = RT_BREP_INTERNAL_MAGIC;
4759 
4760  RT_MemoryArchive archive(ep->ext_buf, ep->ext_nbytes);
4761  ONX_Model model;
4762  ON_TextLog dump(stderr);
4763  //archive.Dump3dmChunk(dump);
4764  model.Read(archive, &dump);
4765 
4766  //if (model.IsValid(&dump)) {
4767  ONX_Model_Object mo = model.m_object_table[0];
4768  // XXX does openNURBS force us to copy? it seems the answer is
4769  // YES due to the const-ness
4770  bi->brep = ON_Brep::New(*ON_Brep::Cast(mo.m_object));
4771  if (mat) {
4772  ON_Xform xform(mat);
4773 
4774  if (!xform.IsIdentity()) {
4775  bi->brep->Transform(xform);
4776  }
4777  }
4778  return 0;
4779  //} else {
4780  // return -1;
4781  //}
4782 }
4783 
4784 
4785 void
4787 {
4788  struct rt_brep_internal* bi;
4789  RT_CK_DB_INTERNAL(ip);
4790 
4791  TRACE1("rt_brep_ifree");
4792 
4793  bi = (struct rt_brep_internal*)ip->idb_ptr;
4794  RT_BREP_CK_MAGIC(bi);
4795  if (bi->brep != NULL)
4796  delete bi->brep;
4797  bu_free(bi, "rt_brep_internal free");
4798  ip->idb_ptr = ((void *)0);
4799 }
4800 
4801 
4802 int
4803 rt_brep_describe(struct bu_vls *str, const struct rt_db_internal *ip, int verbose, double UNUSED(mm2local))
4804 {
4805  BU_CK_VLS(str);
4806  RT_CK_DB_INTERNAL(ip);
4807 
4808  ON_wString wonstr;
4809  ON_TextLog log(wonstr);
4810 
4811  struct rt_brep_internal* bi;
4812  bi = (struct rt_brep_internal*)ip->idb_ptr;
4813  RT_BREP_CK_MAGIC(bi);
4814  if (bi->brep != NULL)
4815  bi->brep->Dump(log);
4816 
4817  ON_String onstr = ON_String(wonstr);
4818  bu_vls_strcat(str, "Boundary Representation (BREP) object\n");
4819 
4820  if (!verbose)
4821  return 0;
4822 
4823  const char *description = onstr.Array();
4824  // skip the first "ON_Brep:" line
4825  while (description && description[0] && description[0] != '\n') {
4826  description++;
4827  }
4828  if (description && description[0] && description[0] == '\n') {
4829  description++;
4830  }
4831  bu_vls_strcat(str, description);
4832 
4833  return 0;
4834 }
4835 
4836 
4837 int
4838 rt_brep_tclget(Tcl_Interp *, const struct rt_db_internal *, const char *)
4839 {
4840  return 0;
4841 }
4842 
4843 
4844 int
4845 rt_brep_tcladjust(Tcl_Interp *, struct rt_db_internal *, int, const char **)
4846 {
4847  return 0;
4848 }
4849 
4850 
4851 int
4852 rt_brep_params(struct pc_pc_set *, const struct rt_db_internal *)
4853 {
4854  return 0;
4855 }
4856 
4857 
4858 int
4859 rt_brep_boolean(struct rt_db_internal *out, const struct rt_db_internal *ip1, const struct rt_db_internal *ip2, db_op_t operation)
4860 {
4861  RT_CK_DB_INTERNAL(ip1);
4862  RT_CK_DB_INTERNAL(ip2);
4863  struct rt_brep_internal *bip1, *bip2;
4864  bip1 = (struct rt_brep_internal *)ip1->idb_ptr;
4865  bip2 = (struct rt_brep_internal *)ip2->idb_ptr;
4866  RT_BREP_CK_MAGIC(bip1);
4867  RT_BREP_CK_MAGIC(bip2);
4868 
4869  ON_Brep *brep1, *brep2, *brep_out;
4870  brep1 = bip1->brep;
4871  brep2 = bip2->brep;
4872  brep_out = ON_Brep::New();
4873 
4874  op_type operation_type;
4875  switch (operation) {
4876  case DB_OP_UNION:
4877  operation_type = BOOLEAN_UNION;
4878  break;
4879  case DB_OP_SUBTRACT:
4880  operation_type = BOOLEAN_DIFF;
4881  break;
4882  case DB_OP_INTERSECT:
4883  operation_type = BOOLEAN_INTERSECT;
4884  break;
4885  default:
4886  return -1;
4887  }
4888 
4889  int ret;
4890  if ((ret = ON_Boolean(brep_out, brep1, brep2, operation_type)) < 0)
4891  return ret;
4892 
4893  // make the final rt_db_internal
4894  struct rt_brep_internal *bip_out;
4895  BU_ALLOC(bip_out, struct rt_brep_internal);
4896  bip_out->magic = RT_BREP_INTERNAL_MAGIC;
4897  bip_out->brep = brep_out;
4898  RT_DB_INTERNAL_INIT(out);
4899  out->idb_ptr = (void *)bip_out;
4900  out->idb_major_type = DB5_MAJORTYPE_BRLCAD;
4901  out->idb_meth = &OBJ[ID_BREP];
4902  out->idb_minor_type = ID_BREP;
4903 
4904  return 0;
4905 }
4906 
4909  int i;
4910  int j;
4913 };
4914 
4915 struct brep_cv {
4917  int i;
4918  int j;
4919 };
4920 
4922  std::list<brep_cv *> *control_vertexes; /**< brep_cv_list */
4923 };
4924 
4925 bool
4927 {
4928  if (c1->sqdist_to_start < c2->sqdist_to_start) {
4929  return true;
4930  }
4931 
4932  return false;
4933 }
4934 
4935 static void
4936 brep_free_selection(struct rt_selection *s)
4937 {
4938  struct brep_selection *bs = (struct brep_selection *)s->obj;
4939  std::list<brep_cv *> *cvs = bs->control_vertexes;
4940 
4941  std::list<brep_cv *>::iterator cv;
4942  for (cv = cvs->begin(); cv != cvs->end(); ++cv) {
4943  delete *cv;
4944  }
4945  cvs->clear();
4946 
4947  delete cvs;
4948  delete bs;
4949  BU_FREE(s, struct rt_selection);
4950 }
4951 
4952 struct rt_selection *
4954 {
4955  // make new brep selection w/ cv list
4956  brep_selection *bs = new brep_selection;
4957  bs->control_vertexes = new std::list<brep_cv *>();
4958 
4959  // add referenced cv to cv list
4960  brep_cv *cvitem = new brep_cv;
4961  cvitem->face_index = s->face_index;
4962  cvitem->i = s->i;
4963  cvitem->j = s->j;
4964  bs->control_vertexes->push_back(cvitem);
4965 
4966  // wrap and return
4967  struct rt_selection *selection;
4968  BU_ALLOC(selection, struct rt_selection);
4969  selection->obj = (void *)bs;
4970 
4971  return selection;
4972 }
4973 
4974 struct rt_selection_set *
4975 rt_brep_find_selections(const struct rt_db_internal *ip, const struct rt_selection_query *query)
4976 {
4977  struct rt_brep_internal *bip;
4978  ON_Brep *brep;
4979 
4980  RT_CK_DB_INTERNAL(ip);
4981  bip = (struct rt_brep_internal *)ip->idb_ptr;
4982  RT_BREP_CK_MAGIC(bip);
4983  brep = bip->brep;
4984 
4985  int num_faces = brep->m_F.Count();
4986  if (num_faces == 0) {
4987  return NULL;
4988  }
4989 
4990  // get a list of all the selectable control vertexes and
4991  // simultaneously find the distance from the closest vertex to the
4992  // query line
4993  std::list<brep_selectable_cv *> selectable;
4994  double min_distsq = INFINITY;
4995  for (int face_index = 0; face_index < num_faces; ++face_index) {
4996  ON_BrepFace *face = brep->Face(face_index);
4997  const ON_Surface *surface = face->SurfaceOf();
4998  const ON_NurbsSurface *nurbs_surface = dynamic_cast<const ON_NurbsSurface *>(surface);
4999 
5000  if (!nurbs_surface) {
5001  continue;
5002  }
5003 
5004  // TODO: should only consider vertices in untrimmed regions
5005  int num_rows = nurbs_surface->m_cv_count[0];
5006  int num_cols = nurbs_surface->m_cv_count[1];
5007  for (int i = 0; i < num_rows; ++i) {
5008  for (int j = 0; j < num_cols; ++j) {
5009  double *cv = nurbs_surface->CV(i, j);
5010 
5012  scv->face_index = face_index;
5013  scv->i = i;
5014  scv->j = j;
5015  scv->sqdist_to_start = DIST_PT_PT_SQ(query->start, cv);
5016  scv->sqdist_to_line =
5017  bn_distsq_line3_pt3(query->start, query->dir, cv);
5018 
5019  selectable.push_back(scv);
5020 
5021  if (scv->sqdist_to_line < min_distsq) {
5022  min_distsq = scv->sqdist_to_line;
5023  }
5024  }
5025  }
5026  }
5027 
5028  // narrow down the list to just the control vertexes closest to
5029  // the query line, and sort them by proximity to the query start
5030  std::list<brep_selectable_cv *>::iterator s, tmp_s;
5031  for (s = selectable.begin(); s != selectable.end();) {
5032  tmp_s = s++;
5033  if ((*tmp_s)->sqdist_to_line > min_distsq) {
5034  delete *tmp_s;
5035  selectable.erase(tmp_s);
5036  }
5037  }
5038  selectable.sort(cmp_cv_startdist);
5039 
5040  // build and return list of selections
5041  struct rt_selection_set *selection_set;
5042  BU_ALLOC(selection_set, struct rt_selection_set);
5043  BU_PTBL_INIT(&selection_set->selections);
5044 
5045  for (s = selectable.begin(); s != selectable.end(); ++s) {
5046  bu_ptbl_ins(&selection_set->selections, (long *)new_cv_selection(*s));
5047  delete *s;
5048  }
5049  selectable.clear();
5050  selection_set->free_selection = brep_free_selection;
5051 
5052  return selection_set;
5053 }
5054 
5055 int
5057  struct rt_db_internal *ip,
5058  const struct rt_selection *selection,
5059  const struct rt_selection_operation *op)
5060 {
5061  if (op->type == RT_SELECTION_NOP) {
5062  return 0;
5063  }
5064 
5065  if (op->type != RT_SELECTION_TRANSLATION) {
5066  return -1;
5067  }
5068 
5069  RT_CK_DB_INTERNAL(ip);
5070  struct rt_brep_internal *bip = (struct rt_brep_internal *)ip->idb_ptr;
5071  RT_BREP_CK_MAGIC(bip);
5072  ON_Brep *brep = bip->brep;
5073 
5074  brep_selection *bs = (brep_selection *)selection->obj;
5075  if (!brep || !bs || bs->control_vertexes->empty()) {
5076  return -1;
5077  }
5078 
5079  fastf_t dx = op->parameters.tran.dx;
5080  fastf_t dy = op->parameters.tran.dy;
5081  fastf_t dz = op->parameters.tran.dz;
5082 
5083  std::list<brep_cv *>::iterator cv = bs->control_vertexes->begin();
5084  for (; cv != bs->control_vertexes->end(); ++cv) {
5085  // TODO: if another face references the same surface, the
5086  // surface needs to be duplicated
5087  int face_index = (*cv)->face_index;
5088  if (face_index < 0 || face_index >= brep->m_F.Count()) {
5089  bu_log("%d is not a valid face index\n", face_index);
5090  return -1;
5091  }
5092  int surface_index = brep->m_F[face_index].m_si;
5093  int ret = brep_translate_scv(brep, surface_index, (*cv)->i, (*cv)->j, dx, dy, dz);
5094  if (ret < 0) {
5095  return ret;
5096  }
5097  }
5098 
5099  return 0;
5100 }
5101 
5102 /** @} */
5103 
5104 /*
5105  * Local Variables:
5106  * mode: C++
5107  * tab-width: 8
5108  * c-basic-offset: 4
5109  * indent-tabs-mode: t
5110  * c-file-style: "stroustrup"
5111  * End:
5112  * ex: shiftwidth=4 tabstop=8
5113  */
HIDDEN int sign(double val)
Definition: brep.cpp:1145
Definition: db_flip.c:35
bool trimmed
Definition: brep.cpp:548
Definition: raytrace.h:800
void bu_log(const char *,...) _BU_ATTR_PRINTF12
Definition: log.c:176
#define BU_LIST_INSERT(old, new)
Definition: list.h:183
ON_2dPoint UnwrapUVPoint(const ON_Surface *surf, const ON_2dPoint &pt, double tol)
void plot_face_from_surface_tree(struct bu_list *vhead, SurfaceTree *st, int isocurveres, int gridres)
Definition: brep.cpp:2156
void plot_bbnode(BBNode *node, struct bu_list *vhead, int depth, int start, int limit)
Definition: brep.cpp:1735
struct hit seg_in
IN information.
Definition: raytrace.h:370
void utah_pushBack(const ON_Surface *surf, ON_2dPoint &uv)
Definition: brep.cpp:686
virtual ~RT_MemoryArchive()
Definition: brep.cpp:4542
bool split_trims_hv_tangent(const ON_Curve *curve, ON_Interval &t, std::list< double > &list)
Definition: brep.cpp:244
#define BREP_MAX_ITERATIONS
Definition: brep.h:63
Definition: list.h:118
void utah_Fv(const ON_3dVector &Sv, const ON_3dVector &p1, const ON_3dVector &p2, double &d0, double &d1)
Definition: brep.cpp:668
#define BU_SEM_LISTS
Definition: parallel.h:179
ustring interp
const ON_BrepFace & face
Definition: brep.cpp:542
point_t start
start point of query ray
Definition: raytrace.h:1990
BrepBoundingVolume * bvh
Definition: brep_local.h:34
enum hit_type hit
Definition: brep.cpp:551
#define RT_CK_APPLICATION(_p)
Definition: raytrace.h:1675
int rt_brep_boolean(struct rt_db_internal *out, const struct rt_db_internal *ip1, const struct rt_db_internal *ip2, db_op_t operation)
Definition: brep.cpp:4859
int rt_brep_plot(struct bu_list *vhead, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol, const struct rt_view_info *info)
Definition: brep.cpp:4245
double dist
>= 0
Definition: tol.h:73
fastf_t uv_u
Range 0..1.
Definition: raytrace.h:341
struct soltab * seg_stp
pointer back to soltab
Definition: raytrace.h:372
if lu s
Definition: nmg_mod.c:3860
void bu_vls_strcat(struct bu_vls *vp, const char *s)
Definition: vls.c:368
#define VSET(a, b, c, d)
Definition: color.c:53
#define VSETALL(a, s)
Definition: color.c:54
Definition: raytrace.h:215
#define N
Definition: randmt.c:39
void utah_F(const ON_3dPoint &S, const ON_3dVector &p1, const double p1d, const ON_3dVector &p2, const double p2d, double &f1, double &f2)
Definition: brep.cpp:652
void bu_semaphore_acquire(unsigned int i)
Definition: semaphore.c:180
SurfaceTree ** faces
Definition: brep.cpp:320
bool utah_isTrimmed(ON_2dPoint uv, const ON_BrepFace *face)
Definition: brep.cpp:928
Definition: pc.h:108
Definition: raytrace.h:368
#define st
int bu_b64_decode(signed char **output_buffer, const signed char *input)
Definition: b64.c:274
bool closeToEdge
Definition: brep.cpp:549
Definition: raytrace.h:248
int rt_brep_get(struct bu_vls *logstr, const struct rt_db_internal *intern, const char *attr)
Definition: brep.cpp:4633
#define SMALL_FASTF
Definition: defines.h:342
int brep_translate_scv(ON_Brep *brep, int surface_index, int i, int j, fastf_t dx, fastf_t dy, fastf_t dz)
fastf_t st_aradius
Radius of APPROXIMATING sphere.
Definition: raytrace.h:433
int rt_brep_shot(struct soltab *stp, register struct xray *rp, struct application *ap, struct seg *seghead)
Definition: brep.cpp:1186
void plotisoUCheckForTrim(struct bu_list *vhead, SurfaceTree *st, fastf_t from, fastf_t to, fastf_t v)
Definition: brep.cpp:1875
double sqdist_to_line
Definition: brep.cpp:4912
Header file for the BRL-CAD common definitions.
int utah_brep_intersect(const BBNode *sbv, const ON_BrepFace *face, const ON_Surface *surf, pt2d_t &uv, ON_Ray &ray, HitList &hits)
Definition: brep.cpp:1045
pt2d_t uv
Definition: brep.cpp:547
void getSurfacePoints(const ON_Surface *s, fastf_t u1, fastf_t u2, fastf_t v1, fastf_t v2, fastf_t min_dist, fastf_t within_dist, fastf_t cos_within_ang, ON_2dPointArray &on_surf_points, bool left, bool below)
Definition: brep.cpp:2413
#define DB_FULL_PATH_CUR_DIR(_pp)
Definition: db_fullpath.h:51
bool cmp_cv_startdist(brep_selectable_cv *c1, brep_selectable_cv *c2)
Definition: brep.cpp:4926
int IsAtSeam(const ON_Surface *surf, int dir, double u, double v, double tol)
int j
Definition: brep.cpp:4918
int bu_ptbl_ins(struct bu_ptbl *b, long *p)
struct resource * a_resource
dynamic memory resources
Definition: raytrace.h:1591
ON_Brep * brep
Definition: brep_local.h:33
point_t origin
Definition: brep.cpp:544
int rt_brep_plot_poly(struct bu_list *vhead, const struct db_full_path *pathp, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol, const struct rt_view_info *info)
Definition: brep.cpp:4350
void SwapUVSeamPoint(const ON_Surface *surf, ON_2dPoint &p, int hint)
bool Flush()
Definition: brep.cpp:4627
int face_index
Definition: brep.cpp:4916
#define HIDDEN
Definition: common.h:86
brep_hit(const ON_BrepFace &f, const ON_Ray &ray, const point_t p, const vect_t n, const pt2d_t _uv)
Definition: brep.cpp:557
struct bu_ptbl selections
holds struct rt_selection
Definition: raytrace.h:1959
struct bu_list l
Definition: raytrace.h:369
point_t point
Definition: brep.cpp:545
void * bu_malloc(size_t siz, const char *str)
Definition: malloc.c:314
brep_hit(const ON_BrepFace &f, fastf_t d, const ON_Ray &ray, const point_t p, const vect_t n, const pt2d_t _uv)
Definition: brep.cpp:569
#define BN_VLIST_TRI_VERTNORM
per-vertex normal, for interpolation
Definition: vlist.h:93
double rel
rel dist tol
Definition: raytrace.h:181
void rt_brep_norm(register struct hit *hitp, struct soltab *stp, register struct xray *rp)
void plotisoV(struct bu_list *vhead, SurfaceTree *st, fastf_t from, fastf_t to, fastf_t u, int curveres)
Definition: brep.cpp:2084
vect_t dir
direction of query ray
Definition: raytrace.h:1991
if(share_geom)
Definition: nmg_mod.c:3829
int idb_major_type
Definition: raytrace.h:192
void rt_brep_ifree(struct rt_db_internal *ip)
Definition: brep.cpp:4786
#define RT_BREP_INTERNAL_MAGIC
Definition: magic.h:86
Definition: color.c:49
COMPLEX data[64]
Definition: fftest.c:34
double find_next_trimming_point(const ON_Curve *crv, const ON_Surface *s, double startdomval, double increment, double tolerance, int stepcount)
Definition: brep.cpp:1791
#define BU_CK_VLS(_vp)
Definition: vls.h:69
hit_direction
Definition: brep.cpp:537
int rt_brep_params(struct pc_pc_set *, const struct rt_db_internal *ip)
Definition: brep.cpp:4852
hit_type
Definition: brep.cpp:530
vect_t hit_vpriv
PRIVATE vector for xxx_*()
Definition: raytrace.h:253
struct bu_list * vhead
Definition: raytrace.h:1926
#define RT_ADD_VLIST(hd, pnt, draw)
Definition: raytrace.h:1865
bool SeekFromCurrentPosition(int)
Definition: brep.cpp:4555
db_op_t
Definition: op.h:33
#define RT_CK_DB_INTERNAL(_p)
Definition: raytrace.h:207
#define BU_ALLOC(_ptr, _type)
Definition: malloc.h:223
void * bu_calloc(size_t nelem, size_t elsize, const char *str)
Definition: malloc.c:321
fastf_t st_bradius
Radius of BOUNDING sphere.
Definition: raytrace.h:434
int rt_brep_prep(struct soltab *stp, struct rt_db_internal *ip, struct rt_i *rtip)
Definition: brep.cpp:453
void utah_Fu(const ON_3dVector &Su, const ON_3dVector &p1, const ON_3dVector &p2, double &d0, double &d1)
Definition: brep.cpp:660
#define BREP_INTERSECTION_ROOT_EPSILON
Definition: brep.h:66
bool SeekFromStart(size_t)
Definition: brep.cpp:4564
void(* free_selection)(struct rt_selection *)
Definition: raytrace.h:1964
#define RT_DB_INTERNAL_INIT(_p)
Definition: raytrace.h:199
void bu_vls_sprintf(struct bu_vls *vls, const char *fmt,...) _BU_ATTR_PRINTF23
Definition: vls.c:707
void plot_sum_surface(struct bu_list *vhead, const ON_Surface *surf, int isocurveres, int gridres)
Definition: brep.cpp:1822
#define BN_VLIST_LINE_MOVE
Definition: vlist.h:82
const struct rt_functab * idb_meth
for ft_ifree(), etc.
Definition: raytrace.h:194
#define NEAR_ZERO(val, epsilon)
Definition: color.c:55
double getHorizontalTangent(const ON_Curve *curve, double min, double max)
Definition: brep.cpp:219
uint8_t * ext_buf
Definition: parse.h:216
point_t hit_point
DEPRECATED: Intersection point, use VJOIN1 hit_dist.
Definition: raytrace.h:251
point_t st_max
max X, Y, Z of bounding RPP
Definition: raytrace.h:438
bool brep_pt_trimmed(pt2d_t pt, const ON_BrepFace &face)
Definition: brep.cpp:148
struct hit seg_out
OUT information.
Definition: raytrace.h:371
int number_of_seam_crossings(const ON_Surface *surf, ON_SimpleArray< BrepTrimPoint > &brep_trim_points)
Definition: brep.cpp:3003
#define BN_VLIST_LINE_DRAW
Definition: vlist.h:83
std::pair< int, int > ip_t
Definition: brep.cpp:1141
void getUVCurveSamples(const ON_Surface *s, const ON_Curve *curve, fastf_t t1, ON_3dPoint &start_2d, ON_3dVector &start_tang, ON_3dPoint &start_3d, ON_3dVector &start_norm, fastf_t t2, ON_3dPoint &end_2d, ON_3dVector &end_tang, ON_3dPoint &end_3d, ON_3dVector &end_norm, fastf_t min_dist, fastf_t max_dist, fastf_t within_dist, fastf_t cos_within_ang, std::map< double, ON_3dPoint * > &param_points)
Definition: brep.cpp:2833
int i
Definition: brep.cpp:4917
bool FindTrimSeamCrossing(const ON_BrepTrim &trim, double t0, double t1, double &seam_t, ON_2dPoint &from, ON_2dPoint &to, double tol)
std::list< brep_hit > HitList
Definition: brep.cpp:619
ON_BOOL32 surface_EvNormal(const ON_Surface *surf, double s, double t, ON_3dPoint &point, ON_3dVector &normal, int side, int *hint)
void rt_brep_free(register struct soltab *stp)
Definition: brep.cpp:1713
int m_adj_face_index
Definition: brep.cpp:553
void plottrim(ON_BrepFace &face, struct bn_vlblock *vbp, int plotres, bool dim3d)
Definition: brep_debug.cpp:341
int rt_brep_adjust(struct bu_vls *logstr, const struct rt_db_internal *intern, int argc, const char **argv)
Definition: brep.cpp:4673
bool AtEnd() const
Definition: brep.cpp:4573
vect_t normal
Definition: brep.cpp:546
#define DARKORANGE
Definition: brep_debug.h:71
int rt_brep_tess(struct nmgregion **r, struct model *m, struct rt_db_internal *ip, const struct rt_tess_tol *ttol, const struct bn_tol *tol)
Definition: brep.cpp:4472
#define UNUSED(parameter)
Definition: common.h:239
#define ROOT_TOL
Definition: brep.cpp:69
#define BU_PTBL_INIT(_p)
Definition: ptbl.h:80
goto out
Definition: nmg_mod.c:3846
int utah_newton_4corner_solver(const BBNode *sbv, const ON_Surface *surf, const ON_Ray &r, ON_2dPoint *ouv, double *t, ON_3dVector *N, bool &converged, int docorners)
Definition: brep.cpp:904
double getVerticalTangent(const ON_Curve *curve, double min, double max)
Definition: brep.cpp:194
Support for uniform tolerances.
Definition: tol.h:71
#define BN_CK_TOL(_p)
Definition: tol.h:82
int rt_brep_tcladjust(Tcl_Interp *interp, struct rt_db_internal *intern, int argc, const char **argv)
Definition: brep.cpp:4845
#define BN_VLIST_TRI_END
last vert (repeats 1st), draw poly
Definition: vlist.h:92
double drand48(void)
size_t Read(size_t, void *)
Definition: brep.cpp:4599
int rt_brep_process_selection(struct rt_db_internal *ip, const struct rt_selection *selection, const struct rt_selection_operation *op)
Definition: brep.cpp:5056
#define BU_FREE(_ptr, _type)
Definition: malloc.h:229
void bu_semaphore_release(unsigned int i)
Definition: semaphore.c:218
void plotisoVCheckForTrim(struct bu_list *vhead, SurfaceTree *st, fastf_t from, fastf_t to, fastf_t u)
Definition: brep.cpp:1970
#define RT_SELECTION_TRANSLATION
Definition: raytrace.h:2018
#define ID_BREP
B-rep object.
Definition: raytrace.h:509
int brep_build_bvh(struct brep_specific *bs)
Definition: brep.cpp:357
vect_t r_dir
Direction of ray (UNIT Length)
Definition: raytrace.h:219
std::list< ip_t > MissList
Definition: brep.cpp:1142
struct bn_tol rti_tol
Math tolerances for this model.
Definition: raytrace.h:1765
size_t CurrentPosition() const
Definition: brep.cpp:4548
void bu_parallel(void(*func)(int func_ncpu, void *func_data), int ncpu, void *data)
#define RT_CK_DBI(_p)
Definition: raytrace.h:829
struct rt_selection_set * rt_brep_find_selections(const struct rt_db_internal *ip, const struct rt_selection_query *query)
Definition: brep.cpp:4975
#define BN_VLIST_TRI_START
pt[] has surface normal
Definition: vlist.h:89
#define RT_GET_SEG(p, res)
Definition: raytrace.h:379
#define MAGENTA
Definition: brep_debug.h:89
fastf_t point_spacing
Definition: raytrace.h:1934
brep_hit(const brep_hit &h)
Definition: brep.cpp:578
bool extend_over_seam_crossings(const ON_Surface *surf, ON_SimpleArray< BrepTrimPoint > &brep_loop_points)
Definition: brep.cpp:3137
struct rt_selection * new_cv_selection(brep_selectable_cv *s)
Definition: brep.cpp:4953
bool oob
Definition: brep.cpp:550
struct rt_selection_translation tran
Definition: raytrace.h:2021
#define ZERO(val)
Definition: units.c:38
void * idb_ptr
Definition: raytrace.h:195
point_t r_pt
Point at which ray starts.
Definition: raytrace.h:218
int rt_brep_export5(struct bu_external *ep, const struct rt_db_internal *ip, double local2mm, const struct db_i *dbip)
Definition: brep.cpp:4695
point_t st_min
min X, Y, Z of bounding RPP
Definition: raytrace.h:437
struct brep_specific * brep_specific_new()
Definition: brep.cpp:128
void rt_brep_curve(register struct curvature *cvp, register struct hit *hitp, struct soltab *stp)
void utah_ray_planes(const ON_Ray &r, ON_3dVector &p1, double &p1d, ON_3dVector &p2, double &p2d)
brep_intersect_reason_t
Definition: brep.cpp:622
bool LoopStraddlesDomain(const ON_Surface *surf, ON_SimpleArray< BrepTrimPoint > &brep_loop_points)
Definition: brep.cpp:3026
const struct rt_functab OBJ[]
Definition: table.c:159
int64_t bu_gettime(void)
Definition: timer.c:42
Definition: op.h:35
int hit(struct application *ap, struct partition *PartHeadp, struct seg *segs)
Definition: gqa.c:963
int rt_brep_tclget(Tcl_Interp *interp, const struct rt_db_internal *intern, const char *attr)
Definition: brep.cpp:4838
bool operator==(const brep_hit &h) const
Definition: brep.cpp:607
fastf_t dist
Definition: brep.cpp:543
double abs
absolute dist tol
Definition: raytrace.h:180
void rt_brep_uv(struct application *ap, struct soltab *stp, register struct hit *hitp, register struct uvcoord *uvp)
Definition: brep.cpp:1695
#define RT_CK_SOLTAB(_p)
Definition: raytrace.h:453
bool ConsecutivePointsCrossClosedSeam(const ON_Surface *surf, const ON_2dPoint &pt, const ON_2dPoint &prev_pt, int &udir, int &vdir, double tol)
#define BREP_GRAZING_DOT_TOL
Definition: brep.h:74
void bu_vls_printf(struct bu_vls *vls, const char *fmt,...) _BU_ATTR_PRINTF23
Definition: vls.c:694
void ForceToClosestSeam(const ON_Surface *surf, ON_2dPoint &pt, double tol)
#define BU_EXTERNAL_INIT(_p)
Definition: parse.h:229
void * st_specific
-> ID-specific (private) struct
Definition: raytrace.h:435
uint8_t * CreateCopy() const
Definition: brep.cpp:4587
int rt_brep_describe(struct bu_vls *str, const struct rt_db_internal *ip, int verbose, double mm2local)
Definition: brep.cpp:4803
void poly2tri_CDT(struct bu_list *vhead, ON_BrepFace &face, const struct rt_tess_tol *ttol, const struct bn_tol *tol, const struct rt_view_info *info, bool watertight=false, int plottype=0, int num_points=-1.0)
Definition: brep.cpp:3751
void getEdgePoints(const ON_BrepTrim &trim, fastf_t t1, ON_3dPoint &start_2d, ON_3dVector &start_tang, ON_3dPoint &start_3d, ON_3dVector &start_norm, fastf_t t2, ON_3dPoint &end_2d, ON_3dVector &end_tang, ON_3dPoint &end_3d, ON_3dVector &end_norm, fastf_t min_dist, fastf_t max_dist, fastf_t within_dist, fastf_t cos_within_ang, std::map< double, ON_3dPoint * > &param_points)
Definition: brep.cpp:2164
double find_next_point(const ON_Curve *crv, double startdomval, double increment, double tolerance, int stepcount)
Definition: brep.cpp:1772
void plotisoU(struct bu_list *vhead, SurfaceTree *st, fastf_t from, fastf_t to, fastf_t v, int curveres)
Definition: brep.cpp:2059
#define BN_VLIST_TRI_DRAW
subsequent triangle vertex
Definition: vlist.h:91
signed char * bu_b64_encode_block(const signed char *input, size_t length_in)
Definition: b64.c:212
int idb_minor_type
ID_xxx.
Definition: raytrace.h:193
void plot_face_trim(struct bu_list *vhead, ON_BrepFace &face, int plotres, bool dim3d)
Definition: brep.cpp:4079
enum hit_direction direction
Definition: brep.cpp:552
Definition: color.c:51
bool shift_loop_straddled_over_seam(const ON_Surface *surf, ON_SimpleArray< BrepTrimPoint > &brep_loop_points, double same_point_tolerance)
Definition: brep.cpp:3078
bool operator<(const brep_hit &h) const
Definition: brep.cpp:612
double utah_calc_t(const ON_Ray &r, ON_3dPoint &S)
Definition: brep.cpp:676
double norm
normal tol
Definition: raytrace.h:182
void plot_BBNode(struct bu_list *vhead, SurfaceTree *st, BBNode *node, int isocurveres, int gridres)
Definition: brep.cpp:2109
int hit_surfno
solid-specific surface indicator
Definition: raytrace.h:255
ON_Ray toXRay(struct xray *rp)
Definition: brep.cpp:117
void bu_free(void *ptr, const char *str)
Definition: malloc.c:328
vect_t hit_normal
DEPRECATED: Surface Normal at hit_point, use RT_HIT_NORMAL.
Definition: raytrace.h:252
#define BU_CK_LIST_HEAD(_p)
Definition: list.h:142
int rt_brep_class(const struct soltab *stp, const fastf_t *min, const fastf_t *max, const struct bn_tol *tol)
Definition: brep.cpp:1677
#define BU_CK_EXTERNAL(_p)
Definition: parse.h:224
union rt_selection_operation::@10 parameters
int ON_Boolean(ON_Brep *evaluated_brep, const ON_Brep *brep1, const ON_Brep *brep2, op_type operation)
Definition: boolean.cpp:3891
int utah_newton_solver(const BBNode *sbv, const ON_Surface *surf, const ON_Ray &r, ON_2dPoint *ouv, double *t, ON_3dVector *N, bool &converged, ON_2dPoint *suv, const int count, const int iu, const int iv)
Definition: brep.cpp:742
int rt_brep_bbox(struct rt_db_internal *ip, point_t *min, point_t *max)
Definition: brep.cpp:429
HIDDEN const char * BREP_INTERSECT_REASON(brep_intersect_reason_t index)
Definition: brep.cpp:634
#define RT_SELECTION_NOP
Definition: raytrace.h:2017
std::list< brep_cv * > * control_vertexes
Definition: brep.cpp:4922
void brep_specific_delete(struct brep_specific *bs)
Definition: brep.cpp:135
bool near_equal(double first, double second)
Definition: brep.cpp:1814
void rt_brep_print(register const struct soltab *stp)
#define M_COLOR_PLOT(c)
Definition: brep_debug.h:96
bool containsNearMiss(HitList *hits)
Definition: brep.cpp:1152
#define MAX_BREP_SUBDIVISION_INTERSECTS
Definition: brep.cpp:1043
int is_entering(const ON_Surface *surf, const ON_SimpleArray< BrepTrimPoint > &brep_loop_points)
Definition: brep.cpp:3044
size_t ext_nbytes
Definition: parse.h:210
struct brep_specific * bs
Definition: brep.cpp:319
int rt_brep_adaptive_plot(struct rt_db_internal *ip, const struct rt_view_info *info)
Definition: brep.cpp:4123
fastf_t hit_dist
dist from r_pt to hit_point
Definition: raytrace.h:250
HIDDEN void verbose(struct human_data_t *dude)
Definition: human.c:2008
double sqdist_to_start
Definition: brep.cpp:4911
#define DARKGREEN
Definition: brep_debug.h:66
Definition: vls.h:56
int rt_brep_import5(struct rt_db_internal *ip, const struct bu_external *ep, register const fastf_t *mat, const struct db_i *dbip)
HIDDEN const point_t delta
Definition: sh_prj.c:618
double fastf_t
Definition: defines.h:300
void * obj
primitive-specific selection object
Definition: raytrace.h:1951
BBNode const * sbv
Definition: brep.cpp:555
double bn_distsq_line3_pt3(const point_t pt, const vect_t dir, const point_t a)
bool containsNearHit(HitList *hits)
Definition: brep.cpp:1165
Definition: color.c:50
fastf_t uv_v
Range 0..1.
Definition: raytrace.h:342
size_t Size() const
Definition: brep.cpp:4580
brep_hit & operator=(const brep_hit &h)
Definition: brep.cpp:588
point_t st_center
Centroid of solid.
Definition: raytrace.h:432
#define BN_VLIST_POINT_DRAW
Draw a single point.
Definition: vlist.h:94
size_t Write(size_t, const void *)
Definition: brep.cpp:4611
#define BN_VLIST_TRI_MOVE
move to first triangle vertex
Definition: vlist.h:90