| 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 | |
|---|
| 38 | CollapseCurveTool *CollapseCurveTool::instance_ = NULL; |
|---|
| 39 | |
|---|
| 40 | // ********** BEGIN PUBLIC FUNCTIONS ********** |
|---|
| 41 | CollapseCurveTool *CollapseCurveTool::instance() |
|---|
| 42 | { |
|---|
| 43 | if (instance_ == NULL) |
|---|
| 44 | instance_ = new CollapseCurveTool(); |
|---|
| 45 | |
|---|
| 46 | return instance_; |
|---|
| 47 | } |
|---|
| 48 | |
|---|
| 49 | CubitStatus 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 | |
|---|
| 894 | CubitStatus 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 ********** |
|---|
| 915 | CollapseCurveTool::CollapseCurveTool() |
|---|
| 916 | { |
|---|
| 917 | } |
|---|
| 918 | |
|---|
| 919 | CollapseCurveTool::~CollapseCurveTool() |
|---|
| 920 | { |
|---|
| 921 | } |
|---|