Esempio n. 1
0
int
brep_edge_check(int reason,
		const SubsurfaceBBNode* sbv,
		const ON_BrepFace* face,
		const ON_Surface* surf,
		const ON_Ray& r,
		HitList& hits)
{
    // if the intersection was not found for any reason, we need to
    // check and see if we are close to any topological edges; we may
    // have hit a crack...

    // the proper way to do this is to only look at edges
    // interesecting with the subsurface bounding box... but for
    // now, we'll look at the edges associated with the face for the bounding box...

    // XXX - optimize this

    set<ON_BrepEdge*> edges;
    ON_3dPoint pt;
    for (int i = 0; i < face->LoopCount(); i++) {
	ON_BrepLoop* loop = face->Loop(i);
	for (int j = 0; j < loop->TrimCount(); j++) {
	    ON_BrepTrim* trim = loop->Trim(j);
	    ON_BrepEdge* edge = trim->Edge();
	    pair<set<ON_BrepEdge*>::iterator, bool> res = edges.insert(edge);
	    //	    if (res.second) {
	    // only check if its the first time we've seen this
	    // edge
	    const ON_Curve* curve = edge->EdgeCurveOf();
	    Sample s;
	    if (curve->CloseTo(ON_3dPoint(hits.back().point), BREP_EDGE_MISS_TOLERANCE, s)) {
		TRACE1("CLOSE TO EDGE");
		hits.back().closeToEdge = true;
		return BREP_INTERSECT_FOUND;
	    }
	}
    }
    return BREP_INTERSECT_TRIMMED;
}
bool ON_Brep::IsValidForV2( const ON_BrepTrim& trim ) const
{
    int ti = trim.m_trim_index;
    if ( ti < 0 || ti >= m_T.Count() )
        return false;
    if ( &trim != &m_T[ti] )
        return false;
    if ( trim.ProxyCurveIsReversed() )
        return false;
    if ( trim.Domain() != trim.ProxyCurveDomain() )
        return false;
    const ON_Curve * curve = trim.TrimCurveOf();
    if ( curve != trim.ProxyCurve() )
        return false;
    const ON_NurbsCurve* nurbs_curve = ON_NurbsCurve::Cast(curve);
    if ( 0 == nurbs_curve )
        return false;
    if ( !nurbs_curve->IsClamped(2) )
        return false;
    if ( nurbs_curve->m_dim != 2 )
        return false;
    if ( nurbs_curve->m_is_rat )
    {
        // 2 June 2003 Dale Lear - RR 8809 fix
        //    V2 likes end weights to be 1.0
        if ( nurbs_curve->m_cv[2] != 1.0 || nurbs_curve->CV(nurbs_curve->m_cv_count-1)[2] != 1.0 )
        {
            return false;
        }
    }

    if (    nurbs_curve->m_cv_count >= 4
            && 0 == ON_ComparePoint( nurbs_curve->m_dim, nurbs_curve->m_is_rat, nurbs_curve->m_cv, nurbs_curve->CV(nurbs_curve->m_cv_count-1) )
       )
    {
        // 14 April 2003 Dale Lear
        //     RR 8843 - V2 wants ends of this trim farther apart
        if ( trim.m_vi[0] != trim.m_vi[1] )
        {
            const ON_BrepLoop* loop = Loop(trim.m_li);
            if ( 0 != loop && loop->m_ti.Count() > 1 )
                return false;
        }
    }

    if ( curve->Domain() != trim.Domain() )
        return false;

    return true;
}
static bool RebuildVertexToTrimEnd(ON_BrepTrim& T, int end)

