BRL-CAD
nmg_brep.cpp
Go to the documentation of this file.
1 /* N M G _ B R E P . C P P
2  * BRL-CAD
3  *
4  * Copyright (c) 2008-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 /** @file nmg_brep.cpp
21  *
22  * b-rep support for NMG
23  *
24  */
25 
26 #include "common.h"
27 
28 #include "raytrace.h"
29 #include "rtgeom.h"
30 #include "wdb.h"
31 #include "bn.h"
32 #include "bu/ptbl.h"
33 #include "bu/malloc.h"
34 
35 /**
36  * Routine to create a planar NURBS surface from 4 points
37  */
38 HIDDEN ON_Surface*
39 sideSurface(const ON_3dPoint& SW, const ON_3dPoint& SE, const ON_3dPoint& NE, const ON_3dPoint& NW)
40 {
41  ON_NurbsSurface *surf = ON_NurbsSurface::New(3, 0, 2, 2, 2, 2);
42  surf->SetCV(0, 0, SW);
43  surf->SetCV(1, 0, SE);
44  surf->SetCV(1, 1, NE);
45  surf->SetCV(0, 1, NW);
46  surf->SetKnot(0, 0, 0.0);
47  surf->SetKnot(0, 1, 1.0);
48  surf->SetKnot(1, 0, 0.0);
49  surf->SetKnot(1, 1, 1.0);
50  return surf;
51 }
52 
53 HIDDEN int
54 nmg_brep_face(ON_Brep **b, const struct faceuse *fu, const struct bn_tol *tol, long *brepi) {
55  const struct face_g_plane *fg = fu->f_p->g.plane_p;
56  struct bu_ptbl vert_table;
57  struct vertex **pt;
58  int ret = 0;
59  int pnt_cnt = 0;
60  int pnt_index = 0;
61  vect_t u_axis, v_axis;
62  point_t obr_center;
63  point_t *points_3d = NULL;
64  point_t *points_obr = NULL;
65  struct loopuse *lu;
66  struct edgeuse *eu;
67 
68  /* Find out how many points we have, set up any uninitialized ON_Brep vertex
69  * structures, and prepare a map of NMG index values to the point array indices */
70  nmg_tabulate_face_g_verts(&vert_table, fg);
71 
72  for (BU_PTBL_FOR(pt, (struct vertex **), &vert_table)) {
73  if (brepi[(*pt)->vg_p->index] == -INT_MAX) {
74  ON_BrepVertex& vert = (*b)->NewVertex((*pt)->vg_p->coord, SMALL_FASTF);
75  brepi[(*pt)->vg_p->index] = vert.m_vertex_index;
76  }
77  pnt_cnt++;
78  }
79 
80  /* Prepare the 3D obr input array */
81  points_3d = (point_t *)bu_calloc(pnt_cnt + 1, sizeof(point_t), "nmg points");
82  for (BU_PTBL_FOR(pt, (struct vertex **), &vert_table)) {
83  VSET(points_3d[pnt_index], (*pt)->vg_p->coord[0],(*pt)->vg_p->coord[1],(*pt)->vg_p->coord[2]);
84  pnt_index++;
85  }
86  bu_ptbl_free(&vert_table);
87 
88 
89  /* Calculate the 3D coplanar oriented bounding rectangle (obr) */
90  ret += bn_3d_coplanar_obr(&obr_center, &u_axis, &v_axis, (const point_t *)points_3d, pnt_cnt);
91  if (ret) {
92  bu_log("Failed to get oriented bounding rectangle for NMG faceuse #%lu\n", fu->index);
93  return -1;
94  }
95  bu_free(points_3d, "done with obr 3d point inputs");
96 
97  /* Use the obr to define the 3D corner points of the NURBS surface */
98  points_obr = (point_t *)bu_calloc(3 + 1, sizeof(point_t), "points_3d");
99  VADD3(points_obr[2], obr_center, u_axis, v_axis);
100  VSCALE(u_axis, u_axis, -1);
101  VADD3(points_obr[3], obr_center, u_axis, v_axis);
102  VSCALE(v_axis, v_axis, -1);
103  VADD3(points_obr[0], obr_center, u_axis, v_axis);
104  VSCALE(u_axis, u_axis, -1);
105  VADD3(points_obr[1], obr_center, u_axis, v_axis);
106 
107  /* We need to orient our surface correctly according to the NMG - using
108  * the openNURBS FlipFace function later does not seem to work very
109  * well. If an outer loop is found in the NMG with a cw orientation,
110  * factor that in in addition to the fu->f_p->flip flag. */
111  int ccw = 0;
112  vect_t vtmp, uv1, uv2, vnormal;
113  point_t center;
114  VADD2(center, points_obr[0], points_obr[1]);
115  VADD2(center, center, points_obr[2]);
116  VADD2(center, center, points_obr[3]);
117  VSCALE(center, center, 0.25);
118  for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) {
119  if (lu->orientation == OT_SAME && nmg_loop_is_ccw(lu, fg->N, tol) == -1) ccw = -1;
120  }
121  if (ccw != -1) {
122  VSET(vnormal, fg->N[0], fg->N[1], fg->N[2]);
123  } else {
124  VSET(vnormal, -fg->N[0], -fg->N[1], -fg->N[2]);
125  }
126  if (fu->f_p->flip)
127  VSET(vnormal, -vnormal[0], -vnormal[1], -vnormal[2]);
128  VSUB2(uv1, points_obr[0], center);
129  VSUB2(uv2, points_obr[1], center);
130  VCROSS(vtmp, uv1, uv2);
131  if (VDOT(vtmp, vnormal) < 0) {
132  VMOVE(vtmp, points_obr[0]);
133  VMOVE(points_obr[0], points_obr[1]);
134  VMOVE(points_obr[1], vtmp);
135  VMOVE(vtmp, points_obr[3]);
136  VMOVE(points_obr[3], points_obr[2]);
137  VMOVE(points_obr[2], vtmp);
138  }
139 
140  /* Now that we've got our points correctly oriented for
141  * the NURBS surface, proceed to create it. */
142  ON_3dPoint p1 = ON_3dPoint(points_obr[0]);
143  ON_3dPoint p2 = ON_3dPoint(points_obr[1]);
144  ON_3dPoint p3 = ON_3dPoint(points_obr[2]);
145  ON_3dPoint p4 = ON_3dPoint(points_obr[3]);
146 
147  (*b)->m_S.Append(sideSurface(p1, p2, p3, p4));
148  ON_Surface *surf = (*(*b)->m_S.Last());
149  int surfindex = (*b)->m_S.Count();
150  ON_BrepFace& face = (*b)->NewFace(surfindex - 1);
151 
152  // With the surface and the face defined, make
153  // trimming loops and create faces. To generate UV
154  // coordinates for each from and to for the
155  // edgecurves, the UV origin is defined to be v1,
156  // v1->v2 is defined as the U domain, and v1->v4 is
157  // defined as the V domain.
158  VSUB2(u_axis, points_obr[2], points_obr[1]);
159  VSUB2(v_axis, points_obr[0], points_obr[1]);
160  fastf_t u_axis_dist = MAGNITUDE(u_axis);
161  fastf_t v_axis_dist = MAGNITUDE(v_axis);
162 
163  /* Now that we have the surface and the face, add the loops */
164  for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) {
165  if (BU_LIST_FIRST_MAGIC(&lu->down_hd) != NMG_EDGEUSE_MAGIC) continue; // loop is a single vertex
166  // Check if this is an inner or outer loop
167  ON_BrepLoop::TYPE looptype = (lu->orientation == OT_SAME) ? ON_BrepLoop::outer : ON_BrepLoop::inner;
168  ON_BrepLoop& loop = (*b)->NewLoop(looptype, face);
169  for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) {
170  vect_t ev1, ev2;
171  struct vertex_g *vg1 = eu->vu_p->v_p->vg_p;
172  struct vertex_g *vg2 = eu->eumate_p->vu_p->v_p->vg_p;
173  NMG_CK_VERTEX_G(vg1);
174  NMG_CK_VERTEX_G(vg2);
175  VMOVE(ev1, vg1->coord);
176  VMOVE(ev2, vg2->coord);
177  // Add edge if not already added
178  if (brepi[eu->e_p->index] == -INT_MAX) {
179  /* always add edges with the small vertex index as from */
180  int vert1 = (vg1->index <= vg2->index) ? brepi[vg1->index] : brepi[vg2->index];
181  int vert2 = (vg1->index > vg2->index) ? brepi[vg1->index] : brepi[vg2->index];
182  // Create and add 3D curve
183  ON_Curve* c3d = new ON_LineCurve((*b)->m_V[vert1].Point(), (*b)->m_V[vert2].Point());
184  c3d->SetDomain(0.0, 1.0);
185  (*b)->m_C3.Append(c3d);
186  // Create and add 3D edge
187  ON_BrepEdge& e = (*b)->NewEdge((*b)->m_V[vert1], (*b)->m_V[vert2] , (*b)->m_C3.Count() - 1);
188  e.m_tolerance = 0.0;
189  brepi[eu->e_p->index] = e.m_edge_index;
190  }
191  // Regardless of whether the edge existed as an object, it needs to be added to the trimming loop
192  ON_3dPoint vg1pt(vg1->coord);
193  int orientation = ((vg1pt != (*b)->m_V[(*b)->m_E[(int)brepi[eu->e_p->index]].m_vi[0]].Point())) ? 1 : 0;
194  // Make a 2d trimming curve, create a trim, and add the trim to the loop
195  vect_t vect1, vect2, u_component, v_component;
196  double u0, u1, v0, v1;
197  ON_2dPoint from_uv, to_uv;
198  VSUB2(vect1, ev1, points_obr[0]);
199  VSUB2(vect2, ev2, points_obr[0]);
200  surf->GetDomain(0, &u0, &u1);
201  surf->GetDomain(1, &v0, &v1);
202  VPROJECT(vect1, u_axis, u_component, v_component);
203  from_uv.y = u0 + MAGNITUDE(u_component)/u_axis_dist*(u1-u0);
204  from_uv.x = v0 + MAGNITUDE(v_component)/v_axis_dist*(v1-v0);
205  VPROJECT(vect2, u_axis, u_component, v_component);
206  to_uv.y = u0 + MAGNITUDE(u_component)/u_axis_dist*(u1-u0);
207  to_uv.x = v0 + MAGNITUDE(v_component)/v_axis_dist*(v1-v0);
208  ON_Curve* c2d = new ON_LineCurve(from_uv, to_uv);
209  c2d->SetDomain(0.0, 1.0);
210  int c2i = (*b)->m_C2.Count();
211  (*b)->m_C2.Append(c2d);
212  ON_BrepTrim& trim = (*b)->NewTrim((*b)->m_E[(int)brepi[eu->e_p->index]], orientation, loop, c2i);
213  trim.m_type = ON_BrepTrim::mated;
214  trim.m_tolerance[0] = 0.0;
215  trim.m_tolerance[1] = 0.0;
216  }
217  }
218 
219  bu_free(points_obr, "Done with obr");
220 
221  return 0;
222 }
223 
224 
225 extern "C" void
226 rt_nmg_brep(ON_Brep **b, const struct rt_db_internal *ip, const struct bn_tol *tol)
227 {
228  struct model *m;
229  struct nmgregion *r;
230  struct shell *s;
231  struct faceuse *fu;
232 
233  // Verify NMG
234  RT_CK_DB_INTERNAL(ip);
235  m = (struct model *)ip->idb_ptr;
236  NMG_CK_MODEL(m);
237 
238  // Both NMG and brep structures re-use components between faces. In order to track
239  // when the conversion routine has already handled an NMG element, use an array.
240  long *brepi = static_cast<long*>(bu_malloc(m->maxindex * sizeof(long), "rt_nmg_brep: brepi[]"));
241  for (int i = 0; i < m->maxindex; i++) brepi[i] = -INT_MAX;
242 
243  // Iterate over all faces in the NMG
244  for (BU_LIST_FOR(r, nmgregion, &m->r_hd)) {
245  for (BU_LIST_FOR(s, shell, &r->s_hd)) {
246  for (BU_LIST_FOR(fu, faceuse, &s->fu_hd)) {
247  NMG_CK_FACEUSE(fu);
248  if (fu->orientation != OT_SAME) continue;
249  if (nmg_brep_face(b, fu, tol, brepi)) return;
250  }
251  (*b)->SetTrimIsoFlags();
252  }
253  }
254 }
255 
256 
257 // Local Variables:
258 // tab-width: 8
259 // mode: C++
260 // c-basic-offset: 4
261 // indent-tabs-mode: t
262 // c-file-style: "stroustrup"
263 // End:
264 // ex: shiftwidth=4 tabstop=8
#define NE
#define BU_LIST_FOR(p, structure, hp)
Definition: list.h:365
#define NMG_EDGEUSE_MAGIC
Definition: magic.h:120
void bu_log(const char *,...) _BU_ATTR_PRINTF12
Definition: log.c:176
#define BU_PTBL_FOR(ip, cast, ptbl)
Definition: ptbl.h:125
if lu s
Definition: nmg_mod.c:3860
lu
Definition: nmg_mod.c:3855
#define VSET(a, b, c, d)
Definition: color.c:53
HIDDEN int nmg_brep_face(ON_Brep **b, const struct faceuse *fu, const struct bn_tol *tol, long *brepi)
Definition: nmg_brep.cpp:54
#define SMALL_FASTF
Definition: defines.h:342
Header file for the BRL-CAD common definitions.
int bn_3d_coplanar_obr(point_t *center, vect_t *v1, vect_t *v2, const point_t *points_3d, int pnt_cnt)
Uses the Rotating Calipers algorithm to find the minimum oriented bounding rectangle for a set of cop...
Definition: obr.c:496
#define HIDDEN
Definition: common.h:86
void * bu_malloc(size_t siz, const char *str)
Definition: malloc.c:314
Definition: ptbl.h:62
int nmg_loop_is_ccw(const struct loopuse *lu, const fastf_t *norm, const struct bn_tol *tol)
Definition: nmg_info.c:533
#define RT_CK_DB_INTERNAL(_p)
Definition: raytrace.h:207
void * bu_calloc(size_t nelem, size_t elsize, const char *str)
Definition: malloc.c:321
HIDDEN ON_Surface * sideSurface(const ON_3dPoint &SW, const ON_3dPoint &SE, const ON_3dPoint &NE, const ON_3dPoint &NW)
Definition: nmg_brep.cpp:39
Support for uniform tolerances.
Definition: tol.h:71
#define BU_LIST_FIRST_MAGIC(hp)
Definition: list.h:416
#define NW
void bu_ptbl_free(struct bu_ptbl *b)
Definition: ptbl.c:226
void * idb_ptr
Definition: raytrace.h:195
#define SW
void nmg_tabulate_face_g_verts(struct bu_ptbl *tab, const struct face_g_plane *fg)
Definition: nmg_misc.c:873
char * SE
Definition: cursor.c:88
void bu_free(void *ptr, const char *str)
Definition: malloc.c:328
void rt_nmg_brep(ON_Brep **b, const struct rt_db_internal *ip, const struct bn_tol *tol)
Definition: nmg_brep.cpp:226
double fastf_t
Definition: defines.h:300
eu1 orientation
Definition: nmg_mod.c:3916