|
cgma
|
#include <CollapseCurveTool.hpp>
Public Member Functions | |
| CubitStatus | collapse_curve (DLIList< RefEdge * > ref_edge_list, DLIList< RefVertex * > ref_vertex_list, int ignore_surfaces, double *small_curve_size=NULL) |
| CubitStatus | collapse_curve_only_virtual (DLIList< RefEdge * > ref_edge_list, DLIList< RefVertex * > ref_vertex_list, int ignore_surfaces, double *small_curve_size=NULL) |
Static Public Member Functions | |
| static CollapseCurveTool * | instance () |
| static void | delete_instance () |
Private Member Functions | |
| CollapseCurveTool () | |
| ~CollapseCurveTool () | |
| CubitStatus | position_from_length (RefEdge *edge, RefVertex *root_vertex, double arc_length, CubitVector &v_new) |
Static Private Attributes | |
| static CollapseCurveTool * | instance_ = NULL |
Definition at line 16 of file CollapseCurveTool.hpp.
| CollapseCurveTool::CollapseCurveTool | ( | ) | [private] |
Definition at line 1985 of file CollapseCurveTool.cpp.
{
}
| CollapseCurveTool::~CollapseCurveTool | ( | ) | [private] |
Definition at line 1989 of file CollapseCurveTool.cpp.
{
}
| CubitStatus CollapseCurveTool::collapse_curve | ( | DLIList< RefEdge * > | ref_edge_list, |
| DLIList< RefVertex * > | ref_vertex_list, | ||
| int | ignore_surfaces, | ||
| double * | small_curve_size = NULL |
||
| ) |
Definition at line 921 of file CollapseCurveTool.cpp.
{
CubitStatus result = CUBIT_SUCCESS;
RefEdge *edge_to_collapse = ref_edge_list.get();
RefVertex *keep_vertex = NULL;
RefVertex *discard_vertex = NULL;
CoEdge *exit_coedge = NULL;
CoEdge *enter_coedge = NULL;
DLIList<RefEdge*> curves_to_partition;
DLIList<RefFace*> surfaces_to_partition;
DLIList<CubitVector> partition_positions;
DLIList<CubitVector> keep_vecs;
DLIList<CubitVector> partition_curve_vecs;
DLIList<RefFace*> adjacent_surfaces;
DLIList<double> angles;
DLIList<double> arc_lengths;
DLIList<RefEdge*> ref_edges_on_discard_vertex;
DLIList<RefEdge*> ref_edges_on_keep_vertex;
DLIList<RefVertex*> new_partition_vertices;
DLIList<RefEdge*> new_partition_edges;
RefEdge *close_edge = NULL;
RefEdge *far_edge = NULL;
DLIList<RefEdge*> edges_to_composite;
int keep_vertex_specified = 0;
int discard_valency = 0;
int keep_valency = 0;
int finished = 0;
double arc_length = 0;
double u = 0, v = 0;
CubitVector left_vec(0,0,0), right_vec(0,0,0);
CubitVector position_on_left_curve(0,0,0), position_on_right_curve(0,0,0);
CubitVector discard_pos(0,0,0), keep_pos(0,0,0);
Body *the_body;
bool undo_state = CubitUndo::get_undo_enabled();
if( undo_state )
CubitUndo::save_state_with_cubit_file( ref_edge_list );
CubitUndo::set_undo_enabled(false);
if(edge_to_collapse == NULL)
{
PRINT_ERROR("No curve was found to collapse.\n");
finished = 1;
result = CUBIT_FAILURE;
}
if(edge_to_collapse->is_merged())
{
PRINT_ERROR("Cannot collapse a merged curve.\n");
finished = 1;
result = CUBIT_FAILURE;
}
if(edge_to_collapse->start_vertex()->is_merged() &&
edge_to_collapse->end_vertex()->is_merged())
{
PRINT_ERROR("Cannot collapse a curve where both vertices are merged.\n");
finished = 1;
result = CUBIT_FAILURE;
}
else if(edge_to_collapse->start_vertex()->is_merged())
{
if(ref_vertex_list.size() > 0)
{
if(ref_vertex_list.get() == edge_to_collapse->end_vertex())
{
PRINT_ERROR("Specified vertex to collapse to is merged--try using other vertex.\n");
finished = 1;
result = CUBIT_FAILURE;
}
}
else
ref_vertex_list.append(edge_to_collapse->start_vertex());
}
else if(edge_to_collapse->end_vertex()->is_merged())
{
if(ref_vertex_list.size() > 0)
{
if(ref_vertex_list.get() == edge_to_collapse->start_vertex())
{
PRINT_ERROR("Specified vertex to collapse to is merged--try using other vertex.\n");
finished = 1;
result = CUBIT_FAILURE;
}
}
else
ref_vertex_list.append(edge_to_collapse->end_vertex());
}
if(!finished)
{
the_body = edge_to_collapse->body();
// Make sure we have a vertex to keep.
if(ref_vertex_list.size() > 0)
{
keep_vertex_specified = 1;
keep_vertex = ref_vertex_list.get();
}
// We need to choose a vertex to keep.
else
{
// Arbitrarily choose start vertex.
keep_vertex = edge_to_collapse->start_vertex();
}
// Get the vertex that will go away.
if(keep_vertex == edge_to_collapse->start_vertex())
{
discard_vertex = edge_to_collapse->end_vertex();
}
else if(keep_vertex == edge_to_collapse->end_vertex())
{
discard_vertex = edge_to_collapse->start_vertex();
}
else
{
PRINT_ERROR("Vertex to keep was not found on the curve being collapsed.\n");
result = CUBIT_FAILURE;
finished = 1;
}
}
if(!finished)
{
// Get the valency of the keep and discard vertices.
discard_vertex->ref_edges(ref_edges_on_discard_vertex);
keep_vertex->ref_edges(ref_edges_on_keep_vertex);
discard_valency = ref_edges_on_discard_vertex.size();
keep_valency = ref_edges_on_keep_vertex.size();
// Now do some error checking and also some logic to try to
// pick the best vertex to keep/discard.
// If one of the valencies is 2 just composite the vertex out.
if(discard_valency == 2)
{
CompositeTool::instance()->composite(ref_edges_on_discard_vertex);
finished = 1;
}
else if (keep_valency == 2)
{
CompositeTool::instance()->composite(ref_edges_on_keep_vertex);
finished = 1;
}
else
{
// Make sure that at least one of the vertices is qualified to
// be the discard vertex (valency of 3 or 4). The keep vertex
// really doesn't have any restrictions.
if((discard_valency > 4 || discard_valency < 3) &&
(keep_valency > 4 || keep_valency < 3))
{
PRINT_ERROR("Cannot currently collapse curves where one of the vertices does not have a valency equal to 3 or 4.\n");
result = CUBIT_FAILURE;
finished = 1;
}
else
{
if(keep_vertex_specified)
{
if(discard_valency < 3 || discard_valency > 4)
{
PRINT_ERROR("Cannot currently collapse curves where the discard vertex valency is not 3 or 4.\n"
"Try specifying the keep vertex so that the discard vertex is 3 or 4.\n");
result = CUBIT_FAILURE;
finished = 1;
}
}
else
{
// The user didn't specify a keep vertex so we can try to choose the best one.
int swap_vertices = 0;
if(discard_valency < 5 && discard_valency > 2 &&
keep_valency < 5 && keep_valency > 2)
{
// Either vertex can be the discard/keep vertex so choose the one with the
// lower valency as the discard vertex because it will require fewer operations.
if(discard_valency > keep_valency)
{
swap_vertices = 1;
}
}
else
{
// Only one of the vertices can be the discard vertex so pick it.
if(discard_valency > 4 || discard_valency < 3)
{
swap_vertices = 1;
}
}
if(swap_vertices)
{
// Swap the vertices.
RefVertex *tmp = discard_vertex;
discard_vertex = keep_vertex;
keep_vertex = tmp;
// Make sure to refresh the discard vertex edge list because
// it is used below.
ref_edges_on_discard_vertex.clean_out();
discard_vertex->ref_edges(ref_edges_on_discard_vertex);
}
}
}
}
}
if(!finished && small_curve_size)
{
// Check if the edges attached to the discard vertex are longer
// than the small curve size.
DLIList<RefEdge*> tmp_edges;
discard_vertex->ref_edges(tmp_edges);
if(tmp_edges.move_to(edge_to_collapse))
tmp_edges.extract();
int y;
bool all_edges_long_enough = true;
for(y=tmp_edges.size(); y && all_edges_long_enough; y--)
{
RefEdge *cur_edge = tmp_edges.get_and_step();
if(cur_edge->get_arc_length() <= *small_curve_size)
all_edges_long_enough = false;
}
if(!all_edges_long_enough)
{
PRINT_ERROR("Cannot collapse curve %d to vertex %d--not all of the curves attached to\n"
"vertex %d are longer than the small_curve_size. Try collapsing to vertex %d instead.\n",
edge_to_collapse->id(), keep_vertex->id(), discard_vertex->id(), discard_vertex->id());
result = CUBIT_FAILURE;
finished = 1;
}
}
// Look at all of the coedges on the curve being collapsed and
// throw out any that are on nonmanifold surfaces. The collapse
// curve may be on a boundary of a merged surface. This is ok
// but we want to make sure we don't involve this surface
// in the partitions and composites so we will remove from the
// list any coedges that are hooked to merged surfaces.
if(!finished)
{
DLIList<CoEdge*> collapse_curve_coedges;
edge_to_collapse->get_co_edges(collapse_curve_coedges);
int initial_size = collapse_curve_coedges.size();
while(collapse_curve_coedges.size() > 2 && initial_size > 0)
{
for(int g=collapse_curve_coedges.size(); g--;)
{
CoEdge *cur_coedge = collapse_curve_coedges.get_and_step();
Loop *loop_ptr = cur_coedge->get_loop_ptr();
if(loop_ptr)
{
RefFace *ref_face_ptr = loop_ptr->get_ref_face_ptr();
if(ref_face_ptr)
{
DLIList<CoFace*> coface_list;
ref_face_ptr->co_faces(coface_list);
if(coface_list.size() > 1)
{
collapse_curve_coedges.remove(cur_coedge);
g = 0;
}
}
}
}
// Keep from looping infinitely.
initial_size--;
}
// If we get to this point and have more than 2 coedges left
// in the list we are not sure what to do.
if(collapse_curve_coedges.size() != 2)
{
PRINT_ERROR("Currently can only collapse curves with manifold topology.\n");
result = CUBIT_FAILURE;
finished = 1;
}
else
{
// Get the collapse curve coedges entering and leaving the discard vertex.
exit_coedge = collapse_curve_coedges.get_and_step();
enter_coedge = collapse_curve_coedges.get();
if(enter_coedge->end_vertex() != discard_vertex)
{
CoEdge *tmp = exit_coedge;
exit_coedge = enter_coedge;
enter_coedge = tmp;
}
}
}
// Next we need to explore the topology around the discard vertex
// so that we can get the edges and surfaces that will be involved
// with the partitioning and compositing. We will identify a "left"
// and "right" edge coming out of the discard vertex and adjacent
// surfacs to these edges.
if(!finished)
{
// Get these values for use later on.
discard_pos = discard_vertex->get_point_ptr()->coordinates();
keep_pos = keep_vertex->get_point_ptr()->coordinates();
CubitVector discard_to_keep = keep_pos - discard_pos;
arc_length = edge_to_collapse->get_arc_length();
// Depending on whether the discard vertex has valency of 3 or 4 we will
// either partition 1 or 2 of the curves coming into the discard vertex
// respectively. Set up lists so that below we can just loop through the
// partitioning and compositing for either the 3 or 4 valency case.
// "Left" and "right" will be defined as if you were standing on the
// keep vertex looking at the discard vertex.
Loop *left_loop = enter_coedge->get_loop_ptr();
Loop *right_loop = exit_coedge->get_loop_ptr();
DLIList<SenseEntity*> left_sense_entities, right_sense_entities;
left_loop->get_sense_entity_list(left_sense_entities);
right_loop->get_sense_entity_list(right_sense_entities);
// We need to get these two coedges because the chains defined by the "next" and
// "previous" pointers in the CoEdge objects are not circular (you can have a NULL
// "previous" or "next" pointer). We will manage the circularity manually.
CoEdge *left_start = dynamic_cast<CoEdge*>(left_loop->get_first_sense_entity_ptr());
CoEdge *right_end = dynamic_cast<CoEdge*>(right_loop->get_last_sense_entity_ptr());
CoEdge *left_coedge = dynamic_cast<CoEdge*>(enter_coedge->next());
if(left_coedge == NULL)
{
left_coedge = left_start;
}
CoEdge *right_coedge = dynamic_cast<CoEdge*>(exit_coedge->previous());
if(right_coedge == NULL)
{
right_coedge = right_end;
}
RefEdge *left_edge = left_coedge->get_ref_edge_ptr();
RefEdge *right_edge = right_coedge->get_ref_edge_ptr();
RefFace *left_common_face = left_edge->common_ref_face(edge_to_collapse);
RefFace *right_common_face = right_edge->common_ref_face(edge_to_collapse);
double left_arc_length = left_edge->get_arc_length();
double right_arc_length = right_edge->get_arc_length();
int left_ok = 1;
int right_ok = 1;
DLIList<RefEdge*> left_face_edges;
DLIList<RefEdge*> right_face_edges;
left_common_face->ref_edges(left_face_edges);
right_common_face->ref_edges(right_face_edges);
if(left_face_edges.size() < 3 || right_face_edges.size() < 3 ||
left_sense_entities.size() < 3 || right_sense_entities.size() < 3)
{
PRINT_ERROR("Cannot collapse a curve that bounds a face or loop with only two edges.\n");
result = CUBIT_FAILURE;
finished = 1;
}
else
{
// We use the length of the curve being collapsed as the distance
// to partition the adjacent curves connected to it. If the
// adjacent curves are shorter than the curve being collapsed we
// will bail because the user should probably be getting rid
// of the adjacent edges instead or at least first.
// Get the length of the adjacent curves.
// If the adjacent curve is within resabs of the length of
// the curve being collapsed we will just snap to the end
// of the adjacent curve for our partition position.
if(arc_length > left_arc_length + GEOMETRY_RESABS)
{
left_ok = 0;
}
if(arc_length > right_arc_length + GEOMETRY_RESABS)
{
right_ok = 0;
}
// If neither curve is ok we need to bail.
if(!left_ok && !right_ok)
{
PRINT_ERROR("Curve being collapsed is too long compared to adjacent curves.\n");
result = CUBIT_FAILURE;
finished = 1;
}
}
// If it looks like the lengths of the adjacent curves are
// ok we will go ahead and try to find a partition position
// on them.
if(!finished)
{
if(left_ok)
{
// First see if we can just use the end point of the
// adjacent curve as the partition position.
if(fabs(left_arc_length-arc_length) < GEOMETRY_RESABS)
{
if(left_edge->start_vertex() == discard_vertex)
position_on_left_curve = left_edge->end_vertex()->coordinates();
else
position_on_left_curve = left_edge->start_vertex()->coordinates();
}
else
{
result = this->position_from_length(left_edge, discard_vertex,
arc_length, position_on_left_curve);
}
}
if(result == CUBIT_SUCCESS && right_ok)
{
// First see if we can just use the end point of the
// adjacent curve as the partition position.
if(fabs(right_arc_length-arc_length) < GEOMETRY_RESABS)
{
if(right_edge->start_vertex() == discard_vertex)
position_on_right_curve = right_edge->end_vertex()->coordinates();
else
position_on_right_curve = right_edge->start_vertex()->coordinates();
}
else
{
result = this->position_from_length(right_edge, discard_vertex,
arc_length, position_on_right_curve);
}
}
if(result == CUBIT_FAILURE)
{
PRINT_ERROR("Was unable to locate appropriate partition points on curves adjacent to curve being collapased.\n");
result = CUBIT_FAILURE;
finished = 1;
}
}
if(!finished)
{
// Get the vectors from the discard vertex to the potential partition locations.
CubitVector left_vec = position_on_left_curve - discard_pos;
CubitVector right_vec = position_on_right_curve - discard_pos;
// Calculate the angles between the left/right edge and the
// edge being collapsed. I am doing it this way rather than just
// calling RefEdge::angle_between() because I want the angle
// calculation done out at the potential partition location.
// This will step over any small kinks in the curve near the
// discard vertex that might otherwise give misleading angles
// that don't represent what is happening out by the potential
// partition position.
left_common_face->u_v_from_position(discard_pos, u, v);
CubitVector left_normal = left_common_face->normal_at(discard_pos, NULL, &u, &v);
double left_angle = left_normal.vector_angle(left_vec, discard_to_keep);
right_common_face->u_v_from_position(discard_pos, u, v);
CubitVector right_normal = right_common_face->normal_at(discard_pos, NULL, &u, &v);
double right_angle = right_normal.vector_angle(discard_to_keep, right_vec);
// 3 valency case:
// We only need to partition one of the curves (left or right) and
// the corresponding surface.
if(ref_edges_on_discard_vertex.size() == 3)
{
int use_left = 0;
// We can use either adjacent curve.
if(left_ok && right_ok)
{
// Choose the side with the smaller angle as this will in general
// give better angles for doing the partitioning on the surface.
CompositeSurface *cs_left = dynamic_cast<CompositeSurface*>(left_common_face->get_surface_ptr());
CompositeSurface *cs_right = dynamic_cast<CompositeSurface*>(right_common_face->get_surface_ptr());
if(!cs_left && cs_right)
use_left = 1;
else if(cs_left && !cs_right)
use_left = 0;
else
{
if(cs_left && cs_right)
{
int edge_on_ignored_left=0, edge_on_ignored_right=0;
DLIList<Surface*> srfs;
cs_left->get_ignored_surfs(srfs);
int g;
for(g=srfs.size(); g>0 && !edge_on_ignored_left; g--)
{
Surface *srf = srfs.get_and_step();
DLIList<Curve*> crvs;
srf->curves(crvs);
if(crvs.is_in_list(edge_to_collapse->get_curve_ptr()))
edge_on_ignored_left = 1;
}
srfs.clean_out();
cs_right->get_ignored_surfs(srfs);
for(g=srfs.size(); g>0 && !edge_on_ignored_right; g--)
{
Surface *srf = srfs.get_and_step();
DLIList<Curve*> crvs;
srf->curves(crvs);
if(crvs.is_in_list(edge_to_collapse->get_curve_ptr()))
edge_on_ignored_right = 1;
}
if(edge_on_ignored_left && !edge_on_ignored_right)
use_left = 0;
else if(!edge_on_ignored_left && edge_on_ignored_right)
use_left = 1;
else
{
if(left_angle < right_angle)
use_left = 1;
}
}
else
{
if(left_angle < right_angle)
use_left = 1;
}
}
}
else if(left_ok)
use_left = 1;
if(use_left)
{
curves_to_partition.append(left_edge);
surfaces_to_partition.append(left_common_face);
angles.append(left_angle);
partition_positions.append(position_on_left_curve);
arc_lengths.append(arc_length);
// These vectors will be used in calculating a bisector direction
// below if necessary.
keep_vecs.append(-discard_to_keep);
partition_curve_vecs.append(left_vec);
}
else
{
curves_to_partition.append(right_edge);
surfaces_to_partition.append(right_common_face);
angles.append(right_angle);
partition_positions.append(position_on_right_curve);
arc_lengths.append(arc_length);
// These vectors will be used in calculating a bisector direction
// below if necessary.
keep_vecs.append(discard_to_keep);
partition_curve_vecs.append(-right_vec);
}
}
else if(ref_edges_on_discard_vertex.size() == 4)
{
// We have to partition both left and right curves so make
// sure we can.
if(!left_ok || !right_ok)
{
PRINT_ERROR("One of the curves adjacent to the collapse curve is not long enough for the collapse operation.\n");
result = CUBIT_FAILURE;
finished = 1;
}
else
{
// Both curves (and surfaces) adjacent to the collapse curve (left and right)
// will need to be partitioned so add them to the lists.
curves_to_partition.append(left_edge);
curves_to_partition.append(right_edge);
surfaces_to_partition.append(left_common_face);
surfaces_to_partition.append(right_common_face);
angles.append(left_angle);
angles.append(right_angle);
keep_vecs.append(-discard_to_keep);
keep_vecs.append(discard_to_keep);
partition_curve_vecs.append(left_vec);
partition_curve_vecs.append(-right_vec);
partition_positions.append(position_on_left_curve);
partition_positions.append(position_on_right_curve);
arc_lengths.append(arc_length);
arc_lengths.append(arc_length);
}
}
else
{
PRINT_ERROR("Currently can only collapse curves with 3 or 4 valency vertices.\n");
result = CUBIT_FAILURE;
finished = 1;
}
}
}
if(!finished)
{
int num_reps = curves_to_partition.size();
curves_to_partition.reset();
surfaces_to_partition.reset();
for(int n=0; n<num_reps && !finished; ++n)
{
RefEdge *side_edge = curves_to_partition.get_and_step();
RefFace *side_face = surfaces_to_partition.get_and_step();
// Now we need to find the face on the other side of the edge.
// Because there may be edges on the boundaries of merged surfaces
// we want to find the
// face on the left/right edge that isn't the face shared by
// the collapse edge and isn't nonmanifold.
DLIList<CoEdge*> side_edge_coedges;
side_edge->co_edges(side_edge_coedges);
DLIList<RefFace*> possible_adj_faces;
// First loop through and get all of the potential faces.
for(int r=side_edge_coedges.size(); r--;)
{
CoEdge *cur_coedge = side_edge_coedges.get_and_step();
if(cur_coedge &&
cur_coedge->get_loop_ptr() &&
cur_coedge->get_loop_ptr()->get_ref_face_ptr())
{
RefFace *cur_ref_face = cur_coedge->get_loop_ptr()->get_ref_face_ptr();
if(cur_ref_face != side_face)
{
DLIList<CoFace*> coface_list;
cur_ref_face->co_faces(coface_list);
// Along with checking for whether the face is manifold we need
// to check if it belongs to the same volume as the side face.
// We have to check this because we can't composite faces
// from different volumes and these faces will be involved in
// a composite below.
if(coface_list.size() == 1 &&
side_face->ref_volume() == cur_ref_face->ref_volume())
{
possible_adj_faces.append(cur_ref_face);
}
}
}
}
// If we ended up with more than one face in the list it isn't clear
// what we should do so bail out.
if(possible_adj_faces.size() != 1)
{
PRINT_ERROR("Couldn't figure out how to perform the collapse curve with the current topology.\n");
result = CUBIT_FAILURE;
finished = 1;
}
else
{
adjacent_surfaces.append(possible_adj_faces.get());
}
}
}
if(!finished)
{
// At this point we should know which curves and surfaces we need
// to partition.
int num_reps = curves_to_partition.size();
curves_to_partition.reset();
surfaces_to_partition.reset();
adjacent_surfaces.reset();
angles.reset();
keep_vecs.reset();
partition_curve_vecs.reset();
partition_positions.reset();
arc_lengths.reset();
for(int i=0; i<num_reps && !finished; ++i)
{
RefEdge *curve_to_partition = curves_to_partition.get_and_step();
RefFace *surface_to_partition = surfaces_to_partition.get_and_step();
// Sanity check to make sure a previous operation has not
// destroyed the current face.
DLIList<RefFace*> body_faces;
the_body->ref_faces(body_faces);
if(body_faces.is_in_list(surface_to_partition))
{
// As we process each curve remove it from the list so that
// at the end we can take the last one in the list and composite
// it with the curve being collapsed.
ref_edges_on_discard_vertex.remove(curve_to_partition);
CubitVector position_on_curve = partition_positions.get_and_step();
DLIList<CubitVector*> positions;
// Add the point on the curve we just partitioned. The other
// point we normally need to add is the keep_vertex. However,
// if the angle between the collapse curve and the curve we
// just partitioned dictates that we need to introduce more points
// (this would be cases where the angle is large and just partitioning the
// surface with one curve--two points--would result in a very skinny
// surface) we need to add them before adding the keep_vertex. Therefore, check
// that now and add the extra points if needed.
positions.append(new CubitVector(position_on_curve));
double cur_angle = angles.get_and_step();
arc_length = arc_lengths.get_and_step();
// These vectors are only used in the block below if we need to
// add extra points but we need to always retrieve them from the lists
// so that the pointer in the list stays in sync with the "for" loop.
CubitVector keep_vec = keep_vecs.get_and_step();
CubitVector partition_vec = partition_curve_vecs.get_and_step();
// Greater than 3*PI/2--add 3 interior points. Two of these
// points will be generated by projecting from the discard vertex
// into the surface normal to the vector from the discard vertex
// to the keep point and new partition point respectively. The third
// point will be obtained by projecting from the discard point in the
// direction of the bisector angle of the two previous projections.
if(cur_angle > 4.71)
{
// Get the u,v position of the discard vertex on this surface.
surface_to_partition->u_v_from_position(discard_pos, u, v);
// Get the normal at the discard vertex.
CubitVector normal = surface_to_partition->normal_at(discard_pos, NULL, &u, &v);
normal.normalize();
// We need to calculate a bisector direction between the
// collape edge and the edge we just partitioned. We will do
// this using the face normal at the discard vertex and the vectors
// we calculated previously with the partition points. Cross
// the face normal into the the direction vectors at the
// discard and partition points to get two vectors pointing
// into the face and then average those two to get the
// bisector direction. This is all approximate but should
// be sufficient for locating another point for partitioning
// the surface.
// I am not normalizing the result here because they should
// be roughly the same length and it shouldn't affect
// the average too much.
CubitVector vec1 = normal * partition_vec;
CubitVector vec2 = normal * keep_vec;
// Get the bisector direction.
CubitVector bisector_dir = vec1 + vec2;
bisector_dir.normalize();
// Now normalise these because they will be used to
// project two of the new interior points.
vec1.normalize();
vec2.normalize();
CubitVector new_pos1 = discard_pos + (arc_length*vec1);
CubitVector mid_pos = discard_pos + (arc_length * bisector_dir);
CubitVector new_pos2 = discard_pos + (arc_length*vec2);
// Use the u,v from the discard vertex because it is fairly
// close to the new position and will at least provide a
// meaningful starting point.
double save_u = u, save_v = v;
surface_to_partition->move_to_surface(new_pos1, &u, &v);
u = save_u; v = save_v;
surface_to_partition->move_to_surface(mid_pos, &u, &v);
u = save_u; v = save_v;
surface_to_partition->move_to_surface(new_pos2, &u, &v);
// Add the new position to the list of partition points.
positions.append(new CubitVector(new_pos1));
positions.append(new CubitVector(mid_pos));
positions.append(new CubitVector(new_pos2));
}
// Greater than 3*PI/4 and less than 3*PI/2--add one interior point
else if(cur_angle > 2.4)
{
CubitVector third_pt;
// Get the u,v position of the discard vertex on this surface.
surface_to_partition->u_v_from_position(discard_pos, u, v);
// Get the normal at the discard vertex.
CubitVector normal = surface_to_partition->normal_at(discard_pos, NULL, &u, &v);
normal.normalize();
// We need to calculate a bisector direction between the
// collape edge and the edge we just partitioned. We will do
// this using the face normal at the discard vertex and the vectors
// we calculated previously with the partition points. Cross
// the face normal into the the direction vectors at the
// discard and partition points to get two vectors pointing
// into the face and then average those two to get the
// bisector direction. This is all approximate but should
// be sufficient for locating another point for partitioning
// the surface.
// I am not normalizing the result here because they should
// be roughly the same length and it shouldn't affect
// the average too much.
CubitVector vec1 = normal * keep_vec;
CubitVector vec2 = normal * partition_vec;
// Get the bisector direction.
CubitVector bisector_dir = vec1 + vec2;
bisector_dir.normalize();
// Project from the discard vertex in the direction of the
// bisector direction to get a new point for partitioning
// the surface.
CubitVector new_pos = discard_pos + (arc_length * bisector_dir);
// Use the u,v from the discard vertex because it is fairly
// close to the new position and will at least provide a
// meaningful starting point.
surface_to_partition->move_to_surface(new_pos, &u, &v);
// Add the new position to the list of partition points.
positions.append(new CubitVector(new_pos));
}
// Finally, add the keep_vertex to the list.
positions.append(new CubitVector(keep_vertex->get_point_ptr()->coordinates()));
DLIList<RefEdge*> new_edges;
DLIList<DLIList<CubitVector*>*> vec_lists;
DLIList<CubitVector*> *vec_list = new DLIList<CubitVector*>;
positions.reset();
for(int m=positions.size(); m--;)
vec_list->append( new CubitVector( *positions.get_and_step() ) );
vec_lists.append( vec_list );
if(!SplitCompositeSurfaceTool::instance()->split_surface(surface_to_partition,
positions, vec_lists ))
{
finished = 1;
result = CUBIT_FAILURE;
}
while( vec_lists.size() )
{
DLIList<CubitVector*> *vec_list = vec_lists.pop();
while( vec_list->size() ) delete vec_list->pop();
delete vec_list;
}
delete positions.get_and_step();
delete positions.get_and_step();
if(cur_angle > 4.71)
{
delete positions.get_and_step();
delete positions.get_and_step();
delete positions.get_and_step();
}
else if(cur_angle > 2.4)
{
delete positions.get();
}
if(!finished)
{
RefFace *new_small_face = NULL;
DLIList<RefEdge*> keep_edges, discard_edges;
DLIList<RefFace*> faces_on_collapse_edge;
keep_vertex->ref_edges(keep_edges);
discard_vertex->ref_edges(discard_edges);
keep_edges.intersect_unordered(discard_edges);
if(keep_edges.size() != 1)
{
finished = 1;
result = CUBIT_FAILURE;
}
else
{
edge_to_collapse = keep_edges.get();
edge_to_collapse->ref_faces(faces_on_collapse_edge);
for(int y=faces_on_collapse_edge.size(); y && !new_small_face; y--)
{
RefFace *cur_face = faces_on_collapse_edge.get_and_step();
DLIList<RefVertex*> verts_in_face;
cur_face->ref_vertices(verts_in_face);
for(int p=verts_in_face.size(); p && !new_small_face; p--)
{
RefVertex *cur_vert = verts_in_face.get_and_step();
if(position_on_curve.about_equal(cur_vert->coordinates()))
new_small_face = cur_face;
}
}
}
if(!new_small_face || new_small_face == surface_to_partition)
{
PRINT_ERROR("Failed to do the split surface operation of the collapse curve.\n");
result = CUBIT_FAILURE;
finished = 1;
}
else
{
RefVertex *vert_at_split_pos;
DLIList<RefEdge*> new_face_edges;
new_small_face->ref_edges(new_face_edges);
if(new_face_edges.is_in_list(curve_to_partition))
{
// The split went right through one of the vertices of the
// curve_to_partition so just set the close edge to be
// this edge and the far edge to be NULL.
close_edge = curve_to_partition;
far_edge = NULL;
vert_at_split_pos = close_edge->other_vertex(discard_vertex);
}
else
{
close_edge = edge_to_collapse->get_other_curve(discard_vertex, new_small_face);
RefVertex *tmp_vert = close_edge->other_vertex(discard_vertex);
if(tmp_vert)
{
RefEdge *tmp_edge = close_edge->get_other_curve(tmp_vert, new_small_face);
if(tmp_edge)
{
RefFace *other_face = tmp_edge->other_face(new_small_face);
if(other_face)
{
far_edge = tmp_edge->get_other_curve(tmp_vert, other_face);
vert_at_split_pos = tmp_vert;
// If close_edge and far_edge are the same it may mean
// that the split really didn't do much other than maybe
// imprint one point on an edge so bail out.
if(far_edge == close_edge)
{
PRINT_ERROR("Failed to do the split surface operation of the collapse curve.\n");
result = CUBIT_FAILURE;
finished = 1;
}
}
else
{
result = CUBIT_FAILURE;
finished = 1;
}
}
else
{
result = CUBIT_FAILURE;
finished = 1;
}
}
else
{
finished = 1;
result = CUBIT_FAILURE;
}
}
if(!finished)
{
RefEdge *cur_edge = close_edge;
RefVertex *cur_vert = vert_at_split_pos;
while(cur_vert != keep_vertex)
{
cur_edge = cur_edge->get_other_curve(cur_vert, new_small_face);
cur_vert = cur_edge->other_vertex(cur_vert);
new_edges.append(cur_edge);
}
DLIList<RefFace*> result_faces;
DLIList<RefFace*> faces_to_composite;
// Used below if "ignore" keyword was specified.
int new_small_face_id = new_small_face->id();
faces_to_composite.append(new_small_face);
faces_to_composite.append(close_edge->other_face(new_small_face));
RefFace *new_comp_face = CompositeTool::instance()->composite(faces_to_composite);
CompositeSurface* csurf = NULL;
if(new_comp_face)
{
csurf = dynamic_cast<CompositeSurface*>(new_comp_face->get_surface_ptr());
}
if(!new_comp_face || !csurf)
{
PRINT_ERROR("Failed to do the composite surface operation of the collapse curve.\n");
result = CUBIT_FAILURE;
finished = 1;
}
else
{
if(ignore_surfaces)
{
csurf->ignore_surface(new_small_face_id);
}
if(far_edge)
{
for(int k=new_edges.size(); k--;)
{
edges_to_composite.append(new_edges.get_and_step());
}
edges_to_composite.append(far_edge);
if(edges_to_composite.size() > 1)
{
CompositeTool::instance()->composite(edges_to_composite);
}
}
edges_to_composite.clean_out();
}
}
}
}
}
}
if(!finished)
{
ref_edges_on_discard_vertex.clean_out();
discard_vertex->ref_edges(ref_edges_on_discard_vertex);
ref_edges_on_discard_vertex.remove(edge_to_collapse);
// Now there should only be one edge in the ref_edges_on_discard_vertex
// list. It should be the edge that hasn't had any modifications
// done to it. We finally want to composite it with the edge
// being collapsed.
if(ref_edges_on_discard_vertex.size() != 1)
{
PRINT_ERROR("Wasn't able to complete collapse operation.\n");
result = CUBIT_FAILURE;
finished = 1;
}
else
{
edges_to_composite.append(ref_edges_on_discard_vertex.get());
edges_to_composite.append(edge_to_collapse);
CompositeTool::instance()->composite(edges_to_composite);
}
}
}
CubitUndo::set_undo_enabled(undo_state);
return result;
}
| CubitStatus CollapseCurveTool::collapse_curve_only_virtual | ( | DLIList< RefEdge * > | ref_edge_list, |
| DLIList< RefVertex * > | ref_vertex_list, | ||
| int | ignore_surfaces, | ||
| double * | small_curve_size = NULL |
||
| ) |
Definition at line 52 of file CollapseCurveTool.cpp.
{
CubitStatus result = CUBIT_SUCCESS;
RefEdge *edge_to_collapse = ref_edge_list.get();
RefVertex *keep_vertex = NULL;
RefVertex *discard_vertex = NULL;
CoEdge *exit_coedge = NULL;
CoEdge *enter_coedge = NULL;
DLIList<RefEdge*> curves_to_partition;
DLIList<RefFace*> surfaces_to_partition;
DLIList<CubitVector> partition_positions;
DLIList<CubitVector> keep_vecs;
DLIList<CubitVector> partition_curve_vecs;
DLIList<RefFace*> adjacent_surfaces;
DLIList<double> angles;
DLIList<double> arc_lengths;
DLIList<RefEdge*> ref_edges_on_discard_vertex;
DLIList<RefEdge*> ref_edges_on_keep_vertex;
DLIList<RefVertex*> new_partition_vertices;
DLIList<RefEdge*> new_partition_edges;
RefEdge *close_edge = NULL;
RefEdge *far_edge = NULL;
DLIList<RefEdge*> edges_to_composite;
int keep_vertex_specified = 0;
int discard_valency = 0;
int keep_valency = 0;
int finished = 0;
double arc_length = 0;
double u = 0, v = 0;
CubitVector left_vec(0,0,0), right_vec(0,0,0);
CubitVector position_on_left_curve(0,0,0), position_on_right_curve(0,0,0);
CubitVector discard_pos(0,0,0), keep_pos(0,0,0);
bool undo_state = CubitUndo::get_undo_enabled();
if( undo_state )
CubitUndo::save_state_with_cubit_file( ref_edge_list );
CubitUndo::set_undo_enabled(false);
if(edge_to_collapse == NULL)
{
PRINT_ERROR("No curve was found to collapse.\n");
finished = 1;
result = CUBIT_FAILURE;
}
if(!finished)
{
// Make sure we have a vertex to keep.
if(ref_vertex_list.size() > 0)
{
keep_vertex_specified = 1;
keep_vertex = ref_vertex_list.get();
}
// We need to choose a vertex to keep.
else
{
// Arbitrarily choose start vertex.
keep_vertex = edge_to_collapse->start_vertex();
}
// Get the vertex that will go away.
if(keep_vertex == edge_to_collapse->start_vertex())
{
discard_vertex = edge_to_collapse->end_vertex();
}
else if(keep_vertex == edge_to_collapse->end_vertex())
{
discard_vertex = edge_to_collapse->start_vertex();
}
else
{
PRINT_ERROR("Vertex to keep was not found on the curve being collapsed.\n");
result = CUBIT_FAILURE;
finished = 1;
}
}
if(!finished)
{
// Get the valency of the keep and discard vertices.
discard_vertex->ref_edges(ref_edges_on_discard_vertex);
keep_vertex->ref_edges(ref_edges_on_keep_vertex);
discard_valency = ref_edges_on_discard_vertex.size();
keep_valency = ref_edges_on_keep_vertex.size();
// Now do some error checking and also some logic to try to
// pick the best vertex to keep/discard.
// If one of the valencies is 2 just composite the vertex out.
if(discard_valency == 2)
{
CompositeTool::instance()->composite(ref_edges_on_discard_vertex);
finished = 1;
}
else if (keep_valency == 2)
{
CompositeTool::instance()->composite(ref_edges_on_keep_vertex);
finished = 1;
}
else
{
// Make sure that at least one of the vertices is qualified to
// be the discard vertex (valency of 3 or 4). The keep vertex
// really doesn't have any restrictions.
if((discard_valency > 4 || discard_valency < 3) &&
(keep_valency > 4 || keep_valency < 3))
{
PRINT_ERROR("Cannot currently collapse curves where one of the vertices does not have a valency equal to 3 or 4.\n");
result = CUBIT_FAILURE;
finished = 1;
}
else
{
if(keep_vertex_specified)
{
if(discard_valency < 3 || discard_valency > 4)
{
PRINT_ERROR("Cannot currently collapse curves where the discard vertex valency is not 3 or 4.\n"
"Try specifying the keep vertex so that the discard vertex is 3 or 4.\n");
result = CUBIT_FAILURE;
finished = 1;
}
}
else
{
// The user didn't specify a keep vertex so we can try to choose the best one.
int swap_vertices = 0;
if(discard_valency < 5 && discard_valency > 2 &&
keep_valency < 5 && keep_valency > 2)
{
// Either vertex can be the discard/keep vertex so choose the one with the
// lower valency as the discard vertex because it will require fewer operations.
if(discard_valency > keep_valency)
{
swap_vertices = 1;
}
}
else
{
// Only one of the vertices can be the discard vertex so pick it.
if(discard_valency > 4 || discard_valency < 3)
{
swap_vertices = 1;
}
}
if(swap_vertices)
{
// Swap the vertices.
RefVertex *tmp = discard_vertex;
discard_vertex = keep_vertex;
keep_vertex = tmp;
// Make sure to refresh the discard vertex edge list because
// it is used below.
ref_edges_on_discard_vertex.clean_out();
discard_vertex->ref_edges(ref_edges_on_discard_vertex);
}
}
}
}
}
if(!finished && small_curve_size)
{
// Check if the edges attached to the discard vertex are longer
// than the small curve size.
DLIList<RefEdge*> tmp_edges;
discard_vertex->ref_edges(tmp_edges);
if(tmp_edges.move_to(edge_to_collapse))
tmp_edges.extract();
int y;
bool all_edges_long_enough = true;
for(y=tmp_edges.size(); y && all_edges_long_enough; y--)
{
RefEdge *cur_edge = tmp_edges.get_and_step();
if(cur_edge->get_arc_length() <= *small_curve_size)
all_edges_long_enough = false;
}
if(!all_edges_long_enough)
{
PRINT_ERROR("Cannot collapse curve %d to vertex %d--not all of the curves attached to\n"
"vertex %d are longer than the small_curve_size. Try collapsing to vertex %d instead.\n",
edge_to_collapse->id(), keep_vertex->id(), discard_vertex->id(), discard_vertex->id());
result = CUBIT_FAILURE;
finished = 1;
}
}
// Look at all of the coedges on the curve being collapsed and
// throw out any that are on nonmanifold surfaces. The collapse
// curve may be on a boundary of a merged surface. This is ok
// but we want to make sure we don't involve this surface
// in the partitions and composites so we will remove from the
// list any coedges that are hooked to merged surfaces.
if(!finished)
{
DLIList<CoEdge*> collapse_curve_coedges;
edge_to_collapse->get_co_edges(collapse_curve_coedges);
int initial_size = collapse_curve_coedges.size();
while(collapse_curve_coedges.size() > 2 && initial_size > 0)
{
for(int g=collapse_curve_coedges.size(); g--;)
{
CoEdge *cur_coedge = collapse_curve_coedges.get_and_step();
Loop *loop_ptr = cur_coedge->get_loop_ptr();
if(loop_ptr)
{
RefFace *ref_face_ptr = loop_ptr->get_ref_face_ptr();
if(ref_face_ptr)
{
DLIList<CoFace*> coface_list;
ref_face_ptr->co_faces(coface_list);
if(coface_list.size() > 1)
{
collapse_curve_coedges.remove(cur_coedge);
g = 0;
}
}
}
}
// Keep from looping infinitely.
initial_size--;
}
// If we get to this point and have more than 2 coedges left
// in the list we are not sure what to do.
if(collapse_curve_coedges.size() != 2)
{
PRINT_ERROR("Currently can only collapse curves with manifold topology.\n");
result = CUBIT_FAILURE;
finished = 1;
}
else
{
// Get the collapse curve coedges entering and leaving the discard vertex.
exit_coedge = collapse_curve_coedges.get_and_step();
enter_coedge = collapse_curve_coedges.get();
if(enter_coedge->end_vertex() != discard_vertex)
{
CoEdge *tmp = exit_coedge;
exit_coedge = enter_coedge;
enter_coedge = tmp;
}
}
}
// Next we need to explore the topology around the discard vertex
// so that we can get the edges and surfaces that will be involved
// with the partitioning and compositing. We will identify a "left"
// and "right" edge coming out of the discard vertex and adjacent
// surfacs to these edges.
if(!finished)
{
// Get these values for use later on.
discard_pos = discard_vertex->get_point_ptr()->coordinates();
keep_pos = keep_vertex->get_point_ptr()->coordinates();
CubitVector discard_to_keep = keep_pos - discard_pos;
arc_length = edge_to_collapse->get_arc_length();
// Depending on whether the discard vertex has valency of 3 or 4 we will
// either partition 1 or 2 of the curves coming into the discard vertex
// respectively. Set up lists so that below we can just loop through the
// partitioning and compositing for either the 3 or 4 valency case.
// "Left" and "right" will be defined as if you were standing on the
// keep vertex looking at the discard vertex.
Loop *left_loop = enter_coedge->get_loop_ptr();
Loop *right_loop = exit_coedge->get_loop_ptr();
DLIList<SenseEntity*> left_sense_entities, right_sense_entities;
left_loop->get_sense_entity_list(left_sense_entities);
right_loop->get_sense_entity_list(right_sense_entities);
// We need to get these two coedges because the chains defined by the "next" and
// "previous" pointers in the CoEdge objects are not circular (you can have a NULL
// "previous" or "next" pointer). We will manage the circularity manually.
CoEdge *left_start = dynamic_cast<CoEdge*>(left_loop->get_first_sense_entity_ptr());
CoEdge *right_end = dynamic_cast<CoEdge*>(right_loop->get_last_sense_entity_ptr());
CoEdge *left_coedge = dynamic_cast<CoEdge*>(enter_coedge->next());
if(left_coedge == NULL)
{
left_coedge = left_start;
}
CoEdge *right_coedge = dynamic_cast<CoEdge*>(exit_coedge->previous());
if(right_coedge == NULL)
{
right_coedge = right_end;
}
RefEdge *left_edge = left_coedge->get_ref_edge_ptr();
RefEdge *right_edge = right_coedge->get_ref_edge_ptr();
RefFace *left_common_face = left_edge->common_ref_face(edge_to_collapse);
RefFace *right_common_face = right_edge->common_ref_face(edge_to_collapse);
double left_arc_length = left_edge->get_arc_length();
double right_arc_length = right_edge->get_arc_length();
int left_ok = 1;
int right_ok = 1;
DLIList<RefEdge*> left_face_edges;
DLIList<RefEdge*> right_face_edges;
left_common_face->ref_edges(left_face_edges);
right_common_face->ref_edges(right_face_edges);
if(left_face_edges.size() < 3 || right_face_edges.size() < 3 ||
left_sense_entities.size() < 3 || right_sense_entities.size() < 3)
{
PRINT_ERROR("Cannot collapse a curve that bounds a face or loop with only two edges.\n");
finished = 1;
}
else
{
// We use the length of the curve being collapsed as the distance
// to partition the adjacent curves connected to it. If the
// adjacent curves are shorter than the curve being collapsed we
// will bail because the user should probably be getting rid
// of the adjacent edges instead or at least first.
// Get the length of the adjacent curves.
// If the adjacent curve is within resabs of the length of
// the curve being collapsed we will just snap to the end
// of the adjacent curve for our partition position.
if(arc_length > left_arc_length + GEOMETRY_RESABS)
{
left_ok = 0;
}
if(arc_length > right_arc_length + GEOMETRY_RESABS)
{
right_ok = 0;
}
// If neither curve is ok we need to bail.
if(!left_ok && !right_ok)
{
PRINT_ERROR("Curve being collapsed is too long compared to adjacent curves.\n");
finished = 1;
}
}
// If it looks like the lengths of the adjacent curves are
// ok we will go ahead and try to find a partition position
// on them.
if(!finished)
{
if(left_ok)
{
// First see if we can just use the end point of the
// adjacent curve as the partition position.
if(fabs(left_arc_length-arc_length) < GEOMETRY_RESABS)
{
if(left_edge->start_vertex() == discard_vertex)
position_on_left_curve = left_edge->end_vertex()->coordinates();
else
position_on_left_curve = left_edge->start_vertex()->coordinates();
}
else
{
result = this->position_from_length(left_edge, discard_vertex,
arc_length, position_on_left_curve);
}
}
if(result == CUBIT_SUCCESS && right_ok)
{
// First see if we can just use the end point of the
// adjacent curve as the partition position.
if(fabs(right_arc_length-arc_length) < GEOMETRY_RESABS)
{
if(right_edge->start_vertex() == discard_vertex)
position_on_right_curve = right_edge->end_vertex()->coordinates();
else
position_on_right_curve = right_edge->start_vertex()->coordinates();
}
else
{
result = this->position_from_length(right_edge, discard_vertex,
arc_length, position_on_right_curve);
}
}
if(result == CUBIT_FAILURE)
{
PRINT_ERROR("Was unable to locate appropriate partition points on curves adjacent to curve being collapased.\n");
finished = 1;
}
}
if(!finished)
{
// Get the vectors from the discard vertex to the potential partition locations.
CubitVector left_vec = position_on_left_curve - discard_pos;
CubitVector right_vec = position_on_right_curve - discard_pos;
// Calculate the angles between the left/right edge and the
// edge being collapsed. I am doing it this way rather than just
// calling RefEdge::angle_between() because I want the angle
// calculation done out at the potential partition location.
// This will step over any small kinks in the curve near the
// discard vertex that might otherwise give misleading angles
// that don't represent what is happening out by the potential
// partition position.
left_common_face->u_v_from_position(discard_pos, u, v);
CubitVector left_normal = left_common_face->normal_at(discard_pos, NULL, &u, &v);
double left_angle = left_normal.vector_angle(left_vec, discard_to_keep);
right_common_face->u_v_from_position(discard_pos, u, v);
CubitVector right_normal = right_common_face->normal_at(discard_pos, NULL, &u, &v);
double right_angle = right_normal.vector_angle(discard_to_keep, right_vec);
// 3 valency case:
// We only need to partition one of the curves (left or right) and
// the corresponding surface.
if(ref_edges_on_discard_vertex.size() == 3)
{
int use_left = 0;
// We can use either adjacent curve.
if(left_ok && right_ok)
{
// Choose the side with the smaller angle as this will in general
// give better angles for doing the partitioning on the surface.
if(left_angle < right_angle)
{
use_left = 1;
}
}
else if(left_ok)
{
use_left = 1;
}
if(use_left)
{
curves_to_partition.append(left_edge);
surfaces_to_partition.append(left_common_face);
angles.append(left_angle);
partition_positions.append(position_on_left_curve);
arc_lengths.append(arc_length);
// These vectors will be used in calculating a bisector direction
// below if necessary.
keep_vecs.append(-discard_to_keep);
partition_curve_vecs.append(left_vec);
}
else
{
curves_to_partition.append(right_edge);
surfaces_to_partition.append(right_common_face);
angles.append(right_angle);
partition_positions.append(position_on_right_curve);
arc_lengths.append(arc_length);
// These vectors will be used in calculating a bisector direction
// below if necessary.
keep_vecs.append(discard_to_keep);
partition_curve_vecs.append(-right_vec);
}
}
else if(ref_edges_on_discard_vertex.size() == 4)
{
// We have to partition both left and right curves so make
// sure we can.
if(!left_ok || !right_ok)
{
PRINT_ERROR("One of the curves adjacent to the collapse curve is not long enough for the collapse operation.\n");
finished = 1;
}
else
{
// Both curves (and surfaces) adjacent to the collapse curve (left and right)
// will need to be partitioned so add them to the lists.
curves_to_partition.append(left_edge);
curves_to_partition.append(right_edge);
surfaces_to_partition.append(left_common_face);
surfaces_to_partition.append(right_common_face);
angles.append(left_angle);
angles.append(right_angle);
keep_vecs.append(-discard_to_keep);
keep_vecs.append(discard_to_keep);
partition_curve_vecs.append(left_vec);
partition_curve_vecs.append(-right_vec);
partition_positions.append(position_on_left_curve);
partition_positions.append(position_on_right_curve);
arc_lengths.append(arc_length);
arc_lengths.append(arc_length);
}
}
else
{
PRINT_ERROR("Currently can only collapse curves with 3 or 4 valency vertices.\n");
result = CUBIT_FAILURE;
finished = 1;
}
}
}
if(!finished)
{
int num_reps = curves_to_partition.size();
curves_to_partition.reset();
surfaces_to_partition.reset();
for(int n=0; n<num_reps && !finished; ++n)
{
RefEdge *side_edge = curves_to_partition.get_and_step();
RefFace *side_face = surfaces_to_partition.get_and_step();
// Now we need to find the face on the other side of the edge.
// Because there may be edges on the boundaries of merged surfaces
// we want to find the
// face on the left/right edge that isn't the face shared by
// the collapse edge and isn't nonmanifold.
DLIList<CoEdge*> side_edge_coedges;
side_edge->co_edges(side_edge_coedges);
DLIList<RefFace*> possible_adj_faces;
// First loop through and get all of the potential faces.
for(int r=side_edge_coedges.size(); r--;)
{
CoEdge *cur_coedge = side_edge_coedges.get_and_step();
if(cur_coedge &&
cur_coedge->get_loop_ptr() &&
cur_coedge->get_loop_ptr()->get_ref_face_ptr())
{
RefFace *cur_ref_face = cur_coedge->get_loop_ptr()->get_ref_face_ptr();
if(cur_ref_face != side_face)
{
DLIList<CoFace*> coface_list;
cur_ref_face->co_faces(coface_list);
// Along with checking for whether the face is manifold we need
// to check if it belongs to the same volume as the side face.
// We have to check this because we can't composite faces
// from different volumes and these faces will be involved in
// a composite below.
if(coface_list.size() == 1 &&
side_face->ref_volume() == cur_ref_face->ref_volume())
{
possible_adj_faces.append(cur_ref_face);
}
}
}
}
// If we ended up with more than one face in the list it isn't clear
// what we should do so bail out.
if(possible_adj_faces.size() != 1)
{
PRINT_ERROR("Couldn't figure out how to perform the collapse curve with the current topology.\n");
result = CUBIT_FAILURE;
finished = 1;
}
else
{
adjacent_surfaces.append(possible_adj_faces.get());
}
}
}
if(!finished)
{
// At this point we should know which curves and surfaces we need
// to partition.
int num_reps = curves_to_partition.size();
curves_to_partition.reset();
surfaces_to_partition.reset();
adjacent_surfaces.reset();
angles.reset();
keep_vecs.reset();
partition_curve_vecs.reset();
partition_positions.reset();
arc_lengths.reset();
for(int i=0; i<num_reps && !finished; ++i)
{
RefEdge *curve_to_partition = curves_to_partition.get_and_step();
// As we process each curve remove it from the list so that
// at the end we can take the last one in the list and composite
// it with the curve being collapsed.
ref_edges_on_discard_vertex.remove(curve_to_partition);
CubitVector position_on_curve = partition_positions.get_and_step();
// Partition the curve adjacent to the collapse curve.
RefEdge *edge1, *edge2;
RefVertex *new_vertex = PartitionTool::instance()->
partition( curve_to_partition, position_on_curve, edge1, edge2 );
// Keep track of these in case we need to undo the partitioning.
if(new_vertex)
{
new_partition_vertices.append(new_vertex);
}
// Get the two new curves and classify them as close and far.
if(edge1 && edge2)
{
close_edge = edge1;
far_edge = edge2;
if(close_edge->start_vertex() != discard_vertex &&
close_edge->end_vertex() != discard_vertex)
{
RefEdge *tmp = close_edge;
close_edge = far_edge;
far_edge = tmp;
}
}
else
{
// If the partition didn't create a new vertex and two new curves
// (the case when the partition position lands on an existing
// vertex) just classify the curve as "close" and set the
// "far" curve to NULL.
close_edge = curve_to_partition;
far_edge = NULL;
}
RefFace *surface_to_partition = surfaces_to_partition.get_and_step();
DLIList<CubitVector*> positions;
// Add the point on the curve we just partitioned. The other
// point we normally need to add is the keep_vertex. However,
// if the angle between the collapse curve and the curve we
// just partitioned dictates that we need to introduce more points
// (this would be cases where the angle is large and just partitioning the
// surface with one curve--two points--would result in a very skinny
// surface) we need to add them before adding the keep_vertex. Therefore, check
// that now and add the extra points if needed.
positions.append(new CubitVector(position_on_curve));
double cur_angle = angles.get_and_step();
arc_length = arc_lengths.get_and_step();
// These vectors are only used in the block below if we need to
// add extra points but we need to always retrieve them from the lists
// so that the pointer in the list stays in sync with the "for" loop.
CubitVector keep_vec = keep_vecs.get_and_step();
CubitVector partition_vec = partition_curve_vecs.get_and_step();
// Greater than 3*PI/2--add 3 interior points. Two of these
// points will be generated by projecting from the discard vertex
// into the surface normal to the vector from the discard vertex
// to the keep point and new partition point respectively. The third
// point will be obtained by projecting from the discard point in the
// direction of the bisector angle of the two previous projections.
if(cur_angle > 4.71)
{
// Get the u,v position of the discard vertex on this surface.
surface_to_partition->u_v_from_position(discard_pos, u, v);
// Get the normal at the discard vertex.
CubitVector normal = surface_to_partition->normal_at(discard_pos, NULL, &u, &v);
normal.normalize();
// We need to calculate a bisector direction between the
// collape edge and the edge we just partitioned. We will do
// this using the face normal at the discard vertex and the vectors
// we calculated previously with the partition points. Cross
// the face normal into the the direction vectors at the
// discard and partition points to get two vectors pointing
// into the face and then average those two to get the
// bisector direction. This is all approximate but should
// be sufficient for locating another point for partitioning
// the surface.
// I am not normalizing the result here because they should
// be roughly the same length and it shouldn't affect
// the average too much.
CubitVector vec1 = normal * partition_vec;
CubitVector vec2 = normal * keep_vec;
// Get the bisector direction.
CubitVector bisector_dir = vec1 + vec2;
bisector_dir.normalize();
// Now normalise these because they will be used to
// project two of the new interior points.
vec1.normalize();
vec2.normalize();
CubitVector new_pos1 = discard_pos + (arc_length*vec1);
CubitVector mid_pos = discard_pos + (arc_length * bisector_dir);
CubitVector new_pos2 = discard_pos + (arc_length*vec2);
// Use the u,v from the discard vertex because it is fairly
// close to the new position and will at least provide a
// meaningful starting point.
double save_u = u, save_v = v;
surface_to_partition->move_to_surface(new_pos1, &u, &v);
u = save_u; v = save_v;
surface_to_partition->move_to_surface(mid_pos, &u, &v);
u = save_u; v = save_v;
surface_to_partition->move_to_surface(new_pos2, &u, &v);
// Add the new position to the list of partition points.
positions.append(new CubitVector(new_pos1));
positions.append(new CubitVector(mid_pos));
positions.append(new CubitVector(new_pos2));
}
// Greater than 3*PI/4 and less than 3*PI/2--add one interior point
else if(cur_angle > 2.4)
{
CubitVector third_pt;
// Get the u,v position of the discard vertex on this surface.
surface_to_partition->u_v_from_position(discard_pos, u, v);
// Get the normal at the discard vertex.
CubitVector normal = surface_to_partition->normal_at(discard_pos, NULL, &u, &v);
normal.normalize();
// We need to calculate a bisector direction between the
// collape edge and the edge we just partitioned. We will do
// this using the face normal at the discard vertex and the vectors
// we calculated previously with the partition points. Cross
// the face normal into the the direction vectors at the
// discard and partition points to get two vectors pointing
// into the face and then average those two to get the
// bisector direction. This is all approximate but should
// be sufficient for locating another point for partitioning
// the surface.
// I am not normalizing the result here because they should
// be roughly the same length and it shouldn't affect
// the average too much.
CubitVector vec1 = normal * keep_vec;
CubitVector vec2 = normal * partition_vec;
// Get the bisector direction.
CubitVector bisector_dir = vec1 + vec2;
bisector_dir.normalize();
// Project from the discard vertex in the direction of the
// bisector direction to get a new point for partitioning
// the surface.
CubitVector new_pos = discard_pos + (arc_length * bisector_dir);
// Use the u,v from the discard vertex because it is fairly
// close to the new position and will at least provide a
// meaningful starting point.
surface_to_partition->move_to_surface(new_pos, &u, &v);
// Add the new position to the list of partition points.
positions.append(new CubitVector(new_pos));
}
// Finally, add the keep_vertex to the list.
positions.append(new CubitVector(keep_vertex->get_point_ptr()->coordinates()));
DLIList<RefEdge*> new_edges;
PartitionTool::instance()->
insert_edge( surface_to_partition, positions, CUBIT_FALSE, new_edges,
0, &arc_length);
// Keep for later in case we need to clean up.
if(new_edges.size() > 0)
{
new_partition_edges += new_edges;
}
delete positions.get_and_step();
delete positions.get_and_step();
if(cur_angle > 4.71)
{
delete positions.get_and_step();
delete positions.get_and_step();
delete positions.get_and_step();
}
else if(cur_angle > 2.4)
{
delete positions.get();
}
RefFace *new_small_face = edge_to_collapse->common_ref_face(close_edge);
if(!new_small_face)
{
PRINT_ERROR("Failed to do the partition surface operation of the collapse curve.\n");
result = CUBIT_FAILURE;
finished = 1;
}
else
{
DLIList<RefFace*> result_faces;
DLIList<RefFace*> faces_to_composite;
// Used below if "ignore" keyword was specified.
int new_small_face_id = new_small_face->id();
faces_to_composite.append(new_small_face);
faces_to_composite.append(adjacent_surfaces.get_and_step());
RefFace *new_comp_face = CompositeTool::instance()->composite(faces_to_composite);
CompositeSurface* csurf = NULL;
if(new_comp_face)
{
csurf = dynamic_cast<CompositeSurface*>(new_comp_face->get_surface_ptr());
}
if(!new_comp_face || !csurf)
{
PRINT_ERROR("Failed to do the composite surface operation of the collapse curve.\n");
result = CUBIT_FAILURE;
finished = 1;
}
else
{
if(ignore_surfaces)
{
csurf->ignore_surface(new_small_face_id);
}
if(far_edge)
{
for(int k=new_edges.size(); k--;)
{
edges_to_composite.append(new_edges.get_and_step());
}
edges_to_composite.append(far_edge);
if(edges_to_composite.size() > 1)
{
CompositeTool::instance()->composite(edges_to_composite);
}
}
edges_to_composite.clean_out();
}
}
}
if(!finished)
{
ref_edges_on_discard_vertex.remove(edge_to_collapse);
// Now there should only be one edge in the ref_edges_on_discard_vertex
// list. It should be the edge that hasn't had any modifications
// done to it. We finally want to composite it with the edge
// being collapsed.
if(ref_edges_on_discard_vertex.size() != 1)
{
PRINT_ERROR("Wasn't able to complete collapse operation.\n");
result = CUBIT_FAILURE;
finished = 1;
}
else
{
edges_to_composite.append(ref_edges_on_discard_vertex.get());
edges_to_composite.append(edge_to_collapse);
CompositeTool::instance()->composite(edges_to_composite);
}
}
}
CubitUndo::set_undo_enabled(undo_state);
return result;
}
| static void CollapseCurveTool::delete_instance | ( | ) | [inline, static] |
Definition at line 20 of file CollapseCurveTool.hpp.
| CollapseCurveTool * CollapseCurveTool::instance | ( | void | ) | [static] |
Definition at line 44 of file CollapseCurveTool.cpp.
{
if (instance_ == NULL)
instance_ = new CollapseCurveTool();
return instance_;
}
| CubitStatus CollapseCurveTool::position_from_length | ( | RefEdge * | edge, |
| RefVertex * | root_vertex, | ||
| double | arc_length, | ||
| CubitVector & | v_new | ||
| ) | [private] |
Definition at line 1964 of file CollapseCurveTool.cpp.
{
CubitStatus result;
double sense = 1.0;
if (root_vertex != edge->start_vertex())
sense = -1.0;
CubitVector v_root = root_vertex->get_point_ptr()->coordinates();
result = edge->point_from_arc_length(v_root, arc_length*sense, v_new);
return result;
}
CollapseCurveTool * CollapseCurveTool::instance_ = NULL [static, private] |
Definition at line 43 of file CollapseCurveTool.hpp.