{
  ON_Brep* pB = T.Brep();
  if (!pB) return false;
  int vid = T.m_vi[end];
  if (vid < 0) return false;
  ON_BrepVertex& V = pB->m_V[vid];
  ON_3dPoint P;
  if (end){
    if (!pB->GetTrim3dEnd(T.m_trim_index, P))
      return false;
  }
  else {
    if (!pB->GetTrim3dStart(T.m_trim_index, P))
      return false;
  }

  V.SetPoint(P);

  return true;

}
Esempio n. 4
0
osg::Node* RhinoReader::BuildShadedFace(const ON_BrepFace* theFace)
{
    osg::ref_ptr<osg::Geode> aGeode = new osg::Geode();
    
    ON_NurbsSurface aSurface;

    if (theFace->GetNurbForm(aSurface) == 0)
    {
        return NULL;
    }

    osg::ref_ptr<osg::Geometry> aGeometry = new osg::Geometry();

    osg::ref_ptr<osg::Vec3Array> aUVPoints = new osg::Vec3Array();
    osg::ref_ptr<osg::Vec3Array> aPoints = new osg::Vec3Array();
    osg::ref_ptr<osg::Vec3Array> aBounds = new osg::Vec3Array();

    osg::ref_ptr<osgUtil::DelaunayTriangulator> dt = new osgUtil::DelaunayTriangulator();
    osg::ref_ptr<osgUtil::DelaunayConstraint> dc = new osgUtil::DelaunayConstraint();

    // add loop for the face.
    for (int i = 0; i < theFace->LoopCount(); ++i)
    {
        ON_BrepLoop* aLoop = theFace->Loop(i);

        if (aLoop->m_type == ON_BrepLoop::outer)
        {
            for (int j = 0; j < aLoop->TrimCount(); ++j)
            {
                ON_BrepTrim* aTrim = aLoop->Trim(j);

                const ON_Curve* aPCurve = aTrim->TrimCurveOf();
                if (aPCurve)
                {
                    ON_3dPoint aStartPoint = aPCurve->PointAtStart();
                    ON_3dPoint aEndPoint = aPCurve->PointAtEnd();

                    aUVPoints->push_back(osg::Vec3(aStartPoint.x, aStartPoint.y, 0.0));
                    aUVPoints->push_back(osg::Vec3(aEndPoint.x, aEndPoint.y, 0.0));
                }
            }
        }
        else if (aLoop->m_type == ON_BrepLoop::inner)
        {
            for (int j = 0; j < aLoop->TrimCount(); ++j)
            {
            }
        }
    }

    dc->setVertexArray(aBounds);
    dc->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_LOOP, 0, aBounds->size()));

    // triangulate the parametric space.
    //dt->addInputConstraint(dc);
    dt->setInputPointArray(aUVPoints);
    dt->triangulate();
    //dt->removeInternalTriangles(dc);

    for (osg::Vec3Array::const_iterator j = aUVPoints->begin(); j != aUVPoints->end(); ++j)
    {
        // evaluate the point on the surface
        ON_3dPoint aPoint = aSurface.PointAt((*j).x(), (*j).y());

        aPoints->push_back(osg::Vec3(aPoint.x, aPoint.y, aPoint.z));
    }

    //aGeometry->setVertexArray(aUVPoints);
    aGeometry->setVertexArray(aPoints);
    aGeometry->addPrimitiveSet(dt->getTriangles());

    aGeode->addDrawable(aGeometry);

    // use smoothing visitor to set the average normals
    //osgUtil::SmoothingVisitor sv;
    //sv.apply(*aGeode);

    return aGeode.release();
}
static
bool SplitSeam( ON_Brep& brep, 
                ON_BrepTrim& trimA, ON_BrepTrim& trimB,
                ON_BrepTrim& prevtrimB,
                ON_BrepTrim& nexttrimB,
                int vcount0 // number of verts before singular fixups
                )
{
  if ( trimA.m_trim_index == trimB.m_trim_index )
    return false;
  if ( trimA.m_trim_index == prevtrimB.m_trim_index )
    return false;
  if ( trimA.m_trim_index == nexttrimB.m_trim_index )
    return false;
  if ( trimB.m_trim_index == prevtrimB.m_trim_index )
    return false;
  if ( trimB.m_trim_index == nexttrimB.m_trim_index )
    return false;
  if ( prevtrimB.m_trim_index == nexttrimB.m_trim_index )
    return false;
  if ( trimA.m_type != ON_BrepTrim::seam )
    return false;
  if ( trimB.m_type != ON_BrepTrim::seam )
    return false;
  if ( trimA.m_ei != trimB.m_ei )
    return false;
  if (    trimA.m_vi[0] != trimB.m_vi[1] 
       && trimA.m_vi[0] < vcount0
       && trimB.m_vi[1] < vcount0 )
    return false;
  if (    trimA.m_vi[1] != trimB.m_vi[0] 
       && trimA.m_vi[1] < vcount0
       && trimB.m_vi[0] < vcount0 )
    return false;
  if ( prevtrimB.m_vi[1] != trimB.m_vi[0] 
       && prevtrimB.m_vi[1] < vcount0
       && trimB.m_vi[0] < vcount0 )
    return false;
  if ( nexttrimB.m_vi[0] != trimB.m_vi[1]
       && prevtrimB.m_vi[0] < vcount0
       && trimB.m_vi[1] < vcount0 )
    return false;
  if ( trimA.m_li != trimB.m_li )
    return false;
  if ( trimA.m_li != prevtrimB.m_li )
    return false;
  if ( trimA.m_li != nexttrimB.m_li )
    return false;
  if ( trimA.m_bRev3d == trimB.m_bRev3d )
    return false;
  const ON_Surface* srf = trimA.SurfaceOf();
  if ( 0 == srf )
    return false;
  ON_BrepEdge* edgeA = brep.Edge(trimA.m_ei);
  if ( 0 == edgeA )
    return false;
  if ( edgeA->m_ti.Count() != 2 )
    return false;
  if ( edgeA->m_ti[0] != trimA.m_trim_index && edgeA->m_ti[1] != trimA.m_trim_index )
    return false;
  if ( edgeA->m_ti[0] != trimB.m_trim_index && edgeA->m_ti[1] != trimB.m_trim_index )
    return false;

  // reserve space now so the vA0 and vA1 pointers
  // will be valid if m_V[] is grown.
  brep.m_V.Reserve( brep.m_V.Count()+2 );

  ON_BrepVertex* vA0 = brep.Vertex(trimA.m_vi[0]);
  if ( 0 == vA0 )
    return false;
  ON_BrepVertex* vA1 = brep.Vertex(trimA.m_vi[1]);
  if ( 0 == vA1 )
    return false;

  // looks like we have a valid seam to blow apart

  // get a new 3d curve for trimB
  ON_Curve* cB3 = PushUpIsoTrim( brep, trimB );
  if ( 0 == cB3 )
    return false;
  int c3i = brep.AddEdgeCurve(cB3);

  vA0->m_tolerance = ON_UNSET_VALUE;
  vA1->m_tolerance = ON_UNSET_VALUE;

  // make new vertices for trimB
  ON_BrepVertex* vB0 = 0;
  ON_BrepVertex* vB1 = 0;

  ON_3dPoint PA, PB;
  bool bSame = false;

  if (brep.GetTrim3dStart(trimB.m_trim_index, PB) && brep.GetTrim3dEnd(trimA.m_trim_index, PA))
    bSame = PB.DistanceTo(PA) < ON_ZERO_TOLERANCE;
  if (bSame || trimB.m_vi[0] != trimA.m_vi[1] )
  {
    // sing fixups have already blown apart this end
    vB0 = brep.Vertex( trimB.m_vi[0] );
  }

  bSame = false;
  if (brep.GetTrim3dStart(trimA.m_trim_index, PA) && brep.GetTrim3dEnd(trimB.m_trim_index, PB))
    bSame = PB.DistanceTo(PA) < ON_ZERO_TOLERANCE;
  if (bSame || trimB.m_vi[1] != trimA.m_vi[0] )
  {
    // sing fixups have already blown apart this end
    vB1 = brep.Vertex( trimB.m_vi[1] );
  }
  if ( 0 == vB0 )
  {
    ON_BrepVertex& v = brep.NewVertex();
    vB0 = &v;
    trimB.m_vi[0] = vB0->m_vertex_index;
  }
  if ( 0 == vB1 )
  {
    ON_BrepVertex& v = brep.NewVertex();
    vB1 = &v;
    trimB.m_vi[1] = vB1->m_vertex_index;
  }

  // disconnect edgeA and trimB
  trimB.m_ei = -1;
  if ( edgeA->m_ti[0] == trimB.m_trim_index )
    edgeA->m_ti.Remove(0);
  else if ( edgeA->m_ti[1] == trimB.m_trim_index )
    edgeA->m_ti.Remove(1);
  ChangeTrimVertex( brep, trimB, 0, vA1->m_vertex_index, vB0->m_vertex_index, true, true );
  ChangeTrimVertex( brep, trimB, 1, vA0->m_vertex_index, vB1->m_vertex_index, true, true );

  ChangeTrimVertex( brep, prevtrimB, 1, vA1->m_vertex_index, vB0->m_vertex_index, true, true );
  ChangeTrimVertex( brep, nexttrimB, 0, vA0->m_vertex_index, vB1->m_vertex_index, true, true );

  // make a new edgeB and connect it to trimB
  ON_BrepEdge& edgeB = brep.NewEdge( *vB0, *vB1, c3i );
  edgeA = 0; // pointer may be invalid after m_E[] grows

  edgeB.m_ti.Append(trimB.m_trim_index);
  trimB.m_ei = edgeB.m_edge_index;
  trimB.m_bRev3d = false;

  trimA.m_type = ON_BrepTrim::boundary;
  trimB.m_type = ON_BrepTrim::boundary;

  return true;
}
static
bool ChangeTrimSingToBdry( ON_Brep& brep, ON_BrepTrim& trim, ON_BrepTrim* nexttrim )
{
  if ( trim.m_vi[0] != trim.m_vi[1] )
    return false;
  if ( trim.m_type != ON_BrepTrim::singular )
    return false;
  if ( trim.m_ei >= 0 )
    return false;

  const ON_Surface* srf = trim.SurfaceOf();
  if ( 0 == srf )
    return false;

  brep.m_V.Reserve( brep.m_V.Count() + 1 );
  ON_BrepVertex* v0 = brep.Vertex(trim.m_vi[0]);
  if ( 0 == v0 )
    return false;

  // get new 3d curve
  ON_Curve* c3 = PushUpIsoTrim( brep, trim );
  if ( 0 == c3 )
    return false;

  // valid singular trim can be changed to non-singular trim


  // create new vertex for end of this trim
  v0->m_tolerance = ON_UNSET_VALUE;

  ON_BrepVertex* v1 = 0;

  if ( c3->IsClosed() )
  {
    // 3d edge is closed so start and end vertex are still the same.
    v1 = v0;
  }
  else
  {
    // new 3d edge is not closed, so the single singular vertex
    // needs to be "split" into two vertices.
    brep.NewVertex();
    v1 = brep.m_V.Last();
  }
  trim.m_vi[1] = v1->m_vertex_index;

  // update the start of the next trim to use new vertex
  if ( nexttrim && nexttrim->m_trim_index != trim.m_trim_index )
  {
    ChangeTrimVertex( brep, *nexttrim, 0, v0->m_vertex_index, v1->m_vertex_index, true, true );
  }              

  // make a new edge
  int ci = brep.AddEdgeCurve(c3);
  c3 = 0;
  ON_BrepEdge& edge = brep.NewEdge(*v0,*v1,ci);
  edge.m_tolerance = 0.0;

  // hook trim to new edge
  trim.m_type = ON_BrepTrim::boundary;
  trim.m_bRev3d = false;
  trim.m_ei = edge.m_edge_index;
  edge.m_ti.Append(trim.m_trim_index);

  return true;
}
void
subbrep_planar_init(struct subbrep_object_data *data)
{
    if (!data) return;
    if (data->planar_obj) return;
    BU_GET(data->planar_obj, struct subbrep_object_data);
    subbrep_object_init(data->planar_obj, data->brep);
    bu_vls_sprintf(data->planar_obj->key, "%s", bu_vls_addr(data->key));
    data->planar_obj->obj_cnt = data->obj_cnt;
    (*data->obj_cnt)++;
    bu_vls_sprintf(data->planar_obj->name_root, "%s_%d", bu_vls_addr(data->name_root), *(data->obj_cnt));
    data->planar_obj->type = PLANAR_VOLUME;

    data->planar_obj->local_brep = ON_Brep::New();
    std::map<int, int> face_map;
    std::map<int, int> surface_map;
    std::map<int, int> edge_map;
    std::map<int, int> vertex_map;
    std::map<int, int> loop_map;
    std::map<int, int> c3_map;
    std::map<int, int> c2_map;
    std::map<int, int> trim_map;
    std::set<int> faces;
    std::set<int> fil;
    std::set<int> loops;
    std::set<int> skip_verts;
    std::set<int> skip_edges;
    std::set<int> keep_verts;
    std::set<int> partial_edges;
    std::set<int> isolated_trims;  // collect 2D trims whose parent loops aren't fully included here
    array_to_set(&faces, data->faces, data->faces_cnt);
    array_to_set(&fil, data->fil, data->fil_cnt);
    array_to_set(&loops, data->loops, data->loops_cnt);
    std::map<int, std::set<int> > face_loops;
    std::map<int, std::set<int> >::iterator fl_it;
    std::set<int>::iterator l_it;

    for (int i = 0; i < data->edges_cnt; i++) {
	int c3i;
	int new_edge_curve = 0;
	const ON_BrepEdge *old_edge = &(data->brep->m_E[data->edges[i]]);
	//std::cout << "old edge: " << old_edge->Vertex(0)->m_vertex_index << "," << old_edge->Vertex(1)->m_vertex_index << "\n";

	// See if the vertices from this edge play a role in the planar volume
	int use_edge = 2;
	for (int vi = 0; vi < 2; vi++) {
	    int vert_test = -1;
	    int vert_ind = old_edge->Vertex(vi)->m_vertex_index;
	    if (skip_verts.find(vert_ind) != skip_verts.end()) {
		vert_test = 1;
	    }
	    if (vert_test == -1 && keep_verts.find(vert_ind) != keep_verts.end()) {
		vert_test = 0;
	    }
	    if (vert_test == -1) {
		vert_test = characterize_vert(data, old_edge->Vertex(vi));
		if (vert_test) {
		    skip_verts.insert(vert_ind);
		    ON_3dPoint vp = old_edge->Vertex(vi)->Point();
		    bu_log("vert %d (%f %f %f): %d\n", vert_ind, vp.x, vp.y, vp.z, vert_test);
		} else {
		    keep_verts.insert(vert_ind);
		}
	    }
	    if (vert_test == 1) {
		use_edge--;
	    }
	}

	if (use_edge == 0) {
	    bu_log("skipping edge %d - both verts are skips\n", old_edge->m_edge_index);
	    skip_edges.insert(old_edge->m_edge_index);
	    continue;
	}

	if (use_edge == 1) {
	    bu_log("One of the verts for edge %d is a skip.\n", old_edge->m_edge_index);
	    partial_edges.insert(old_edge->m_edge_index);
	    continue;
	}

	// Get the 3D curves from the edges
	if (c3_map.find(old_edge->EdgeCurveIndexOf()) == c3_map.end()) {
	    ON_Curve *nc = old_edge->EdgeCurveOf()->Duplicate();
	    ON_Curve *tc = old_edge->EdgeCurveOf()->Duplicate();
	    if (tc->IsLinear()) {
		c3i = data->planar_obj->local_brep->AddEdgeCurve(nc);
		c3_map[old_edge->EdgeCurveIndexOf()] = c3i;
	    } else {
		ON_Curve *c3 = new ON_LineCurve(old_edge->Vertex(0)->Point(), old_edge->Vertex(1)->Point());
		c3i = data->planar_obj->local_brep->AddEdgeCurve(c3);
		c3_map[old_edge->EdgeCurveIndexOf()] = c3i;
		new_edge_curve = 1;
	    }
	} else {
	    c3i = c3_map[old_edge->EdgeCurveIndexOf()];
	}


	// Get the vertices from the edges
	int v[2];
	for (int vi = 0; vi < 2; vi++) {
	    if (vertex_map.find(old_edge->Vertex(vi)->m_vertex_index) == vertex_map.end()) {
		ON_BrepVertex& newvvi = data->planar_obj->local_brep->NewVertex(old_edge->Vertex(vi)->Point(), old_edge->Vertex(vi)->m_tolerance);
		v[vi] = newvvi.m_vertex_index;
		vertex_map[old_edge->Vertex(vi)->m_vertex_index] = v[vi];
	    } else {
		v[vi] = vertex_map[old_edge->Vertex(vi)->m_vertex_index];
	    }
	}

	ON_BrepEdge& new_edge = data->planar_obj->local_brep->NewEdge(data->planar_obj->local_brep->m_V[v[0]], data->planar_obj->local_brep->m_V[v[1]], c3i, NULL ,0);
	edge_map[old_edge->m_edge_index] = new_edge.m_edge_index;

	// Get the 2D curves from the trims
	for (int j = 0; j < old_edge->TrimCount(); j++) {
	    ON_BrepTrim *old_trim = old_edge->Trim(j);
	    if (faces.find(old_trim->Face()->m_face_index) != faces.end()) {
		if (c2_map.find(old_trim->TrimCurveIndexOf()) == c2_map.end()) {
		    ON_Curve *nc = old_trim->TrimCurveOf()->Duplicate();
		    int c2i = data->planar_obj->local_brep->AddTrimCurve(nc);
		    c2_map[old_trim->TrimCurveIndexOf()] = c2i;
		    //std::cout << "c2i: " << c2i << "\n";
		}
	    }
	}

	// Get the faces and surfaces from the trims
	for (int j = 0; j < old_edge->TrimCount(); j++) {
	    ON_BrepTrim *old_trim = old_edge->Trim(j);
	    if (face_map.find(old_trim->Face()->m_face_index) == face_map.end()) {
		if (faces.find(old_trim->Face()->m_face_index) != faces.end()) {
		    ON_Surface *ns = old_trim->Face()->SurfaceOf()->Duplicate();
		    ON_Surface *ts = old_trim->Face()->SurfaceOf()->Duplicate();
		    if (ts->IsPlanar(NULL, BREP_PLANAR_TOL)) {
			int nsid = data->planar_obj->local_brep->AddSurface(ns);
			surface_map[old_trim->Face()->SurfaceIndexOf()] = nsid;
			ON_BrepFace &new_face = data->planar_obj->local_brep->NewFace(nsid);
			face_map[old_trim->Face()->m_face_index] = new_face.m_face_index;
			//std::cout << "old face " << old_trim->Face()->m_face_index << " is now " << new_face.m_face_index << "\n";
			if (fil.find(old_trim->Face()->m_face_index) != fil.end()) {
			    data->planar_obj->local_brep->FlipFace(new_face);
			}
		    }
		}
	    }
	}

	// Get the loops from the trims
	for (int j = 0; j < old_edge->TrimCount(); j++) {
	    ON_BrepTrim *old_trim = old_edge->Trim(j);
	    ON_BrepLoop *old_loop = old_trim->Loop();
	    if (face_map.find(old_trim->Face()->m_face_index) != face_map.end()) {
		if (loops.find(old_loop->m_loop_index) != loops.end()) {
		    if (loop_map.find(old_loop->m_loop_index) == loop_map.end()) {
			face_loops[old_trim->Face()->m_face_index].insert(old_loop->m_loop_index);
		    }
		}
	    }
	}
    }
    for (fl_it = face_loops.begin(); fl_it != face_loops.end(); fl_it++) {
	int loop_cnt = fl_it->second.size();
	if (loop_cnt == 1) {
	    // If we have only one loop on a face it's an outer loop,
	    // whatever it was in the original brep.
	    const ON_BrepLoop *old_loop = &(data->brep->m_L[*(fl_it->second.begin())]);
	    ON_BrepLoop &nl = data->planar_obj->local_brep->NewLoop(ON_BrepLoop::outer, data->planar_obj->local_brep->m_F[face_map[fl_it->first]]);
	    loop_map[old_loop->m_loop_index] = nl.m_loop_index;
	} else {
	    bu_log("loop_cnt: %d\n", loop_cnt);
	    // If we ended up with multiple loops, one of them should be an outer loop
	    // and the rest inner loops
	    // Get the outer loop first
	    for (l_it = fl_it->second.begin(); l_it != fl_it->second.end(); l_it++) {
		const ON_BrepLoop *old_loop = &(data->brep->m_L[*l_it]);
		if (data->brep->LoopDirection(data->brep->m_L[*l_it]) == 1) {
		    ON_BrepLoop &nl = data->planar_obj->local_brep->NewLoop(ON_BrepLoop::outer, data->planar_obj->local_brep->m_F[face_map[fl_it->first]]);
		    loop_map[old_loop->m_loop_index] = nl.m_loop_index;
		}
	    }
	    // Now get the inner loops;
	    for (l_it = fl_it->second.begin(); l_it != fl_it->second.end(); l_it++) {
		const ON_BrepLoop *old_loop = &(data->brep->m_L[*l_it]);
		if (data->brep->LoopDirection(data->brep->m_L[*l_it]) != 1) {
		    ON_BrepLoop &nl = data->planar_obj->local_brep->NewLoop(ON_BrepLoop::inner, data->planar_obj->local_brep->m_F[face_map[fl_it->first]]);
		    loop_map[old_loop->m_loop_index] = nl.m_loop_index;
		}
	    }
	}
    }

    // Now, create new trims using the old loop definitions and the maps
    std::map<int, int>::iterator loop_it;
    std::set<int> evaluated;
    for (loop_it = loop_map.begin(); loop_it != loop_map.end(); loop_it++) {
	const ON_BrepLoop *old_loop = &(data->brep->m_L[(*loop_it).first]);
	ON_BrepLoop &new_loop = data->planar_obj->local_brep->m_L[(*loop_it).second];
	for (int j = 0; j < old_loop->TrimCount(); j++) {
	    const ON_BrepTrim *old_trim = old_loop->Trim(j);
	    ON_BrepEdge *o_edge = old_trim->Edge();
	    if (!o_edge) {
		/* If we didn't have an edge originally, we need to add the 2d curve here */
		if (c2_map.find(old_trim->TrimCurveIndexOf()) == c2_map.end()) {
		    ON_Curve *nc = old_trim->TrimCurveOf()->Duplicate();
		    int c2i = data->planar_obj->local_brep->AddTrimCurve(nc);
		    c2_map[old_trim->TrimCurveIndexOf()] = c2i;
		}
		if (vertex_map.find(old_trim->Vertex(0)->m_vertex_index) == vertex_map.end()) {
		    ON_BrepVertex& newvs = data->planar_obj->local_brep->NewVertex(old_trim->Vertex(0)->Point(), old_trim->Vertex(0)->m_tolerance);
		    vertex_map[old_trim->Vertex(0)->m_vertex_index] = newvs.m_vertex_index;
		    ON_BrepTrim &nt = data->planar_obj->local_brep->NewSingularTrim(newvs, new_loop, old_trim->m_iso, c2_map[old_trim->TrimCurveIndexOf()]);
		    nt.m_tolerance[0] = old_trim->m_tolerance[0];
		    nt.m_tolerance[1] = old_trim->m_tolerance[1];
		} else {
		    ON_BrepTrim &nt = data->planar_obj->local_brep->NewSingularTrim(data->planar_obj->local_brep->m_V[vertex_map[old_trim->Vertex(0)->m_vertex_index]], new_loop, old_trim->m_iso, c2_map[old_trim->TrimCurveIndexOf()]);
		    nt.m_tolerance[0] = old_trim->m_tolerance[0];
		    nt.m_tolerance[1] = old_trim->m_tolerance[1];
		}
		continue;
	    }

	    if (evaluated.find(o_edge->m_edge_index) != evaluated.end()) {
		bu_log("edge %d already handled, continuing...\n", o_edge->m_edge_index);
		continue;
	    }

	    // Don't use a trim connected to an edge we are skipping
	    if (skip_edges.find(o_edge->m_edge_index) != skip_edges.end()) {
		bu_log("edge %d is skipped, continuing...\n", o_edge->m_edge_index);
		evaluated.insert(o_edge->m_edge_index);
		continue;
	    }

	    int is_partial = 0;
	    if (partial_edges.find(o_edge->m_edge_index) != partial_edges.end()) is_partial = 1;

	    if (!is_partial) {
		ON_BrepEdge &n_edge = data->planar_obj->local_brep->m_E[edge_map[o_edge->m_edge_index]];
		ON_Curve *ec = o_edge->EdgeCurveOf()->Duplicate();
		if (ec->IsLinear()) {
		    ON_BrepTrim &nt = data->planar_obj->local_brep->NewTrim(n_edge, old_trim->m_bRev3d, new_loop, c2_map[old_trim->TrimCurveIndexOf()]);
		    nt.m_tolerance[0] = old_trim->m_tolerance[0];
		    nt.m_tolerance[1] = old_trim->m_tolerance[1];
		    nt.m_iso = old_trim->m_iso;
		} else {
		    // Wasn't linear, but wasn't partial either - replace with a line
		    ON_Curve *c2_orig = old_trim->TrimCurveOf()->Duplicate();
		    ON_3dPoint p1 = c2_orig->PointAt(c2_orig->Domain().Min());
		    ON_3dPoint p2 = c2_orig->PointAt(c2_orig->Domain().Max());
		    ON_Curve *c2 = new ON_LineCurve(p1, p2);
		    c2->ChangeDimension(2);
		    int c2i = data->planar_obj->local_brep->AddTrimCurve(c2);
		    ON_BrepTrim &nt = data->planar_obj->local_brep->NewTrim(n_edge, old_trim->m_bRev3d, new_loop, c2i);
		    nt.m_tolerance[0] = old_trim->m_tolerance[0];
		    nt.m_tolerance[1] = old_trim->m_tolerance[1];
		    nt.m_iso = old_trim->m_iso;
		    delete c2_orig;
		}
		delete ec;
	    } else {
		// Partial edge - let the fun begin
		ON_3dPoint p1, p2;
		ON_BrepEdge *next_edge;
		bu_log("working a partial edge: %d\n", o_edge->m_edge_index);
		int v[2];
		v[0] = o_edge->Vertex(0)->m_vertex_index;
		v[1] = o_edge->Vertex(1)->m_vertex_index;
		// figure out which trim point we can use, the min or max
		int pos1 = 0;
		if (skip_verts.find(v[0]) != skip_verts.end()) {
		    pos1 = 1;
		}
		int j_next = j;
		ON_Curve *c2_orig = old_trim->TrimCurveOf()->Duplicate();
		ON_Curve *c2_next = NULL;
		int walk_dir = 1;
		// bump the loop iterator to get passed any skipped edges to
		// the next partial
		while (!c2_next) {
		    (walk_dir == 1) ? j_next++ : j_next--;
		    if (j_next == old_loop->TrimCount()) {
			j_next = 0;
		    }
		    if (j_next == -1) {
			j_next = old_loop->TrimCount() - 1;
		    }
		    const ON_BrepTrim *next_trim = old_loop->Trim(j_next);
		    next_edge = next_trim->Edge();
		    if (!next_edge) continue;
		    if (skip_edges.find(next_edge->m_edge_index) == skip_edges.end()) {
			if (partial_edges.find(next_edge->m_edge_index) != partial_edges.end()) {
			    bu_log("found next partial edge %d\n", next_edge->m_edge_index);
			    evaluated.insert(next_edge->m_edge_index);
			    c2_next = next_trim->TrimCurveOf()->Duplicate();
			} else {
			    bu_log("partial edge %d followed by non-partial %d, need to go the other way\n", o_edge->m_edge_index, next_edge->m_edge_index);
			    j_next--;
			    walk_dir = -1;
			}
		    } else {
			bu_log("skipping fully ignored edge %d\n", next_edge->m_edge_index);
			evaluated.insert(next_edge->m_edge_index);
		    }
		}
		int v2[2];
		v2[0] = next_edge->Vertex(0)->m_vertex_index;
		v2[1] = next_edge->Vertex(1)->m_vertex_index;
		// figure out which trim point we can use, the min or max
		int pos2 = 0;
		if (skip_verts.find(v2[0]) != skip_verts.end()) {
		    pos2 = 1;
		}

		int vmapped[2];
		if (vertex_map.find(o_edge->Vertex(pos1)->m_vertex_index) == vertex_map.end()) {
		    ON_BrepVertex& newvvi = data->planar_obj->local_brep->NewVertex(o_edge->Vertex(pos1)->Point(), o_edge->Vertex(pos1)->m_tolerance);
		    vertex_map[o_edge->Vertex(pos1)->m_vertex_index] = newvvi.m_vertex_index;
		}
		if (vertex_map.find(next_edge->Vertex(pos2)->m_vertex_index) == vertex_map.end()) {
		    ON_BrepVertex& newvvi = data->planar_obj->local_brep->NewVertex(next_edge->Vertex(pos2)->Point(), next_edge->Vertex(pos2)->m_tolerance);
		    vertex_map[next_edge->Vertex(pos2)->m_vertex_index] = newvvi.m_vertex_index;
		}

		// If walk_dir is -1, need to flip things around (I think...) the verts and trim points
		// will be swapped compared to a forward walk
		if (walk_dir == -1) {
		    vmapped[1] = vertex_map[o_edge->Vertex(pos1)->m_vertex_index];
		    vmapped[0] = vertex_map[next_edge->Vertex(pos2)->m_vertex_index];
		} else {
		    vmapped[0] = vertex_map[o_edge->Vertex(pos1)->m_vertex_index];
		    vmapped[1] = vertex_map[next_edge->Vertex(pos2)->m_vertex_index];
		}

		// New Edge curve
		ON_Curve *c3 = new ON_LineCurve(o_edge->Vertex(pos1)->Point(), next_edge->Vertex(pos2)->Point());
		int c3i = data->planar_obj->local_brep->AddEdgeCurve(c3);
		ON_BrepEdge& new_edge = data->planar_obj->local_brep->NewEdge(data->planar_obj->local_brep->m_V[vmapped[0]], data->planar_obj->local_brep->m_V[vmapped[1]], c3i, NULL ,0);

		// Again, flip if walk_dir is -1
		if (walk_dir == -1) {
		    p2 = c2_orig->PointAt(c2_orig->Domain().Min());
		    p1 = c2_next->PointAt(c2_orig->Domain().Max());
		} else {
		    p1 = c2_orig->PointAt(c2_orig->Domain().Min());
		    p2 = c2_next->PointAt(c2_orig->Domain().Max());
		}
		std::cout << "p1: " << pout(p1) << "\n";
		std::cout << "p2: " << pout(p2) << "\n";
		ON_Curve *c2 = new ON_LineCurve(p1, p2);
		c2->ChangeDimension(2);
		int c2i = data->planar_obj->local_brep->AddTrimCurve(c2);
		ON_BrepTrim &nt = data->planar_obj->local_brep->NewTrim(new_edge, false, new_loop, c2i);
		nt.m_tolerance[0] = old_trim->m_tolerance[0];
		nt.m_tolerance[1] = old_trim->m_tolerance[1];
		nt.m_iso = old_trim->m_iso;
		delete c2_orig;
		delete c2_next;
	    }
	}
    }

    // If there is a possibility of a negative volume for the planar solid, do a test.
    // The only way to get a negative planar solid in this context is if that solid is
    // "inside" a non-planar shape (it would be "part of" the parent shape if it were
    // planar and it would be a separate shape altogether if it were not topologically
    // connected.  So we take one partial edge, find its associated non-planar faces,
    // and collect all the partial and skipped edges from that face and any non-planar
    // faces associated with the other partial/skipped edges.
    //
    // TODO - We still have an unhandled possibility here - the self-intersecting
    // planar_obj.  For example:
    //
    //           *                *
    //       *       *        *       *
    //     *     *      *   *    *      *
    //    *     * *      * *    * *      *
    //   *     *   *           *   *      *
    //   * *  *     * * * * * *     *  *  *
    //
    if (partial_edges.size() > 0) {
	std::queue<int> connected_faces;
	std::set<int> relevant_edges;
	std::set<int>::iterator re_it;
	std::set<int> efaces;
	std::set<int>::iterator f_it;
	std::set<int> found_faces;
	const ON_BrepEdge *seed_edge = &(data->brep->m_E[*partial_edges.begin()]);
	for (int j = 0; j < seed_edge->TrimCount(); j++) {
	    ON_BrepTrim *trim = seed_edge->Trim(j);
	    efaces.insert(trim->Face()->m_face_index);
	}
	for(f_it = efaces.begin(); f_it != efaces.end(); f_it++) {
	    surface_t stype = GetSurfaceType(data->brep->m_F[*f_it].SurfaceOf(), NULL);
	    if (stype != SURFACE_PLANE) {
		connected_faces.push(data->brep->m_F[*f_it].m_face_index);
	    }
	}
	while (!connected_faces.empty()) {
	    int face_index = connected_faces.front();
	    connected_faces.pop();
	    std::set<int> local_edges;
	    std::set<int>::iterator le_it;
	    found_faces.insert(face_index);
	    const ON_BrepFace *face = &(data->brep->m_F[face_index]);
	    const ON_BrepLoop *loop = NULL;
	    // Find the loop in this face that is associated with this subbrep
	    for (int i = 0; i < face->LoopCount(); i++) {
		int loop_ind = face->Loop(i)->m_loop_index;
		if (loops.find(loop_ind) != loops.end()) {
		    loop = &(data->brep->m_L[loop_ind]);
		    break;
		}
	    }
	    // Collect the edges that are partial or skipped
	    for (int i = 0; i < loop->TrimCount(); i++) {
		const ON_BrepTrim *trim = loop->Trim(i);
		ON_BrepEdge *edge = trim->Edge();
		if (edge) {
		    if (partial_edges.find(edge->m_edge_index) != partial_edges.end()) {
			relevant_edges.insert(edge->m_edge_index);
			local_edges.insert(edge->m_edge_index);
		    }
		    if (skip_edges.find(edge->m_edge_index) != skip_edges.end()) {
			relevant_edges.insert(edge->m_edge_index);
			local_edges.insert(edge->m_edge_index);
		    }
		}
	    }
	    // For each collected partial/skipped edge, add any faces not already
	    // found to the queue.
	    for (le_it = local_edges.begin(); le_it != local_edges.end(); le_it++) {
		const ON_BrepEdge *edge = &(data->brep->m_E[*le_it]);
		for (int j = 0; j < edge->TrimCount(); j++) {
		    ON_BrepTrim *trim = edge->Trim(j);
		    if (found_faces.find(trim->Face()->m_face_index) == found_faces.end()) {
			found_faces.insert(trim->Face()->m_face_index);
			connected_faces.push(trim->Face()->m_face_index);
		    }
		}
	    }
	}
	// Build two bounding boxes - one with the new verts in planar_obj, and the other with
	// the edges found above.
	ON_BoundingBox pbb, ebb;
	ON_MinMaxInit(&pbb.m_min, &pbb.m_max);
	ON_MinMaxInit(&ebb.m_min, &ebb.m_max);
	for (int i = 0; i < data->planar_obj->local_brep->m_V.Count(); i++) {
	    const ON_BrepVertex *v = &(data->planar_obj->local_brep->m_V[i]);
	    pbb.Set(v->Point(), true);
	}
	for (re_it = relevant_edges.begin(); re_it != relevant_edges.end(); re_it++) {
	    const ON_BrepEdge *e = &(data->brep->m_E[*re_it]);
	    ON_BoundingBox cbb = e->EdgeCurveOf()->BoundingBox();
	    ebb.Set(cbb.m_min, true);
	    ebb.Set(cbb.m_max, true);
	}
	//std::cout << "in pbb.s rpp " << pout(pbb.m_min) << " " << pout(pbb.m_max) << "\n";
	//std::cout << "in ebb.s rpp " << pout(ebb.m_min) << " " << pout(ebb.m_max) << "\n";

	if (ebb.Includes(pbb)) {
	    bu_log("negative volume\n");
	    data->planar_obj->negative_shape = -1;
	} else {
	    bu_log("positive volume\n");
	    data->planar_obj->negative_shape = 1;
	}
	data->planar_obj->params->bool_op = (data->planar_obj->negative_shape == -1) ? '-' : 'u';
    }

    // Need to preserve the vertex map for this, since we're not done building up the brep
    map_to_array(&(data->planar_obj->planar_obj_vert_map), &(data->planar_obj->planar_obj_vert_cnt), &vertex_map);

    data->planar_obj->local_brep->SetTrimTypeFlags(true);

}
// Criteria:
//
// 1.  A linear edge associated with a planar face == 0
// 2.  All linear edges associated with non-planar faces are part
//     of the same CSG shape AND all non-linear edges' non-planar faces
//     are also part of that same CSG shape = 1
// 3.  If not 2, 0
int
characterize_vert(struct subbrep_object_data *data, const ON_BrepVertex *v)
{
    std::set<int> non_planar_faces;
    std::set<int>::iterator f_it;
    std::set<struct filter_obj *> fobjs;
    std::set<struct filter_obj *>::iterator fo_it;
    struct filter_obj *control = NULL;

    for (int i = 0; i < v->m_ei.Count(); i++) {
	std::set<int> efaces;
	const ON_BrepEdge *edge = &(data->brep->m_E[v->m_ei[i]]);
	ON_Curve *tc = edge->EdgeCurveOf()->Duplicate();
	int is_linear = tc->IsLinear();
	delete tc;
	// Get the faces associated with the edge
	for (int j = 0; j < edge->TrimCount(); j++) {
	    ON_BrepTrim *trim = edge->Trim(j);
	    efaces.insert(trim->Face()->m_face_index);
	}
	for(f_it = efaces.begin(); f_it != efaces.end(); f_it++) {
	    struct filter_obj *new_obj;
	    BU_GET(new_obj, struct filter_obj);
	    surface_t stype = GetSurfaceType(data->brep->m_F[*f_it].SurfaceOf(), new_obj);
	    if (stype == SURFACE_PLANE) {
		filter_obj_free(new_obj);
		BU_PUT(new_obj, struct filter_obj);
		if (is_linear) {
		    for (fo_it = fobjs.begin(); fo_it != fobjs.end(); fo_it++) {
			struct filter_obj *obj = (struct filter_obj *)(*fo_it);
			filter_obj_free(obj);
			BU_PUT(obj, struct filter_obj);
		    }
		    return 0;
		}
	    } else {
		if (!control) {
		    control = new_obj;
		} else {
		    fobjs.insert(new_obj);
		}
	    }
	}
    }

    // Can this happen?
    if (fobjs.size() == 0) {
	if (control) {
	    filter_obj_free(control);
	    BU_PUT(control, struct filter_obj);
	}
	return 0;
    }

    int equal = 1;
    for(fo_it = fobjs.begin(); fo_it != fobjs.end(); fo_it++) {
	if (equal && !filter_objs_equal(*fo_it, control)) equal = 0;
	struct filter_obj *obj = (struct filter_obj *)(*fo_it);
	filter_obj_free(obj);
	BU_PUT(obj, struct filter_obj);
    }
    filter_obj_free(control);
    BU_PUT(control, struct filter_obj);

    return equal;
}