Revision: 73808
http://sourceforge.net/p/brlcad/code/73808
Author: starseeker
Date: 2019-08-31 19:19:20 +0000 (Sat, 31 Aug 2019)
Log Message:
-----------
Start working on mapping the surface sampling logic onto the new structures.
Will need some careful testing and probably printing/plotting to make sure the
pieces are right here...
Modified Paths:
--------------
brlcad/trunk/src/libbrep/CMakeLists.txt
Added Paths:
-----------
brlcad/trunk/src/libbrep/cdt_surf2.cpp
Modified: brlcad/trunk/src/libbrep/CMakeLists.txt
===================================================================
--- brlcad/trunk/src/libbrep/CMakeLists.txt 2019-08-31 18:25:13 UTC (rev
73807)
+++ brlcad/trunk/src/libbrep/CMakeLists.txt 2019-08-31 19:19:20 UTC (rev
73808)
@@ -28,6 +28,7 @@
cdt_edge.cpp
cdt_patch.cpp
cdt_surf.cpp
+ cdt_surf2.cpp
cdt_util.cpp
cdt_validate.cpp
cdt.cpp
Added: brlcad/trunk/src/libbrep/cdt_surf2.cpp
===================================================================
--- brlcad/trunk/src/libbrep/cdt_surf2.cpp (rev 0)
+++ brlcad/trunk/src/libbrep/cdt_surf2.cpp 2019-08-31 19:19:20 UTC (rev
73808)
@@ -0,0 +1,922 @@
+/* C D T _ S U R F . C P P
+ * BRL-CAD
+ *
+ * Copyright (c) 2007-2019 United States Government as represented by
+ * the U.S. Army Research Laboratory.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this file; see the file named COPYING for more
+ * information.
+ */
+/** @addtogroup libbrep */
+/** @{ */
+/** @file cdt_surf.cpp
+ *
+ * Constrained Delaunay Triangulation - Surface Point sampling of NURBS B-Rep
+ * objects.
+ *
+ */
+
+#include "common.h"
+#include "bn/rand.h"
+#include "./cdt.h"
+
+struct cdt_surf_info_2 {
+ std::set<ON_2dPoint *> on_surf_points;
+ struct ON_Brep_CDT_State *s_cdt;
+ const ON_Surface *s;
+ const ON_BrepFace *f;
+ RTree<void *, double, 2> *rt_trims;
+ RTree<void *, double, 3> *rt_trims_3d;
+ std::map<int,ON_3dPoint *> *strim_pnts;
+ std::map<int,ON_3dPoint *> *strim_norms;
+ double u1, u2, v1, v2;
+ fastf_t ulen;
+ fastf_t u_lower_3dlen;
+ fastf_t u_mid_3dlen;
+ fastf_t u_upper_3dlen;
+ fastf_t vlen;
+ fastf_t v_lower_3dlen;
+ fastf_t v_mid_3dlen;
+ fastf_t v_upper_3dlen;
+ fastf_t min_edge;
+ fastf_t max_edge;
+ fastf_t min_dist;
+ fastf_t within_dist;
+ fastf_t cos_within_ang;
+ std::set<ON_BoundingBox *> leaf_bboxes;
+};
+
+
+class SPatch {
+
+ public:
+ SPatch(double u1, double u2, double v1, double v2)
+ {
+ umin = u1;
+ umax = u2;
+ vmin = v1;
+ vmax = v2;
+ }
+
+ double umin;
+ double umax;
+ double vmin;
+ double vmax;
+};
+
+static double
+uline_len_est(struct cdt_surf_info_2 *sinfo, double u1, double u2, double v)
+{
+ double t, lenfact, lenest;
+ int active_half = (fabs(sinfo->v1 - v) < fabs(sinfo->v2 - v)) ? 0 : 1;
+ t = (active_half == 0) ? 1 - fabs(sinfo->v1 - v)/fabs((sinfo->v2 -
sinfo->v1)*0.5) : 1 - fabs(sinfo->v2 - v)/fabs((sinfo->v2 - sinfo->v1)*0.5);
+ if (active_half == 0) {
+ lenfact = sinfo->u_lower_3dlen * (1 - (t)) + sinfo->u_mid_3dlen * (t);
+ lenest = (u2 - u1)/sinfo->ulen * lenfact;
+ } else {
+ lenfact = sinfo->u_mid_3dlen * (1 - (t)) + sinfo->u_upper_3dlen * (t);
+ lenest = (u2 - u1)/sinfo->ulen * lenfact;
+ }
+ return lenest;
+}
+
+
+static double
+vline_len_est(struct cdt_surf_info_2 *sinfo, double u, double v1, double v2)
+{
+ double t, lenfact, lenest;
+ int active_half = (fabs(sinfo->u1 - u) < fabs(sinfo->u2 - u)) ? 0 : 1;
+ t = (active_half == 0) ? 1 - fabs(sinfo->u1 - u)/fabs((sinfo->u2 -
sinfo->u1)*0.5) : 1 - fabs(sinfo->u2 - u)/fabs((sinfo->u2 - sinfo->u1)*0.5);
+ if (active_half == 0) {
+ lenfact = sinfo->v_lower_3dlen * (1 - (t)) + sinfo->v_mid_3dlen * (t);
+ lenest = (v2 - v1)/sinfo->vlen * lenfact;
+ } else {
+ lenfact = sinfo->v_mid_3dlen * (1 - (t)) + sinfo->v_upper_3dlen * (t);
+ lenest = (v2 - v1)/sinfo->vlen * lenfact;
+ }
+ return lenest;
+}
+
+static ON_3dPoint *
+singular_trim_norm(struct cdt_surf_info_2 *sinfo, fastf_t uc, fastf_t vc)
+{
+ if (sinfo->strim_pnts->find(sinfo->f->m_face_index) !=
sinfo->strim_pnts->end()) {
+ //bu_log("Face %d has singular trims\n", sinfo->f->m_face_index);
+ if (sinfo->strim_norms->find(sinfo->f->m_face_index) ==
sinfo->strim_norms->end()) {
+ //bu_log("Face %d has no singular trim normal information\n",
sinfo->f->m_face_index);
+ return NULL;
+ }
+ std::map<int, ON_3dPoint *>::iterator m_it;
+ // Check the trims to see if uc,vc is on one of them
+ for (m_it = sinfo->strim_pnts->begin(); m_it !=
sinfo->strim_pnts->end(); m_it++) {
+ //bu_log(" trim %d\n", (*m_it).first);
+ ON_Interval trim_dom =
sinfo->f->Brep()->m_T[(*m_it).first].Domain();
+ ON_2dPoint p2d1 =
sinfo->f->Brep()->m_T[(*m_it).first].PointAt(trim_dom.m_t[0]);
+ ON_2dPoint p2d2 =
sinfo->f->Brep()->m_T[(*m_it).first].PointAt(trim_dom.m_t[1]);
+ //bu_log(" points: %f,%f -> %f,%f\n", p2d1.x, p2d1.y, p2d2.x,
p2d2.y);
+ int on_trim = 1;
+ if (NEAR_EQUAL(p2d1.x, p2d2.x, ON_ZERO_TOLERANCE)) {
+ if (!NEAR_EQUAL(p2d1.x, uc, ON_ZERO_TOLERANCE)) {
+ on_trim = 0;
+ }
+ } else {
+ if (!NEAR_EQUAL(p2d1.x, uc, ON_ZERO_TOLERANCE) &&
!NEAR_EQUAL(p2d2.x, uc, ON_ZERO_TOLERANCE)) {
+ if (!((uc > p2d1.x && uc < p2d2.x) || (uc < p2d1.x && uc >
p2d2.x))) {
+ on_trim = 0;
+ }
+ }
+ }
+ if (NEAR_EQUAL(p2d1.y, p2d2.y, ON_ZERO_TOLERANCE)) {
+ if (!NEAR_EQUAL(p2d1.y, vc, ON_ZERO_TOLERANCE)) {
+ on_trim = 0;
+ }
+ } else {
+ if (!NEAR_EQUAL(p2d1.y, vc, ON_ZERO_TOLERANCE) &&
!NEAR_EQUAL(p2d2.y, vc, ON_ZERO_TOLERANCE)) {
+ if (!((vc > p2d1.y && vc < p2d2.y) || (vc < p2d1.y && vc >
p2d2.y))) {
+ on_trim = 0;
+ }
+ }
+ }
+
+ if (on_trim) {
+ if (sinfo->strim_norms->find((*m_it).first) !=
sinfo->strim_norms->end()) {
+ ON_3dPoint *vnorm = NULL;
+ vnorm = (*sinfo->strim_norms)[(*m_it).first];
+ //bu_log(" normal: %f, %f, %f\n", vnorm->x, vnorm->y,
vnorm->z);
+ return vnorm;
+ } else {
+ bu_log("Face %d: on singular trim, but no matching normal:
%f, %f\n", sinfo->f->m_face_index, uc, vc);
+ return NULL;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+static bool EdgeSegCallback(void *data, void *a_context) {
+ struct BrepEdgeSegment *eseg = (struct BrepEdgeSegment *)data;
+ std::set<struct BrepEdgeSegment *> *segs = (std::set<struct
BrepEdgeSegment *> *)a_context;
+ segs->insert(eseg);
+ return true;
+}
+
+struct trim_seg_context {
+ const ON_2dPoint *p;
+ bool on_edge;
+};
+
+static bool TrimSegCallback(void *data, void *a_context) {
+ cdt_mesh::cpolyedge_t *pe = (cdt_mesh::cpolyedge_t *)data;
+ struct trim_seg_context *sc = (struct trim_seg_context *)a_context;
+ ON_2dPoint p2d1(pe->polygon->pnts_2d[pe->v[0]].first,
pe->polygon->pnts_2d[pe->v[0]].second);
+ ON_2dPoint p2d2(pe->polygon->pnts_2d[pe->v[1]].first,
pe->polygon->pnts_2d[pe->v[1]].second);
+ ON_Line l(p2d1, p2d2);
+ double t;
+ if (l.ClosestPointTo(*sc->p, &t)) {
+ // If the closest point on the line isn't in the line segment, skip
+ if (t < 0 || t > 1) return true;
+ }
+ double dist = l.MinimumDistanceTo(*sc->p);
+ if (NEAR_ZERO(dist, BN_TOL_DIST)) {
+ sc->on_edge = true;
+ }
+ return (sc->on_edge) ? false : true;
+}
+
+
+/* If we've got trimming curves involved, we need to be more careful about
respecting
+ * the min edge distance. */
+static bool involves_trims(double *min_edge, struct cdt_surf_info_2 *sinfo,
ON_3dPoint &p1, ON_3dPoint &p2)
+{
+ double min_edge_dist = sinfo->max_edge;
+
+ // Bump out the intersection box a bit - we want to be aggressive when
adapting to local
+ // trimming curve segments
+ ON_3dPoint wpc = (p1+p2) * 0.5;
+ ON_3dVector vec1 = p1 - wpc;
+ ON_3dVector vec2 = p2 - wpc;
+ ON_3dPoint wp1 = wpc + (vec1 * 1.1);
+ ON_3dPoint wp2 = wpc + (vec2 * 1.1);
+
+ ON_BoundingBox uvbb;
+ uvbb.Set(wp1, true);
+ uvbb.Set(wp2, true);
+
+ //plot_on_bbox(uvbb, "uvbb.plot3");
+
+ //plot_rtree_3d(sinfo->s_cdt->edge_segs_3d[sinfo->f->m_face_index],
"rtree.plot3");
+
+ double fMin[3];
+ fMin[0] = wp1.x;
+ fMin[1] = wp1.y;
+ fMin[2] = wp1.z;
+ double fMax[3];
+ fMax[0] = wp2.x;
+ fMax[1] = wp2.y;
+ fMax[2] = wp2.z;
+
+ std::set<struct BrepEdgeSegment *> segs;
+ size_t nhits =
sinfo->s_cdt->edge_segs_3d[sinfo->f->m_face_index].Search(fMin, fMax,
EdgeSegCallback, (void *)&segs);
+ //bu_log("new tree found %zu boxes and %zu segments\n", nhits,
segs.size());
+
+ if (!nhits) {
+ return false;
+ }
+
+ if (nhits > 40) {
+ // Lot of edges, probably a high level box - just return max_edge
+ (*min_edge) = min_edge_dist;
+ return true;
+ }
+
+ std::set<struct BrepEdgeSegment *>::iterator s_it;
+ for (s_it = segs.begin(); s_it != segs.end(); s_it++) {
+ struct BrepEdgeSegment *seg = *s_it;
+ ON_BoundingBox lbb;
+ lbb.Set(*seg->sbtp1->p3d, true);
+ lbb.Set(*seg->ebtp1->p3d, true);
+ if (!uvbb.IsDisjoint(lbb)) {
+ fastf_t dist = lbb.Diagonal().Length();
+ if ((dist > BN_TOL_DIST) && (dist < min_edge_dist)) {
+ min_edge_dist = dist;
+ }
+ }
+ }
+ (*min_edge) = min_edge_dist;
+
+ return true;
+}
+
+/* flags identifying which side of the surface we're calculating
+ *
+ * u_upper
+ * (2,0)
+ *
+ * u1v2---------------- u2v2
+ * | | |
+ * | | |
+ * | u_lmid | |
+ * v_lower |----------|---------| v_upper
+ * (0,1) | (1,0) | | (2,1)
+ * | v|lmid |
+ * | |(1,1) |
+ * u1v1-----------------u2v1
+ *
+ * u_lower
+ * (0,0)
+ */
+static double
+_cdt_get_uv_edge_3d_len(struct cdt_surf_info_2 *sinfo, int c1, int c2)
+{
+ int line_set = 0;
+ double wu1, wv1, wu2, wv2, umid, vmid = 0.0;
+
+ /* u_lower */
+ if (c1 == 0 && c2 == 0) {
+ wu1 = sinfo->u1;
+ wu2 = sinfo->u2;
+ wv1 = sinfo->v1;
+ wv2 = sinfo->v1;
+ umid = (sinfo->u2 - sinfo->u1)/2.0;
+ vmid = sinfo->v1;
+ line_set = 1;
+ }
+
+ /* u_lmid */
+ if (c1 == 1 && c2 == 0) {
+ wu1 = sinfo->u1;
+ wu2 = sinfo->u2;
+ wv1 = (sinfo->v2 - sinfo->v1)/2.0;
+ wv2 = (sinfo->v2 - sinfo->v1)/2.0;
+ umid = (sinfo->u2 - sinfo->u1)/2.0;
+ vmid = (sinfo->v2 - sinfo->v1)/2.0;
+ line_set = 1;
+ }
+
+ /* u_upper */
+ if (c1 == 2 && c2 == 0) {
+ wu1 = sinfo->u1;
+ wu2 = sinfo->u2;
+ wv1 = sinfo->v2;
+ wv2 = sinfo->v2;
+ umid = (sinfo->u2 - sinfo->u1)/2.0;
+ vmid = sinfo->v2;
+ line_set = 1;
+ }
+
+ /* v_lower */
+ if (c1 == 0 && c2 == 1) {
+ wu1 = sinfo->u1;
+ wu2 = sinfo->u1;
+ wv1 = sinfo->v1;
+ wv2 = sinfo->v2;
+ umid = sinfo->u1;
+ vmid = (sinfo->v2 - sinfo->v1)/2.0;
+ line_set = 1;
+ }
+
+ /* v_lmid */
+ if (c1 == 1 && c2 == 1) {
+ wu1 = (sinfo->u2 - sinfo->u1)/2.0;
+ wu2 = (sinfo->u2 - sinfo->u1)/2.0;
+ wv1 = sinfo->v1;
+ wv2 = sinfo->v2;
+ umid = (sinfo->u2 - sinfo->u1)/2.0;
+ vmid = (sinfo->v2 - sinfo->v1)/2.0;
+ line_set = 1;
+ }
+
+ /* v_upper */
+ if (c1 == 2 && c2 == 1) {
+ wu1 = sinfo->u2;
+ wu2 = sinfo->u2;
+ wv1 = sinfo->v1;
+ wv2 = sinfo->v2;
+ umid = sinfo->u2;
+ vmid = (sinfo->v2 - sinfo->v1)/2.0;
+ line_set = 1;
+ }
+
+ if (!line_set) {
+ bu_log("Invalid edge %d, %d specified\n", c1, c2);
+ return DBL_MAX;
+ }
+
+ // 1st 3d point
+ ON_3dPoint p1 = sinfo->s->PointAt(wu1, wv1);
+
+ // middle 3d point
+ ON_3dPoint pmid = sinfo->s->PointAt(umid, vmid);
+
+ // last 3d point
+ ON_3dPoint p2 = sinfo->s->PointAt(wu2, wv2);
+
+ // length
+ double d1 = pmid.DistanceTo(p1);
+ double d2 = p2.DistanceTo(pmid);
+ return d1+d2;
+}
+
+void
+filter_surface_edge_pnts_2(struct cdt_surf_info_2 *sinfo)
+{
+ // TODO - it's looking like a 2D check isn't going to be enough - we
probably
+ // need BOTH a 2D and a 3D check to make sure none of the points are in a
+ // position that will cause trouble. Will need to build a 3D RTree of the
line
+ // segments from the edges, as well as 2D rt_trims tree.
+ std::set<ON_2dPoint *> rm_pnts;
+ std::set<ON_2dPoint *>::iterator osp_it;
+ for (osp_it = sinfo->on_surf_points.begin(); osp_it !=
sinfo->on_surf_points.end(); osp_it++) {
+ const ON_2dPoint *p = *osp_it;
+ double fMin[2];
+ double fMax[2];
+ fMin[0] = p->x - ON_ZERO_TOLERANCE;
+ fMin[1] = p->y - ON_ZERO_TOLERANCE;
+ fMax[0] = p->x + ON_ZERO_TOLERANCE;
+ fMax[1] = p->y + ON_ZERO_TOLERANCE;
+ struct trim_seg_context sc;
+ sc.p = p;
+ sc.on_edge = false;
+ sinfo->rt_trims->Search(fMin, fMax, TrimSegCallback, (void *)&sc);
+ if (sc.on_edge) {
+ rm_pnts.insert((ON_2dPoint *)p);
+ }
+ }
+
+ for (osp_it = rm_pnts.begin(); osp_it != rm_pnts.end(); osp_it++) {
+ const ON_2dPoint *p = *osp_it;
+ sinfo->on_surf_points.erase((ON_2dPoint *)p);
+ }
+
+
+ // TODO - In addition to removing points on the line in 2D, we don't want
points that
+ // would be outside the edge polygon in projection. Find the "close" trims
(if any)
+ // for the candidate 3D point, then use the normals of the Brep edge
points and
+ // the edge direction to do a local "inside/outside" test. Not sure yet
exactly how
+ // to do this - possibilities include rtree search for the area around
each surface
+ // point, or a nanoflann based nearest lookup for the edge points to get
candidates
+ // near each edge in turn - in the latter case, look for points common to
the result
+ // sets for both edge points to localize on that particular segment.
+
+ // Populate m_interior_pnts with the final set
+ cdt_mesh::cdt_mesh_t *fmesh =
&sinfo->s_cdt->fmeshes[sinfo->f->m_face_index];
+ for (osp_it = sinfo->on_surf_points.begin(); osp_it !=
sinfo->on_surf_points.end(); osp_it++) {
+ ON_2dPoint n2dp(**osp_it);
+ long f_ind2d = fmesh->add_point(n2dp);
+ fmesh->m_interior_pnts.insert(f_ind2d);
+
+ // Add new 3D point and normal values to the fmesh as well TODO - store
these during
+ // the build-down in sinfo and then just look them up here...
+ }
+}
+
+static bool
+getSurfacePoint(
+ struct cdt_surf_info_2 *sinfo,
+ SPatch &sp,
+ std::queue<SPatch> &nq
+ )
+{
+ fastf_t u1 = sp.umin;
+ fastf_t u2 = sp.umax;
+ fastf_t v1 = sp.vmin;
+ fastf_t v2 = sp.vmax;
+ double ldfactor = 2.0;
+ int split_u = 0;
+ int split_v = 0;
+ ON_2dPoint p2d(0.0, 0.0);
+ fastf_t u = (u1 + u2) / 2.0;
+ fastf_t v = (v1 + v2) / 2.0;
+ fastf_t udist = u2 - u1;
+ fastf_t vdist = v2 - v1;
+
+ if ((udist < sinfo->min_dist + ON_ZERO_TOLERANCE)
+ || (vdist < sinfo->min_dist + ON_ZERO_TOLERANCE)) {
+ return false;
+ }
+
+ double est1 = uline_len_est(sinfo, u1, u2, v1);
+ double est2 = uline_len_est(sinfo, u1, u2, v2);
+ double est3 = vline_len_est(sinfo, u1, v1, v2);
+ double est4 = vline_len_est(sinfo, u2, v1, v2);
+
+ double uavg = (est1+est2)/2.0;
+ double vavg = (est3+est4)/2.0;
+
+#if 0
+ double umin = (est1 < est2) ? est1 : est2;
+ double vmin = (est3 < est4) ? est3 : est4;
+ double umax = (est1 > est2) ? est1 : est2;
+ double vmax = (est3 > est4) ? est3 : est4;
+
+ bu_log("umin,vmin: %f, %f\n", umin, vmin);
+ bu_log("umax,vmax: %f, %f\n", umax, vmax);
+ bu_log("uavg,vavg: %f, %f\n", uavg, vavg);
+ bu_log("min_edge %f\n", sinfo->min_edge);
+#endif
+ if (est1 < 0.01*sinfo->within_dist && est2 < 0.01*sinfo->within_dist) {
+ //bu_log("e12 Small estimates: %f, %f\n", est1, est2);
+ return false;
+ }
+ if (est3 < 0.01*sinfo->within_dist && est4 < 0.01*sinfo->within_dist) {
+ //bu_log("e34 Small estimates: %f, %f\n", est3, est4);
+ return false;
+ }
+
+ if (uavg < sinfo->min_edge && vavg < sinfo->min_edge) {
+ return false;
+ }
+
+
+ if (uavg > ldfactor * vavg) {
+ split_u = 1;
+ }
+
+ if (vavg > ldfactor * uavg) {
+ split_v = 1;
+ }
+
+ ON_3dPoint p[4] = {ON_3dPoint(), ON_3dPoint(), ON_3dPoint(), ON_3dPoint()};
+ ON_3dVector norm[4] = {ON_3dVector(), ON_3dVector(), ON_3dVector(),
ON_3dVector()};
+ bool ev_success = false;
+
+ if (!split_u || !split_v) {
+ // Don't know if we're splitting in at least one direction - check if
we're close
+ // enough to trims to need to worry about edges
+
+ double min_edge_len = -1.0;
+
+ // If we're dealing with a curved surface, don't get bigger than
max_edge
+ if (!sinfo->s->IsPlanar(NULL, BN_TOL_DIST)) {
+ min_edge_len = sinfo->max_edge;
+ if (uavg > min_edge_len && vavg > min_edge_len) {
+ split_u = 1;
+ }
+
+ if (uavg > min_edge_len && vavg > min_edge_len) {
+ split_v = 1;
+ }
+ }
+
+ // If the above test didn't resolve things, keep going
+ if (!split_u || !split_v) {
+ if ((surface_EvNormal(sinfo->s, u1, v1, p[0], norm[0]))
+ && (surface_EvNormal(sinfo->s, u2, v1, p[1], norm[1]))
+ && (surface_EvNormal(sinfo->s, u2, v2, p[2], norm[2]))
+ && (surface_EvNormal(sinfo->s, u1, v2, p[3], norm[3]))) {
+
+ ON_BoundingBox uvbb;
+ for (int i = 0; i < 4; i++) {
+ uvbb.Set(p[i], true);
+ }
+ //plot_on_bbox(uvbb, "uvbb.plot3");
+
+ ON_3dPoint pmin = uvbb.Min();
+ ON_3dPoint pmax = uvbb.Max();
+ if (involves_trims(&min_edge_len, sinfo, pmin, pmax)) {
+
+ if (min_edge_len > 0 && uavg > min_edge_len && vavg >
min_edge_len) {
+ split_u = 1;
+ }
+
+ if (min_edge_len > 0 && uavg > min_edge_len && vavg >
min_edge_len) {
+ split_v = 1;
+ }
+ }
+
+ ev_success = true;
+ }
+ }
+ }
+
+
+ if (ev_success && (!split_u || !split_v)) {
+ // Don't know if we're splitting in at least one direction - check dot
products
+ ON_3dPoint mid(0.0, 0.0, 0.0);
+ ON_3dVector norm_mid(0.0, 0.0, 0.0);
+ if ((surface_EvNormal(sinfo->s, u2, v1, p[1], norm[1])) // for u
+ && (surface_EvNormal(sinfo->s, u1, v2, p[3], norm[3]))
+ && (surface_EvNormal(sinfo->s, u, v, mid, norm_mid))) {
+ double udot;
+ double vdot;
+ ON_Line line1(p[0], p[2]);
+ ON_Line line2(p[1], p[3]);
+ double dist = mid.DistanceTo(line1.ClosestPointTo(mid));
+ V_MAX(dist, mid.DistanceTo(line2.ClosestPointTo(mid)));
+
+ for (int i = 0; i < 4; i++) {
+ fastf_t uc = (i == 0 || i == 3) ? u1 : u2;
+ fastf_t vc = (i == 0 || i == 1) ? v1 : v2;
+ ON_3dPoint *vnorm = singular_trim_norm(sinfo, uc, vc);
+ if (vnorm && ON_DotProduct(*vnorm, norm_mid) > 0) {
+ //bu_log("vert norm %f %f %f works\n", vnorm->x, vnorm->y,
vnorm->z);
+ norm[i] = *vnorm;
+ }
+ }
+
+
+ if (dist < sinfo->min_dist + ON_ZERO_TOLERANCE) {
+ return false;
+ }
+
+ udot = (VNEAR_EQUAL(norm[0], norm[1], ON_ZERO_TOLERANCE)) ? 1.0 :
norm[0] * norm[1];
+ vdot = (VNEAR_EQUAL(norm[0], norm[3], ON_ZERO_TOLERANCE)) ? 1.0 :
norm[0] * norm[3];
+ if (udot < sinfo->cos_within_ang - ON_ZERO_TOLERANCE) {
+ split_u = 1;
+ }
+ if (vdot < sinfo->cos_within_ang - ON_ZERO_TOLERANCE) {
+ split_v = 1;
+ }
+ }
+ }
+
+ if (split_u && split_v) {
+ nq.push(SPatch(u1, u, v1, v));
+ nq.push(SPatch(u1, u, v, v2));
+ nq.push(SPatch(u, u2, v1, v));
+ nq.push(SPatch(u, u2, v, v2));
+ return true;
+ }
+ if (split_u) {
+ nq.push(SPatch(u1, u, v1, v2));
+ nq.push(SPatch(u, u2, v1, v2));
+ return true;
+ }
+ if (split_v) {
+ nq.push(SPatch(u1, u2, v1, v));
+ nq.push(SPatch(u1, u2, v, v2));
+ return true;
+ }
+
+ return false;
+}
+
+void
+GetInteriorPnts(struct ON_Brep_CDT_State *s_cdt, int face_index)
+{
+ double surface_width, surface_height;
+
+ ON_BrepFace &face = s_cdt->brep->m_F[face_index];
+ const ON_Surface *s = face.SurfaceOf();
+ const ON_Brep *brep = face.Brep();
+
+ if (s->GetSurfaceSize(&surface_width, &surface_height)) {
+ double dist = 0.0;
+ double min_dist = 0.0;
+ double within_dist = 0.0;
+ double cos_within_ang = 0.0;
+
+ if ((surface_width < BN_TOL_DIST) || (surface_height < BN_TOL_DIST)) {
+ return;
+ }
+
+ struct cdt_surf_info_2 sinfo;
+ sinfo.s_cdt = s_cdt;
+ sinfo.s = s;
+ sinfo.f = &face;
+ sinfo.rt_trims = &(s_cdt->trim_segs[face_index]);
+ sinfo.rt_trims_3d = &(s_cdt->edge_segs_3d[face_index]);
+ sinfo.strim_pnts = &(s_cdt->strim_pnts[face_index]);
+ sinfo.strim_norms = &(s_cdt->strim_norms[face_index]);
+ double t1, t2;
+ s->GetDomain(0, &t1, &t2);
+ sinfo.ulen = fabs(t2 - t1);
+ s->GetDomain(1, &t1, &t2);
+ sinfo.vlen = fabs(t2 - t1);
+ s->GetDomain(0, &sinfo.u1, &sinfo.u2);
+ s->GetDomain(1, &sinfo.v1, &sinfo.v2);
+ sinfo.u_lower_3dlen = _cdt_get_uv_edge_3d_len(&sinfo, 0, 0);
+ sinfo.u_mid_3dlen = _cdt_get_uv_edge_3d_len(&sinfo, 1, 0);
+ sinfo.u_upper_3dlen = _cdt_get_uv_edge_3d_len(&sinfo, 2, 0);
+ sinfo.v_lower_3dlen = _cdt_get_uv_edge_3d_len(&sinfo, 0, 1);
+ sinfo.v_mid_3dlen = _cdt_get_uv_edge_3d_len(&sinfo, 1, 1);
+ sinfo.v_upper_3dlen = _cdt_get_uv_edge_3d_len(&sinfo, 2, 1);
+ sinfo.min_edge = (*s_cdt->min_edge_seg_len)[face_index];
+ sinfo.max_edge = (*s_cdt->max_edge_seg_len)[face_index];
+
+ // may be a smaller trimmed subset of surface so worth getting
+ // face boundary
+ bool bGrowBox = false;
+ ON_3dPoint min, max;
+ for (int li = 0; li < face.LoopCount(); li++) {
+ for (int ti = 0; ti < face.Loop(li)->TrimCount(); ti++) {
+ const ON_BrepTrim *trim = face.Loop(li)->Trim(ti);
+ trim->GetBoundingBox(min, max, bGrowBox);
+ bGrowBox = true;
+ }
+ }
+
+ ON_BoundingBox tight_bbox;
+ if (brep->GetTightBoundingBox(tight_bbox)) {
+ // Note: this needs to be based on the smallest dimension of the
+ // box, not the diagonal, in case we've got something really long
+ // and narrow.
+ fastf_t d1 = tight_bbox.m_max[0] - tight_bbox.m_min[0];
+ fastf_t d2 = tight_bbox.m_max[1] - tight_bbox.m_min[1];
+ dist = (d1 < d2) ? d1 : d2;
+ }
+
+ if (s_cdt->tol.abs < BN_TOL_DIST + ON_ZERO_TOLERANCE) {
+ min_dist = BN_TOL_DIST;
+ } else {
+ min_dist = s_cdt->tol.abs;
+ }
+
+ double rel = 0.0;
+ if (s_cdt->tol.rel > 0.0 + ON_ZERO_TOLERANCE) {
+ rel = s_cdt->tol.rel * dist;
+ within_dist = rel < min_dist ? min_dist : rel;
+ //if (s_cdt->abs < s_cdt->dist + ON_ZERO_TOLERANCE) {
+ // min_dist = within_dist;
+ //}
+ } else if ((s_cdt->tol.abs > 0.0 + ON_ZERO_TOLERANCE)
+ && (s_cdt->tol.norm < 0.0 + ON_ZERO_TOLERANCE)) {
+ within_dist = min_dist;
+ } else if ((s_cdt->tol.abs > 0.0 + ON_ZERO_TOLERANCE)
+ || (s_cdt->tol.norm > 0.0 + ON_ZERO_TOLERANCE)) {
+ within_dist = dist;
+ } else {
+ within_dist = 0.01 * dist; // default to 1% minimum surface distance
+ }
+
+ if (s_cdt->tol.norm > 0.0 + ON_ZERO_TOLERANCE) {
+ cos_within_ang = cos(s_cdt->tol.norm);
+ } else {
+ cos_within_ang = cos(ON_PI / 2.0);
+ }
+
+ sinfo.min_dist = min_dist;
+ sinfo.within_dist = within_dist;
+ sinfo.cos_within_ang = cos_within_ang;
+
+ std::queue<SPatch> spq1, spq2;
+
+ /**
+ * Sample portions of the surface to collect sufficient points
+ * to capture the surface shape according to the settings
+ *
+ * M = max
+ * m = min
+ * o = mid
+ *
+ * umvM------uovM-------uMvM
+ * | | |
+ * | | |
+ * | | |
+ * umvo------uovo-------uMvo
+ * | | |
+ * | | |
+ * | | |
+ * umvm------uovm-------uMvm
+ *
+ * left bottom = umvm
+ * left midy = umvo
+ * left top = umvM
+ * midx bottom = uovm
+ * midx midy = uovo
+ * midx top = uovM
+ * right bottom = uMvm
+ * right midy = uMvo
+ * right top = uMvM
+ */
+
+ ON_BOOL32 uclosed = s->IsClosed(0);
+ ON_BOOL32 vclosed = s->IsClosed(1);
+ double midx = (min.x + max.x) / 2.0;
+ double midy = (min.y + max.y) / 2.0;
+
+ if (uclosed && vclosed) {
+ /*
+ * #--------------------#
+ * | | |
+ * | | |
+ * | | |
+ * umvo------uovo--------#
+ * | | |
+ * | | |
+ * | | |
+ * umvm------uovm--------#
+ */
+ spq1.push(SPatch(min.x, midx, min.y, midy));
+
+ /*
+ * #----------#---------#
+ * | | |
+ * | | |
+ * | | |
+ * #--------uovo-------uMvo
+ * | | |
+ * | | |
+ * | | |
+ * #--------uovm-------uMvm
+ */
+ spq1.push(SPatch(midx, max.x, min.y, midy));
+
+ /*
+ * umvM------uovM--------#
+ * | | |
+ * | | |
+ * | | |
+ * umvo------uovo--------#
+ * | | |
+ * | | |
+ * | | |
+ * #----------#---------#
+ */
+ spq1.push(SPatch(min.x, midx, midy, max.y));
+
+ /*
+ * #--------uovM------ uMvM
+ * | | |
+ * | | |
+ * | | |
+ * #--------uovo-------uMvo
+ * | | |
+ * | | |
+ * | | |
+ * #----------#---------#
+ */
+ spq1.push(SPatch(midx, max.x, midy, max.y));
+
+ } else if (uclosed) {
+
+ /*
+ * umvM------uovM--------#
+ * | | |
+ * | | |
+ * | | |
+ * #----------#---------#
+ * | | |
+ * | | |
+ * | | |
+ * umvm------uovm--------#
+ */
+ spq1.push(SPatch(min.x, midx, min.y, max.y));
+
+ /*
+ * #--------uovM------ uMvM
+ * | | |
+ * | | |
+ * | | |
+ * #----------#---------#
+ * | | |
+ * | | |
+ * | | |
+ * #--------uovm-------uMvm
+ */
+ spq1.push(SPatch(midx, max.x, min.y, max.y));
+
+ } else if (vclosed) {
+
+ /*
+ * #----------#---------#
+ * | | |
+ * | | |
+ * | | |
+ * umvo--------#--------uMvo
+ * | | |
+ * | | |
+ * | | |
+ * umvm--------#--------uMvm
+ */
+ spq1.push(SPatch(min.x, max.x, min.y, midy));
+
+ /*
+ * umvM--------#------- uMvM
+ * | | |
+ * | | |
+ * | | |
+ * umvo--------#--------uMvo
+ * | | |
+ * | | |
+ * | | |
+ * #----------#---------#
+ */
+ spq1.push(SPatch(min.x, max.x, midy, max.y));
+
+ } else {
+
+ /*
+ * umvM--------#------- uMvM
+ * | | |
+ * | | |
+ * | | |
+ * #----------#---------#
+ * | | |
+ * | | |
+ * | | |
+ * umvm--------#--------uMvm
+ */
+ spq1.push(SPatch(min.x, max.x, min.y, max.y));
+ }
+
+ std::queue<SPatch> *wq = &spq1;
+ std::queue<SPatch> *nq = &spq2;
+ int split_depth = 0;
+
+ while (!wq->empty()) {
+ SPatch sp = wq->front();
+ wq->pop();
+ if (!getSurfacePoint(&sinfo, sp, *nq)) {
+ ON_BoundingBox
bb(ON_2dPoint(sp.umin,sp.vmin),ON_2dPoint(sp.umax, sp.vmax));
+ sinfo.leaf_bboxes.insert(new ON_BoundingBox(bb));
+ }
+
+ // Once we've processed the current level,
+ // work on the next if we need to
+ if (wq->empty() && !nq->empty()) {
+ std::queue<SPatch> *tq = wq;
+ wq = nq;
+ nq = tq;
+ // Let the counter know we're going deeper
+ split_depth++;
+ }
+ }
+
+ float *prand;
+ std::set<ON_BoundingBox *>::iterator b_it;
+ /* We want to jitter sampled 2D points out of linearity */
+ bn_rand_init(prand, 0);
+ for (b_it = sinfo.leaf_bboxes.begin(); b_it != sinfo.leaf_bboxes.end();
b_it++) {
+ ON_3dPoint p3d = (*b_it)->Center();
+ ON_3dPoint pmax = (*b_it)->Max();
+ ON_3dPoint pmin = (*b_it)->Min();
+ double ulen = pmax.x - pmin.x;
+ double vlen = pmax.y - pmin.y;
+ double px = p3d.x + (bn_rand_half(prand) * 0.3*ulen);
+ double py = p3d.y + (bn_rand_half(prand) * 0.3*vlen);
+ sinfo.on_surf_points.insert(new ON_2dPoint(px,py));
+ }
+
+ // Strip out points from the surface that are on the trimming curves.
Trim
+ // points require special handling for watertightness and introducing
them
+ // from the surface also runs the risk of adding duplicate 2D points,
which
+ // aren't allowed for facetization.
+ filter_surface_edge_pnts_2(&sinfo);
+
+ }
+}
+
+
+/** @} */
+
+// Local Variables:
+// mode: C++
+// tab-width: 8
+// c-basic-offset: 4
+// indent-tabs-mode: t
+// c-file-style: "stroustrup"
+// End:
+// ex: shiftwidth=4 tabstop=8
+
Property changes on: brlcad/trunk/src/libbrep/cdt_surf2.cpp
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
_______________________________________________
BRL-CAD Source Commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/brlcad-commits