root/cgm/trunk/geom/virtual/CollapseCurveTool.cpp

Revision 1040, 33.0 KB (checked in by tautges, 2 years ago)

Version 10.2 of cgm.

Line 
1//-------------------------------------------------------------------------
2//- Filename:       CollapseCurveTool
3//- Purpose:  To collapse small curves for preparing for mesh
4//-      "collapse curve <id> vertex <id>\n",
5//-
6//- Creator:       Brett Clark
7//- Creation date: 01/10/2006
8//-------------------------------------------------------------------------
9
10// ********** BEGIN STANDARD INCLUDES         **********
11// ********** END STANDARD INCLUDES           **********
12                                                                               
13// ********** BEGIN MOTIF INCLUDES            **********
14// ********** END MOTIF INCLUDES              **********
15                                                                               
16// ********** BEGIN ACIS INCLUDES             **********
17// ********** END ACIS INCLUDES               **********
18                                                                               
19// ********** BEGIN CUBIT INCLUDES            **********
20#include "GMem.hpp"                                                           
21#include "RefVertex.hpp"
22#include "RefEdge.hpp"
23#include "DLIList.hpp"
24#include "CoEdge.hpp"
25#include "CoFace.hpp"
26#include "Shell.hpp"
27#include "Point.hpp"
28#include "Loop.hpp"
29#include "RefFace.hpp"
30#include "PartitionTool.hpp"
31#include "CompositeTool.hpp"
32#include "CollapseCurveTool.hpp"
33
34/*
35*/
36// ********** END CUBIT INCLUDES              **********
37
38CollapseCurveTool *CollapseCurveTool::instance_ = NULL;
39
40// ********** BEGIN PUBLIC FUNCTIONS          **********
41CollapseCurveTool *CollapseCurveTool::instance()
42{
43  if (instance_ == NULL) 
44    instance_ = new CollapseCurveTool();
45                                                                               
46  return instance_;
47}
48
49CubitStatus CollapseCurveTool::collapse_curve(DLIList <RefEdge*> ref_edge_list, 
50                                              DLIList<RefVertex*> ref_vertex_list,
51                                              int ignore_surfaces)
52{
53  CubitStatus result = CUBIT_SUCCESS;
54
55  RefEdge *edge_to_collapse = ref_edge_list.get();
56  RefVertex *keep_vertex = NULL;
57  RefVertex *discard_vertex = NULL;
58  CoEdge *exit_coedge = NULL;
59  CoEdge *enter_coedge = NULL;
60  DLIList<RefEdge*> curves_to_partition;
61  DLIList<RefFace*> surfaces_to_partition;
62  DLIList<CubitVector> partition_positions;
63  DLIList<CubitVector> keep_vecs;
64  DLIList<CubitVector> partition_curve_vecs;
65  DLIList<RefFace*> adjacent_surfaces;
66  DLIList<double> angles;
67  DLIList<double> arc_lengths;
68  DLIList<RefEdge*> ref_edges_on_discard_vertex;
69  DLIList<RefEdge*> ref_edges_on_keep_vertex;
70  DLIList<RefVertex*> new_partition_vertices;
71  DLIList<RefEdge*> new_partition_edges;
72  RefEdge *close_edge = NULL;
73  RefEdge *far_edge = NULL;
74  DLIList<RefEdge*> edges_to_composite;
75  int keep_vertex_specified = 0;
76  int discard_valency = 0;
77  int keep_valency = 0;
78  int finished = 0;
79  double arc_length = 0;
80  double u = 0, v = 0;
81  CubitVector left_vec(0,0,0), right_vec(0,0,0);
82  CubitVector position_on_left_curve(0,0,0), position_on_right_curve(0,0,0);
83  CubitVector discard_pos(0,0,0), keep_pos(0,0,0);
84
85  if(edge_to_collapse == NULL)
86  {
87    PRINT_ERROR("No curve was found to collapse.\n");
88    finished = 1;
89    result = CUBIT_FAILURE;
90  }
91
92  if(!finished)
93  {
94    // Make sure we have a vertex to keep.
95    if(ref_vertex_list.size() > 0)
96    {
97      keep_vertex_specified = 1;
98      keep_vertex = ref_vertex_list.get();
99    }
100    // We need to choose a vertex to keep.
101    else
102    {
103      // Arbitrarily choose start vertex.
104      keep_vertex = edge_to_collapse->start_vertex();
105    }
106
107    // Get the vertex that will go away.
108    if(keep_vertex == edge_to_collapse->start_vertex())
109    {
110      discard_vertex = edge_to_collapse->end_vertex();
111    }
112    else if(keep_vertex == edge_to_collapse->end_vertex())
113    {
114      discard_vertex = edge_to_collapse->start_vertex();
115    }
116    else
117    {
118      PRINT_ERROR("Vertex to keep was not found on the curve being collapsed.\n");
119      result = CUBIT_FAILURE;
120      finished = 1;
121    }
122  }
123
124  if(!finished)
125  {
126    // Get the valency of the keep and discard vertices.
127    discard_vertex->ref_edges(ref_edges_on_discard_vertex);
128    keep_vertex->ref_edges(ref_edges_on_keep_vertex);
129    discard_valency = ref_edges_on_discard_vertex.size();
130    keep_valency = ref_edges_on_keep_vertex.size();
131
132    // Now do some error checking and also some logic to try to
133    // pick the best vertex to keep/discard.
134
135    // If one of the valencies is 2 just composite the vertex out.
136    if(discard_valency == 2)
137    {
138      CompositeTool::instance()->composite(ref_edges_on_discard_vertex);
139      finished = 1;
140    }
141    else if (keep_valency == 2)
142    {
143      CompositeTool::instance()->composite(ref_edges_on_keep_vertex);
144      finished = 1;
145    }
146    else
147    {
148      // Make sure that at least one of the vertices is qualified to
149      // be the discard vertex (valency of 3 or 4).  The keep vertex
150      // really doesn't have any restrictions.
151      if((discard_valency > 4 || discard_valency < 3) &&
152        (keep_valency > 4 || keep_valency < 3))
153      {
154        PRINT_ERROR("Cannot currently collapse curves where one of the vertices does not have a valency equal to 3 or 4.\n");
155        result = CUBIT_FAILURE;
156        finished = 1;
157      }
158      else
159      {
160        if(keep_vertex_specified)
161        {
162          if(discard_valency < 3 || discard_valency > 4)
163          {
164            PRINT_ERROR("Cannot currently collapse curves where the discard vertex valency is not 3 or 4.\n"
165                  "Try specifying the keep vertex so that the discard vertex is 3 or 4.\n");
166            result = CUBIT_FAILURE;
167            finished = 1;
168          }
169        }
170        else
171        {
172          // The user didn't specify a keep vertex so we can try to choose the best one.
173         
174          int swap_vertices = 0;
175          if(discard_valency < 5 && discard_valency > 2 &&
176            keep_valency < 5 && keep_valency > 2)
177          {
178            // Either vertex can be the discard/keep vertex so choose the one with the
179            // lower valency as the discard vertex because it will require fewer operations.
180            if(discard_valency > keep_valency)
181            {
182              swap_vertices = 1;
183            }
184          }
185          else
186          {
187            // Only one of the vertices can be the discard vertex so pick it.
188            if(discard_valency > 4 || discard_valency < 3)
189            {
190              swap_vertices = 1;
191            }
192          }
193
194          if(swap_vertices)
195          {
196            // Swap the vertices.
197            RefVertex *tmp = discard_vertex;
198            discard_vertex = keep_vertex;
199            keep_vertex = tmp;
200
201            // Make sure to refresh the discard vertex edge list because
202            // it is used below.
203            ref_edges_on_discard_vertex.clean_out();
204            discard_vertex->ref_edges(ref_edges_on_discard_vertex);
205          }
206        }
207      }
208    }
209  }
210
211  // Look at all of the coedges on the curve being collapsed and
212  // throw out any that are on nonmanifold surfaces.  The collapse
213  // curve may be on a boundary of a merged surface.  This is ok
214  // but we want to make sure we don't involve this surface
215  // in the partitions and composites so we will remove from the
216  // list any coedges that are hooked to merged surfaces.
217  if(!finished)
218  {
219    DLIList<CoEdge*> collapse_curve_coedges;
220    edge_to_collapse->get_co_edges(collapse_curve_coedges);
221
222    int initial_size = collapse_curve_coedges.size();
223    while(collapse_curve_coedges.size() > 2 && initial_size > 0)
224    {
225      for(int g=collapse_curve_coedges.size(); g--;)
226      {
227        CoEdge *cur_coedge = collapse_curve_coedges.get_and_step();
228        Loop *loop_ptr = cur_coedge->get_loop_ptr();
229        if(loop_ptr)
230        {
231          RefFace *ref_face_ptr = loop_ptr->get_ref_face_ptr();
232          if(ref_face_ptr)
233          {
234            DLIList<CoFace*> coface_list;
235            ref_face_ptr->co_faces(coface_list);
236            if(coface_list.size() > 1)
237            {
238              collapse_curve_coedges.remove(cur_coedge);
239              g = 0;
240            }
241          }
242        }
243      }
244
245      // Keep from looping infinitely.
246      initial_size--;
247    }
248
249    // If we get to this point and have more than 2 coedges left
250    // in the list we are not sure what to do.
251    if(collapse_curve_coedges.size() != 2)
252    {
253      PRINT_ERROR("Currently can only collapse curves with manifold topology.\n");
254      result = CUBIT_FAILURE;
255      finished = 1;
256    }
257    else
258    {
259      // Get the collapse curve coedges entering and leaving the discard vertex.
260      exit_coedge = collapse_curve_coedges.get_and_step();
261      enter_coedge = collapse_curve_coedges.get();
262      if(enter_coedge->end_vertex() != discard_vertex)
263      {
264        CoEdge *tmp = exit_coedge;
265        exit_coedge = enter_coedge;
266        enter_coedge = tmp;
267      }
268    }
269  }
270
271  // Next we need to explore the topology around the discard vertex
272  // so that we can get the edges and surfaces that will be involved
273  // with the partitioning and compositing.  We will identify a "left"
274  // and "right" edge coming out of the discard vertex and adjacent
275  // surfacs to these edges.
276  if(!finished)
277  {
278    // Get these values for use later on.
279    discard_pos = discard_vertex->get_point_ptr()->coordinates();
280    keep_pos = keep_vertex->get_point_ptr()->coordinates();
281    CubitVector discard_to_keep = keep_pos - discard_pos;
282    arc_length = edge_to_collapse->get_arc_length();
283
284    // Depending on whether the discard vertex has valency of 3 or 4 we will
285    // either partition 1 or 2 of the curves coming into the discard vertex
286    // respectively.  Set up lists so that below we can just loop through the
287    // partitioning and compositing for either the 3 or 4 valency case.
288
289    // "Left" and "right" will be defined as if you were standing on the
290    // keep vertex looking at the discard vertex.
291    Loop *left_loop = enter_coedge->get_loop_ptr();
292    Loop *right_loop = exit_coedge->get_loop_ptr();
293
294    // We need to get these two coedges because the chains defined by the "next" and
295    // "previous" pointers in the CoEdge objects are not circular (you can have a NULL
296    // "previous" or "next" pointer).  We will manage the circularity manually.
297    CoEdge *left_start = dynamic_cast<CoEdge*>(left_loop->get_first_sense_entity_ptr()); 
298    CoEdge *right_end = dynamic_cast<CoEdge*>(right_loop->get_last_sense_entity_ptr()); 
299   
300    CoEdge *left_coedge = dynamic_cast<CoEdge*>(enter_coedge->next());
301    if(left_coedge == NULL)
302    {
303      left_coedge = left_start;
304    }
305    CoEdge *right_coedge = dynamic_cast<CoEdge*>(exit_coedge->previous());
306    if(right_coedge == NULL)
307    {
308      right_coedge = right_end;
309    }
310
311    RefEdge *left_edge = left_coedge->get_ref_edge_ptr();
312    RefEdge *right_edge = right_coedge->get_ref_edge_ptr();
313    RefFace *left_common_face = left_edge->common_ref_face(edge_to_collapse);
314    RefFace *right_common_face = right_edge->common_ref_face(edge_to_collapse);
315
316    double left_arc_length = left_edge->get_arc_length();
317    double right_arc_length = right_edge->get_arc_length();
318    int left_ok = 1;
319    int right_ok = 1;
320
321    DLIList<RefEdge*> left_face_edges;
322    DLIList<RefEdge*> right_face_edges;
323    left_common_face->ref_edges(left_face_edges);
324    right_common_face->ref_edges(right_face_edges);
325    if(left_face_edges.size() < 3 || right_face_edges.size() < 3)
326    {
327      PRINT_ERROR("Cannot collapse a curve that bounds a face with only two edges.\n");
328      finished = 1;
329    }
330    else
331    {
332      // We use the length of the curve being collapsed as the distance
333      // to partition the adjacent curves connected to it.  If the
334      // adjacent curves are shorter than the curve being collapsed we
335      // will bail because the user should probably be getting rid
336      // of the adjacent edges instead or at least first.
337
338      // Get the length of the adjacent curves.
339     
340      // If the adjacent curve is within resabs of the length of
341      // the curve being collapsed we will just snap to the end
342      // of the adjacent curve for our partition position.
343      if(arc_length > left_arc_length + GEOMETRY_RESABS)
344      {
345        left_ok = 0;
346      }
347      if(arc_length > right_arc_length + GEOMETRY_RESABS)
348      {
349        right_ok = 0;
350      }
351
352      // If neither curve is ok we need to bail.
353      if(!left_ok && !right_ok)
354      {
355        PRINT_ERROR("Curve being collapsed is too long compared to adjacent curves.\n");
356        finished = 1;
357      }
358    }
359
360    // If it looks like the lengths of the adjacent curves are
361    // ok we will go ahead and try to find a partition position
362    // on them.
363    if(!finished)
364    {
365      if(left_ok)
366      {
367         // First see if we can just use the end point of the
368         // adjacent curve as the partition position.
369         if(fabs(left_arc_length-arc_length) < GEOMETRY_RESABS)
370         {
371           if(left_edge->start_vertex() == discard_vertex)
372             position_on_left_curve = left_edge->end_vertex()->coordinates();
373           else
374             position_on_left_curve = left_edge->start_vertex()->coordinates();
375         }
376         else
377         {
378           result = this->position_from_length(left_edge, discard_vertex,
379                arc_length, position_on_left_curve);
380         }
381      }
382      if(result == CUBIT_SUCCESS && right_ok)
383      {
384         // First see if we can just use the end point of the
385         // adjacent curve as the partition position.
386         if(fabs(right_arc_length-arc_length) < GEOMETRY_RESABS)
387         {
388           if(right_edge->start_vertex() == discard_vertex)
389             position_on_right_curve = right_edge->end_vertex()->coordinates();
390           else
391             position_on_right_curve = right_edge->start_vertex()->coordinates();
392         }
393         else
394         {
395            result = this->position_from_length(right_edge, discard_vertex,
396                  arc_length, position_on_right_curve);
397         }
398      }
399      if(result == CUBIT_FAILURE)
400      {
401        PRINT_ERROR("Was unable to locate appropriate partition points on curves adjacent to curve being collapased.\n");
402        finished = 1;
403      }
404    }
405     
406    if(!finished)
407    {
408      // Get the vectors from the discard vertex to the potential partition locations.
409      CubitVector left_vec = position_on_left_curve - discard_pos;
410      CubitVector right_vec = position_on_right_curve - discard_pos;
411
412      // Calculate the angles between the left/right edge and the
413      // edge being collapsed.  I am doing it this way rather than just
414      // calling RefEdge::angle_between() because I want the angle
415      // calculation done out at the potential partition location.
416      // This will step over any small kinks in the curve near the
417      // discard vertex that might otherwise give misleading angles
418      // that don't represent what is happening out by the potential
419      // partition position.
420      left_common_face->u_v_from_position(discard_pos, u, v);
421      CubitVector left_normal = left_common_face->normal_at(discard_pos, NULL, &u, &v);
422      double left_angle = left_normal.vector_angle(left_vec, discard_to_keep);
423
424      right_common_face->u_v_from_position(discard_pos, u, v);
425      CubitVector right_normal = right_common_face->normal_at(discard_pos, NULL, &u, &v);
426      double right_angle = right_normal.vector_angle(discard_to_keep, right_vec);
427
428      // 3 valency case:
429      // We only need to partition one of the curves (left or right) and
430      // the corresponding surface.
431      if(ref_edges_on_discard_vertex.size() == 3)
432      {
433        int use_left = 0;
434        // We can use either adjacent curve.
435        if(left_ok && right_ok)
436        {
437          // Choose the side with the smaller angle as this will in general
438          // give better angles for doing the partitioning on the surface.
439          if(left_angle < right_angle)
440          {
441            use_left = 1;
442          }
443        }
444        else if(left_ok)
445        {
446          use_left = 1;
447        }
448        if(use_left)
449        {
450          curves_to_partition.append(left_edge);
451          surfaces_to_partition.append(left_common_face);
452          angles.append(left_angle);
453          partition_positions.append(position_on_left_curve);
454          arc_lengths.append(arc_length);
455 
456          // These vectors will be used in calculating a bisector direction
457          // below if necessary.
458          keep_vecs.append(-discard_to_keep);
459          partition_curve_vecs.append(left_vec);
460        }
461        else
462        {
463          curves_to_partition.append(right_edge);
464          surfaces_to_partition.append(right_common_face);
465          angles.append(right_angle);
466          partition_positions.append(position_on_right_curve);
467          arc_lengths.append(arc_length);
468 
469          // These vectors will be used in calculating a bisector direction
470          // below if necessary.
471          keep_vecs.append(discard_to_keep);
472          partition_curve_vecs.append(-right_vec);
473        }
474      }
475      else if(ref_edges_on_discard_vertex.size() == 4)
476      {
477        // We have to partition both left and right curves so make
478        // sure we can.
479        if(!left_ok || !right_ok)
480        {
481          PRINT_ERROR("One of the curves adjacent to the collapse curve is not long enough for the collapse operation.\n");
482          finished = 1;
483        }
484        else
485        {
486          // Both curves (and surfaces) adjacent to the collapse curve (left and right)
487          // will need to be partitioned so add them to the lists.
488
489          curves_to_partition.append(left_edge);
490          curves_to_partition.append(right_edge);
491          surfaces_to_partition.append(left_common_face);
492          surfaces_to_partition.append(right_common_face);
493          angles.append(left_angle);
494          angles.append(right_angle);
495          keep_vecs.append(-discard_to_keep);
496          keep_vecs.append(discard_to_keep);
497          partition_curve_vecs.append(left_vec);
498          partition_curve_vecs.append(-right_vec);
499          partition_positions.append(position_on_left_curve);
500          partition_positions.append(position_on_right_curve);
501          arc_lengths.append(arc_length);
502          arc_lengths.append(arc_length);
503        }
504      }
505      else
506      {
507        PRINT_ERROR("Currently can only collapse curves with 3 or 4 valency vertices.\n");
508        result = CUBIT_FAILURE;
509        finished = 1;
510      }
511    }
512  }
513
514  if(!finished)
515  {
516    int num_reps = curves_to_partition.size();
517    curves_to_partition.reset();
518    surfaces_to_partition.reset();
519    for(int n=0; n<num_reps && !finished; ++n)
520    {
521      RefEdge *side_edge = curves_to_partition.get_and_step();
522      RefFace *side_face = surfaces_to_partition.get_and_step();
523
524      // Now we need to find the face on the other side of the edge.
525      // Because there may be edges on the boundaries of merged surfaces
526      // we want to find the
527      // face on the left/right edge that isn't the face shared by
528      // the collapse edge and isn't nonmanifold.
529      DLIList<CoEdge*> side_edge_coedges;
530      side_edge->co_edges(side_edge_coedges);
531      RefFace *adjacent_face = NULL;
532      DLIList<RefFace*> possible_adj_faces;
533
534      // First loop through and get all of the potential faces.
535      for(int r=side_edge_coedges.size(); r--;)
536      {
537        CoEdge *cur_coedge = side_edge_coedges.get_and_step();
538        if(cur_coedge &&
539          cur_coedge->get_loop_ptr() &&
540          cur_coedge->get_loop_ptr()->get_ref_face_ptr())
541        {
542          RefFace *cur_ref_face = cur_coedge->get_loop_ptr()->get_ref_face_ptr();
543          if(cur_ref_face != side_face)
544          {
545            DLIList<CoFace*> coface_list;
546            cur_ref_face->co_faces(coface_list);
547
548            // Along with checking for whether the face is manifold we need
549            // to check if it belongs to the same volume as the side face.
550            // We have to check this because we can't composite faces
551            // from different volumes and these faces will be involved in
552            // a composite below.
553            if(coface_list.size() == 1 &&
554              side_face->ref_volume() == cur_ref_face->ref_volume())
555            {
556              possible_adj_faces.append(cur_ref_face);
557            }
558          }
559        }
560      }
561
562      // If we ended up with more than one face in the list it isn't clear
563      // what we should do so bail out.
564      if(possible_adj_faces.size() != 1)
565      {
566        PRINT_ERROR("Couldn't figure out how to perform the collapse curve with the current topology.\n");
567        result = CUBIT_FAILURE;
568        finished = 1;
569      }
570      else
571      {
572        adjacent_surfaces.append(possible_adj_faces.get());
573      }
574    }
575  }
576
577  if(!finished)
578  {
579    // At this point we should know which curves and surfaces we need
580    // to partition.
581
582    int num_reps = curves_to_partition.size();
583    curves_to_partition.reset();
584    surfaces_to_partition.reset();
585    adjacent_surfaces.reset();
586    angles.reset();
587    keep_vecs.reset();
588    partition_curve_vecs.reset();
589    partition_positions.reset();
590    arc_lengths.reset();
591
592    for(int i=0; i<num_reps && !finished; ++i)
593    {
594      RefEdge *curve_to_partition = curves_to_partition.get_and_step();
595
596      // As we process each curve remove it from the list so that
597      // at the end we can take the last one in the list and composite
598      // it with the curve being collapsed.
599      ref_edges_on_discard_vertex.remove(curve_to_partition);
600
601      CubitVector position_on_curve = partition_positions.get_and_step();
602
603      // Partition the curve adjacent to the collapse curve.
604      RefEdge *edge1, *edge2;
605      RefVertex *new_vertex = PartitionTool::instance()->
606        partition( curve_to_partition, position_on_curve, edge1, edge2 );
607
608      // Keep track of these in case we need to undo the partitioning.
609      if(new_vertex)
610      {
611        new_partition_vertices.append(new_vertex);
612      }
613
614      // Get the two new curves and classify them as close and far.
615      if(edge1 && edge2)
616      {
617        close_edge = edge1;
618        far_edge = edge2;
619        if(close_edge->start_vertex() != discard_vertex &&
620          close_edge->end_vertex() != discard_vertex)
621        {
622          RefEdge *tmp = close_edge;
623          close_edge = far_edge;
624          far_edge = tmp;
625        }
626      }
627      else
628      {
629        // If the partition didn't create a new vertex and two new curves
630        // (the case when the partition position lands on an existing
631        // vertex) just classify the curve as "close" and set the
632        // "far" curve to NULL.
633        close_edge = curve_to_partition;
634        far_edge = NULL;
635      }
636
637      RefFace *surface_to_partition = surfaces_to_partition.get_and_step();
638
639      DLIList<CubitVector*> positions;
640
641      // Add the point on the curve we just partitioned.  The other
642      // point we normally need to add is the keep_vertex.  However,
643      // if the angle between the collapse curve and the curve we
644      // just partitioned dictates that we need to introduce more points
645      // (this would be cases where the angle is large and just partitioning the
646      // surface with one curve--two points--would result in a very skinny
647      // surface) we need to add them before adding the keep_vertex.  Therefore, check
648      // that now and add the extra points if needed.
649      positions.append(new CubitVector(position_on_curve));
650
651      double cur_angle = angles.get_and_step();
652      arc_length = arc_lengths.get_and_step();
653
654      // These vectors are only used in the block below if we need to
655      // add extra points but we need to always retrieve them from the lists
656      // so that the pointer in the list stays in sync with the "for" loop.
657      CubitVector keep_vec = keep_vecs.get_and_step();
658      CubitVector partition_vec = partition_curve_vecs.get_and_step();
659
660      // Greater than 3*PI/2--add 3 interior points.  Two of these
661      // points will be generated by projecting from the discard vertex
662      // into the surface normal to the vector from the discard vertex
663      // to the keep point and new partition point respectively.  The third
664      // point will be obtained by projecting from the discard point in the
665      // direction of the bisector angle of the two previous projections.
666      if(cur_angle > 4.71)
667      {
668        // Get the u,v position of the discard vertex on this surface.
669        surface_to_partition->u_v_from_position(discard_pos, u, v);
670       
671        // Get the normal at the discard vertex.
672        CubitVector normal = surface_to_partition->normal_at(discard_pos, NULL, &u, &v);
673        normal.normalize();
674       
675        // We need to calculate a bisector direction between the
676        // collape edge and the edge we just partitioned.  We will do
677        // this using the face normal at the discard vertex and the vectors
678        // we calculated previously with the partition points.  Cross
679        // the face normal into the the direction vectors at the
680        // discard and partition points to get two vectors pointing
681        // into the face and then average those two to get the
682        // bisector direction.  This is all approximate but should
683        // be sufficient for locating another point for partitioning
684        // the surface.
685
686        // I am not normalizing the result here because they should
687        // be roughly the same length and it shouldn't affect
688        // the average too much.
689        CubitVector vec1 = normal * partition_vec;
690        CubitVector vec2 = normal * keep_vec;
691
692        // Get the bisector direction.
693        CubitVector bisector_dir = vec1 + vec2;
694        bisector_dir.normalize();
695
696        // Now normalise these because they will be used to
697        // project two of the new interior points.
698        vec1.normalize();
699        vec2.normalize();
700
701        CubitVector new_pos1 = discard_pos + (arc_length*vec1);
702        CubitVector mid_pos = discard_pos + (arc_length * bisector_dir);
703        CubitVector new_pos2 = discard_pos + (arc_length*vec2);
704
705        // Use the u,v from the discard vertex because it is fairly
706        // close to the new position and will at least provide a
707        // meaningful starting point.
708        double save_u = u, save_v = v;
709        surface_to_partition->move_to_surface(new_pos1, &u, &v);
710        u = save_u; v = save_v;
711        surface_to_partition->move_to_surface(mid_pos, &u, &v);
712        u = save_u; v = save_v;
713        surface_to_partition->move_to_surface(new_pos2, &u, &v);
714
715        // Add the new position to the list of partition points.
716        positions.append(new CubitVector(new_pos1));
717        positions.append(new CubitVector(mid_pos));
718        positions.append(new CubitVector(new_pos2));
719      }
720      // Greater than 3*PI/4 and less than 3*PI/2--add one interior point
721      else if(cur_angle > 2.4)
722      {
723        CubitVector third_pt;
724       
725        // Get the u,v position of the discard vertex on this surface.
726        surface_to_partition->u_v_from_position(discard_pos, u, v);
727       
728        // Get the normal at the discard vertex.
729        CubitVector normal = surface_to_partition->normal_at(discard_pos, NULL, &u, &v);
730        normal.normalize();
731       
732        // We need to calculate a bisector direction between the
733        // collape edge and the edge we just partitioned.  We will do
734        // this using the face normal at the discard vertex and the vectors
735        // we calculated previously with the partition points.  Cross
736        // the face normal into the the direction vectors at the
737        // discard and partition points to get two vectors pointing
738        // into the face and then average those two to get the
739        // bisector direction.  This is all approximate but should
740        // be sufficient for locating another point for partitioning
741        // the surface.
742
743        // I am not normalizing the result here because they should
744        // be roughly the same length and it shouldn't affect
745        // the average too much.
746        CubitVector vec1 = normal * keep_vec;
747        CubitVector vec2 = normal * partition_vec;
748
749        // Get the bisector direction.
750        CubitVector bisector_dir = vec1 + vec2;
751        bisector_dir.normalize();
752
753        // Project from the discard vertex in the direction of the
754        // bisector direction to get a new point for partitioning
755        // the surface.
756        CubitVector new_pos = discard_pos + (arc_length * bisector_dir);
757
758        // Use the u,v from the discard vertex because it is fairly
759        // close to the new position and will at least provide a
760        // meaningful starting point.
761        surface_to_partition->move_to_surface(new_pos, &u, &v);
762
763        // Add the new position to the list of partition points.
764        positions.append(new CubitVector(new_pos));
765      }
766
767      // Finally, add the keep_vertex to the list.
768      positions.append(new CubitVector(keep_vertex->get_point_ptr()->coordinates()));
769                                                                                   
770      DLIList<RefEdge*> new_edges;
771      PartitionTool::instance()->
772          insert_edge( surface_to_partition, positions, CUBIT_FALSE, new_edges,
773                        0, &arc_length);
774
775      // Keep for later in case we need to clean up.
776      if(new_edges.size() > 0)
777      {
778        new_partition_edges += new_edges;
779      }
780
781      delete positions.get_and_step();
782      delete positions.get_and_step();
783
784      if(cur_angle > 4.71)
785      {
786        delete positions.get_and_step();
787        delete positions.get_and_step();
788        delete positions.get_and_step();
789      }
790      else if(cur_angle > 2.4)
791      {
792        delete positions.get();
793      }
794
795      RefFace *new_small_face = edge_to_collapse->common_ref_face(close_edge);
796
797      if(!new_small_face)
798      {
799        PRINT_ERROR("Failed to do the partition surface operation of the collapse curve.\n");
800        result = CUBIT_FAILURE;
801        finished = 1;
802      }
803      else
804      {
805        DLIList<RefFace*> result_faces;
806        DLIList<RefFace*> faces_to_composite;
807
808        // Used below if "ignore" keyword was specified.
809        int new_small_face_id = new_small_face->id();
810
811        faces_to_composite.append(new_small_face);
812        faces_to_composite.append(adjacent_surfaces.get_and_step());
813
814        RefFace *new_comp_face = CompositeTool::instance()->composite(faces_to_composite);
815
816        CompositeSurface* csurf = NULL;
817       
818        if(new_comp_face)
819        {
820          csurf = dynamic_cast<CompositeSurface*>(new_comp_face->get_surface_ptr());
821        }
822
823        if(!new_comp_face || !csurf)
824        {
825          PRINT_ERROR("Failed to do the composite surface operation of the collapse curve.\n");
826          result = CUBIT_FAILURE;
827          finished = 1;
828        }
829        else
830        {
831          if(ignore_surfaces)
832          {
833            csurf->ignore_surface(new_small_face_id);
834          }
835
836          if(far_edge)
837          {
838            for(int k=new_edges.size(); k--;)
839            {
840              edges_to_composite.append(new_edges.get_and_step());
841            }
842            edges_to_composite.append(far_edge);
843
844            if(edges_to_composite.size() > 1)
845            {
846              CompositeTool::instance()->composite(edges_to_composite);
847            }
848          }
849
850          edges_to_composite.clean_out();
851        }
852      }
853    }
854
855    if(!finished)
856    {
857      ref_edges_on_discard_vertex.remove(edge_to_collapse);
858
859      // Now there should only be one edge in the ref_edges_on_discard_vertex
860      // list.  It should be the edge that hasn't had any modifications
861      // done to it.  We finally want to composite it with the edge
862      // being collapsed.
863      if(ref_edges_on_discard_vertex.size() != 1)
864      {
865        PRINT_ERROR("Wasn't able to complete collapse operation.\n");
866        result = CUBIT_FAILURE;
867        finished = 1;
868      }
869      else
870      {
871        edges_to_composite.append(ref_edges_on_discard_vertex.get());
872        edges_to_composite.append(edge_to_collapse);
873        CompositeTool::instance()->composite(edges_to_composite);
874      }
875    }
876  }
877
878  if(result == CUBIT_FAILURE)
879  {
880    int i;
881    for(i=new_partition_edges.size(); i--;)
882    {
883      CompositeTool::instance()->remove_edge(new_partition_edges.get_and_step(), true);
884    }
885    for(i=new_partition_vertices.size(); i--;)
886    {
887      CompositeTool::instance()->remove_vertex(new_partition_vertices.get_and_step(), true);
888    }
889  }
890
891  return result;
892}
893
894CubitStatus CollapseCurveTool::position_from_length(RefEdge *edge,
895                                                  RefVertex *root_vertex,
896                                                  double  arc_length,
897                                                  CubitVector& v_new)
898{
899  CubitStatus result;
900  double sense = 1.0;
901  if (root_vertex != edge->start_vertex())
902    sense = -1.0;
903  CubitVector v_root = root_vertex->get_point_ptr()->coordinates();
904  result = edge->point_from_arc_length(v_root, arc_length*sense, v_new);
905  return result;
906}
907
908
909// ********** END PUBLIC FUNCTIONS            **********
910                                                                               
911// ********** BEGIN PROTECTED FUNCTIONS       **********
912// ********** END PROTECTED FUNCTIONS         **********
913                                                                               
914// ********** BEGIN PRIVATE FUNCTIONS         **********
915CollapseCurveTool::CollapseCurveTool()
916{
917}
918
919CollapseCurveTool::~CollapseCurveTool()
920{
921}
Note: See TracBrowser for help on using the browser.