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