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;
}