Revision: 73855
http://sourceforge.net/p/brlcad/code/73855
Author: starseeker
Date: 2019-09-07 22:51:47 +0000 (Sat, 07 Sep 2019)
Log Message:
-----------
We're accumulating a fair bit of specialized edge logic again - break it back
out so the top level flow is easier to follow.
Modified Paths:
--------------
brlcad/trunk/src/libbrep/CMakeLists.txt
brlcad/trunk/src/libbrep/cdt.cpp
brlcad/trunk/src/libbrep/cdt.h
Added Paths:
-----------
brlcad/trunk/src/libbrep/cdt_edge.cpp
Modified: brlcad/trunk/src/libbrep/CMakeLists.txt
===================================================================
--- brlcad/trunk/src/libbrep/CMakeLists.txt 2019-09-07 21:56:13 UTC (rev
73854)
+++ brlcad/trunk/src/libbrep/CMakeLists.txt 2019-09-07 22:51:47 UTC (rev
73855)
@@ -28,6 +28,7 @@
cdt_util.cpp
cdt_validate.cpp
cdt.cpp
+ cdt_edge.cpp
cdt_mesh.cpp
intersect.cpp
libbrep_brep_tools.cpp
Modified: brlcad/trunk/src/libbrep/cdt.cpp
===================================================================
--- brlcad/trunk/src/libbrep/cdt.cpp 2019-09-07 21:56:13 UTC (rev 73854)
+++ brlcad/trunk/src/libbrep/cdt.cpp 2019-09-07 22:51:47 UTC (rev 73855)
@@ -68,268 +68,7 @@
std::cout << "\n";
}
#endif
-#if 0
-void
-debug_bseg(cdt_mesh::bedge_seg_t *bseg, int seg_id)
-{
-#if 0
- int face_index = 34;
- if (bseg->edge_ind < 93 && bseg->edge_ind > 96) return;
-#endif
- ON_BrepEdge& edge = bseg->brep->m_E[bseg->edge_ind];
- ON_BrepTrim *trim1 = edge.Trim(0);
- ON_BrepTrim *trim2 = edge.Trim(1);
- if (!trim1 || !trim2) return ;
-#if 0
- if (trim1->Face()->m_face_index != face_index &&
trim2->Face()->m_face_index != face_index) return;
- ON_BrepTrim *ftrim = (trim1->Face()->m_face_index == face_index) ? trim1 :
trim2;
- cdt_mesh::cpolyedge_t *tseg = (bseg->tseg1->trim_ind ==
ftrim->m_trim_index) ? bseg->tseg1 : bseg->tseg2;
-
- std::cout << "bseg " << bseg->edge_ind << "-" << seg_id << ", trim " <<
tseg->trim_ind << " (" << bseg->brep->m_T[tseg->trim_ind].m_bRev3d << "):\n";
- std::cout << " edge point start (x,y,z): (" << bseg->e_start->x << ","
<< bseg->e_start->y << "," << bseg->e_start->z << ")\n";
- ON_3dPoint es = bseg->nc->PointAt(bseg->edge_start);
- std::cout << " edge_start (t)(x,y,z): (" << bseg->edge_start << ") (" <<
es.x << "," << es.y << "," << es.z << ")\n";
- std::cout << " edge point end (x,y,z): (" << bseg->e_end->x << "," <<
bseg->e_end->y << "," << bseg->e_end->z << ")\n";
- ON_3dPoint ee = bseg->nc->PointAt(bseg->edge_end);
- std::cout << " edge_end (t)(x,y,z): (" << bseg->edge_end << ") (" <<
ee.x << "," << ee.y << "," << ee.z << ")\n";
-
- ON_2dPoint p2s = ftrim->PointAt(tseg->trim_start);
- ON_2dPoint p2e = ftrim->PointAt(tseg->trim_end);
- ON_3dPoint p3s = ftrim->SurfaceOf()->PointAt(p2s.x, p2s.y);
- ON_3dPoint p3e = ftrim->SurfaceOf()->PointAt(p2e.x, p2e.y);
- std::cout << " start point: p2d(x,y): " << p2s.x << "," << p2s.y << ")
p3d(x,y,z): (" << p3s.x << "," << p3s.y << "," << p3s.z << ")\n";
- std::cout << " end point : p2d(x,y): " << p2e.x << "," << p2e.y << ")
p3d(x,y,z): (" << p3e.x << "," << p3e.y << "," << p3e.z << ")\n";
-
- if (ftrim->m_bRev3d) {
- if (bseg->e_start->DistanceTo(p3e) > BN_TOL_DIST) {
- std::cout << " WARNING - bseg edge and trim start points
don't match\n";
- }
- if (bseg->e_end->DistanceTo(p3s) > BN_TOL_DIST) {
- std::cout << " WARNING - bseg edge and trim end points
don't match\n";
- }
- } else {
- if (bseg->e_start->DistanceTo(p3s) > BN_TOL_DIST) {
- std::cout << " WARNING - bseg edge and trim start points
don't match\n";
- }
- if (bseg->e_end->DistanceTo(p3e) > BN_TOL_DIST) {
- std::cout << " WARNING - bseg edge and trim end points
don't match\n";
- }
- }
-#endif
-
- std::cout << "bseg " << bseg->edge_ind << "-" << seg_id << ":\n";
- std::cout << "tseg1(" << bseg->tseg1->v[0] << "," << bseg->tseg1->v[1] <<
") polygon: ";
- bseg->tseg1->polygon->print();
- std::cout << "tseg2(" << bseg->tseg2->v[0] << "," << bseg->tseg2->v[1] <<
") polygon: ";
- bseg->tseg2->polygon->print();
- std::cout << "\n";
-
-}
-#endif
-
-void
-rtree_bbox_2d(struct ON_Brep_CDT_State *s_cdt, cdt_mesh::cpolyedge_t *pe)
-{
- ON_BrepTrim& trim = s_cdt->brep->m_T[pe->trim_ind];
- ON_2dPoint p2d1 = trim.PointAt(pe->trim_start);
- ON_2dPoint p2d2 = trim.PointAt(pe->trim_end);
- ON_Line line(p2d1, p2d2);
- ON_BoundingBox bb = line.BoundingBox();
- bb.m_max.x = bb.m_max.x + ON_ZERO_TOLERANCE;
- bb.m_max.y = bb.m_max.y + ON_ZERO_TOLERANCE;
- bb.m_min.x = bb.m_min.x - ON_ZERO_TOLERANCE;
- bb.m_min.y = bb.m_min.y - ON_ZERO_TOLERANCE;
-
- double dist = p2d1.DistanceTo(p2d2);
- double bdist = 0.5*dist;
- double xdist = bb.m_max.x - bb.m_min.x;
- double ydist = bb.m_max.y - bb.m_min.y;
- // If we're close to the edge, we want to know - the Search callback will
- // check the precise distance and make a decision on what to do.
- if (xdist < bdist) {
- bb.m_min.x = bb.m_min.x - 0.5*bdist;
- bb.m_max.x = bb.m_max.x + 0.5*bdist;
- }
- if (ydist < bdist) {
- bb.m_min.y = bb.m_min.y - 0.5*bdist;
- bb.m_max.y = bb.m_max.y + 0.5*bdist;
- }
-
- double p1[2];
- p1[0] = bb.Min().x;
- p1[1] = bb.Min().y;
- double p2[2];
- p2[0] = bb.Max().x;
- p2[1] = bb.Max().y;
- s_cdt->trim_segs[trim.Face()->m_face_index].Insert(p1, p2, (void *)pe);
-}
-
-void
-rtree_bbox_3d(struct ON_Brep_CDT_State *s_cdt, cdt_mesh::cpolyedge_t *pe)
-{
- if (!pe->eseg) return;
- ON_BrepTrim& trim = s_cdt->brep->m_T[pe->trim_ind];
- ON_3dPoint *p3d1 = pe->eseg->e_start;
- ON_3dPoint *p3d2 = pe->eseg->e_end;
- ON_Line line(*p3d1, *p3d2);
- ON_BoundingBox bb = line.BoundingBox();
- bb.m_max.x = bb.m_max.x + ON_ZERO_TOLERANCE;
- bb.m_max.y = bb.m_max.y + ON_ZERO_TOLERANCE;
- bb.m_max.z = bb.m_max.z + ON_ZERO_TOLERANCE;
- bb.m_min.x = bb.m_min.x - ON_ZERO_TOLERANCE;
- bb.m_min.y = bb.m_min.y - ON_ZERO_TOLERANCE;
- bb.m_min.z = bb.m_min.z - ON_ZERO_TOLERANCE;
-
- double dist = p3d1->DistanceTo(*p3d2);
- double bdist = 0.5*dist;
- double xdist = bb.m_max.x - bb.m_min.x;
- double ydist = bb.m_max.y - bb.m_min.y;
- double zdist = bb.m_max.z - bb.m_min.z;
- // If we're close to the edge, we want to know - the Search callback will
- // check the precise distance and make a decision on what to do.
- if (xdist < bdist) {
- bb.m_min.x = bb.m_min.x - 0.5*bdist;
- bb.m_max.x = bb.m_max.x + 0.5*bdist;
- }
- if (ydist < bdist) {
- bb.m_min.y = bb.m_min.y - 0.5*bdist;
- bb.m_max.y = bb.m_max.y + 0.5*bdist;
- }
- if (zdist < bdist) {
- bb.m_min.z = bb.m_min.z - 0.5*bdist;
- bb.m_max.z = bb.m_max.z + 0.5*bdist;
- }
-
- double p1[3];
- p1[0] = bb.Min().x;
- p1[1] = bb.Min().y;
- p1[2] = bb.Min().z;
- double p2[3];
- p2[0] = bb.Max().x;
- p2[1] = bb.Max().y;
- p2[2] = bb.Max().z;
- s_cdt->edge_segs_3d[trim.Face()->m_face_index].Insert(p1, p2, (void *)pe);
-}
-
-#if 0
-struct rtree_loop_leaf {
- struct ON_Brep_CDT_State *s_cdt;
- int loop_index;
-};
-
-// Used for finding "close" loops that might require further edge splitting
-static void
-rtree_loop_2d(struct ON_Brep_CDT_State *s_cdt, int loop_index)
-{
- ON_BrepLoop& loop = s_cdt->brep->m_L[loop_index];
- ON_BrepFace *face = loop.Face();
-
- struct rtree_loop_leaf *leaf = new struct rtree_loop_leaf;
-
- leaf->s_cdt = s_cdt;
- leaf->loop_index = loop_index;
-
- ON_BoundingBox bb;
- loop.GetBoundingBox(bb);
- bb.m_max.x = bb.m_max.x + ON_ZERO_TOLERANCE;
- bb.m_max.y = bb.m_max.y + ON_ZERO_TOLERANCE;
- bb.m_min.x = bb.m_min.x - ON_ZERO_TOLERANCE;
- bb.m_min.y = bb.m_min.y - ON_ZERO_TOLERANCE;
- double p1[2];
- p1[0] = bb.Min().x;
- p1[1] = bb.Min().y;
- double p2[2];
- p2[0] = bb.Max().x;
- p2[1] = bb.Max().y;
- s_cdt->loops_2d[face->m_face_index].Insert(p1, p2, (void *)leaf);
-}
-
-struct rtree_loop_context {
- double seg_len;
- bool *split_edge;
- double target_len;
-};
-
-static bool Loop2dCallback(void *data, void *a_context) {
- struct rtree_loop_leaf *ldata = (struct rtree_loop_leaf *)data;
- struct rtree_loop_context *edata = (struct rtree_loop_context *)a_context;
-
- // Get loop's median distance
- double lmed = ldata->s_cdt->l_median_len[ldata->loop_index];
- if (edata->seg_len > 5*lmed) {
- *edata->split_edge = true;
- }
- if (edata->target_len > 5*lmed) {
- edata->target_len = 5*lmed;
- }
-
- // Keep checking for other loops - we want the smallest target length
- return true;
-}
-#endif
-
-#if 0
-struct rtree_minsplit_context {
- struct ON_Brep_CDT_State *s_cdt;
- std::set<cdt_mesh::bedge_seg_t *> *split_segs;
- cdt_mesh::cpolyedge_t *cseg;
-};
-
-static bool MinSplit2dCallback(void *data, void *a_context) {
- cdt_mesh::cpolyedge_t *tseg = (cdt_mesh::cpolyedge_t *)data;
- struct rtree_minsplit_context *context= (struct rtree_minsplit_context
*)a_context;
-
- // Intersecting with oneself or immediate neighbors isn't cause for
splitting
- if (tseg == cseg || tseg == cseg->prev || tseg == cseg->next) return true;
-
- // Mark this segment down as a segment to split
- context->split_segs->insert(tseg);
-
- // No need to keep checking if we already know we're going to split
- return false;
-}
-#endif
-
-double
-median_seg_len(std::vector<double> &lsegs)
-{
- // Get the median segment length (https://stackoverflow.com/a/42791986)
- double median, e1, e2;
- std::vector<double>::iterator v1, v2;
-
- if (!lsegs.size()) return -DBL_MAX;
- if (lsegs.size() % 2 == 0) {
- v1 = lsegs.begin() + lsegs.size() / 2 - 1;
- v2 = lsegs.begin() + lsegs.size() / 2;
- std::nth_element(lsegs.begin(), v1, lsegs.end());
- e1 = *v1;
- std::nth_element(lsegs.begin(), v2, lsegs.end());
- e2 = *v2;
- median = (e1+e2)*0.5;
- } else {
- v2 = lsegs.begin() + lsegs.size() / 2;
- std::nth_element(lsegs.begin(), v2, lsegs.end());
- median = *v2;
- }
-
- return median;
-}
-
-double
-edge_median_seg_len(struct ON_Brep_CDT_State *s_cdt, int m_edge_index)
-{
- std::vector<double> lsegs;
- std::set<cdt_mesh::bedge_seg_t *> &epsegs =
s_cdt->e2polysegs[m_edge_index];
- std::set<cdt_mesh::bedge_seg_t *>::iterator e_it;
- for (e_it = epsegs.begin(); e_it != epsegs.end(); e_it++) {
- cdt_mesh::bedge_seg_t *b = *e_it;
- double seg_dist = b->e_start->DistanceTo(*b->e_end);
- lsegs.push_back(seg_dist);
- }
- return median_seg_len(lsegs);
-}
-
ON_3dVector
bseg_tangent(struct ON_Brep_CDT_State *s_cdt, cdt_mesh::bedge_seg_t *bseg,
double eparam, double t1param, double t2param)
{
@@ -357,626 +96,9 @@
return tangent;
}
-ON_3dVector
-trim_normal(ON_BrepTrim *trim, ON_2dPoint &cp)
-{
- ON_3dVector norm = ON_3dVector::UnsetVector;
- if (trim->m_type != ON_BrepTrim::singular) {
- // 3D points are globally unique, but normals are not - the same edge
point may
- // have different normals from two faces at a sharp edge. Calculate the
- // face normal for this point on this surface.
- ON_Plane fplane;
- const ON_Surface *s = trim->SurfaceOf();
- double ptol = s->BoundingBox().Diagonal().Length()*0.001;
- ptol = (ptol < BREP_PLANAR_TOL) ? ptol : BREP_PLANAR_TOL;
- if (s->IsPlanar(&fplane, ptol)) {
- norm = fplane.Normal();
- } else {
- ON_3dPoint tmp1;
- surface_EvNormal(trim->SurfaceOf(), cp.x, cp.y, tmp1, norm);
- }
- if (trim->Face()->m_bRev) {
- norm = -1 * norm;
- }
- //std::cout << "Face " << trim->Face()->m_face_index << ", Loop " <<
trim->Loop()->m_loop_index << " norm: " << norm.x << "," << norm.y << "," <<
norm.z << "\n";
- }
- return norm;
-}
-double
-pnt_binary_search(fastf_t *tparam, const ON_BrepTrim &trim, double tstart,
double tend, ON_3dPoint &edge_3d, double tol, int verbose, int depth, int force)
-{
- double tcparam = (tstart + tend) / 2.0;
- ON_3dPoint trim_2d = trim.PointAt(tcparam);
- const ON_Surface *s = trim.SurfaceOf();
- ON_3dPoint trim_3d = s->PointAt(trim_2d.x, trim_2d.y);
- double dist = edge_3d.DistanceTo(trim_3d);
-
- if (dist > tol && !force) {
- ON_3dPoint trim_start_2d = trim.PointAt(tstart);
- ON_3dPoint trim_end_2d = trim.PointAt(tend);
- ON_3dPoint trim_start_3d = s->PointAt(trim_start_2d.x, trim_start_2d.y);
- ON_3dPoint trim_end_3d = s->PointAt(trim_end_2d.x, trim_end_2d.y);
-
- ON_3dVector v1 = edge_3d - trim_start_3d;
- ON_3dVector v2 = edge_3d - trim_end_3d;
- double sedist = trim_start_3d.DistanceTo(trim_end_3d);
-
- if (verbose) {
- //bu_log("start point (%f %f %f) and end point (%f %f %f)\n",
trim_start_3d.x, trim_start_3d.y, trim_start_3d.z, trim_end_3d.x,
trim_end_3d.y, trim_end_3d.z);
- }
-
- double vdot = ON_DotProduct(v1,v2);
-
- if (vdot < 0 && dist > ON_ZERO_TOLERANCE) {
- //if (verbose)
- // bu_log("(%f - %f - %f (%f): searching left and right
subspans\n", tstart, tcparam, tend, ON_DotProduct(v1,v2));
- double tlparam, trparam;
- double fldist = pnt_binary_search(&tlparam, trim, tstart, tcparam,
edge_3d, tol, verbose, depth+1, 0);
- double frdist = pnt_binary_search(&trparam, trim, tcparam, tend,
edge_3d, tol, verbose, depth+1, 0);
- if (fldist >= 0 && frdist < -1) {
- // if (verbose)
- // bu_log("(%f - %f - %f: going with fldist: %f\n",
tstart, tcparam, tend, fldist);
- (*tparam) = tlparam;
- return fldist;
- }
- if (frdist >= 0 && fldist < -1) {
- // if (verbose)
- // bu_log("(%f - %f - %f: going with frdist: %f\n",
tstart, tcparam, tend, frdist);
- (*tparam) = trparam;
- return frdist;
- }
- if (fldist < -1 && frdist < -1) {
- fldist = pnt_binary_search(&tlparam, trim, tstart, tcparam,
edge_3d, tol, verbose, depth+1, 1);
- frdist = pnt_binary_search(&trparam, trim, tcparam, tend,
edge_3d, tol, verbose, depth+1, 1);
- if (verbose) {
- bu_log("Trim %d: point not in either subspan according to
dot product (distances are %f and %f, distance between sampling segment ends is
%f), forcing the issue\n", trim.m_trim_index, fldist, frdist, sedist);
- }
-
- if ((fldist < frdist) && (fldist < dist)) {
- (*tparam) = tlparam;
- return fldist;
- }
- if ((frdist < fldist) && (frdist < dist)) {
- (*tparam) = trparam;
- return frdist;
- }
- (*tparam) = tcparam;
- return dist;
-
- }
- } else if (NEAR_ZERO(vdot, ON_ZERO_TOLERANCE)) {
- (*tparam) = tcparam;
- return dist;
- } else {
- // Not in this span
- if (verbose && depth < 2) {
- //bu_log("Trim %d: (%f:%f)%f - edge point (%f %f %f) and trim
point (%f %f %f): distance between them is %f, tol is %f, search seg length:
%f\n", trim.m_trim_index, tstart, tend, ON_DotProduct(v1,v2), edge_3d.x,
edge_3d.y, edge_3d.z, trim_3d.x, trim_3d.y, trim_3d.z, dist, tol, sedist);
- }
- if (depth == 0) {
- (*tparam) = tcparam;
- return dist;
- } else {
- return -2;
- }
- }
- }
-
- // close enough - this works
- //if (verbose)
- // bu_log("Workable (%f:%f) - edge point (%f %f %f) and trim point (%f %f
%f): %f, %f\n", tstart, tend, edge_3d.x, edge_3d.y, edge_3d.z, trim_3d.x,
trim_3d.y, trim_3d.z, dist, tol);
-
- (*tparam) = tcparam;
- return dist;
-}
-
-ON_2dPoint
-get_trim_midpt(fastf_t *t, struct ON_Brep_CDT_State *s_cdt,
cdt_mesh::cpolyedge_t *pe, ON_3dPoint &edge_mid_3d, double elen, double
brep_edge_tol)
-{
- int verbose = 1;
- double tol;
- if (!NEAR_EQUAL(brep_edge_tol, ON_UNSET_VALUE, ON_ZERO_TOLERANCE)) {
- tol = brep_edge_tol;
- } else {
- tol = (elen < BN_TOL_DIST) ? 0.01*elen : 0.1*BN_TOL_DIST;
- }
- ON_BrepTrim& trim = s_cdt->brep->m_T[pe->trim_ind];
-
- double tmid;
- double dist = pnt_binary_search(&tmid, trim, pe->trim_start, pe->trim_end,
edge_mid_3d, tol, 0, 0, 0);
- if (dist < 0) {
- if (verbose) {
- bu_log("Warning - could not find suitable trim point\n");
- }
- tmid = (pe->trim_start + pe->trim_end) / 2.0;
- } else {
- if (verbose && (dist > BN_TOL_DIST) && (dist > tol)) {
- if (trim.m_bRev3d) {
- //bu_log("Reversed trim: going with distance %f greater than
desired tolerance %f\n", dist, tol);
- } else {
- //bu_log("Non-reversed trim: going with distance %f greater
than desired tolerance %f\n", dist, tol);
- }
- if (dist > 10*tol) {
- dist = pnt_binary_search(&tmid, trim, pe->trim_start,
pe->trim_end, edge_mid_3d, tol, 0, 0, 0);
- }
- }
- }
-
- ON_2dPoint trim_mid_2d = trim.PointAt(tmid);
- (*t) = tmid;
- return trim_mid_2d;
-}
-
bool
-tol_need_split(struct ON_Brep_CDT_State *s_cdt, cdt_mesh::bedge_seg_t *bseg,
ON_3dPoint &edge_mid_3d)
-{
- ON_Line line3d(*(bseg->e_start), *(bseg->e_end));
- double seg_len = line3d.Length();
-
- double max_allowed = (s_cdt->tol.absmax > ON_ZERO_TOLERANCE) ?
s_cdt->tol.absmax : 1.1*bseg->cp_len;
- double min_allowed = (s_cdt->tol.rel > ON_ZERO_TOLERANCE) ? s_cdt->tol.rel
* bseg->cp_len : 0.0;
- double max_edgept_dist_from_edge = (s_cdt->tol.abs > ON_ZERO_TOLERANCE) ?
s_cdt->tol.abs : seg_len;
- ON_BrepLoop *l1 = s_cdt->brep->m_T[bseg->tseg1->trim_ind].Loop();
- ON_BrepLoop *l2 = s_cdt->brep->m_T[bseg->tseg2->trim_ind].Loop();
- const ON_Surface *s1= l1->SurfaceOf();
- const ON_Surface *s2= l2->SurfaceOf();
- double len_1 = -1;
- double len_2 = -1;
- double s_len;
-
- switch (bseg->edge_type) {
- case 0:
- // singularity splitting is handled in a separate step, since it
isn't based
- // on 3D information
- return false;
- case 1:
- // Curved edge - default assigned values are correct.
- break;
- case 2:
- // Linear edge on non-planar surface - use the median segment
lengths
- // from the trims from non-planar faces associated with this edge
- len_1 = (!s1->IsPlanar(NULL, BN_TOL_DIST)) ?
s_cdt->l_median_len[l1->m_loop_index] : -1;
- len_2 = (!s2->IsPlanar(NULL, BN_TOL_DIST)) ?
s_cdt->l_median_len[l2->m_loop_index] : -1;
- if (len_1 < 0 && len_2 < 0) {
- bu_log("Error - both loops report invalid median lengths\n");
- return false;
- }
- s_len = (len_1 > 0) ? len_1 : len_2;
- s_len = (len_2 > 0 && len_2 < s_len) ? len_2 : s_len;
- max_allowed = 5*s_len;
- min_allowed = 0.2*s_len;
- break;
- case 3:
- // Linear edge connected to one or more non-linear edges. If the
start or end points
- // are the same as the root start or end points, use the median
edge length of the
- // connected edge per the vert lookup.
- if (bseg->e_start == bseg->e_root_start || bseg->e_end ==
bseg->e_root_start) {
- len_1 = s_cdt->v_min_seg_len[bseg->e_root_start];
- }
- if (bseg->e_start == bseg->e_root_end || bseg->e_end ==
bseg->e_root_end) {
- len_2 = s_cdt->v_min_seg_len[bseg->e_root_end];
- }
- if (bseg->e_start == bseg->e_root_start || bseg->e_end ==
bseg->e_root_start) {
- if (len_1 < 0 && len_2 < 0) {
- bu_log("Error - verts report invalid lengths on type 3 line
segment\n");
- return false;
- }
- }
- s_len = (len_1 > 0) ? len_1 : len_2;
- s_len = (len_2 > 0 && len_2 < s_len) ? len_2 : s_len;
- if (s_len > 0) {
- max_allowed = 2*s_len;
- min_allowed = 0.5*s_len;
- }
- break;
- case 4:
- // Linear segment, no curves involved
- break;
- default:
- bu_log("Error - invalid edge type: %d\n", bseg->edge_type);
- return false;
- }
-
-
- if (seg_len > max_allowed) return true;
-
- if (seg_len < min_allowed) return false;
-
- // If we're linear and not already split, tangents and normals won't
change that
- if (bseg->edge_type > 1) return false;
-
- double dist3d = edge_mid_3d.DistanceTo(line3d.ClosestPointTo(edge_mid_3d));
-
- if (dist3d > max_edgept_dist_from_edge) return true;
-
- if ((bseg->tan_start * bseg->tan_end) < s_cdt->cos_within_ang) return true;
-
- ON_3dPoint *n1, *n2;
-
- ON_BrepEdge& edge = s_cdt->brep->m_E[bseg->edge_ind];
- ON_BrepTrim *trim1 = edge.Trim(0);
- ON_BrepFace *face1 = trim1->Face();
- cdt_mesh::cdt_mesh_t *fmesh1 = &s_cdt->fmeshes[face1->m_face_index];
- n1 = fmesh1->normals[fmesh1->nmap[fmesh1->p2ind[bseg->e_start]]];
- n2 = fmesh1->normals[fmesh1->nmap[fmesh1->p2ind[bseg->e_end]]];
-
- if (ON_3dVector(*n1) != ON_3dVector::UnsetVector && ON_3dVector(*n2) !=
ON_3dVector::UnsetVector) {
- if ((ON_3dVector(*n1) * ON_3dVector(*n2)) < s_cdt->cos_within_ang -
VUNITIZE_TOL) return true;
- }
-
- ON_BrepTrim *trim2 = edge.Trim(1);
- ON_BrepFace *face2 = trim2->Face();
- cdt_mesh::cdt_mesh_t *fmesh2 = &s_cdt->fmeshes[face2->m_face_index];
- n1 = fmesh2->normals[fmesh2->nmap[fmesh2->p2ind[bseg->e_start]]];
- n2 = fmesh2->normals[fmesh2->nmap[fmesh2->p2ind[bseg->e_end]]];
-
- if (ON_3dVector(*n1) != ON_3dVector::UnsetVector && ON_3dVector(*n2) !=
ON_3dVector::UnsetVector) {
- if ((ON_3dVector(*n1) * ON_3dVector(*n2)) < s_cdt->cos_within_ang -
VUNITIZE_TOL) return true;
- }
-
- return false;
-}
-
-std::set<cdt_mesh::bedge_seg_t *>
-split_edge_seg(struct ON_Brep_CDT_State *s_cdt, cdt_mesh::bedge_seg_t *bseg,
int force)
-{
- std::set<cdt_mesh::bedge_seg_t *> nedges;
-
- // If we don't have associated segments, we can't do anything
- if (!bseg->tseg1 || !bseg->tseg2 || !bseg->nc) return nedges;
-
- ON_BrepEdge& edge = s_cdt->brep->m_E[bseg->edge_ind];
- ON_BrepTrim *trim1 = &s_cdt->brep->m_T[bseg->tseg1->trim_ind];
- ON_BrepTrim *trim2 = &s_cdt->brep->m_T[bseg->tseg2->trim_ind];
-
- // If we don't have associated trims, we can't do anything
- if (!trim1 || !trim2) return nedges;
-
- ON_BrepFace *face1 = trim1->Face();
- ON_BrepFace *face2 = trim2->Face();
- cdt_mesh::cdt_mesh_t *fmesh1 = &s_cdt->fmeshes[face1->m_face_index];
- cdt_mesh::cdt_mesh_t *fmesh2 = &s_cdt->fmeshes[face2->m_face_index];
-
-
- // Get the 3D midpoint (and tangent, if we can) from the edge curve
- ON_3dPoint edge_mid_3d = ON_3dPoint::UnsetPoint;
- ON_3dVector edge_mid_tan = ON_3dVector::UnsetVector;
- fastf_t emid = (bseg->edge_start + bseg->edge_end) / 2.0;
- bool evtangent_status = bseg->nc->EvTangent(emid, edge_mid_3d,
edge_mid_tan);
- if (!evtangent_status) {
- // EvTangent call failed, get 3d point
- edge_mid_3d = bseg->nc->PointAt(emid);
- edge_mid_tan = ON_3dVector::UnsetVector;
- }
-
- // Unless we're forcing a split this is the point at which we do tolerance
- // based testing to determine whether to proceed with the split or halt.
- if (!force && !tol_need_split(s_cdt, bseg, edge_mid_3d)) {
- return nedges;
- }
-
- // edge_mid_3d is a new point in the cdt and the fmesh, as well as a new
- // edge point - add it to the appropriate containers
- ON_3dPoint *mid_3d = new ON_3dPoint(edge_mid_3d);
- CDT_Add3DPnt(s_cdt, mid_3d, -1, -1, -1, edge.m_edge_index, 0, 0);
- s_cdt->edge_pnts->insert(mid_3d);
-
- // Find the 2D points
- double elen1 =
(bseg->nc->PointAt(bseg->edge_start)).DistanceTo(bseg->nc->PointAt(emid));
- double elen2 =
(bseg->nc->PointAt(emid)).DistanceTo(bseg->nc->PointAt(bseg->edge_end));
- double elen = (elen1 + elen2) * 0.5;
- fastf_t t1mid, t2mid;
- ON_2dPoint trim1_mid_2d, trim2_mid_2d;
- trim1_mid_2d = get_trim_midpt(&t1mid, s_cdt, bseg->tseg1, edge_mid_3d,
elen, edge.m_tolerance);
- trim2_mid_2d = get_trim_midpt(&t2mid, s_cdt, bseg->tseg2, edge_mid_3d,
elen, edge.m_tolerance);
-
- // Update the 2D and 2D->3D info in the fmeshes
- long f1_ind2d = fmesh1->add_point(trim1_mid_2d);
- long f1_ind3d = fmesh1->add_point(mid_3d);
- fmesh1->p2d3d[f1_ind2d] = f1_ind3d;
- long f2_ind2d = fmesh2->add_point(trim2_mid_2d);
- long f2_ind3d = fmesh2->add_point(mid_3d);
- fmesh2->p2d3d[f2_ind2d] = f2_ind3d;
-
- // Trims get their own normals
- ON_3dVector norm1 = trim_normal(trim1, trim1_mid_2d);
- fmesh1->normals.push_back(new ON_3dPoint(norm1));
- long f1_nind = fmesh1->normals.size() - 1;
- fmesh1->nmap[f1_ind3d] = f1_nind;
- ON_3dVector norm2 = trim_normal(trim2, trim2_mid_2d);
- fmesh2->normals.push_back(new ON_3dPoint(norm2));
- long f2_nind = fmesh2->normals.size() - 1;
- fmesh2->nmap[f2_ind3d] = f2_nind;
-
- // From the existing polyedge, make the two new polyedges that will
replace the old one
- cdt_mesh::bedge_seg_t *bseg1 = new cdt_mesh::bedge_seg_t(bseg);
- bseg1->edge_start = bseg->edge_start;
- bseg1->edge_end = emid;
- bseg1->e_start = bseg->e_start;
- bseg1->e_end = mid_3d;
- bseg1->tan_start = bseg->tan_start;
- bseg1->tan_end = edge_mid_tan;
-
- cdt_mesh::bedge_seg_t *bseg2 = new cdt_mesh::bedge_seg_t(bseg);
- bseg2->edge_start = emid;
- bseg2->edge_end = bseg->edge_end;
- bseg2->e_start = mid_3d;
- bseg2->e_end = bseg->e_end;
- bseg2->tan_start = edge_mid_tan;
- bseg2->tan_end = bseg->tan_end;
-
- // Using the 2d mid points, update the polygons associated with tseg1 and
tseg2.
- cdt_mesh::cpolyedge_t *poly1_ne1, *poly1_ne2, *poly2_ne1, *poly2_ne2;
- {
- cdt_mesh::cpolygon_t *poly1 = bseg->tseg1->polygon;
- int v[2];
- v[0] = bseg->tseg1->v[0];
- v[1] = bseg->tseg1->v[1];
- int trim_ind = bseg->tseg1->trim_ind;
- double old_trim_start = bseg->tseg1->trim_start;
- double old_trim_end = bseg->tseg1->trim_end;
- poly1->remove_ordered_edge(cdt_mesh::edge_t(v[0], v[1]));
- long poly1_2dind = poly1->add_point(trim1_mid_2d, f1_ind2d);
- struct cdt_mesh::edge_t poly1_edge1(v[0], poly1_2dind);
- poly1_ne1 = poly1->add_ordered_edge(poly1_edge1);
- poly1_ne1->trim_ind = trim_ind;
- poly1_ne1->trim_start = old_trim_start;
- poly1_ne1->trim_end = t1mid;
- struct cdt_mesh::edge_t poly1_edge2(poly1_2dind, v[1]);
- poly1_ne2 = poly1->add_ordered_edge(poly1_edge2);
- poly1_ne2->trim_ind = trim_ind;
- poly1_ne2->trim_start = t1mid;
- poly1_ne2->trim_end = old_trim_end;
- }
- {
- cdt_mesh::cpolygon_t *poly2 = bseg->tseg2->polygon;
- int v[2];
- v[0] = bseg->tseg2->v[0];
- v[1] = bseg->tseg2->v[1];
- int trim_ind = bseg->tseg2->trim_ind;
- double old_trim_start = bseg->tseg2->trim_start;
- double old_trim_end = bseg->tseg2->trim_end;
- poly2->remove_ordered_edge(cdt_mesh::edge_t(v[0], v[1]));
- long poly2_2dind = poly2->add_point(trim2_mid_2d, f2_ind2d);
- struct cdt_mesh::edge_t poly2_edge1(v[0], poly2_2dind);
- poly2_ne1 = poly2->add_ordered_edge(poly2_edge1);
- poly2_ne1->trim_ind = trim_ind;
- poly2_ne1->trim_start = old_trim_start;
- poly2_ne1->trim_end = t2mid;
- struct cdt_mesh::edge_t poly2_edge2(poly2_2dind, v[1]);
- poly2_ne2 = poly2->add_ordered_edge(poly2_edge2);
- poly2_ne2->trim_ind = trim_ind;
- poly2_ne2->trim_start = t2mid;
- poly2_ne2->trim_end = old_trim_end;
- }
-
- // The new trim segments are then associated with the new bounding edge
- // segments.
- // NOTE: the m_bRev3d logic below is CRITICALLY important when it comes to
- // associating the correct portion of the edge curve with the correct part
- // of the polygon in parametric space. If this is NOT correct, the 3D
- // polycurves manifested by the 2D polygon will be self intersecting, as
- // will the 3D triangles generated from the 2D CDT.
- bseg1->tseg1 = (trim1->m_bRev3d) ? poly1_ne2 : poly1_ne1;
- bseg1->tseg2 = (trim2->m_bRev3d) ? poly2_ne2 : poly2_ne1;
- bseg2->tseg1 = (trim1->m_bRev3d) ? poly1_ne1 : poly1_ne2;
- bseg2->tseg2 = (trim2->m_bRev3d) ? poly2_ne1 : poly2_ne2;
-
- // Associated the trim segments with the edge segment they actually
- // wound up assigned to
- bseg1->tseg1->eseg = bseg1;
- bseg1->tseg2->eseg = bseg1;
- bseg2->tseg1->eseg = bseg2;
- bseg2->tseg2->eseg = bseg2;
-
- nedges.insert(bseg1);
- nedges.insert(bseg2);
-
- delete bseg;
- return nedges;
-}
-
-// Calculate loop avg segment length
-static double
-loop_avg_seg_len(struct ON_Brep_CDT_State *s_cdt, int loop_index)
-{
- const ON_BrepLoop &loop = s_cdt->brep->m_L[loop_index];
- std::vector<double> lsegs;
- for (int lti = 0; lti < loop.TrimCount(); lti++) {
- ON_BrepTrim *trim = loop.Trim(lti);
- ON_BrepEdge *edge = trim->Edge();
- if (!edge) continue;
- const ON_Curve* crv = edge->EdgeCurveOf();
- if (!crv) continue;
- std::set<cdt_mesh::bedge_seg_t *> &epsegs =
s_cdt->e2polysegs[edge->m_edge_index];
- if (!epsegs.size()) continue;
- std::set<cdt_mesh::bedge_seg_t *>::iterator e_it;
- for (e_it = epsegs.begin(); e_it != epsegs.end(); e_it++) {
- cdt_mesh::bedge_seg_t *b = *e_it;
- double seg_dist = b->e_start->DistanceTo(*b->e_end);
- lsegs.push_back(seg_dist);
- }
- }
- return (std::accumulate(lsegs.begin(), lsegs.end(), 0.0)/lsegs.size());
-}
-
-static void
-split_long_edges(struct ON_Brep_CDT_State *s_cdt, int face_index)
-{
- ON_BrepFace &face = s_cdt->brep->m_F[face_index];
- int loop_cnt = face.LoopCount();
-
- for (int li = 0; li < loop_cnt; li++) {
- const ON_BrepLoop *loop = face.Loop(li);
- double avg_seg_len = loop_avg_seg_len(s_cdt, loop->m_loop_index);
- int trim_count = loop->TrimCount();
- for (int lti = 0; lti < trim_count; lti++) {
- ON_BrepTrim *trim = loop->Trim(lti);
- ON_BrepEdge *edge = trim->Edge();
- if (!edge) continue;
- const ON_Curve* crv = edge->EdgeCurveOf();
- if (!crv || crv->IsLinear(BN_TOL_DIST)) {
- continue;
- }
- std::set<cdt_mesh::bedge_seg_t *> &epsegs =
s_cdt->e2polysegs[edge->m_edge_index];
- if (!epsegs.size()) continue;
- std::set<cdt_mesh::bedge_seg_t *>::iterator e_it;
- std::set<cdt_mesh::bedge_seg_t *> new_segs;
- std::set<cdt_mesh::bedge_seg_t *> ws1, ws2;
- std::set<cdt_mesh::bedge_seg_t *> *ws = &ws1;
- std::set<cdt_mesh::bedge_seg_t *> *ns = &ws2;
- for (e_it = epsegs.begin(); e_it != epsegs.end(); e_it++) {
- cdt_mesh::bedge_seg_t *b = *e_it;
- ws->insert(b);
- }
- while (ws->size()) {
- cdt_mesh::bedge_seg_t *b = *ws->begin();
- ws->erase(ws->begin());
- double seg_dist = b->e_start->DistanceTo(*b->e_end);
- if (seg_dist > 0.5*avg_seg_len) {
- std::set<cdt_mesh::bedge_seg_t *> esegs_split =
split_edge_seg(s_cdt, b, 1);
- if (esegs_split.size()) {
- ns->insert(esegs_split.begin(), esegs_split.end());
- } else {
- new_segs.insert(b);
- }
- } else {
- new_segs.insert(b);
- }
- if (!ws->size() && ns->size()) {
- std::set<cdt_mesh::bedge_seg_t *> *tmp = ws;
- ws = ns;
- ns = tmp;
- }
- }
- s_cdt->e2polysegs[edge->m_edge_index].clear();
- s_cdt->e2polysegs[edge->m_edge_index].insert(new_segs.begin(),
new_segs.end());
- }
- }
-}
-
-
-
-
-std::set<cdt_mesh::cpolyedge_t *>
-split_singular_seg(struct ON_Brep_CDT_State *s_cdt, cdt_mesh::cpolyedge_t *ce)
-{
- std::set<cdt_mesh::cpolyedge_t *> nedges;
- cdt_mesh::cpolygon_t *poly = ce->polygon;
- int trim_ind = ce->trim_ind;
-
- ON_BrepTrim& trim = s_cdt->brep->m_T[ce->trim_ind];
- double tcparam = (ce->trim_start + ce->trim_end) / 2.0;
- ON_3dPoint trim_mid_2d_ev = trim.PointAt(tcparam);
- ON_2dPoint trim_mid_2d(trim_mid_2d_ev.x, trim_mid_2d_ev.y);
-
- ON_BrepFace *face = trim.Face();
- cdt_mesh::cdt_mesh_t *fmesh = &s_cdt->fmeshes[face->m_face_index];
- long f_ind2d = fmesh->add_point(trim_mid_2d);
-
- // Singularity - new 2D point points to the same 3D point as both of the
existing
- // vertices
- fmesh->p2d3d[f_ind2d] = fmesh->p2d3d[poly->p2o[ce->v[0]]];
-
- // Using the 2d mid points, update the polygons associated with tseg1 and
tseg2.
- cdt_mesh::cpolyedge_t *poly_ne1, *poly_ne2;
- int v[2];
- v[0] = ce->v[0];
- v[1] = ce->v[1];
- double old_trim_start = ce->trim_start;
- double old_trim_end = ce->trim_end;
- poly->remove_edge(cdt_mesh::edge_t(v[0], v[1]));
- long poly_2dind = poly->add_point(trim_mid_2d, f_ind2d);
- struct cdt_mesh::edge_t poly_edge1(v[0], poly_2dind);
- poly_ne1 = poly->add_edge(poly_edge1);
- poly_ne1->trim_ind = trim_ind;
- poly_ne1->trim_start = old_trim_start;
- poly_ne1->trim_end = tcparam;
- poly_ne1->eseg = NULL;
- struct cdt_mesh::edge_t poly_edge2(poly_2dind, v[1]);
- poly_ne2 = poly->add_edge(poly_edge2);
- poly_ne2->trim_ind = trim_ind;
- poly_ne2->trim_start = tcparam;
- poly_ne2->trim_end = old_trim_end;
- poly_ne2->eseg = NULL;
-
- nedges.insert(poly_ne1);
- nedges.insert(poly_ne2);
-
- return nedges;
-}
-
-
-// There are a couple of edge splitting operations that have to happen in the
-// beginning regardless of tolerance settings. Do them up front so the
subsequent
-// working set has consistent properties.
-bool
-initialize_edge_segs(struct ON_Brep_CDT_State *s_cdt, cdt_mesh::bedge_seg_t *e)
-{
- ON_BrepEdge& edge = s_cdt->brep->m_E[e->edge_ind];
- ON_BrepTrim *trim1 = edge.Trim(0);
- ON_BrepTrim *trim2 = edge.Trim(1);
- std::set<cdt_mesh::bedge_seg_t *> esegs_closed;
-
- if (!trim1 || !trim2) return false;
-
- if (trim1->m_type == ON_BrepTrim::singular || trim1->m_type ==
ON_BrepTrim::singular) return false;
-
- // 1. Any edges with at least 1 closed trim are split.
- if (trim1->IsClosed() || trim2->IsClosed()) {
- esegs_closed = split_edge_seg(s_cdt, e, 1);
- if (!esegs_closed.size()) {
- // split failed?? On a closed edge this is fatal - we must split it
- // to work with it at all
- return false;
- }
- } else {
- esegs_closed.insert(e);
- }
-
- // 2. Any edges with a non-linear edge curve are split. (If non-linear
- // and closed, split again - a curved, closed curve must be split twice
- // to have chance of producing a non-degenerate polygon.)
- std::set<cdt_mesh::bedge_seg_t *> esegs_csplit;
- const ON_Curve* crv = edge.EdgeCurveOf();
- if (!crv->IsLinear(BN_TOL_DIST)) {
- std::set<cdt_mesh::bedge_seg_t *>::iterator e_it;
- for (e_it = esegs_closed.begin(); e_it != esegs_closed.end(); e_it++) {
- std::set<cdt_mesh::bedge_seg_t *> efirst = split_edge_seg(s_cdt,
*e_it, 1);
- if (!efirst.size()) {
- // split failed?? On a curved edge we must split at least once
to
- // avoid potentially degenerate polygons (if we had to split a
closed
- // loop from step 1, for example;
- return false;
- } else {
- // To avoid representing circles with squares, split curved
segments
- // one additional time
- std::set<cdt_mesh::bedge_seg_t *>::iterator s_it;
- for (s_it = efirst.begin(); s_it != efirst.end(); s_it++) {
- std::set<cdt_mesh::bedge_seg_t *> etmp =
split_edge_seg(s_cdt, *s_it, 1);
- if (!etmp.size()) {
- // split failed?? This isn't good and shouldn't
- // happen, but it's not fatal the way the previous two
- // failure cases are...
- esegs_csplit.insert(*s_it);
- } else {
- esegs_csplit.insert(etmp.begin(), etmp.end());
- }
- }
- }
- }
- } else {
- esegs_csplit = esegs_closed;
- }
-
- s_cdt->e2polysegs[edge.m_edge_index].clear();
- s_cdt->e2polysegs[edge.m_edge_index].insert(esegs_csplit.begin(),
esegs_csplit.end());
-
- return true;
-}
-
-bool
refine_triangulation(struct ON_Brep_CDT_State *s_cdt, cdt_mesh::cdt_mesh_t
*fmesh, int cnt, int rebuild)
{
if (!s_cdt || !fmesh) return false;
@@ -1119,7 +241,7 @@
return refine_triangulation(s_cdt, fmesh, 0, 0);
}
-static ON_3dVector
+ON_3dVector
calc_trim_vnorm(ON_BrepVertex& v, ON_BrepTrim *trim)
{
ON_3dPoint t1, t2;
@@ -1360,238 +482,19 @@
}
}
- // Characterize the vertices - are they used by non-linear edges?
- std::vector<int> vert_type;
- for (int i = 0; i < brep->m_V.Count(); i++) {
- int has_curved_edge = 0;
- for (int j = 0; j < brep->m_V[i].m_ei.Count(); j++) {
- ON_BrepEdge &edge = brep->m_E[brep->m_V[i].m_ei[j]];
- const ON_Curve* crv = edge.EdgeCurveOf();
- if (crv && !crv->IsLinear(BN_TOL_DIST)) {
- has_curved_edge = 1;
- break;
- }
- }
- vert_type.push_back(has_curved_edge);
- }
+ // Set up the edge containers that will manage the edge subdivision.
+ initialize_edge_containers(s_cdt);
- // Charcterize the edges. Five possibilities:
- //
- // 0. Singularity
- // 1. Curved edge
- // 2. Linear edge, associated with at least 1 non-planar surface
- // 3. Linear edge, associated with planar surfaces but sharing one or
more vertices with
- // curved edges.
- // 4. Linear edge, associated only with planar faces and linear edges.
- std::vector<int> edge_type;
- for (int index = 0; index < brep->m_E.Count(); index++) {
- ON_BrepEdge& edge = brep->m_E[index];
- const ON_Curve* crv = edge.EdgeCurveOf();
-
- // Singularity
- if (!crv) {
- edge_type.push_back(0);
- continue;
- }
-
- // Curved edge
- if (!crv->IsLinear(BN_TOL_DIST)) {
- edge_type.push_back(1);
- continue;
- }
-
- // Linear edge, at least one non-planar surface
- const ON_Surface *s1= edge.Trim(0)->SurfaceOf();
- const ON_Surface *s2= edge.Trim(1)->SurfaceOf();
- if (!s1->IsPlanar(NULL, BN_TOL_DIST) || !s2->IsPlanar(NULL,
BN_TOL_DIST)) {
- edge_type.push_back(2);
- continue;
- }
-
- // Linear edge, at least one associated non-linear edge
- if (vert_type[edge.Vertex(0)->m_vertex_index] ||
vert_type[edge.Vertex(1)->m_vertex_index]) {
- edge_type.push_back(3);
- continue;
- }
-
- // Linear edge, only associated with linear edges and planar faces
- edge_type.push_back(4);
- }
-
- // Set up the edge containers that will manage the edge subdivision.
Loop
- // ordering is not the job of these containers - that's handled by the
trim loop
- // polygons. These containers maintain the association between trims
in different
- // faces and the 3D edge curve information used to drive shared points.
- for (int index = 0; index < brep->m_E.Count(); index++) {
- ON_BrepEdge& edge = brep->m_E[index];
- cdt_mesh::bedge_seg_t *bseg = new cdt_mesh::bedge_seg_t;
- bseg->edge_ind = edge.m_edge_index;
- bseg->brep = s_cdt->brep;
-
- // Provide a normalize edge NURBS curve
- const ON_Curve* crv = edge.EdgeCurveOf();
- bseg->nc = crv->NurbsCurve();
- bseg->cp_len = bseg->nc->ControlPolygonLength();
- bseg->nc->SetDomain(0.0, bseg->cp_len);
-
- // Set the initial edge curve t parameter values
- bseg->edge_start = 0.0;
- bseg->edge_end = bseg->cp_len;
-
- // Get the trims and normalize their domains as well.
- // NOTE - another point where this won't work if we don't have a
1->2 edge to trims relationship
- ON_BrepTrim *trim1 = edge.Trim(0);
- ON_BrepTrim *trim2 = edge.Trim(1);
-
s_cdt->brep->m_T[trim1->TrimCurveIndexOf()].SetDomain(bseg->edge_start,
bseg->edge_end);
-
s_cdt->brep->m_T[trim2->TrimCurveIndexOf()].SetDomain(bseg->edge_start,
bseg->edge_end);
-
- // The 3D start and endpoints will be vertex points (they are
shared with other edges).
- bseg->e_start = (*s_cdt->vert_pnts)[edge.Vertex(0)->m_vertex_index];
- bseg->e_end = (*s_cdt->vert_pnts)[edge.Vertex(1)->m_vertex_index];
-
- // These are also the root start and end points - type 3 edges will
need this information later
- bseg->e_root_start = bseg->e_start;
- bseg->e_root_end = bseg->e_end;
-
- // Stash the edge type - we will need it during refinement
- bseg->edge_type = edge_type[edge.m_edge_index];
-
- s_cdt->e2polysegs[edge.m_edge_index].insert(bseg);
- }
-
// Next, for each face and each loop in each face define the initial
// loop polygons. Note there is no splitting of edges at this point -
// we are simply establishing the initial closed polygons.
std::set<cdt_mesh::cpolyedge_t *> singular_edges;
- for (int face_index = 0; face_index < brep->m_F.Count(); face_index++) {
- ON_BrepFace &face = s_cdt->brep->m_F[face_index];
- int loop_cnt = face.LoopCount();
- cdt_mesh::cdt_mesh_t *fmesh = &s_cdt->fmeshes[face_index];
- fmesh->f_id = face_index;
- fmesh->m_bRev = face.m_bRev;
- fmesh->has_singularities = false;
- cdt_mesh::cpolygon_t *cpoly = NULL;
-
- for (int li = 0; li < loop_cnt; li++) {
- const ON_BrepLoop *loop = face.Loop(li);
- bool is_outer = (face.OuterLoop()->m_loop_index ==
loop->m_loop_index) ? true : false;
- if (is_outer) {
- cpoly = &fmesh->outer_loop;
- } else {
- cpoly = new cdt_mesh::cpolygon_t;
- fmesh->inner_loops[li] = cpoly;
- }
- int trim_count = loop->TrimCount();
-
- ON_2dPoint cp(0,0);
-
- long cv = -1;
- long pv = -1;
- long fv = -1;
-
- for (int lti = 0; lti < trim_count; lti++) {
- ON_BrepTrim *trim = loop->Trim(lti);
- ON_Interval range = trim->Domain();
- if (lti == 0) {
- // Get the 2D point, add it to the mesh and current
polygon
- cp = trim->PointAt(range.m_t[0]);
- long find = fmesh->add_point(cp);
- pv = cpoly->add_point(cp, find);
- fv = pv;
-
- // Let cdt_mesh know about new 3D information
- ON_3dPoint *op3d =
(*s_cdt->vert_pnts)[trim->Vertex(0)->m_vertex_index];
- ON_3dVector norm = ON_3dVector::UnsetVector;
- if (trim->m_type != ON_BrepTrim::singular) {
- // 3D points are globally unique, but normals are
not - the same edge point may
- // have different normals from two faces at a sharp
edge. Calculate the
- // face normal for this point on this surface.
- norm = calc_trim_vnorm(*trim->Vertex(0), trim);
- //std::cout << "Face " << face.m_face_index << ",
Loop " << loop->m_loop_index << ", Vert " << trim->Vertex(0)->m_vertex_index <<
" norm: " << norm.x << "," << norm.y << "," << norm.z << "\n";
- } else {
- // Surface sampling will need some information
about singularities
- s_cdt->strim_pnts[face_index][trim->m_trim_index] =
op3d;
- ON_3dPoint *sn3d =
(*s_cdt->vert_avg_norms)[trim->Vertex(0)->m_vertex_index];
- if (sn3d) {
-
s_cdt->strim_norms[face_index][trim->m_trim_index] = sn3d;
- }
- }
- long f3ind = fmesh->add_point(op3d);
- long fnind = fmesh->add_normal(new ON_3dPoint(norm));
- fmesh->p2d3d[find] = f3ind;
- fmesh->nmap[f3ind] = fnind;
-
- } else {
- pv = cv;
- }
-
- // Get the 2D point, add it to the mesh and current polygon
- cp = trim->PointAt(range.m_t[1]);
- if (lti == trim_count - 1) {
- cv = fv;
- } else {
- long find;
- find = fmesh->add_point(cp);
- cv = cpoly->add_point(cp, find);
-
- // Let cdt_mesh know about the 3D information
- ON_3dPoint *cp3d =
(*s_cdt->vert_pnts)[trim->Vertex(1)->m_vertex_index];
- ON_3dVector norm = ON_3dVector::UnsetVector;
- if (trim->m_type != ON_BrepTrim::singular) {
- // 3D points are globally unique, but normals are
not - the same edge point may
- // have different normals from two faces at a sharp
edge. Calculate the
- // face normal for this point on this surface.
- norm = calc_trim_vnorm(*trim->Vertex(1), trim);
- //std::cout << "Face " << face.m_face_index << ",
Loop " << loop->m_loop_index << ", Vert " << trim->Vertex(1)->m_vertex_index <<
" norm: " << norm.x << "," << norm.y << "," << norm.z << "\n";
- } else {
- // Surface sampling will need some information
about singularities
- s_cdt->strim_pnts[face_index][trim->m_trim_index] =
cp3d;
- ON_3dPoint *sn3d =
(*s_cdt->vert_avg_norms)[trim->Vertex(1)->m_vertex_index];
- if (sn3d) {
-
s_cdt->strim_norms[face_index][trim->m_trim_index] = sn3d;
- }
- }
-
- long f3ind = fmesh->add_point(cp3d);
- long fnind = fmesh->add_normal(new ON_3dPoint(norm));
- fmesh->p2d3d[find] = f3ind;
- fmesh->nmap[f3ind] = fnind;
- }
-
- struct cdt_mesh::edge_t lseg(pv, cv);
- cdt_mesh::cpolyedge_t *ne = cpoly->add_ordered_edge(lseg);
- ne->trim_ind = trim->m_trim_index;
-
- ne->trim_start = range.m_t[0];
- ne->trim_end = range.m_t[1];
-
- if (trim->m_ei >= 0) {
- cdt_mesh::bedge_seg_t *eseg =
*s_cdt->e2polysegs[trim->m_ei].begin();
- // Associate the edge segment with the trim segment and
vice versa
- ne->eseg = eseg;
- if (eseg->tseg1 && eseg->tseg2) {
- bu_log("error - more than two trims associated with
an edge\n");
- return -1;
- }
- if (eseg->tseg1) {
- eseg->tseg2 = ne;
- } else {
- eseg->tseg1 = ne;
- }
- } else {
- // A null eseg will indicate a singularity and a need
for special case
- // splitting of the 2D edge only
- ne->eseg = NULL;
- singular_edges.insert(ne);
- fmesh->has_singularities = true;
- }
- }
- }
+ if (!initialize_loop_polygons(s_cdt, &singular_edges)) {
+ return -1;
}
+ // Initialize the tangents.
std::map<int, std::set<cdt_mesh::bedge_seg_t *>>::iterator epoly_it;
-
- // Initialize the tangents.
for (epoly_it = s_cdt->e2polysegs.begin(); epoly_it !=
s_cdt->e2polysegs.end(); epoly_it++) {
std::set<cdt_mesh::bedge_seg_t *>::iterator seg_it;
for (seg_it = epoly_it->second.begin(); seg_it !=
epoly_it->second.end(); seg_it++) {
@@ -1633,6 +536,7 @@
// refine, but we need to test Remove in the RTree.h code to make sure
it does
// what is expected - there's a TODO note in there.
//
+ // A good test case is NIST2 face 493
for (int index = 0; index < brep->m_F.Count(); index++) {
ON_BrepFace &face = s_cdt->brep->m_F[index];
cdt_mesh::cdt_mesh_t *fmesh = &s_cdt->fmeshes[face.m_face_index];
@@ -1668,7 +572,7 @@
#endif
fmesh->reset();
- split_long_edges(s_cdt, index);
+ //split_long_edges(s_cdt, index);
// Replace old edge list with new edges
fmesh->brep_edges.clear();
@@ -1693,338 +597,20 @@
#if 0
// On to tolerance based splitting. Process the non-linear edges first
-
// we will need information from them to handle the linear edges
- //
- // TODO - investigate behavior of NIST2 edge 613
- for (int index = 0; index < brep->m_E.Count(); index++) {
- ON_BrepEdge& edge = brep->m_E[index];
- const ON_Curve* crv = edge.EdgeCurveOf();
- if (crv && !crv->IsLinear(BN_TOL_DIST)) {
- std::set<cdt_mesh::bedge_seg_t *> &epsegs =
s_cdt->e2polysegs[edge.m_edge_index];
- std::set<cdt_mesh::bedge_seg_t *>::iterator e_it;
- std::set<cdt_mesh::bedge_seg_t *> new_segs;
- std::set<cdt_mesh::bedge_seg_t *> ws1, ws2;
- std::set<cdt_mesh::bedge_seg_t *> *ws = &ws1;
- std::set<cdt_mesh::bedge_seg_t *> *ns = &ws2;
- for (e_it = epsegs.begin(); e_it != epsegs.end(); e_it++) {
- cdt_mesh::bedge_seg_t *b = *e_it;
- ws->insert(b);
- }
- while (ws->size()) {
- cdt_mesh::bedge_seg_t *b = *ws->begin();
- ws->erase(ws->begin());
- std::set<cdt_mesh::bedge_seg_t *> esegs_split =
split_edge_seg(s_cdt, b, 0);
- if (esegs_split.size()) {
- ns->insert(esegs_split.begin(), esegs_split.end());
- } else {
- new_segs.insert(b);
- }
- if (!ws->size() && ns->size()) {
- std::set<cdt_mesh::bedge_seg_t *> *tmp = ws;
- ws = ns;
- ns = tmp;
- }
- }
- s_cdt->e2polysegs[edge.m_edge_index].clear();
- s_cdt->e2polysegs[edge.m_edge_index].insert(new_segs.begin(),
new_segs.end());
- }
- }
+ tol_curved_edges_split(s_cdt);
- // Calculate for each vertex involved with curved edges the minimum
individual bedge_seg
- // length involved.
- for (int i = 0; i < brep->m_V.Count(); i++) {
- ON_3dPoint *p3d = (*s_cdt->vert_pnts)[i];
- double emin = DBL_MAX;
- for (int j = 0; j < brep->m_V[i].m_ei.Count(); j++) {
- ON_BrepEdge &edge = brep->m_E[brep->m_V[i].m_ei[j]];
- std::set<cdt_mesh::bedge_seg_t *> &epsegs =
s_cdt->e2polysegs[edge.m_edge_index];
- std::set<cdt_mesh::bedge_seg_t *>::iterator e_it;
- for (e_it = epsegs.begin(); e_it != epsegs.end(); e_it++) {
- cdt_mesh::bedge_seg_t *b = *e_it;
- if (b->e_start == p3d || b->e_end == p3d) {
- ON_Line line3d(*(b->e_start), *(b->e_end));
- double seg_len = line3d.Length();
- if (seg_len < emin) {
- emin = seg_len;
- }
- }
- }
- }
- s_cdt->v_min_seg_len[p3d] = emin;
- //std::cout << "Minimum vert seg length, vert " << i << ": " <<
s_cdt->v_min_seg_len[p3d] << "\n";
- }
-
- // Calculate loop median segment lengths contributed from the curved
edges
- for (int index = 0; index < brep->m_L.Count(); index++) {
- const ON_BrepLoop &loop = brep->m_L[index];
- std::vector<double> lsegs;
- for (int lti = 0; lti < loop.TrimCount(); lti++) {
- ON_BrepTrim *trim = loop.Trim(lti);
- ON_BrepEdge *edge = trim->Edge();
- if (!edge) continue;
- const ON_Curve* crv = edge->EdgeCurveOf();
- if (!crv || crv->IsLinear(BN_TOL_DIST)) {
- continue;
- }
- std::set<cdt_mesh::bedge_seg_t *> &epsegs =
s_cdt->e2polysegs[edge->m_edge_index];
- if (!epsegs.size()) continue;
- std::set<cdt_mesh::bedge_seg_t *>::iterator e_it;
- for (e_it = epsegs.begin(); e_it != epsegs.end(); e_it++) {
- cdt_mesh::bedge_seg_t *b = *e_it;
- double seg_dist = b->e_start->DistanceTo(*b->e_end);
- lsegs.push_back(seg_dist);
- }
- }
- if (!lsegs.size()) {
- // No non-linear edges, so no segments to use
- s_cdt->l_median_len[index] = -1;
- } else {
- s_cdt->l_median_len[index] = median_seg_len(lsegs);
- //std::cout << "Median loop seg length, loop " << index << ": "
<< s_cdt->l_median_len[index] << "\n";
- }
- }
-
// After the initial curve split, make another pass looking for curved
// edges sharing a vertex. We want larger curves to refine close to the
// median segment length of the smaller ones, since this situation can
be a
// sign that the surface will generate small triangles near large ones.
- std::map<int, double> refine_targets;
- for (int index = 0; index < brep->m_E.Count(); index++) {
- ON_BrepEdge& edge = brep->m_E[index];
- const ON_Curve* crv = edge.EdgeCurveOf();
- if (!crv || crv->IsLinear(BN_TOL_DIST)) continue;
- bool refine = false;
- double target_len = DBL_MAX;
- double lmed = edge_median_seg_len(s_cdt, edge.m_edge_index);
- for (int i = 0; i < 2; i++) {
- int vert_ind = edge.Vertex(i)->m_vertex_index;
- for (int j = 0; j < brep->m_V[vert_ind].m_ei.Count(); j++) {
- ON_BrepEdge &e2= brep->m_E[brep->m_V[vert_ind].m_ei[j]];
- const ON_Curve* crv2 = e2.EdgeCurveOf();
- if (crv2 && !crv2->IsLinear(BN_TOL_DIST)) {
- double emed = edge_median_seg_len(s_cdt,
e2.m_edge_index);
- if (emed < lmed) {
- target_len = (2*emed < target_len) ? 2*emed :
target_len;
- refine = true;
- }
- }
- }
- }
- if (refine) {
- refine_targets[index] = target_len;
- }
- }
- std::map<int, double>::iterator r_it;
- for (r_it = refine_targets.begin(); r_it != refine_targets.end();
r_it++) {
- ON_BrepEdge& edge = brep->m_E[r_it->first];
- double split_tol = r_it->second;
- std::set<cdt_mesh::bedge_seg_t *> &epsegs =
s_cdt->e2polysegs[r_it->first];
- std::set<cdt_mesh::bedge_seg_t *>::iterator e_it;
- std::set<cdt_mesh::bedge_seg_t *> new_segs;
- std::set<cdt_mesh::bedge_seg_t *> ws1, ws2;
- std::set<cdt_mesh::bedge_seg_t *> *ws = &ws1;
- std::set<cdt_mesh::bedge_seg_t *> *ns = &ws2;
- for (e_it = epsegs.begin(); e_it != epsegs.end(); e_it++) {
- cdt_mesh::bedge_seg_t *b = *e_it;
- ws->insert(b);
- }
- while (ws->size()) {
- cdt_mesh::bedge_seg_t *b = *ws->begin();
- ws->erase(ws->begin());
- bool split_edge = (b->e_start->DistanceTo(*b->e_end) >
split_tol);
- if (split_edge) {
- // If we need to split, do so
- std::set<cdt_mesh::bedge_seg_t *> esegs_split =
split_edge_seg(s_cdt, b, 1);
- if (esegs_split.size()) {
- ws->insert(esegs_split.begin(), esegs_split.end());
- } else {
- new_segs.insert(b);
- }
- } else {
- new_segs.insert(b);
- }
- if (!ws->size() && ns->size()) {
- std::set<cdt_mesh::bedge_seg_t *> *tmp = ws;
- ws = ns;
- ns = tmp;
- }
- }
- s_cdt->e2polysegs[edge.m_edge_index].clear();
- s_cdt->e2polysegs[edge.m_edge_index].insert(new_segs.begin(),
new_segs.end());
- }
+ curved_edges_refine(s_cdt);
- // Recalculate the curved median segment lengths for use by the linear
- // edges
- for (int index = 0; index < brep->m_L.Count(); index++) {
- const ON_BrepLoop &loop = brep->m_L[index];
- std::vector<double> lsegs;
- for (int lti = 0; lti < loop.TrimCount(); lti++) {
- ON_BrepTrim *trim = loop.Trim(lti);
- ON_BrepEdge *edge = trim->Edge();
- if (!edge) continue;
- const ON_Curve* crv = edge->EdgeCurveOf();
- if (!crv || crv->IsLinear(BN_TOL_DIST)) {
- continue;
- }
- std::set<cdt_mesh::bedge_seg_t *> &epsegs =
s_cdt->e2polysegs[edge->m_edge_index];
- if (!epsegs.size()) continue;
- std::set<cdt_mesh::bedge_seg_t *>::iterator e_it;
- for (e_it = epsegs.begin(); e_it != epsegs.end(); e_it++) {
- cdt_mesh::bedge_seg_t *b = *e_it;
- double seg_dist = b->e_start->DistanceTo(*b->e_end);
- lsegs.push_back(seg_dist);
- }
- }
- if (!lsegs.size()) {
- s_cdt->l_median_len[index] = -1;
- } else {
- s_cdt->l_median_len[index] = median_seg_len(lsegs);
- }
- }
-
// Now, process the linear edges
- for (int index = 0; index < brep->m_E.Count(); index++) {
- ON_BrepEdge& edge = brep->m_E[index];
- const ON_Curve* crv = edge.EdgeCurveOf();
- if (crv && crv->IsLinear(BN_TOL_DIST)) {
- std::set<cdt_mesh::bedge_seg_t *> &epsegs =
s_cdt->e2polysegs[edge.m_edge_index];
- std::set<cdt_mesh::bedge_seg_t *>::iterator e_it;
- std::set<cdt_mesh::bedge_seg_t *> new_segs;
- std::set<cdt_mesh::bedge_seg_t *> ws1, ws2;
- std::set<cdt_mesh::bedge_seg_t *> *ws = &ws1;
- std::set<cdt_mesh::bedge_seg_t *> *ns = &ws2;
- for (e_it = epsegs.begin(); e_it != epsegs.end(); e_it++) {
- cdt_mesh::bedge_seg_t *b = *e_it;
- ws->insert(b);
- }
- while (ws->size()) {
- cdt_mesh::bedge_seg_t *b = *ws->begin();
- ws->erase(ws->begin());
- std::set<cdt_mesh::bedge_seg_t *> esegs_split =
split_edge_seg(s_cdt, b, 0);
- if (esegs_split.size()) {
- ns->insert(esegs_split.begin(), esegs_split.end());
- } else {
- new_segs.insert(b);
- }
- if (!ws->size() && ns->size()) {
- std::set<cdt_mesh::bedge_seg_t *> *tmp = ws;
- ws = ns;
- ns = tmp;
- }
- }
- s_cdt->e2polysegs[edge.m_edge_index].clear();
- s_cdt->e2polysegs[edge.m_edge_index].insert(new_segs.begin(),
new_segs.end());
- }
- }
+ tol_linear_edges_split(s_cdt);
// Do another pass to break down edges that are close to other loops
and have segment
// lengths that are large compared to the nearby loop polygons
-
- // First, build the loop rtree and get the median lengths again. This
time we use all loop
- // segments, not just curved segments.
- for (int index = 0; index < brep->m_L.Count(); index++) {
-
- // Build the rtree leaf
- rtree_loop_2d(s_cdt, index);
-
- // Get inclusive median length
- const ON_BrepLoop &loop = brep->m_L[index];
- std::vector<double> lsegs;
- for (int lti = 0; lti < loop.TrimCount(); lti++) {
- ON_BrepTrim *trim = loop.Trim(lti);
- ON_BrepEdge *edge = trim->Edge();
- if (!edge) continue;
- const ON_Curve* crv = edge->EdgeCurveOf();
- if (!crv) continue;
- std::set<cdt_mesh::bedge_seg_t *> &epsegs =
s_cdt->e2polysegs[edge->m_edge_index];
- if (!epsegs.size()) continue;
- std::set<cdt_mesh::bedge_seg_t *>::iterator e_it;
- for (e_it = epsegs.begin(); e_it != epsegs.end(); e_it++) {
- cdt_mesh::bedge_seg_t *b = *e_it;
- double seg_dist = b->e_start->DistanceTo(*b->e_end);
- lsegs.push_back(seg_dist);
- }
- }
- s_cdt->l_median_len[index] = median_seg_len(lsegs);
- }
-
- // Now, check all the edge segments to see if we are close to a loop
with
- // smaller segments (or if our own loop has a median segment length
smaller
- // than the current segment.) If so, split.
- for (int index = 0; index < brep->m_E.Count(); index++) {
- ON_BrepEdge& edge = brep->m_E[index];
- const ON_Curve* crv = edge.EdgeCurveOf();
- if (!crv) continue;
- std::set<cdt_mesh::bedge_seg_t *> &epsegs =
s_cdt->e2polysegs[edge.m_edge_index];
- std::set<cdt_mesh::bedge_seg_t *>::iterator e_it;
- std::set<cdt_mesh::bedge_seg_t *> new_segs;
- std::set<cdt_mesh::bedge_seg_t *> ws1, ws2;
- std::set<cdt_mesh::bedge_seg_t *> *ws = &ws1;
- std::set<cdt_mesh::bedge_seg_t *> *ns = &ws2;
- for (e_it = epsegs.begin(); e_it != epsegs.end(); e_it++) {
- cdt_mesh::bedge_seg_t *b = *e_it;
- ws->insert(b);
- }
- while (ws->size()) {
- cdt_mesh::bedge_seg_t *b = *ws->begin();
- ws->erase(ws->begin());
- bool split_edge = false;
- double target_len = DBL_MAX;
- for (int i = 0; i < 2; i++) {
- ON_BrepTrim *trim = edge.Trim(i);
- ON_BrepFace *face = trim->Face();
-
- // Get segment length - should be smaller than our target
length.
- cdt_mesh::cpolyedge_t *tseg = (b->tseg1->trim_ind ==
trim->m_trim_index) ? b->tseg1 : b->tseg2;
- ON_2dPoint p2d1 =
s_cdt->brep->m_T[tseg->trim_ind].PointAt(tseg->trim_start);
- ON_2dPoint p2d2 =
s_cdt->brep->m_T[tseg->trim_ind].PointAt(tseg->trim_end);
- ON_Line l(p2d1, p2d2);
- double slen = l.Length();
- // Trim 2D bbox
- ON_BoundingBox tbb(p2d1, p2d2);
- double tMin[2];
- double tMax[2];
- double xbump = (fabs(tbb.Max().x - tbb.Min().x)) < slen ?
0.8*slen : ON_ZERO_TOLERANCE;
- double ybump = (fabs(tbb.Max().y - tbb.Min().y)) < slen ?
0.8*slen : ON_ZERO_TOLERANCE;
- tMin[0] = tbb.Min().x - xbump;
- tMin[1] = tbb.Min().y - ybump;
- tMax[0] = tbb.Max().x + xbump;
- tMax[1] = tbb.Max().y + ybump;
-
- // Edge context info
- struct rtree_loop_context a_context;
- a_context.seg_len = l.Length();
- a_context.split_edge = &split_edge;
- a_context.target_len = DBL_MAX;
-
- // Do the search
- if (!s_cdt->loops_2d[face->m_face_index].Search(tMin, tMax,
Loop2dCallback, (void *)&a_context)) {
- continue;
- } else {
- target_len = (a_context.target_len < target_len) ?
a_context.target_len : target_len;
- }
- }
-
- if (split_edge) {
- // If we need to split, do so
- std::set<cdt_mesh::bedge_seg_t *> esegs_split =
split_edge_seg(s_cdt, b, 1);
- if (esegs_split.size()) {
- ws->insert(esegs_split.begin(), esegs_split.end());
- } else {
- new_segs.insert(b);
- }
- } else {
- new_segs.insert(b);
- }
- if (!ws->size() && ns->size()) {
- std::set<cdt_mesh::bedge_seg_t *> *tmp = ws;
- ws = ns;
- ns = tmp;
- }
- }
- s_cdt->e2polysegs[edge.m_edge_index].clear();
- s_cdt->e2polysegs[edge.m_edge_index].insert(new_segs.begin(),
new_segs.end());
- }
-
+ refine_near_loops(s_cdt);
#endif
// Split singularity trims in 2D to provide an easier input to the 2D
CDT logic. NOTE: these
@@ -2058,6 +644,7 @@
}
}
+#if 0
// Build RTrees of 2D and 3D edge segments for edge aware processing
for (int index = 0; index < brep->m_E.Count(); index++) {
std::set<cdt_mesh::bedge_seg_t *> &epsegs =
s_cdt->e2polysegs[index];
@@ -2071,7 +658,6 @@
}
}
-#if 1
for (int index = 0; index < brep->m_F.Count(); index++) {
struct bu_vls fname = BU_VLS_INIT_ZERO;
bu_vls_sprintf(&fname, "%d-rtree_outer_polygon.plot3", index);
Modified: brlcad/trunk/src/libbrep/cdt.h
===================================================================
--- brlcad/trunk/src/libbrep/cdt.h 2019-09-07 21:56:13 UTC (rev 73854)
+++ brlcad/trunk/src/libbrep/cdt.h 2019-09-07 22:51:47 UTC (rev 73855)
@@ -184,7 +184,23 @@
void
GetInteriorPoints(struct ON_Brep_CDT_State *s_cdt, int face_index);
+ON_3dVector
+calc_trim_vnorm(ON_BrepVertex& v, ON_BrepTrim *trim);
+std::set<cdt_mesh::cpolyedge_t *>
+split_singular_seg(struct ON_Brep_CDT_State *s_cdt, cdt_mesh::cpolyedge_t *ce);
+
+bool initialize_edge_segs(struct ON_Brep_CDT_State *s_cdt,
cdt_mesh::bedge_seg_t *e);
+std::vector<int> characterize_edges(struct ON_Brep_CDT_State *s_cdt);
+void initialize_edge_containers(struct ON_Brep_CDT_State *s_cdt);
+bool initialize_loop_polygons(struct ON_Brep_CDT_State *s_cdt,
std::set<cdt_mesh::cpolyedge_t *> *singular_edges);
+void tol_curved_edges_split(struct ON_Brep_CDT_State *s_cdt);
+void update_vert_edge_seg_lengths(struct ON_Brep_CDT_State *s_cdt);
+void update_loop_median_curved_edge_seg_lengths(struct ON_Brep_CDT_State
*s_cdt);
+void curved_edges_refine(struct ON_Brep_CDT_State *s_cdt);
+void tol_linear_edges_split(struct ON_Brep_CDT_State *s_cdt);
+void refine_near_loops(struct ON_Brep_CDT_State *s_cdt);
+
void plot_rtree_2d(ON_RTree *rtree, const char *filename);
void plot_rtree_2d2(RTree<void *, double, 2> &rtree, const char *filename);
void plot_rtree_3d(RTree<void *, double, 3> &rtree, const char *filename);
Added: brlcad/trunk/src/libbrep/cdt_edge.cpp
===================================================================
--- brlcad/trunk/src/libbrep/cdt_edge.cpp (rev 0)
+++ brlcad/trunk/src/libbrep/cdt_edge.cpp 2019-09-07 22:51:47 UTC (rev
73855)
@@ -0,0 +1,1555 @@
+/* C D T . 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_edge.cpp
+ *
+ * Constrained Delaunay Triangulation of NURBS B-Rep objects.
+ *
+ */
+
+#include "common.h"
+#include <queue>
+#include <numeric>
+#include "bg/chull.h"
+#include "./cdt.h"
+
+#define BREP_PLANAR_TOL 0.05
+#define MAX_TRIANGULATION_ATTEMPTS 5
+
+#if 0
+int debug_ecnt;
+
+static void
+debug_plot(struct ON_Brep_CDT_State *s_cdt, cdt_mesh::cpolygon_t *cpoly, int
m_face_index, int m_loop_index, int m_edge_index, int m_trim_index, int
step_cnt, int *d_cnt) {
+ if (m_face_index > 0 && m_face_index != 34) return;
+ if (m_edge_index > 0 && (m_edge_index < 93 || m_edge_index > 96)) return;
+ cdt_mesh::cdt_mesh_t *fmesh = &s_cdt->fmeshes[34];
+ std::cout << "\n";
+ if (m_loop_index > 0) {
+ std::cout << step_cnt << "-" << (*d_cnt) << ": generating plots for
loop " << m_loop_index << "...\n";
+ }
+ if (m_edge_index > 0) {
+ std::cout << step_cnt << "-" << (*d_cnt) << ": generating plots for
edge " << m_edge_index << "...\n";
+ }
+ if (m_trim_index > 0) {
+ std::cout << step_cnt << "-" << (*d_cnt) << ": generating plots for
trim " << m_trim_index << "...\n";
+ }
+ cpoly->print();
+ fmesh->polygon_print_3d(cpoly);
+ struct bu_vls fname = BU_VLS_INIT_ZERO;
+ bu_vls_sprintf(&fname, "%d-%d-%d-poly2d.p3", m_face_index, step_cnt,
(*d_cnt));
+ fmesh->polygon_plot_2d(cpoly, bu_vls_cstr(&fname));
+ bu_vls_sprintf(&fname, "%d-%d-%d-poly3d.p3", m_face_index, step_cnt,
(*d_cnt));
+ fmesh->polygon_plot_3d(cpoly, bu_vls_cstr(&fname));
+ fmesh->cdt();
+ bu_vls_sprintf(&fname, "%d-%d-%d-tris_2d.p3", m_face_index, step_cnt,
(*d_cnt));
+ fmesh->tris_plot_2d(bu_vls_cstr(&fname));
+ bu_vls_sprintf(&fname, "%d-%d-%d-tris.p3", m_face_index, step_cnt,
(*d_cnt));
+ fmesh->tris_plot(bu_vls_cstr(&fname));
+ (*d_cnt)++;
+ std::cout << "\n";
+}
+#endif
+#if 0
+static void
+debug_bseg(cdt_mesh::bedge_seg_t *bseg, int seg_id)
+{
+#if 0
+ int face_index = 34;
+ if (bseg->edge_ind < 93 && bseg->edge_ind > 96) return;
+#endif
+ ON_BrepEdge& edge = bseg->brep->m_E[bseg->edge_ind];
+ ON_BrepTrim *trim1 = edge.Trim(0);
+ ON_BrepTrim *trim2 = edge.Trim(1);
+ if (!trim1 || !trim2) return ;
+
+#if 0
+ if (trim1->Face()->m_face_index != face_index &&
trim2->Face()->m_face_index != face_index) return;
+ ON_BrepTrim *ftrim = (trim1->Face()->m_face_index == face_index) ? trim1 :
trim2;
+ cdt_mesh::cpolyedge_t *tseg = (bseg->tseg1->trim_ind ==
ftrim->m_trim_index) ? bseg->tseg1 : bseg->tseg2;
+
+ std::cout << "bseg " << bseg->edge_ind << "-" << seg_id << ", trim " <<
tseg->trim_ind << " (" << bseg->brep->m_T[tseg->trim_ind].m_bRev3d << "):\n";
+ std::cout << " edge point start (x,y,z): (" << bseg->e_start->x << ","
<< bseg->e_start->y << "," << bseg->e_start->z << ")\n";
+ ON_3dPoint es = bseg->nc->PointAt(bseg->edge_start);
+ std::cout << " edge_start (t)(x,y,z): (" << bseg->edge_start << ") (" <<
es.x << "," << es.y << "," << es.z << ")\n";
+ std::cout << " edge point end (x,y,z): (" << bseg->e_end->x << "," <<
bseg->e_end->y << "," << bseg->e_end->z << ")\n";
+ ON_3dPoint ee = bseg->nc->PointAt(bseg->edge_end);
+ std::cout << " edge_end (t)(x,y,z): (" << bseg->edge_end << ") (" <<
ee.x << "," << ee.y << "," << ee.z << ")\n";
+
+ ON_2dPoint p2s = ftrim->PointAt(tseg->trim_start);
+ ON_2dPoint p2e = ftrim->PointAt(tseg->trim_end);
+ ON_3dPoint p3s = ftrim->SurfaceOf()->PointAt(p2s.x, p2s.y);
+ ON_3dPoint p3e = ftrim->SurfaceOf()->PointAt(p2e.x, p2e.y);
+ std::cout << " start point: p2d(x,y): " << p2s.x << "," << p2s.y << ")
p3d(x,y,z): (" << p3s.x << "," << p3s.y << "," << p3s.z << ")\n";
+ std::cout << " end point : p2d(x,y): " << p2e.x << "," << p2e.y << ")
p3d(x,y,z): (" << p3e.x << "," << p3e.y << "," << p3e.z << ")\n";
+
+ if (ftrim->m_bRev3d) {
+ if (bseg->e_start->DistanceTo(p3e) > BN_TOL_DIST) {
+ std::cout << " WARNING - bseg edge and trim start points
don't match\n";
+ }
+ if (bseg->e_end->DistanceTo(p3s) > BN_TOL_DIST) {
+ std::cout << " WARNING - bseg edge and trim end points
don't match\n";
+ }
+ } else {
+ if (bseg->e_start->DistanceTo(p3s) > BN_TOL_DIST) {
+ std::cout << " WARNING - bseg edge and trim start points
don't match\n";
+ }
+ if (bseg->e_end->DistanceTo(p3e) > BN_TOL_DIST) {
+ std::cout << " WARNING - bseg edge and trim end points
don't match\n";
+ }
+ }
+#endif
+
+ std::cout << "bseg " << bseg->edge_ind << "-" << seg_id << ":\n";
+ std::cout << "tseg1(" << bseg->tseg1->v[0] << "," << bseg->tseg1->v[1] <<
") polygon: ";
+ bseg->tseg1->polygon->print();
+ std::cout << "tseg2(" << bseg->tseg2->v[0] << "," << bseg->tseg2->v[1] <<
") polygon: ";
+ bseg->tseg2->polygon->print();
+ std::cout << "\n";
+
+}
+#endif
+
+void
+rtree_bbox_2d(struct ON_Brep_CDT_State *s_cdt, cdt_mesh::cpolyedge_t *pe)
+{
+ ON_BrepTrim& trim = s_cdt->brep->m_T[pe->trim_ind];
+ ON_2dPoint p2d1 = trim.PointAt(pe->trim_start);
+ ON_2dPoint p2d2 = trim.PointAt(pe->trim_end);
+ ON_Line line(p2d1, p2d2);
+ ON_BoundingBox bb = line.BoundingBox();
+ bb.m_max.x = bb.m_max.x + ON_ZERO_TOLERANCE;
+ bb.m_max.y = bb.m_max.y + ON_ZERO_TOLERANCE;
+ bb.m_min.x = bb.m_min.x - ON_ZERO_TOLERANCE;
+ bb.m_min.y = bb.m_min.y - ON_ZERO_TOLERANCE;
+
+ double dist = p2d1.DistanceTo(p2d2);
+ double bdist = 0.5*dist;
+ double xdist = bb.m_max.x - bb.m_min.x;
+ double ydist = bb.m_max.y - bb.m_min.y;
+ // If we're close to the edge, we want to know - the Search callback will
+ // check the precise distance and make a decision on what to do.
+ if (xdist < bdist) {
+ bb.m_min.x = bb.m_min.x - 0.5*bdist;
+ bb.m_max.x = bb.m_max.x + 0.5*bdist;
+ }
+ if (ydist < bdist) {
+ bb.m_min.y = bb.m_min.y - 0.5*bdist;
+ bb.m_max.y = bb.m_max.y + 0.5*bdist;
+ }
+
+ double p1[2];
+ p1[0] = bb.Min().x;
+ p1[1] = bb.Min().y;
+ double p2[2];
+ p2[0] = bb.Max().x;
+ p2[1] = bb.Max().y;
+ s_cdt->trim_segs[trim.Face()->m_face_index].Insert(p1, p2, (void *)pe);
+}
+
+void
+rtree_bbox_3d(struct ON_Brep_CDT_State *s_cdt, cdt_mesh::cpolyedge_t *pe)
+{
+ if (!pe->eseg) return;
+ ON_BrepTrim& trim = s_cdt->brep->m_T[pe->trim_ind];
+ ON_3dPoint *p3d1 = pe->eseg->e_start;
+ ON_3dPoint *p3d2 = pe->eseg->e_end;
+ ON_Line line(*p3d1, *p3d2);
+ ON_BoundingBox bb = line.BoundingBox();
+ bb.m_max.x = bb.m_max.x + ON_ZERO_TOLERANCE;
+ bb.m_max.y = bb.m_max.y + ON_ZERO_TOLERANCE;
+ bb.m_max.z = bb.m_max.z + ON_ZERO_TOLERANCE;
+ bb.m_min.x = bb.m_min.x - ON_ZERO_TOLERANCE;
+ bb.m_min.y = bb.m_min.y - ON_ZERO_TOLERANCE;
+ bb.m_min.z = bb.m_min.z - ON_ZERO_TOLERANCE;
+
+ double dist = p3d1->DistanceTo(*p3d2);
+ double bdist = 0.5*dist;
+ double xdist = bb.m_max.x - bb.m_min.x;
+ double ydist = bb.m_max.y - bb.m_min.y;
+ double zdist = bb.m_max.z - bb.m_min.z;
+ // If we're close to the edge, we want to know - the Search callback will
+ // check the precise distance and make a decision on what to do.
+ if (xdist < bdist) {
+ bb.m_min.x = bb.m_min.x - 0.5*bdist;
+ bb.m_max.x = bb.m_max.x + 0.5*bdist;
+ }
+ if (ydist < bdist) {
+ bb.m_min.y = bb.m_min.y - 0.5*bdist;
+ bb.m_max.y = bb.m_max.y + 0.5*bdist;
+ }
+ if (zdist < bdist) {
+ bb.m_min.z = bb.m_min.z - 0.5*bdist;
+ bb.m_max.z = bb.m_max.z + 0.5*bdist;
+ }
+
+ double p1[3];
+ p1[0] = bb.Min().x;
+ p1[1] = bb.Min().y;
+ p1[2] = bb.Min().z;
+ double p2[3];
+ p2[0] = bb.Max().x;
+ p2[1] = bb.Max().y;
+ p2[2] = bb.Max().z;
+ s_cdt->edge_segs_3d[trim.Face()->m_face_index].Insert(p1, p2, (void *)pe);
+}
+
+struct rtree_loop_leaf {
+ struct ON_Brep_CDT_State *s_cdt;
+ int loop_index;
+};
+
+// Used for finding "close" loops that might require further edge splitting
+static void
+rtree_loop_2d(struct ON_Brep_CDT_State *s_cdt, int loop_index)
+{
+ ON_BrepLoop& loop = s_cdt->brep->m_L[loop_index];
+ ON_BrepFace *face = loop.Face();
+
+ struct rtree_loop_leaf *leaf = new struct rtree_loop_leaf;
+
+ leaf->s_cdt = s_cdt;
+ leaf->loop_index = loop_index;
+
+ ON_BoundingBox bb;
+ loop.GetBoundingBox(bb);
+ bb.m_max.x = bb.m_max.x + ON_ZERO_TOLERANCE;
+ bb.m_max.y = bb.m_max.y + ON_ZERO_TOLERANCE;
+ bb.m_min.x = bb.m_min.x - ON_ZERO_TOLERANCE;
+ bb.m_min.y = bb.m_min.y - ON_ZERO_TOLERANCE;
+ double p1[2];
+ p1[0] = bb.Min().x;
+ p1[1] = bb.Min().y;
+ double p2[2];
+ p2[0] = bb.Max().x;
+ p2[1] = bb.Max().y;
+ s_cdt->loops_2d[face->m_face_index].Insert(p1, p2, (void *)leaf);
+}
+
+struct rtree_loop_context {
+ double seg_len;
+ bool *split_edge;
+ double target_len;
+};
+
+static bool Loop2dCallback(void *data, void *a_context) {
+ struct rtree_loop_leaf *ldata = (struct rtree_loop_leaf *)data;
+ struct rtree_loop_context *edata = (struct rtree_loop_context *)a_context;
+
+ // Get loop's median distance
+ double lmed = ldata->s_cdt->l_median_len[ldata->loop_index];
+ if (edata->seg_len > 5*lmed) {
+ *edata->split_edge = true;
+ }
+ if (edata->target_len > 5*lmed) {
+ edata->target_len = 5*lmed;
+ }
+
+ // Keep checking for other loops - we want the smallest target length
+ return true;
+}
+
+#if 0
+struct rtree_minsplit_context {
+ struct ON_Brep_CDT_State *s_cdt;
+ std::set<cdt_mesh::bedge_seg_t *> *split_segs;
+ cdt_mesh::cpolyedge_t *cseg;
+};
+
+static bool MinSplit2dCallback(void *data, void *a_context) {
+ cdt_mesh::cpolyedge_t *tseg = (cdt_mesh::cpolyedge_t *)data;
+ struct rtree_minsplit_context *context= (struct rtree_minsplit_context
*)a_context;
+
+ // Intersecting with oneself or immediate neighbors isn't cause for
splitting
+ if (tseg == cseg || tseg == cseg->prev || tseg == cseg->next) return true;
+
+ // Mark this segment down as a segment to split
+ context->split_segs->insert(tseg);
+
+ // No need to keep checking if we already know we're going to split
+ return false;
+}
+#endif
+
+double
+median_seg_len(std::vector<double> &lsegs)
+{
+ // Get the median segment length (https://stackoverflow.com/a/42791986)
+ double median, e1, e2;
+ std::vector<double>::iterator v1, v2;
+
+ if (!lsegs.size()) return -DBL_MAX;
+ if (lsegs.size() % 2 == 0) {
+ v1 = lsegs.begin() + lsegs.size() / 2 - 1;
+ v2 = lsegs.begin() + lsegs.size() / 2;
+ std::nth_element(lsegs.begin(), v1, lsegs.end());
+ e1 = *v1;
+ std::nth_element(lsegs.begin(), v2, lsegs.end());
+ e2 = *v2;
+ median = (e1+e2)*0.5;
+ } else {
+ v2 = lsegs.begin() + lsegs.size() / 2;
+ std::nth_element(lsegs.begin(), v2, lsegs.end());
+ median = *v2;
+ }
+
+ return median;
+}
+
+double
+edge_median_seg_len(struct ON_Brep_CDT_State *s_cdt, int m_edge_index)
+{
+ std::vector<double> lsegs;
+ std::set<cdt_mesh::bedge_seg_t *> &epsegs =
s_cdt->e2polysegs[m_edge_index];
+ std::set<cdt_mesh::bedge_seg_t *>::iterator e_it;
+ for (e_it = epsegs.begin(); e_it != epsegs.end(); e_it++) {
+ cdt_mesh::bedge_seg_t *b = *e_it;
+ double seg_dist = b->e_start->DistanceTo(*b->e_end);
+ lsegs.push_back(seg_dist);
+ }
+ return median_seg_len(lsegs);
+}
+
+ON_3dVector
+trim_normal(ON_BrepTrim *trim, ON_2dPoint &cp)
+{
+ ON_3dVector norm = ON_3dVector::UnsetVector;
+ if (trim->m_type != ON_BrepTrim::singular) {
+ // 3D points are globally unique, but normals are not - the same edge
point may
+ // have different normals from two faces at a sharp edge. Calculate the
+ // face normal for this point on this surface.
+ ON_Plane fplane;
+ const ON_Surface *s = trim->SurfaceOf();
+ double ptol = s->BoundingBox().Diagonal().Length()*0.001;
+ ptol = (ptol < BREP_PLANAR_TOL) ? ptol : BREP_PLANAR_TOL;
+ if (s->IsPlanar(&fplane, ptol)) {
+ norm = fplane.Normal();
+ } else {
+ ON_3dPoint tmp1;
+ surface_EvNormal(trim->SurfaceOf(), cp.x, cp.y, tmp1, norm);
+ }
+ if (trim->Face()->m_bRev) {
+ norm = -1 * norm;
+ }
+ //std::cout << "Face " << trim->Face()->m_face_index << ", Loop " <<
trim->Loop()->m_loop_index << " norm: " << norm.x << "," << norm.y << "," <<
norm.z << "\n";
+ }
+ return norm;
+}
+
+
+double
+pnt_binary_search(fastf_t *tparam, const ON_BrepTrim &trim, double tstart,
double tend, ON_3dPoint &edge_3d, double tol, int verbose, int depth, int force)
+{
+ double tcparam = (tstart + tend) / 2.0;
+ ON_3dPoint trim_2d = trim.PointAt(tcparam);
+ const ON_Surface *s = trim.SurfaceOf();
+ ON_3dPoint trim_3d = s->PointAt(trim_2d.x, trim_2d.y);
+ double dist = edge_3d.DistanceTo(trim_3d);
+
+ if (dist > tol && !force) {
+ ON_3dPoint trim_start_2d = trim.PointAt(tstart);
+ ON_3dPoint trim_end_2d = trim.PointAt(tend);
+ ON_3dPoint trim_start_3d = s->PointAt(trim_start_2d.x, trim_start_2d.y);
+ ON_3dPoint trim_end_3d = s->PointAt(trim_end_2d.x, trim_end_2d.y);
+
+ ON_3dVector v1 = edge_3d - trim_start_3d;
+ ON_3dVector v2 = edge_3d - trim_end_3d;
+ double sedist = trim_start_3d.DistanceTo(trim_end_3d);
+
+ if (verbose) {
+ //bu_log("start point (%f %f %f) and end point (%f %f %f)\n",
trim_start_3d.x, trim_start_3d.y, trim_start_3d.z, trim_end_3d.x,
trim_end_3d.y, trim_end_3d.z);
+ }
+
+ double vdot = ON_DotProduct(v1,v2);
+
+ if (vdot < 0 && dist > ON_ZERO_TOLERANCE) {
+ //if (verbose)
+ // bu_log("(%f - %f - %f (%f): searching left and right
subspans\n", tstart, tcparam, tend, ON_DotProduct(v1,v2));
+ double tlparam, trparam;
+ double fldist = pnt_binary_search(&tlparam, trim, tstart, tcparam,
edge_3d, tol, verbose, depth+1, 0);
+ double frdist = pnt_binary_search(&trparam, trim, tcparam, tend,
edge_3d, tol, verbose, depth+1, 0);
+ if (fldist >= 0 && frdist < -1) {
+ // if (verbose)
+ // bu_log("(%f - %f - %f: going with fldist: %f\n",
tstart, tcparam, tend, fldist);
+ (*tparam) = tlparam;
+ return fldist;
+ }
+ if (frdist >= 0 && fldist < -1) {
+ // if (verbose)
+ // bu_log("(%f - %f - %f: going with frdist: %f\n",
tstart, tcparam, tend, frdist);
+ (*tparam) = trparam;
+ return frdist;
+ }
+ if (fldist < -1 && frdist < -1) {
+ fldist = pnt_binary_search(&tlparam, trim, tstart, tcparam,
edge_3d, tol, verbose, depth+1, 1);
+ frdist = pnt_binary_search(&trparam, trim, tcparam, tend,
edge_3d, tol, verbose, depth+1, 1);
+ if (verbose) {
+ bu_log("Trim %d: point not in either subspan according to
dot product (distances are %f and %f, distance between sampling segment ends is
%f), forcing the issue\n", trim.m_trim_index, fldist, frdist, sedist);
+ }
+
+ if ((fldist < frdist) && (fldist < dist)) {
+ (*tparam) = tlparam;
+ return fldist;
+ }
+ if ((frdist < fldist) && (frdist < dist)) {
+ (*tparam) = trparam;
+ return frdist;
+ }
+ (*tparam) = tcparam;
+ return dist;
+
+ }
+ } else if (NEAR_ZERO(vdot, ON_ZERO_TOLERANCE)) {
+ (*tparam) = tcparam;
+ return dist;
+ } else {
+ // Not in this span
+ if (verbose && depth < 2) {
+ //bu_log("Trim %d: (%f:%f)%f - edge point (%f %f %f) and trim
point (%f %f %f): distance between them is %f, tol is %f, search seg length:
%f\n", trim.m_trim_index, tstart, tend, ON_DotProduct(v1,v2), edge_3d.x,
edge_3d.y, edge_3d.z, trim_3d.x, trim_3d.y, trim_3d.z, dist, tol, sedist);
+ }
+ if (depth == 0) {
+ (*tparam) = tcparam;
+ return dist;
+ } else {
+ return -2;
+ }
+ }
+ }
+
+ // close enough - this works
+ //if (verbose)
+ // bu_log("Workable (%f:%f) - edge point (%f %f %f) and trim point (%f %f
%f): %f, %f\n", tstart, tend, edge_3d.x, edge_3d.y, edge_3d.z, trim_3d.x,
trim_3d.y, trim_3d.z, dist, tol);
+
+ (*tparam) = tcparam;
+ return dist;
+}
+
+ON_2dPoint
+get_trim_midpt(fastf_t *t, struct ON_Brep_CDT_State *s_cdt,
cdt_mesh::cpolyedge_t *pe, ON_3dPoint &edge_mid_3d, double elen, double
brep_edge_tol)
+{
+ int verbose = 1;
+ double tol;
+ if (!NEAR_EQUAL(brep_edge_tol, ON_UNSET_VALUE, ON_ZERO_TOLERANCE)) {
+ tol = brep_edge_tol;
+ } else {
+ tol = (elen < BN_TOL_DIST) ? 0.01*elen : 0.1*BN_TOL_DIST;
+ }
+ ON_BrepTrim& trim = s_cdt->brep->m_T[pe->trim_ind];
+
+ double tmid;
+ double dist = pnt_binary_search(&tmid, trim, pe->trim_start, pe->trim_end,
edge_mid_3d, tol, 0, 0, 0);
+ if (dist < 0) {
+ if (verbose) {
+ bu_log("Warning - could not find suitable trim point\n");
+ }
+ tmid = (pe->trim_start + pe->trim_end) / 2.0;
+ } else {
+ if (verbose && (dist > BN_TOL_DIST) && (dist > tol)) {
+ if (trim.m_bRev3d) {
+ //bu_log("Reversed trim: going with distance %f greater than
desired tolerance %f\n", dist, tol);
+ } else {
+ //bu_log("Non-reversed trim: going with distance %f greater
than desired tolerance %f\n", dist, tol);
+ }
+ if (dist > 10*tol) {
+ dist = pnt_binary_search(&tmid, trim, pe->trim_start,
pe->trim_end, edge_mid_3d, tol, 0, 0, 0);
+ }
+ }
+ }
+
+ ON_2dPoint trim_mid_2d = trim.PointAt(tmid);
+ (*t) = tmid;
+ return trim_mid_2d;
+}
+
+bool
+tol_need_split(struct ON_Brep_CDT_State *s_cdt, cdt_mesh::bedge_seg_t *bseg,
ON_3dPoint &edge_mid_3d)
+{
+ ON_Line line3d(*(bseg->e_start), *(bseg->e_end));
+ double seg_len = line3d.Length();
+
+ double max_allowed = (s_cdt->tol.absmax > ON_ZERO_TOLERANCE) ?
s_cdt->tol.absmax : 1.1*bseg->cp_len;
+ double min_allowed = (s_cdt->tol.rel > ON_ZERO_TOLERANCE) ? s_cdt->tol.rel
* bseg->cp_len : 0.0;
+ double max_edgept_dist_from_edge = (s_cdt->tol.abs > ON_ZERO_TOLERANCE) ?
s_cdt->tol.abs : seg_len;
+ ON_BrepLoop *l1 = s_cdt->brep->m_T[bseg->tseg1->trim_ind].Loop();
+ ON_BrepLoop *l2 = s_cdt->brep->m_T[bseg->tseg2->trim_ind].Loop();
+ const ON_Surface *s1= l1->SurfaceOf();
+ const ON_Surface *s2= l2->SurfaceOf();
+ double len_1 = -1;
+ double len_2 = -1;
+ double s_len;
+
+ switch (bseg->edge_type) {
+ case 0:
+ // singularity splitting is handled in a separate step, since it
isn't based
+ // on 3D information
+ return false;
+ case 1:
+ // Curved edge - default assigned values are correct.
+ break;
+ case 2:
+ // Linear edge on non-planar surface - use the median segment
lengths
+ // from the trims from non-planar faces associated with this edge
+ len_1 = (!s1->IsPlanar(NULL, BN_TOL_DIST)) ?
s_cdt->l_median_len[l1->m_loop_index] : -1;
+ len_2 = (!s2->IsPlanar(NULL, BN_TOL_DIST)) ?
s_cdt->l_median_len[l2->m_loop_index] : -1;
+ if (len_1 < 0 && len_2 < 0) {
+ bu_log("Error - both loops report invalid median lengths\n");
+ return false;
+ }
+ s_len = (len_1 > 0) ? len_1 : len_2;
+ s_len = (len_2 > 0 && len_2 < s_len) ? len_2 : s_len;
+ max_allowed = 5*s_len;
+ min_allowed = 0.2*s_len;
+ break;
+ case 3:
+ // Linear edge connected to one or more non-linear edges. If the
start or end points
+ // are the same as the root start or end points, use the median
edge length of the
+ // connected edge per the vert lookup.
+ if (bseg->e_start == bseg->e_root_start || bseg->e_end ==
bseg->e_root_start) {
+ len_1 = s_cdt->v_min_seg_len[bseg->e_root_start];
+ }
+ if (bseg->e_start == bseg->e_root_end || bseg->e_end ==
bseg->e_root_end) {
+ len_2 = s_cdt->v_min_seg_len[bseg->e_root_end];
+ }
+ if (bseg->e_start == bseg->e_root_start || bseg->e_end ==
bseg->e_root_start) {
+ if (len_1 < 0 && len_2 < 0) {
+ bu_log("Error - verts report invalid lengths on type 3 line
segment\n");
+ return false;
+ }
+ }
+ s_len = (len_1 > 0) ? len_1 : len_2;
+ s_len = (len_2 > 0 && len_2 < s_len) ? len_2 : s_len;
+ if (s_len > 0) {
+ max_allowed = 2*s_len;
+ min_allowed = 0.5*s_len;
+ }
+ break;
+ case 4:
+ // Linear segment, no curves involved
+ break;
+ default:
+ bu_log("Error - invalid edge type: %d\n", bseg->edge_type);
+ return false;
+ }
+
+
+ if (seg_len > max_allowed) return true;
+
+ if (seg_len < min_allowed) return false;
+
+ // If we're linear and not already split, tangents and normals won't
change that
+ if (bseg->edge_type > 1) return false;
+
+ double dist3d = edge_mid_3d.DistanceTo(line3d.ClosestPointTo(edge_mid_3d));
+
+ if (dist3d > max_edgept_dist_from_edge) return true;
+
+ if ((bseg->tan_start * bseg->tan_end) < s_cdt->cos_within_ang) return true;
+
+ ON_3dPoint *n1, *n2;
+
+ ON_BrepEdge& edge = s_cdt->brep->m_E[bseg->edge_ind];
+ ON_BrepTrim *trim1 = edge.Trim(0);
+ ON_BrepFace *face1 = trim1->Face();
+ cdt_mesh::cdt_mesh_t *fmesh1 = &s_cdt->fmeshes[face1->m_face_index];
+ n1 = fmesh1->normals[fmesh1->nmap[fmesh1->p2ind[bseg->e_start]]];
+ n2 = fmesh1->normals[fmesh1->nmap[fmesh1->p2ind[bseg->e_end]]];
+
+ if (ON_3dVector(*n1) != ON_3dVector::UnsetVector && ON_3dVector(*n2) !=
ON_3dVector::UnsetVector) {
+ if ((ON_3dVector(*n1) * ON_3dVector(*n2)) < s_cdt->cos_within_ang -
VUNITIZE_TOL) return true;
+ }
+
+ ON_BrepTrim *trim2 = edge.Trim(1);
+ ON_BrepFace *face2 = trim2->Face();
+ cdt_mesh::cdt_mesh_t *fmesh2 = &s_cdt->fmeshes[face2->m_face_index];
+ n1 = fmesh2->normals[fmesh2->nmap[fmesh2->p2ind[bseg->e_start]]];
+ n2 = fmesh2->normals[fmesh2->nmap[fmesh2->p2ind[bseg->e_end]]];
+
+ if (ON_3dVector(*n1) != ON_3dVector::UnsetVector && ON_3dVector(*n2) !=
ON_3dVector::UnsetVector) {
+ if ((ON_3dVector(*n1) * ON_3dVector(*n2)) < s_cdt->cos_within_ang -
VUNITIZE_TOL) return true;
+ }
+
+ return false;
+}
+
+std::set<cdt_mesh::bedge_seg_t *>
+split_edge_seg(struct ON_Brep_CDT_State *s_cdt, cdt_mesh::bedge_seg_t *bseg,
int force)
+{
+ std::set<cdt_mesh::bedge_seg_t *> nedges;
+
+ // If we don't have associated segments, we can't do anything
+ if (!bseg->tseg1 || !bseg->tseg2 || !bseg->nc) return nedges;
+
+ ON_BrepEdge& edge = s_cdt->brep->m_E[bseg->edge_ind];
+ ON_BrepTrim *trim1 = &s_cdt->brep->m_T[bseg->tseg1->trim_ind];
+ ON_BrepTrim *trim2 = &s_cdt->brep->m_T[bseg->tseg2->trim_ind];
+
+ // If we don't have associated trims, we can't do anything
+ if (!trim1 || !trim2) return nedges;
+
+ ON_BrepFace *face1 = trim1->Face();
+ ON_BrepFace *face2 = trim2->Face();
+ cdt_mesh::cdt_mesh_t *fmesh1 = &s_cdt->fmeshes[face1->m_face_index];
+ cdt_mesh::cdt_mesh_t *fmesh2 = &s_cdt->fmeshes[face2->m_face_index];
+
+
+ // Get the 3D midpoint (and tangent, if we can) from the edge curve
+ ON_3dPoint edge_mid_3d = ON_3dPoint::UnsetPoint;
+ ON_3dVector edge_mid_tan = ON_3dVector::UnsetVector;
+ fastf_t emid = (bseg->edge_start + bseg->edge_end) / 2.0;
+ bool evtangent_status = bseg->nc->EvTangent(emid, edge_mid_3d,
edge_mid_tan);
+ if (!evtangent_status) {
+ // EvTangent call failed, get 3d point
+ edge_mid_3d = bseg->nc->PointAt(emid);
+ edge_mid_tan = ON_3dVector::UnsetVector;
+ }
+
+ // Unless we're forcing a split this is the point at which we do tolerance
+ // based testing to determine whether to proceed with the split or halt.
+ if (!force && !tol_need_split(s_cdt, bseg, edge_mid_3d)) {
+ return nedges;
+ }
+
+ // edge_mid_3d is a new point in the cdt and the fmesh, as well as a new
+ // edge point - add it to the appropriate containers
+ ON_3dPoint *mid_3d = new ON_3dPoint(edge_mid_3d);
+ CDT_Add3DPnt(s_cdt, mid_3d, -1, -1, -1, edge.m_edge_index, 0, 0);
+ s_cdt->edge_pnts->insert(mid_3d);
+
+ // Find the 2D points
+ double elen1 =
(bseg->nc->PointAt(bseg->edge_start)).DistanceTo(bseg->nc->PointAt(emid));
+ double elen2 =
(bseg->nc->PointAt(emid)).DistanceTo(bseg->nc->PointAt(bseg->edge_end));
+ double elen = (elen1 + elen2) * 0.5;
+ fastf_t t1mid, t2mid;
+ ON_2dPoint trim1_mid_2d, trim2_mid_2d;
+ trim1_mid_2d = get_trim_midpt(&t1mid, s_cdt, bseg->tseg1, edge_mid_3d,
elen, edge.m_tolerance);
+ trim2_mid_2d = get_trim_midpt(&t2mid, s_cdt, bseg->tseg2, edge_mid_3d,
elen, edge.m_tolerance);
+
+ // Update the 2D and 2D->3D info in the fmeshes
+ long f1_ind2d = fmesh1->add_point(trim1_mid_2d);
+ long f1_ind3d = fmesh1->add_point(mid_3d);
+ fmesh1->p2d3d[f1_ind2d] = f1_ind3d;
+ long f2_ind2d = fmesh2->add_point(trim2_mid_2d);
+ long f2_ind3d = fmesh2->add_point(mid_3d);
+ fmesh2->p2d3d[f2_ind2d] = f2_ind3d;
+
+ // Trims get their own normals
+ ON_3dVector norm1 = trim_normal(trim1, trim1_mid_2d);
+ fmesh1->normals.push_back(new ON_3dPoint(norm1));
+ long f1_nind = fmesh1->normals.size() - 1;
+ fmesh1->nmap[f1_ind3d] = f1_nind;
+ ON_3dVector norm2 = trim_normal(trim2, trim2_mid_2d);
+ fmesh2->normals.push_back(new ON_3dPoint(norm2));
+ long f2_nind = fmesh2->normals.size() - 1;
+ fmesh2->nmap[f2_ind3d] = f2_nind;
+
+ // From the existing polyedge, make the two new polyedges that will
replace the old one
+ cdt_mesh::bedge_seg_t *bseg1 = new cdt_mesh::bedge_seg_t(bseg);
+ bseg1->edge_start = bseg->edge_start;
+ bseg1->edge_end = emid;
+ bseg1->e_start = bseg->e_start;
+ bseg1->e_end = mid_3d;
+ bseg1->tan_start = bseg->tan_start;
+ bseg1->tan_end = edge_mid_tan;
+
+ cdt_mesh::bedge_seg_t *bseg2 = new cdt_mesh::bedge_seg_t(bseg);
+ bseg2->edge_start = emid;
+ bseg2->edge_end = bseg->edge_end;
+ bseg2->e_start = mid_3d;
+ bseg2->e_end = bseg->e_end;
+ bseg2->tan_start = edge_mid_tan;
+ bseg2->tan_end = bseg->tan_end;
+
+ // Using the 2d mid points, update the polygons associated with tseg1 and
tseg2.
+ cdt_mesh::cpolyedge_t *poly1_ne1, *poly1_ne2, *poly2_ne1, *poly2_ne2;
+ {
+ cdt_mesh::cpolygon_t *poly1 = bseg->tseg1->polygon;
+ int v[2];
+ v[0] = bseg->tseg1->v[0];
+ v[1] = bseg->tseg1->v[1];
+ int trim_ind = bseg->tseg1->trim_ind;
+ double old_trim_start = bseg->tseg1->trim_start;
+ double old_trim_end = bseg->tseg1->trim_end;
+ poly1->remove_ordered_edge(cdt_mesh::edge_t(v[0], v[1]));
+ long poly1_2dind = poly1->add_point(trim1_mid_2d, f1_ind2d);
+ struct cdt_mesh::edge_t poly1_edge1(v[0], poly1_2dind);
+ poly1_ne1 = poly1->add_ordered_edge(poly1_edge1);
+ poly1_ne1->trim_ind = trim_ind;
+ poly1_ne1->trim_start = old_trim_start;
+ poly1_ne1->trim_end = t1mid;
+ struct cdt_mesh::edge_t poly1_edge2(poly1_2dind, v[1]);
+ poly1_ne2 = poly1->add_ordered_edge(poly1_edge2);
+ poly1_ne2->trim_ind = trim_ind;
+ poly1_ne2->trim_start = t1mid;
+ poly1_ne2->trim_end = old_trim_end;
+ }
+ {
+ cdt_mesh::cpolygon_t *poly2 = bseg->tseg2->polygon;
+ int v[2];
+ v[0] = bseg->tseg2->v[0];
+ v[1] = bseg->tseg2->v[1];
+ int trim_ind = bseg->tseg2->trim_ind;
+ double old_trim_start = bseg->tseg2->trim_start;
+ double old_trim_end = bseg->tseg2->trim_end;
+ poly2->remove_ordered_edge(cdt_mesh::edge_t(v[0], v[1]));
+ long poly2_2dind = poly2->add_point(trim2_mid_2d, f2_ind2d);
+ struct cdt_mesh::edge_t poly2_edge1(v[0], poly2_2dind);
+ poly2_ne1 = poly2->add_ordered_edge(poly2_edge1);
+ poly2_ne1->trim_ind = trim_ind;
+ poly2_ne1->trim_start = old_trim_start;
+ poly2_ne1->trim_end = t2mid;
+ struct cdt_mesh::edge_t poly2_edge2(poly2_2dind, v[1]);
+ poly2_ne2 = poly2->add_ordered_edge(poly2_edge2);
+ poly2_ne2->trim_ind = trim_ind;
+ poly2_ne2->trim_start = t2mid;
+ poly2_ne2->trim_end = old_trim_end;
+ }
+
+ // The new trim segments are then associated with the new bounding edge
+ // segments.
+ // NOTE: the m_bRev3d logic below is CRITICALLY important when it comes to
+ // associating the correct portion of the edge curve with the correct part
+ // of the polygon in parametric space. If this is NOT correct, the 3D
+ // polycurves manifested by the 2D polygon will be self intersecting, as
+ // will the 3D triangles generated from the 2D CDT.
+ bseg1->tseg1 = (trim1->m_bRev3d) ? poly1_ne2 : poly1_ne1;
+ bseg1->tseg2 = (trim2->m_bRev3d) ? poly2_ne2 : poly2_ne1;
+ bseg2->tseg1 = (trim1->m_bRev3d) ? poly1_ne1 : poly1_ne2;
+ bseg2->tseg2 = (trim2->m_bRev3d) ? poly2_ne1 : poly2_ne2;
+
+ // Associated the trim segments with the edge segment they actually
+ // wound up assigned to
+ bseg1->tseg1->eseg = bseg1;
+ bseg1->tseg2->eseg = bseg1;
+ bseg2->tseg1->eseg = bseg2;
+ bseg2->tseg2->eseg = bseg2;
+
+ nedges.insert(bseg1);
+ nedges.insert(bseg2);
+
+ delete bseg;
+ return nedges;
+}
+
+#if 0
+// Calculate loop avg segment length
+static double
+loop_avg_seg_len(struct ON_Brep_CDT_State *s_cdt, int loop_index)
+{
+ const ON_BrepLoop &loop = s_cdt->brep->m_L[loop_index];
+ std::vector<double> lsegs;
+ for (int lti = 0; lti < loop.TrimCount(); lti++) {
+ ON_BrepTrim *trim = loop.Trim(lti);
+ ON_BrepEdge *edge = trim->Edge();
+ if (!edge) continue;
+ const ON_Curve* crv = edge->EdgeCurveOf();
+ if (!crv) continue;
+ std::set<cdt_mesh::bedge_seg_t *> &epsegs =
s_cdt->e2polysegs[edge->m_edge_index];
+ if (!epsegs.size()) continue;
+ std::set<cdt_mesh::bedge_seg_t *>::iterator e_it;
+ for (e_it = epsegs.begin(); e_it != epsegs.end(); e_it++) {
+ cdt_mesh::bedge_seg_t *b = *e_it;
+ double seg_dist = b->e_start->DistanceTo(*b->e_end);
+ lsegs.push_back(seg_dist);
+ }
+ }
+ return (std::accumulate(lsegs.begin(), lsegs.end(), 0.0)/lsegs.size());
+}
+
+static void
+split_long_edges(struct ON_Brep_CDT_State *s_cdt, int face_index)
+{
+ ON_BrepFace &face = s_cdt->brep->m_F[face_index];
+ int loop_cnt = face.LoopCount();
+
+ for (int li = 0; li < loop_cnt; li++) {
+ const ON_BrepLoop *loop = face.Loop(li);
+ double avg_seg_len = loop_avg_seg_len(s_cdt, loop->m_loop_index);
+ int trim_count = loop->TrimCount();
+ for (int lti = 0; lti < trim_count; lti++) {
+ ON_BrepTrim *trim = loop->Trim(lti);
+ ON_BrepEdge *edge = trim->Edge();
+ if (!edge) continue;
+ const ON_Curve* crv = edge->EdgeCurveOf();
+ if (!crv || crv->IsLinear(BN_TOL_DIST)) {
+ continue;
+ }
+ std::set<cdt_mesh::bedge_seg_t *> &epsegs =
s_cdt->e2polysegs[edge->m_edge_index];
+ if (!epsegs.size()) continue;
+ std::set<cdt_mesh::bedge_seg_t *>::iterator e_it;
+ std::set<cdt_mesh::bedge_seg_t *> new_segs;
+ std::set<cdt_mesh::bedge_seg_t *> ws1, ws2;
+ std::set<cdt_mesh::bedge_seg_t *> *ws = &ws1;
+ std::set<cdt_mesh::bedge_seg_t *> *ns = &ws2;
+ for (e_it = epsegs.begin(); e_it != epsegs.end(); e_it++) {
+ cdt_mesh::bedge_seg_t *b = *e_it;
+ ws->insert(b);
+ }
+ while (ws->size()) {
+ cdt_mesh::bedge_seg_t *b = *ws->begin();
+ ws->erase(ws->begin());
+ double seg_dist = b->e_start->DistanceTo(*b->e_end);
+ if (seg_dist > 0.5*avg_seg_len) {
+ std::set<cdt_mesh::bedge_seg_t *> esegs_split =
split_edge_seg(s_cdt, b, 1);
+ if (esegs_split.size()) {
+ ns->insert(esegs_split.begin(), esegs_split.end());
+ } else {
+ new_segs.insert(b);
+ }
+ } else {
+ new_segs.insert(b);
+ }
+ if (!ws->size() && ns->size()) {
+ std::set<cdt_mesh::bedge_seg_t *> *tmp = ws;
+ ws = ns;
+ ns = tmp;
+ }
+ }
+ s_cdt->e2polysegs[edge->m_edge_index].clear();
+ s_cdt->e2polysegs[edge->m_edge_index].insert(new_segs.begin(),
new_segs.end());
+ }
+ }
+}
+#endif
+
+std::set<cdt_mesh::cpolyedge_t *>
+split_singular_seg(struct ON_Brep_CDT_State *s_cdt, cdt_mesh::cpolyedge_t *ce)
+{
+ std::set<cdt_mesh::cpolyedge_t *> nedges;
+ cdt_mesh::cpolygon_t *poly = ce->polygon;
+ int trim_ind = ce->trim_ind;
+
+ ON_BrepTrim& trim = s_cdt->brep->m_T[ce->trim_ind];
+ double tcparam = (ce->trim_start + ce->trim_end) / 2.0;
+ ON_3dPoint trim_mid_2d_ev = trim.PointAt(tcparam);
+ ON_2dPoint trim_mid_2d(trim_mid_2d_ev.x, trim_mid_2d_ev.y);
+
+ ON_BrepFace *face = trim.Face();
+ cdt_mesh::cdt_mesh_t *fmesh = &s_cdt->fmeshes[face->m_face_index];
+ long f_ind2d = fmesh->add_point(trim_mid_2d);
+
+ // Singularity - new 2D point points to the same 3D point as both of the
existing
+ // vertices
+ fmesh->p2d3d[f_ind2d] = fmesh->p2d3d[poly->p2o[ce->v[0]]];
+
+ // Using the 2d mid points, update the polygons associated with tseg1 and
tseg2.
+ cdt_mesh::cpolyedge_t *poly_ne1, *poly_ne2;
+ int v[2];
+ v[0] = ce->v[0];
+ v[1] = ce->v[1];
+ double old_trim_start = ce->trim_start;
+ double old_trim_end = ce->trim_end;
+ poly->remove_edge(cdt_mesh::edge_t(v[0], v[1]));
+ long poly_2dind = poly->add_point(trim_mid_2d, f_ind2d);
+ struct cdt_mesh::edge_t poly_edge1(v[0], poly_2dind);
+ poly_ne1 = poly->add_edge(poly_edge1);
+ poly_ne1->trim_ind = trim_ind;
+ poly_ne1->trim_start = old_trim_start;
+ poly_ne1->trim_end = tcparam;
+ poly_ne1->eseg = NULL;
+ struct cdt_mesh::edge_t poly_edge2(poly_2dind, v[1]);
+ poly_ne2 = poly->add_edge(poly_edge2);
+ poly_ne2->trim_ind = trim_ind;
+ poly_ne2->trim_start = tcparam;
+ poly_ne2->trim_end = old_trim_end;
+ poly_ne2->eseg = NULL;
+
+ nedges.insert(poly_ne1);
+ nedges.insert(poly_ne2);
+
+ return nedges;
+}
+
+
+// There are a couple of edge splitting operations that have to happen in the
+// beginning regardless of tolerance settings. Do them up front so the
subsequent
+// working set has consistent properties.
+bool
+initialize_edge_segs(struct ON_Brep_CDT_State *s_cdt, cdt_mesh::bedge_seg_t *e)
+{
+ ON_BrepEdge& edge = s_cdt->brep->m_E[e->edge_ind];
+ ON_BrepTrim *trim1 = edge.Trim(0);
+ ON_BrepTrim *trim2 = edge.Trim(1);
+ std::set<cdt_mesh::bedge_seg_t *> esegs_closed;
+
+ if (!trim1 || !trim2) return false;
+
+ if (trim1->m_type == ON_BrepTrim::singular || trim1->m_type ==
ON_BrepTrim::singular) return false;
+
+ // 1. Any edges with at least 1 closed trim are split.
+ if (trim1->IsClosed() || trim2->IsClosed()) {
+ esegs_closed = split_edge_seg(s_cdt, e, 1);
+ if (!esegs_closed.size()) {
+ // split failed?? On a closed edge this is fatal - we must split it
+ // to work with it at all
+ return false;
+ }
+ } else {
+ esegs_closed.insert(e);
+ }
+
+ // 2. Any edges with a non-linear edge curve are split. (If non-linear
+ // and closed, split again - a curved, closed curve must be split twice
+ // to have chance of producing a non-degenerate polygon.)
+ std::set<cdt_mesh::bedge_seg_t *> esegs_csplit;
+ const ON_Curve* crv = edge.EdgeCurveOf();
+ if (!crv->IsLinear(BN_TOL_DIST)) {
+ std::set<cdt_mesh::bedge_seg_t *>::iterator e_it;
+ for (e_it = esegs_closed.begin(); e_it != esegs_closed.end(); e_it++) {
+ std::set<cdt_mesh::bedge_seg_t *> efirst = split_edge_seg(s_cdt,
*e_it, 1);
+ if (!efirst.size()) {
+ // split failed?? On a curved edge we must split at least once
to
+ // avoid potentially degenerate polygons (if we had to split a
closed
+ // loop from step 1, for example;
+ return false;
+ } else {
+ // To avoid representing circles with squares, split curved
segments
+ // one additional time
+ std::set<cdt_mesh::bedge_seg_t *>::iterator s_it;
+ for (s_it = efirst.begin(); s_it != efirst.end(); s_it++) {
+ std::set<cdt_mesh::bedge_seg_t *> etmp =
split_edge_seg(s_cdt, *s_it, 1);
+ if (!etmp.size()) {
+ // split failed?? This isn't good and shouldn't
+ // happen, but it's not fatal the way the previous two
+ // failure cases are...
+ esegs_csplit.insert(*s_it);
+ } else {
+ esegs_csplit.insert(etmp.begin(), etmp.end());
+ }
+ }
+ }
+ }
+ } else {
+ esegs_csplit = esegs_closed;
+ }
+
+ s_cdt->e2polysegs[edge.m_edge_index].clear();
+ s_cdt->e2polysegs[edge.m_edge_index].insert(esegs_csplit.begin(),
esegs_csplit.end());
+
+ return true;
+}
+
+// Charcterize the edges. Five possibilities:
+//
+// 0. Singularity
+// 1. Curved edge
+// 2. Linear edge, associated with at least 1 non-planar surface
+// 3. Linear edge, associated with planar surfaces but sharing one or more
vertices with
+// curved edges.
+// 4. Linear edge, associated only with planar faces and linear edges.
+std::vector<int>
+characterize_edges(struct ON_Brep_CDT_State *s_cdt)
+{
+ ON_Brep* brep = s_cdt->brep;
+
+ // Characterize the vertices - are they used by non-linear edges?
+ std::vector<int> vert_type;
+ for (int i = 0; i < brep->m_V.Count(); i++) {
+ int has_curved_edge = 0;
+ for (int j = 0; j < brep->m_V[i].m_ei.Count(); j++) {
+ ON_BrepEdge &edge = brep->m_E[brep->m_V[i].m_ei[j]];
+ const ON_Curve* crv = edge.EdgeCurveOf();
+ if (crv && !crv->IsLinear(BN_TOL_DIST)) {
+ has_curved_edge = 1;
+ break;
+ }
+ }
+ vert_type.push_back(has_curved_edge);
+ }
+
+ std::vector<int> edge_type;
+ for (int index = 0; index < brep->m_E.Count(); index++) {
+ ON_BrepEdge& edge = brep->m_E[index];
+ const ON_Curve* crv = edge.EdgeCurveOf();
+
+ // Singularity
+ if (!crv) {
+ edge_type.push_back(0);
+ continue;
+ }
+
+ // Curved edge
+ if (!crv->IsLinear(BN_TOL_DIST)) {
+ edge_type.push_back(1);
+ continue;
+ }
+
+ // Linear edge, at least one non-planar surface
+ const ON_Surface *s1= edge.Trim(0)->SurfaceOf();
+ const ON_Surface *s2= edge.Trim(1)->SurfaceOf();
+ if (!s1->IsPlanar(NULL, BN_TOL_DIST) || !s2->IsPlanar(NULL,
BN_TOL_DIST)) {
+ edge_type.push_back(2);
+ continue;
+ }
+
+ // Linear edge, at least one associated non-linear edge
+ if (vert_type[edge.Vertex(0)->m_vertex_index] ||
vert_type[edge.Vertex(1)->m_vertex_index]) {
+ edge_type.push_back(3);
+ continue;
+ }
+
+ // Linear edge, only associated with linear edges and planar faces
+ edge_type.push_back(4);
+ }
+ return edge_type;
+}
+
+// Set up the edge containers that will manage the edge subdivision. Loop
+// ordering is not the job of these containers - that's handled by the trim
loop
+// polygons. These containers maintain the association between trims in
different
+// faces and the 3D edge curve information used to drive shared points.
+void
+initialize_edge_containers(struct ON_Brep_CDT_State *s_cdt)
+{
+ ON_Brep* brep = s_cdt->brep;
+
+ // Charcterize the edges.
+ std::vector<int> edge_type = characterize_edges(s_cdt);
+
+ for (int index = 0; index < brep->m_E.Count(); index++) {
+ ON_BrepEdge& edge = brep->m_E[index];
+ cdt_mesh::bedge_seg_t *bseg = new cdt_mesh::bedge_seg_t;
+ bseg->edge_ind = edge.m_edge_index;
+ bseg->brep = s_cdt->brep;
+
+ // Provide a normalize edge NURBS curve
+ const ON_Curve* crv = edge.EdgeCurveOf();
+ bseg->nc = crv->NurbsCurve();
+ bseg->cp_len = bseg->nc->ControlPolygonLength();
+ bseg->nc->SetDomain(0.0, bseg->cp_len);
+
+ // Set the initial edge curve t parameter values
+ bseg->edge_start = 0.0;
+ bseg->edge_end = bseg->cp_len;
+
+ // Get the trims and normalize their domains as well.
+ // NOTE - another point where this won't work if we don't have a 1->2
edge to trims relationship
+ ON_BrepTrim *trim1 = edge.Trim(0);
+ ON_BrepTrim *trim2 = edge.Trim(1);
+ s_cdt->brep->m_T[trim1->TrimCurveIndexOf()].SetDomain(bseg->edge_start,
bseg->edge_end);
+ s_cdt->brep->m_T[trim2->TrimCurveIndexOf()].SetDomain(bseg->edge_start,
bseg->edge_end);
+
+ // The 3D start and endpoints will be vertex points (they are shared
with other edges).
+ bseg->e_start = (*s_cdt->vert_pnts)[edge.Vertex(0)->m_vertex_index];
+ bseg->e_end = (*s_cdt->vert_pnts)[edge.Vertex(1)->m_vertex_index];
+
+ // These are also the root start and end points - type 3 edges will
need this information later
+ bseg->e_root_start = bseg->e_start;
+ bseg->e_root_end = bseg->e_end;
+
+ // Stash the edge type - we will need it during refinement
+ bseg->edge_type = edge_type[edge.m_edge_index];
+
+ s_cdt->e2polysegs[edge.m_edge_index].insert(bseg);
+ }
+}
+
+// For each face and each loop in each face define the initial
+// loop polygons. Note there is no splitting of edges at this point -
+// we are simply establishing the initial closed polygons.
+bool
+initialize_loop_polygons(struct ON_Brep_CDT_State *s_cdt,
std::set<cdt_mesh::cpolyedge_t *> *singular_edges)
+{
+ ON_Brep* brep = s_cdt->brep;
+ for (int face_index = 0; face_index < brep->m_F.Count(); face_index++) {
+ ON_BrepFace &face = s_cdt->brep->m_F[face_index];
+ int loop_cnt = face.LoopCount();
+ cdt_mesh::cdt_mesh_t *fmesh = &s_cdt->fmeshes[face_index];
+ fmesh->f_id = face_index;
+ fmesh->m_bRev = face.m_bRev;
+ fmesh->has_singularities = false;
+ cdt_mesh::cpolygon_t *cpoly = NULL;
+
+ for (int li = 0; li < loop_cnt; li++) {
+ const ON_BrepLoop *loop = face.Loop(li);
+ bool is_outer = (face.OuterLoop()->m_loop_index ==
loop->m_loop_index) ? true : false;
+ if (is_outer) {
+ cpoly = &fmesh->outer_loop;
+ } else {
+ cpoly = new cdt_mesh::cpolygon_t;
+ fmesh->inner_loops[li] = cpoly;
+ }
+ int trim_count = loop->TrimCount();
+
+ ON_2dPoint cp(0,0);
+
+ long cv = -1;
+ long pv = -1;
+ long fv = -1;
+
+ for (int lti = 0; lti < trim_count; lti++) {
+ ON_BrepTrim *trim = loop->Trim(lti);
+ ON_Interval range = trim->Domain();
+ if (lti == 0) {
+ // Get the 2D point, add it to the mesh and current polygon
+ cp = trim->PointAt(range.m_t[0]);
+ long find = fmesh->add_point(cp);
+ pv = cpoly->add_point(cp, find);
+ fv = pv;
+
+ // Let cdt_mesh know about new 3D information
+ ON_3dPoint *op3d =
(*s_cdt->vert_pnts)[trim->Vertex(0)->m_vertex_index];
+ ON_3dVector norm = ON_3dVector::UnsetVector;
+ if (trim->m_type != ON_BrepTrim::singular) {
+ // 3D points are globally unique, but normals are not -
the same edge point may
+ // have different normals from two faces at a sharp
edge. Calculate the
+ // face normal for this point on this surface.
+ norm = calc_trim_vnorm(*trim->Vertex(0), trim);
@@ Diff output truncated at 100000 characters. @@
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