1 /* NAME: 2 E3GeometryLine.c 3 4 DESCRIPTION: 5 Implementation of Quesa Line geometry class. 6 7 COPYRIGHT: 8 Copyright (c) 1999-2005, Quesa Developers. All rights reserved. 9 10 For the current release of Quesa, please see: 11 12 <http://www.quesa.org/> 13 14 Redistribution and use in source and binary forms, with or without 15 modification, are permitted provided that the following conditions 16 are met: 17 18 o Redistributions of source code must retain the above copyright 19 notice, this list of conditions and the following disclaimer. 20 21 o Redistributions in binary form must reproduce the above 22 copyright notice, this list of conditions and the following 23 disclaimer in the documentation and/or other materials provided 24 with the distribution. 25 26 o Neither the name of Quesa nor the names of its contributors 27 may be used to endorse or promote products derived from this 28 software without specific prior written permission. 29 30 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 31 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 32 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 33 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 34 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 35 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 36 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 37 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 38 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 39 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 40 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 41 ___________________________________________________________________________ 42 */ 43 //============================================================================= 44 // Include files 45 //----------------------------------------------------------------------------- 46 #include "E3Prefix.h" 47 #include "E3View.h" 48 #include "E3Pick.h" 49 #include "E3Geometry.h" 50 #include "E3GeometryLine.h" 51 52 53 54 55 56 //============================================================================= 57 // Internal types 58 //----------------------------------------------------------------------------- 59 60 class E3Line : public E3Geometry // This is a leaf class so no other classes use this, 61 // so it can be here in the .c file rather than in 62 // the .h file, hence all the fields can be public 63 // as nobody should be including this file 64 { 65 Q3_CLASS_ENUMS ( kQ3GeometryTypeLine, E3Line, E3Geometry ) 66 public : 67 68 TQ3LineData instanceData ; 69 70 } ; 71 72 73 74 //============================================================================= 75 // Internal functions 76 //----------------------------------------------------------------------------- 77 // e3geom_line_ray_intersect : Intersect a line with a ray. 78 //----------------------------------------------------------------------------- 79 // Note : Returns the smallest segment between a line and a ray. This 80 // segment starts from a point on theLine, and ends on a point on 81 // theRay. Algorithm obtained from: 82 // http://astronomy.swin.edu.au/pbourke/geometry/lineline3d/ 83 //----------------------------------------------------------------------------- 84 static TQ3Boolean 85 e3geom_line_ray_intersect(const TQ3Point3D linePoints[2], 86 const TQ3Ray3D *theRay, 87 TQ3Point3D smallestSegment[2]) 88 { float d1, d2, d1343, d4321, d1321, d4343, d2121; 89 TQ3Vector3D raySegment, rayLine1, rayLine2; 90 float numer, denom, mua, mub; 91 TQ3Point3D p1, p2, p3, p4, pa, pb; 92 TQ3Point3D p13, p43, p21; 93 94 95 96 // Validate our parameters 97 Q3_REQUIRE_OR_RESULT(Q3_VALID_PTR(linePoints), kQ3False); 98 Q3_REQUIRE_OR_RESULT(Q3_VALID_PTR(theRay), kQ3False); 99 Q3_REQUIRE_OR_RESULT(Q3_VALID_PTR(smallestSegment), kQ3False); 100 101 102 103 // Grab a copy of the line 104 p1 = linePoints[0]; 105 p2 = linePoints[1]; 106 107 108 109 // Grab a copy of the ray. We convert the ray to a line segment that 110 // will overshoot the line intersection (if one exists) by extending 111 // the ray from its origin out past the distance to the furthest 112 // vertex. 113 p3 = theRay->origin; 114 115 Q3Point3D_Subtract(&p1, &p3, &rayLine1); 116 Q3Point3D_Subtract(&p2, &p3, &rayLine2); 117 118 d1 = Q3Vector3D_Length(&rayLine1); 119 d2 = Q3Vector3D_Length(&rayLine2); 120 121 Q3Vector3D_Scale(&theRay->direction, E3Num_Max(d1, d2) * 3.0f, &raySegment); 122 Q3Point3D_Vector3D_Add(&p3, &raySegment, &p4); 123 124 125 126 // Calculate the line segment PaPb that is the shortest route between 127 // two lines P1P2 and P3P4. Calculate also the values of mua and mub where 128 // 129 // Pa = P1 + mua (P2 - P1) 130 // Pb = P3 + mub (P4 - P3) 131 // 132 // Returns kQ3False if no solution exists 133 p13.x = p1.x - p3.x; 134 p13.y = p1.y - p3.y; 135 p13.z = p1.z - p3.z; 136 p43.x = p4.x - p3.x; 137 p43.y = p4.y - p3.y; 138 p43.z = p4.z - p3.z; 139 if (E3Float_Abs(p43.x) < kQ3RealZero && E3Float_Abs(p43.y) < kQ3RealZero && E3Float_Abs(p43.z) < kQ3RealZero) 140 return(kQ3False); 141 142 p21.x = p2.x - p1.x; 143 p21.y = p2.y - p1.y; 144 p21.z = p2.z - p1.z; 145 if (E3Float_Abs(p21.x) < kQ3RealZero && E3Float_Abs(p21.y) < kQ3RealZero && E3Float_Abs(p21.z) < kQ3RealZero) 146 return(kQ3False); 147 148 d1343 = p13.x * p43.x + p13.y * p43.y + p13.z * p43.z; 149 d4321 = p43.x * p21.x + p43.y * p21.y + p43.z * p21.z; 150 d1321 = p13.x * p21.x + p13.y * p21.y + p13.z * p21.z; 151 d4343 = p43.x * p43.x + p43.y * p43.y + p43.z * p43.z; 152 d2121 = p21.x * p21.x + p21.y * p21.y + p21.z * p21.z; 153 154 denom = d2121 * d4343 - d4321 * d4321; 155 if (E3Float_Abs(denom) < kQ3RealZero) 156 return(kQ3False); 157 numer = d1343 * d4321 - d1321 * d4343; 158 159 mua = numer / denom; 160 mub = (d1343 + d4321 * (mua)) / d4343; 161 162 pa.x = p1.x + mua * p21.x; 163 pa.y = p1.y + mua * p21.y; 164 pa.z = p1.z + mua * p21.z; 165 pb.x = p3.x + mub * p43.x; 166 pb.y = p3.y + mub * p43.y; 167 pb.z = p3.z + mub * p43.z; 168 169 170 171 // Set up the returning segment. pa is the point on theLine, so 172 // the segment we want runs from pa to pb. 173 smallestSegment[0] = pa; 174 smallestSegment[1] = pb; 175 176 return(kQ3True); 177 } 178 179 180 181 182 183 //============================================================================= 184 // e3geom_line_new : Line new method. 185 //----------------------------------------------------------------------------- 186 static TQ3Status 187 e3geom_line_new(TQ3Object theObject, void *privateData, const void *paramData) 188 { TQ3LineData *instanceData = (TQ3LineData *) privateData; 189 const TQ3LineData *lineData = (const TQ3LineData *) paramData; 190 TQ3Status qd3dStatus; 191 192 193 194 // Initialise our instance data 195 Q3Memory_Clear(instanceData, sizeof(TQ3LineData)); 196 197 qd3dStatus = Q3Line_SetData(theObject, lineData); 198 199 return(qd3dStatus); 200 } 201 202 203 204 205 206 //============================================================================= 207 // e3geom_line_delete : Line delete method. 208 //----------------------------------------------------------------------------- 209 static void 210 e3geom_line_delete(TQ3Object theObject, void *privateData) 211 { TQ3LineData *instanceData = (TQ3LineData *) privateData; 212 TQ3Status qd3dStatus; 213 #pragma unused(theObject) 214 215 216 217 // Dispose of our instance data 218 qd3dStatus = Q3Line_EmptyData(instanceData); 219 } 220 221 222 223 224 225 //============================================================================= 226 // e3geom_line_copydata : Copy TQ3LineData from one to another. 227 //----------------------------------------------------------------------------- 228 // Note : If isDuplicate is true, we duplicate shared objects rather than 229 // obtaining new references to them. 230 //----------------------------------------------------------------------------- 231 static TQ3Status 232 e3geom_line_copydata( const TQ3LineData* src, TQ3LineData* dst, TQ3Boolean isDuplicate ) 233 { 234 TQ3Uns32 n; 235 TQ3Status q3status = kQ3Success; 236 237 for (n = 0; n < 2; ++n) 238 { 239 dst->vertices[n].point = src->vertices[n].point; 240 241 242 if (src->vertices[n].attributeSet == NULL) 243 { 244 dst->vertices[n].attributeSet = NULL; 245 } 246 else if (isDuplicate) 247 { 248 dst->vertices[n].attributeSet = Q3Object_Duplicate( src->vertices[n].attributeSet ); 249 if (dst->vertices[n].attributeSet == NULL) 250 q3status = kQ3Failure; 251 } 252 else 253 { 254 E3Shared_Acquire( &dst->vertices[n].attributeSet, src->vertices[n].attributeSet ); 255 } 256 } 257 258 if (src->lineAttributeSet == NULL) 259 { 260 dst->lineAttributeSet = NULL; 261 } 262 else if (isDuplicate) 263 { 264 dst->lineAttributeSet = Q3Object_Duplicate( src->lineAttributeSet ); 265 if (dst->lineAttributeSet == NULL) 266 q3status = kQ3Failure; 267 } 268 else 269 { 270 E3Shared_Acquire( &dst->lineAttributeSet, src->lineAttributeSet ); 271 } 272 273 274 // Clean up after failure 275 if (q3status == kQ3Failure) 276 { 277 E3Line_EmptyData( dst ); 278 } 279 280 281 return q3status; 282 } 283 284 285 286 287 288 //============================================================================= 289 // e3geom_line_duplicate : Line duplicate method. 290 //----------------------------------------------------------------------------- 291 static TQ3Status 292 e3geom_line_duplicate(TQ3Object fromObject, const void *fromPrivateData, 293 TQ3Object toObject, void *toPrivateData) 294 { TQ3LineData *toInstanceData = (TQ3LineData *) toPrivateData; 295 TQ3LineData *fromInstanceData = (TQ3LineData *) fromPrivateData; 296 TQ3Status qd3dStatus; 297 #pragma unused(fromPrivateData) 298 #pragma unused(toObject) 299 300 301 302 // Validate our parameters 303 Q3_REQUIRE_OR_RESULT(Q3_VALID_PTR(fromObject), kQ3Failure); 304 Q3_REQUIRE_OR_RESULT(Q3_VALID_PTR(toPrivateData), kQ3Failure); 305 306 307 308 // Copy the data from fromObject to toObject 309 qd3dStatus = e3geom_line_copydata( fromInstanceData, toInstanceData, kQ3True ); 310 311 return(qd3dStatus); 312 } 313 314 315 316 317 318 //============================================================================= 319 // e3geom_line_pick_window_point : Line window-point picking method. 320 //----------------------------------------------------------------------------- 321 // Note : Point-line intersection from comp.graphics.algorithms FAQ. 322 // <http://www.faqs.org/faqs/graphics/algorithms-faq/> 323 //----------------------------------------------------------------------------- 324 static TQ3Status 325 e3geom_line_pick_window_point(TQ3ViewObject theView, TQ3PickObject thePick, TQ3Object theObject, const void *objectData) 326 { const TQ3LineData *instanceData = (const TQ3LineData *) objectData; 327 TQ3Vector2D windowStartToPick, windowStartToEnd, windowHitToPick; 328 TQ3Matrix4x4 worldToFrustum, frustumToWindow, worldToWindow; 329 TQ3Point2D hitXY, windowPoints[2]; 330 TQ3Point3D hitXYZ, worldPoints[2]; 331 float d, divisorX, divisorY; 332 TQ3Vector3D worldStartToEnd; 333 TQ3Status qd3dStatus; 334 TQ3WindowPointPickData pickData; 335 336 337 338 // Get the pick data 339 Q3WindowPointPick_GetData(thePick, &pickData); 340 341 342 343 // Transform our points 344 Q3View_TransformLocalToWindow(theView, &instanceData->vertices[0].point, &windowPoints[0]); 345 Q3View_TransformLocalToWindow(theView, &instanceData->vertices[1].point, &windowPoints[1]); 346 347 348 349 // Calculate the distance d along the line to its closest point to the pick point. 350 // If it's outside the range 0-1 then the closest point is before or after the 351 // bounds of the line and so we know we can't possibly have a hit. 352 Q3FastPoint2D_Subtract(&pickData.point, &windowPoints[0], &windowStartToPick); 353 Q3FastPoint2D_Subtract(&windowPoints[1], &windowPoints[0], &windowStartToEnd); 354 355 float windowLineLenSq = Q3FastVector2D_LengthSquared(&windowStartToEnd); 356 if (windowLineLenSq < kQ3RealZero) 357 { 358 // Line is edge-on; we do not want to divide by 0, let's say there is no hit. 359 return(kQ3Success); 360 } 361 d = Q3FastVector2D_Dot(&windowStartToPick, &windowStartToEnd) / windowLineLenSq; 362 if (d < 0.0f || d > 1.0f) 363 return(kQ3Success); 364 365 366 367 // Scale the line vector by d to obtain its closest point to the pick point 368 Q3Vector2D_Scale(&windowStartToEnd, d, &windowStartToEnd); 369 Q3Point2D_Vector2D_Add(&windowPoints[0], &windowStartToEnd, &hitXY); 370 371 372 373 // Get the distance between that point and the pick point 374 Q3Point2D_Subtract(&pickData.point, &hitXY, &windowHitToPick); 375 d = Q3Vector2D_Length(&windowHitToPick); 376 377 378 379 // See if we fall within the pick 380 qd3dStatus = kQ3Success; 381 382 if (d <= pickData.edgeTolerance) 383 { 384 // Create a world to window matrix 385 Q3View_GetWorldToFrustumMatrixState(theView, &worldToFrustum); 386 Q3View_GetFrustumToWindowMatrixState(theView, &frustumToWindow); 387 Q3Matrix4x4_Multiply(&worldToFrustum, &frustumToWindow, &worldToWindow); 388 389 390 // Calculate the intersection point on the 3D line 391 Q3View_TransformLocalToWorld(theView, &instanceData->vertices[0].point, &worldPoints[0]); 392 Q3View_TransformLocalToWorld(theView, &instanceData->vertices[1].point, &worldPoints[1]); 393 394 Q3Point3D_Subtract(&worldPoints[1], &worldPoints[0], &worldStartToEnd); 395 396 divisorX = ( worldToWindow.value[0][3] * worldStartToEnd.x + 397 worldToWindow.value[1][3] * worldStartToEnd.y + 398 worldToWindow.value[2][3] * worldStartToEnd.z ) * hitXY.x - 399 worldToWindow.value[0][0] * worldStartToEnd.x - 400 worldToWindow.value[1][0] * worldStartToEnd.y - 401 worldToWindow.value[2][0] * worldStartToEnd.z; 402 403 divisorY = ( worldToWindow.value[0][3] * worldStartToEnd.x + 404 worldToWindow.value[1][3] * worldStartToEnd.y + 405 worldToWindow.value[2][3] * worldStartToEnd.z ) * hitXY.y - 406 worldToWindow.value[0][1] * worldStartToEnd.x - 407 worldToWindow.value[1][1] * worldStartToEnd.y - 408 worldToWindow.value[2][1] * worldStartToEnd.z; 409 410 if ( divisorX * divisorX >= divisorY * divisorY ) 411 d = ( ( worldToWindow.value[0][3] * worldPoints[0].x + 412 worldToWindow.value[1][3] * worldPoints[0].y + 413 worldToWindow.value[2][3] * worldPoints[0].z + 414 worldToWindow.value[3][3] ) * hitXY.x - 415 worldToWindow.value[0][0] * worldPoints[0].x - 416 worldToWindow.value[1][0] * worldPoints[0].y - 417 worldToWindow.value[2][0] * worldPoints[0].z - 418 worldToWindow.value[3][0] ) / -divisorX; 419 else 420 d = ( ( worldToWindow.value[0][3] * worldPoints[0].x + 421 worldToWindow.value[1][3] * worldPoints[0].y + 422 worldToWindow.value[2][3] * worldPoints[0].z + 423 worldToWindow.value[3][3] ) * hitXY.y - 424 worldToWindow.value[0][1] * worldPoints[0].x - 425 worldToWindow.value[1][1] * worldPoints[0].y - 426 worldToWindow.value[2][1] * worldPoints[0].z - 427 worldToWindow.value[3][1] ) / -divisorY; 428 429 Q3Vector3D_Scale(&worldStartToEnd, d, &worldStartToEnd); 430 Q3Point3D_Vector3D_Add(&worldPoints[0], &worldStartToEnd, &hitXYZ); 431 432 433 // Record the hit 434 qd3dStatus = E3Pick_RecordHit(thePick, theView, &hitXYZ, NULL, NULL, NULL); 435 } 436 437 return(qd3dStatus); 438 } 439 440 441 442 443 444 //============================================================================= 445 // e3geom_line_pick_window_rect : Line window-rect picking method. 446 //----------------------------------------------------------------------------- 447 static TQ3Status 448 e3geom_line_pick_window_rect(TQ3ViewObject theView, TQ3PickObject thePick, TQ3Object theObject, const void *objectData) 449 { const TQ3LineData *instanceData = (const TQ3LineData *) objectData; 450 TQ3Status qd3dStatus = kQ3Success; 451 TQ3Point2D windowPoints[2]; 452 TQ3WindowRectPickData pickData; 453 454 455 456 // Get the pick data 457 Q3WindowRectPick_GetData(thePick, &pickData); 458 459 460 461 // Transform our points 462 Q3View_TransformLocalToWindow(theView, &instanceData->vertices[0].point, &windowPoints[0]); 463 Q3View_TransformLocalToWindow(theView, &instanceData->vertices[1].point, &windowPoints[1]); 464 465 466 467 // See if we fall within the pick 468 if (E3Rect_ContainsLine(&pickData.rect, &windowPoints[0], &windowPoints[1])) 469 qd3dStatus = E3Pick_RecordHit(thePick, theView, NULL, NULL, NULL, NULL); 470 471 return(qd3dStatus); 472 } 473 474 475 476 477 478 //============================================================================= 479 // e3geom_line_pick_world_ray : Line world-ray picking method. 480 //----------------------------------------------------------------------------- 481 static TQ3Status 482 e3geom_line_pick_world_ray(TQ3ViewObject theView, TQ3PickObject thePick, TQ3Object theObject, const void *objectData) 483 { const TQ3LineData *instanceData = (const TQ3LineData *) objectData; 484 TQ3Status qd3dStatus = kQ3Success; 485 TQ3Point3D worldSegment[2]; 486 TQ3Point3D worldPoints[2]; 487 TQ3Vector3D theVector; 488 TQ3WorldRayPickData pickData; 489 float d; 490 491 492 493 // Get the pick data 494 Q3WorldRayPick_GetData(thePick, &pickData); 495 496 497 498 // Transform our points 499 Q3View_TransformLocalToWorld(theView, &instanceData->vertices[0].point, &worldPoints[0]); 500 Q3View_TransformLocalToWorld(theView, &instanceData->vertices[1].point, &worldPoints[1]); 501 502 503 504 // Test for an intersection 505 if (!e3geom_line_ray_intersect(worldPoints, &pickData.ray, worldSegment)) 506 return(qd3dStatus); 507 508 509 510 // Calculate the distance between the closest point and the ray 511 Q3Point3D_Subtract(&worldSegment[1], &worldSegment[0], &theVector); 512 d = Q3Vector3D_Length(&theVector); 513 514 515 516 // See if we fall within the pick 517 if (d <= pickData.edgeTolerance) 518 qd3dStatus = E3Pick_RecordHit(thePick, theView, &worldSegment[0], NULL, NULL, NULL); 519 520 return(qd3dStatus); 521 } 522 523 524 525 526 527 //============================================================================= 528 // e3geom_line_pick : Line picking method. 529 //----------------------------------------------------------------------------- 530 static TQ3Status 531 e3geom_line_pick(TQ3ViewObject theView, TQ3ObjectType objectType, TQ3Object theObject, const void *objectData) 532 { TQ3Status qd3dStatus; 533 TQ3PickObject thePick; 534 535 536 537 // Handle the pick 538 thePick = E3View_AccessPick(theView); 539 switch (Q3Pick_GetType(thePick)) { 540 case kQ3PickTypeWindowPoint: 541 qd3dStatus = e3geom_line_pick_window_point(theView, thePick, theObject, objectData); 542 break; 543 544 case kQ3PickTypeWindowRect: 545 qd3dStatus = e3geom_line_pick_window_rect(theView, thePick, theObject, objectData); 546 break; 547 548 case kQ3PickTypeWorldRay: 549 qd3dStatus = e3geom_line_pick_world_ray(theView, thePick, theObject, objectData); 550 break; 551 552 default: 553 qd3dStatus = kQ3Failure; 554 break; 555 } 556 557 return(qd3dStatus); 558 } 559 560 561 562 563 564 //============================================================================= 565 // e3geom_line_bounds : Line bounds method. 566 //----------------------------------------------------------------------------- 567 static TQ3Status 568 e3geom_line_bounds(TQ3ViewObject theView, TQ3ObjectType objectType, TQ3Object theObject, const void *objectData) 569 { const TQ3LineData *instanceData = (const TQ3LineData *) objectData; 570 #pragma unused(objectType) 571 #pragma unused(theObject) 572 573 574 575 // Update the bounds 576 E3View_UpdateBounds(theView, 2, sizeof(TQ3Vertex3D), &instanceData->vertices[0].point); 577 578 return(kQ3Success); 579 } 580 581 582 583 584 585 //============================================================================= 586 // e3geom_line_get_attribute : Line get attribute set pointer. 587 //----------------------------------------------------------------------------- 588 static TQ3AttributeSet * 589 e3geom_line_get_attribute ( E3Line* line ) 590 { 591 // Return the address of the geometry attribute set 592 return & line->instanceData.lineAttributeSet ; 593 } 594 595 596 597 598 599 //============================================================================= 600 // e3geom_line_metahandler : Line metahandler. 601 //----------------------------------------------------------------------------- 602 static TQ3XFunctionPointer 603 e3geom_line_metahandler(TQ3XMethodType methodType) 604 { 605 TQ3XFunctionPointer theMethod = NULL; 606 607 // Return our methods 608 switch (methodType) { 609 case kQ3XMethodTypeObjectNew: 610 theMethod = (TQ3XFunctionPointer) e3geom_line_new; 611 break; 612 613 case kQ3XMethodTypeObjectDelete: 614 theMethod = (TQ3XFunctionPointer) e3geom_line_delete; 615 break; 616 617 case kQ3XMethodTypeObjectDuplicate: 618 theMethod = (TQ3XFunctionPointer) e3geom_line_duplicate; 619 break; 620 621 case kQ3XMethodTypeObjectSubmitPick: 622 theMethod = (TQ3XFunctionPointer) e3geom_line_pick; 623 break; 624 625 case kQ3XMethodTypeObjectSubmitBounds: 626 theMethod = (TQ3XFunctionPointer) e3geom_line_bounds; 627 break; 628 629 case kQ3XMethodTypeGeomGetAttribute: 630 theMethod = (TQ3XFunctionPointer) e3geom_line_get_attribute; 631 } 632 633 return(theMethod); 634 } 635 636 637 638 639 640 //============================================================================= 641 // Public functions 642 //----------------------------------------------------------------------------- 643 // E3GeometryLine_RegisterClass : Register the class. 644 //----------------------------------------------------------------------------- 645 #pragma mark - 646 TQ3Status 647 E3GeometryLine_RegisterClass(void) 648 { 649 // Register the class 650 return Q3_REGISTER_CLASS ( kQ3ClassNameGeometryLine, 651 e3geom_line_metahandler, 652 E3Line ) ; 653 } 654 655 656 657 658 659 //============================================================================= 660 // E3GeometryLine_UnregisterClass : Unregister the class. 661 //----------------------------------------------------------------------------- 662 TQ3Status 663 E3GeometryLine_UnregisterClass(void) 664 { TQ3Status qd3dStatus; 665 666 667 668 // Unregister the class 669 qd3dStatus = E3ClassTree::UnregisterClass(kQ3GeometryTypeLine, kQ3True); 670 671 return(qd3dStatus); 672 } 673 674 675 676 677 678 //============================================================================= 679 // E3Line_New : Create a line object. 680 //----------------------------------------------------------------------------- 681 #pragma mark - 682 TQ3GeometryObject 683 E3Line_New(const TQ3LineData *lineData) 684 { TQ3Object theObject; 685 686 687 688 // Create the object 689 theObject = E3ClassTree::CreateInstance ( kQ3GeometryTypeLine, kQ3False, lineData); 690 return(theObject); 691 } 692 693 694 695 696 697 //============================================================================= 698 // E3Line_Submit : Submit a line. 699 //----------------------------------------------------------------------------- 700 TQ3Status 701 E3Line_Submit(const TQ3LineData *lineData, TQ3ViewObject theView) 702 { TQ3Status qd3dStatus; 703 704 705 706 // Submit the geometry 707 qd3dStatus = E3View_SubmitImmediate(theView, kQ3GeometryTypeLine, lineData); 708 return(qd3dStatus); 709 } 710 711 712 713 714 715 //============================================================================= 716 // E3Line_GetData : Get the data that describes theLine 717 //----------------------------------------------------------------------------- 718 // Note : Allocates memory for lineData internally, you must call 719 // Q3Line_EmptyData to dispose of this memory 720 //----------------------------------------------------------------------------- 721 TQ3Status 722 E3Line_GetData(TQ3GeometryObject theLine, TQ3LineData *lineData) 723 { 724 E3Line* line = (E3Line*) theLine ; 725 726 e3geom_line_copydata ( & line->instanceData, lineData, kQ3False ) ; 727 728 return kQ3Success ; 729 } 730 731 732 733 734 735 //============================================================================= 736 // E3Line_SetData : Set the data describing a line and its attributes 737 //----------------------------------------------------------------------------- 738 TQ3Status 739 E3Line_SetData(TQ3GeometryObject theLine, const TQ3LineData *lineData) 740 { 741 E3Line* line = (E3Line*) theLine ; 742 743 E3Line_EmptyData ( & line->instanceData ) ; 744 745 TQ3Status q3status = e3geom_line_copydata ( lineData, & line->instanceData, kQ3False ) ; 746 747 Q3Shared_Edited ( line ) ; 748 749 return q3status ; 750 } 751 752 753 754 755 756 //============================================================================= 757 // E3Line_GetVertexPosition : Get the vertex position at index 758 //----------------------------------------------------------------------------- 759 TQ3Status 760 E3Line_GetVertexPosition(TQ3GeometryObject theLine, TQ3Uns32 index, TQ3Point3D *position) 761 { 762 E3Line* line = (E3Line*) theLine ; 763 764 //get the position 765 *position = line->instanceData.vertices [ index ].point ; 766 767 return kQ3Success ; 768 } 769 770 771 772 773 774 //============================================================================= 775 // E3Line_SetVertexPosition : Set the vertex at index 776 //----------------------------------------------------------------------------- 777 TQ3Status 778 E3Line_SetVertexPosition(TQ3GeometryObject theLine, TQ3Uns32 index, const TQ3Point3D *position) 779 { 780 E3Line* line = (E3Line*) theLine ; 781 782 //set the position 783 line->instanceData.vertices [ index ].point = *position ; 784 785 Q3Shared_Edited ( line ) ; 786 787 return kQ3Success ; 788 } 789 790 791 792 793 794 //============================================================================= 795 // E3Line_GetVertexAttributeSet : Get attributes for vertex at index 796 //----------------------------------------------------------------------------- 797 TQ3Status 798 E3Line_GetVertexAttributeSet(TQ3GeometryObject theLine, TQ3Uns32 index, TQ3AttributeSet *attributeSet) 799 { 800 E3Line* line = (E3Line*) theLine ; 801 802 // Return the attribute set 803 E3Shared_Acquire ( attributeSet, line->instanceData.vertices [ index ].attributeSet ) ; 804 805 return kQ3Success ; 806 } 807 808 809 810 811 812 //============================================================================= 813 // E3Line_SetVertexAttributeSet : Set the attributes for vertex at index. 814 //----------------------------------------------------------------------------- 815 TQ3Status 816 E3Line_SetVertexAttributeSet(TQ3GeometryObject theLine, TQ3Uns32 index, TQ3AttributeSet attributeSet) 817 { 818 E3Line* line = (E3Line*) theLine ; 819 820 // Set the attribute set 821 E3Shared_Replace ( & line->instanceData.vertices [ index ].attributeSet, attributeSet ) ; 822 823 Q3Shared_Edited ( line ) ; 824 825 return kQ3Success ; 826 } 827 828 829 830 831 832 //============================================================================= 833 // E3Line_EmptyData : Empty the data for a line object 834 //----------------------------------------------------------------------------- 835 // Note : The memory for lineData was allocated by Q3Line_GetData 836 //----------------------------------------------------------------------------- 837 TQ3Status 838 E3Line_EmptyData(TQ3LineData *lineData) 839 { 840 // Release the data 841 for ( TQ3Uns32 n = 0 ; n < 2 ; ++n ) 842 Q3Object_CleanDispose ( & lineData->vertices [ n ].attributeSet ) ; 843 844 Q3Object_CleanDispose ( & lineData->lineAttributeSet ) ; 845 846 return kQ3Success ; 847 } 848 849 850