1 /* $NoKeywords: $ */
2 /*
3 //
4 // Copyright (c) 1993-2012 Robert McNeel & Associates. All rights reserved.
5 // OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
6 // McNeel & Associates.
7 //
8 // THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
9 // ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
10 // MERCHANTABILITY ARE HEREBY DISCLAIMED.
11 //
12 // For complete openNURBS copyright information see <http://www.opennurbs.org>.
13 //
14 ////////////////////////////////////////////////////////////////
15 */
16
17 #include "pcl/surface/3rdparty/opennurbs/opennurbs.h"
18
19 #include <pcl/pcl_macros.h>
20
21 // This define is up here so anybody who want's to defeat the
22 // bozo vaccine has to be doing it on purpose.
23 #define BOZO_VACCINE_699FCC4262D4488c9109F1B7A37CE926
24
25 // Added for v5 - 12-10-2009 LW
26 ON_OBJECT_IMPLEMENT(ON_TextExtra,ON_UserData,"D90490A5-DB86-49f8-BDA1-9080B1F4E976");
27
ON_TextExtra()28 ON_TextExtra::ON_TextExtra()
29 {
30 m_userdata_uuid = ON_TextExtra::m_ON_TextExtra_class_id.Uuid();
31 m_application_uuid = ON_opennurbs5_id; // opennurbs.dll reads/writes this userdata
32 // The id must be the version 5 id because
33 // V6 SaveAs V5 needs to work, but SaveAs
34 // V4 should not write this userdata.
35 m_userdata_copycount = 1;
36 SetDefaults();
37 }
38
~ON_TextExtra()39 ON_TextExtra::~ON_TextExtra()
40 {
41 }
42
TextExtension(ON_TextEntity2 * pText,bool bCreate)43 ON_TextExtra* ON_TextExtra::TextExtension(ON_TextEntity2* pText, bool bCreate)
44 {
45 ON_TextExtra* pExtra = 0;
46 if(pText)
47 {
48 pExtra = ON_TextExtra::Cast(pText->GetUserData(ON_TextExtra::m_ON_TextExtra_class_id.Uuid()));
49 if(pExtra == 0 && bCreate)
50 {
51 pExtra = new ON_TextExtra;
52 if(pExtra)
53 {
54 if(!pText->AttachUserData(pExtra))
55 {
56 delete pExtra;
57 pExtra = 0;
58 }
59 }
60 }
61 }
62 return pExtra;
63 }
64
65 const
TextExtension(const ON_TextEntity2 * pText,bool bCreate)66 ON_TextExtra* ON_TextExtra::TextExtension(const ON_TextEntity2* pText, bool bCreate)
67 {
68 return TextExtension((ON_TextEntity2*)pText, bCreate);
69 }
70
SetDefaults()71 void ON_TextExtra::SetDefaults()
72 {
73 m_parent_uuid = ON_nil_uuid;
74
75 m_color_source = 0;
76 m_mask_color = 0;
77 m_border_offset = 0.1;
78 }
79
Dump(ON_TextLog &) const80 void ON_TextExtra::Dump( ON_TextLog& ) const
81 {
82 // do nothing
83 }
84
SizeOf() const85 unsigned int ON_TextExtra::SizeOf() const
86 {
87 unsigned int sz = ON_UserData::SizeOf();
88 sz += sizeof(*this) - sizeof(ON_UserData);
89 return sz;
90 }
91
Write(ON_BinaryArchive & archive) const92 ON_BOOL32 ON_TextExtra::Write(ON_BinaryArchive& archive) const
93 {
94 bool rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0);
95
96 if(rc) rc = archive.WriteUuid(m_parent_uuid);
97 if(rc) rc = archive.WriteBool(m_bDrawMask);
98 if(rc) rc = archive.WriteInt(m_color_source);
99 if(rc) rc = archive.WriteColor(m_mask_color);
100 if(rc) rc = archive.WriteDouble(m_border_offset);
101
102 if(!archive.EndWrite3dmChunk())
103 rc = false;
104
105 return rc;
106 }
107
Read(ON_BinaryArchive & archive)108 ON_BOOL32 ON_TextExtra::Read(ON_BinaryArchive& archive)
109 {
110 int major_version = 1;
111 int minor_version = 0;
112 bool rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version);
113 if(!rc)
114 return false;
115 if(major_version != 1)
116 return false;
117
118 if(rc) rc = archive.ReadUuid(m_parent_uuid);
119 if(rc) rc = archive.ReadBool(&m_bDrawMask);
120 if(rc) rc = archive.ReadInt(&m_color_source);
121 if(rc) rc = archive.ReadColor(m_mask_color);
122 if(rc) rc = archive.ReadDouble(&m_border_offset);
123
124 if ( !archive.EndRead3dmChunk() )
125 rc = false;
126
127 return rc;
128 }
129
GetDescription(ON_wString & description)130 ON_BOOL32 ON_TextExtra::GetDescription( ON_wString& description)
131 {
132 description.Format( "Userdata extension of ON_TextEntity");
133 return true;
134 }
135
Archive() const136 ON_BOOL32 ON_TextExtra::Archive() const
137 {
138 // true to write to file
139 return true;
140 }
141
142
ParentUUID() const143 ON_UUID ON_TextExtra::ParentUUID() const
144 {
145 return m_parent_uuid;
146 }
147
SetParentUUID(ON_UUID parent_uuid)148 void ON_TextExtra::SetParentUUID( ON_UUID parent_uuid)
149 {
150 m_parent_uuid = parent_uuid;
151 }
152
DrawTextMask() const153 bool ON_TextExtra::DrawTextMask() const
154 {
155 return m_bDrawMask;
156 }
157
SetDrawTextMask(bool bDraw)158 void ON_TextExtra::SetDrawTextMask(bool bDraw)
159 {
160 m_bDrawMask = bDraw;
161 }
162
MaskColorSource() const163 int ON_TextExtra::MaskColorSource() const
164 {
165 return m_color_source;
166 }
167
SetMaskColorSource(int source)168 void ON_TextExtra::SetMaskColorSource(int source)
169 {
170 if(source == 1)
171 m_color_source = 1;
172 else
173 m_color_source = 0;
174 }
175
MaskColor() const176 ON_Color ON_TextExtra::MaskColor() const
177 {
178 return m_mask_color;
179 }
180
SetMaskColor(ON_Color color)181 void ON_TextExtra::SetMaskColor(ON_Color color)
182 {
183 m_mask_color = color;
184 }
185
MaskOffsetFactor() const186 double ON_TextExtra::MaskOffsetFactor() const
187 {
188 return m_border_offset;
189 }
190
SetMaskOffsetFactor(double offset)191 void ON_TextExtra::SetMaskOffsetFactor(double offset)
192 {
193 m_border_offset = offset;
194 }
195
196 //--------------------
197
198
199
200 // Added for v5 - 4-20-07 LW
201 ON_OBJECT_IMPLEMENT(ON_DimensionExtra,ON_UserData,"8AD5B9FC-0D5C-47fb-ADFD-74C28B6F661E");
202
ON_DimensionExtra()203 ON_DimensionExtra::ON_DimensionExtra()
204 {
205 m_userdata_uuid = ON_DimensionExtra::m_ON_DimensionExtra_class_id.Uuid();
206 m_application_uuid = ON_opennurbs5_id; // opennurbs.dll reads/writes this userdata
207 // The id must be the version 5 id because
208 // V6 SaveAs V5 needs to work, but SaveAs
209 // V4 should not write this userdata.
210 m_userdata_copycount = 1;
211 SetDefaults();
212 }
213
~ON_DimensionExtra()214 ON_DimensionExtra::~ON_DimensionExtra()
215 {
216 }
217
AnnotationExtension(ON_Annotation2 * pDim,bool bCreate)218 static ON_DimensionExtra* AnnotationExtension(ON_Annotation2* pDim, bool bCreate)
219 {
220 ON_DimensionExtra* pExtra = 0;
221 if(pDim)
222 {
223 pExtra = ON_DimensionExtra::Cast(pDim->GetUserData(ON_DimensionExtra::m_ON_DimensionExtra_class_id.Uuid()));
224 if(pExtra == 0 && bCreate)
225 {
226 pExtra = new ON_DimensionExtra;
227 if( pExtra)
228 {
229 if(!pDim->AttachUserData(pExtra))
230 {
231 delete pExtra;
232 pExtra = 0;
233 }
234 }
235 }
236 }
237 return pExtra;
238 }
239
DimensionExtension(ON_LinearDimension2 * pDim,bool bCreate)240 ON_DimensionExtra* ON_DimensionExtra::DimensionExtension(ON_LinearDimension2* pDim, bool bCreate)
241 {
242 return AnnotationExtension((ON_Annotation2*)pDim, bCreate);
243 }
244
245 const
DimensionExtension(const ON_LinearDimension2 * pDim,bool bCreate)246 ON_DimensionExtra* ON_DimensionExtra::DimensionExtension(const ON_LinearDimension2* pDim, bool bCreate)
247 {
248 return DimensionExtension((ON_LinearDimension2*)pDim, bCreate);
249 }
250
DimensionExtension(ON_RadialDimension2 * pDim,bool bCreate)251 ON_DimensionExtra* ON_DimensionExtra::DimensionExtension(ON_RadialDimension2* pDim, bool bCreate)
252 {
253 return AnnotationExtension((ON_Annotation2*)pDim, bCreate);
254 }
255
256 const
DimensionExtension(const ON_RadialDimension2 * pDim,bool bCreate)257 ON_DimensionExtra* ON_DimensionExtra::DimensionExtension(const ON_RadialDimension2* pDim, bool bCreate)
258 {
259 return DimensionExtension((ON_RadialDimension2*)pDim, bCreate);
260 }
261
DimensionExtension(ON_OrdinateDimension2 * pDim,bool bCreate)262 ON_DimensionExtra* ON_DimensionExtra::DimensionExtension(ON_OrdinateDimension2* pDim, bool bCreate)
263 {
264 return AnnotationExtension((ON_Annotation2*)pDim, bCreate);
265 }
266
267 const
DimensionExtension(const ON_OrdinateDimension2 * pDim,bool bCreate)268 ON_DimensionExtra* ON_DimensionExtra::DimensionExtension(const ON_OrdinateDimension2* pDim, bool bCreate)
269 {
270 return DimensionExtension((ON_OrdinateDimension2*)pDim, bCreate);
271 }
272
SetDefaults()273 void ON_DimensionExtra::SetDefaults()
274 {
275 m_partent_uuid = ON_nil_uuid;
276
277 m_arrow_position = 0;
278 m_text_rects = 0;
279 m_distance_scale = 1.0;
280 m_modelspace_basepoint = ON_origin;
281 }
282
Dump(ON_TextLog &) const283 void ON_DimensionExtra::Dump( ON_TextLog& ) const
284 {
285 // do nothing
286 }
287
SizeOf() const288 unsigned int ON_DimensionExtra::SizeOf() const
289 {
290 unsigned int sz = ON_UserData::SizeOf();
291 sz += sizeof(*this) - sizeof(ON_UserData);
292 return sz;
293 }
294
Write(ON_BinaryArchive & archive) const295 ON_BOOL32 ON_DimensionExtra::Write(ON_BinaryArchive& archive) const
296 {
297 int major_version = 1;
298 int minor_version = 1;
299 bool rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,major_version,minor_version);
300
301 if(rc) rc = archive.WriteUuid( m_partent_uuid);
302 if(rc) rc = archive.WriteInt( m_arrow_position);
303 if(rc)
304 {
305 if( m_text_rects)
306 {
307 rc = archive.WriteInt( 7);
308 rc = archive.WriteInt( 28, (const int*)m_text_rects);
309 }
310 else
311 rc = archive.WriteInt( 0);
312
313 }
314 // 21 June 2010 Added distance scale, minor version 1
315 if(rc) rc = archive.WriteDouble(m_distance_scale);
316
317 if(!archive.EndWrite3dmChunk())
318 rc = false;
319
320 return rc;
321 }
322
Read(ON_BinaryArchive & archive)323 ON_BOOL32 ON_DimensionExtra::Read(ON_BinaryArchive& archive)
324 {
325 int major_version = 1;
326 int minor_version = 0;
327 bool rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version);
328 if(!rc)
329 return false;
330 if(major_version != 1)
331 return false;
332
333 if(rc) rc = archive.ReadUuid(m_partent_uuid);
334 if(rc) rc = archive.ReadInt(&m_arrow_position);
335
336 int rect_count = 0;
337 if(rc) rc = archive.ReadInt( &rect_count);
338 if( rc && rect_count)
339 rc = archive.ReadInt( rect_count, (int*)m_text_rects);
340
341 // 21 June 2010 Added distance scale, minor version 1
342 if(minor_version > 0)
343 {
344 if(rc) rc = archive.ReadDouble(&m_distance_scale);
345 }
346
347 if ( !archive.EndRead3dmChunk() )
348 rc = false;
349
350 return rc;
351 }
352
GetDescription(ON_wString & description)353 ON_BOOL32 ON_DimensionExtra::GetDescription( ON_wString& description)
354 {
355 description.Format( "Userdata extension of ON_Dimensions");
356 return true;
357 }
358
Archive() const359 ON_BOOL32 ON_DimensionExtra::Archive() const
360 {
361 // true to write to file
362 return true;
363 }
364
365
ParentUUID() const366 ON_UUID ON_DimensionExtra::ParentUUID() const
367 {
368 return m_partent_uuid;
369 }
370
SetParentUUID(ON_UUID partent_uuid)371 void ON_DimensionExtra::SetParentUUID( ON_UUID partent_uuid)
372 {
373 m_partent_uuid = partent_uuid;
374 }
375
ArrowPosition() const376 int ON_DimensionExtra::ArrowPosition() const
377 {
378 return m_arrow_position;
379 }
380
SetArrowPosition(int position)381 void ON_DimensionExtra::SetArrowPosition( int position)
382 {
383 if( position > 0)
384 m_arrow_position = 1;
385 else if( position < 0)
386 m_arrow_position = -1;
387 else
388 m_arrow_position = 0;
389 }
390
DistanceScale() const391 double ON_DimensionExtra::DistanceScale() const
392 {
393 return m_distance_scale;
394 }
395
SetDistanceScale(double s)396 void ON_DimensionExtra::SetDistanceScale(double s)
397 {
398 m_distance_scale = s;
399 }
400
SetModelSpaceBasePoint(ON_3dPoint basepoint)401 void ON_DimensionExtra::SetModelSpaceBasePoint(ON_3dPoint basepoint)
402 {
403 m_modelspace_basepoint = basepoint;
404 }
405
ModelSpaceBasePoint() const406 ON_3dPoint ON_DimensionExtra::ModelSpaceBasePoint() const
407 {
408 return m_modelspace_basepoint;
409 }
410
411 /*
412 const wchar_t* ON_DimensionExtra::ToleranceUpperString() const
413 {
414 return m_upper_string;
415 }
416
417 ON_wString& ON_DimensionExtra::ToleranceUpperString()
418 {
419 return m_upper_string;
420 }
421
422 void ON_DimensionExtra::SetToleranceUpperString( const wchar_t* upper_string)
423 {
424 m_upper_string = upper_string;
425 }
426
427 void ON_DimensionExtra::SetToleranceUpperString( ON_wString& upper_string)
428 {
429 m_upper_string = upper_string;
430 }
431
432 const wchar_t* ON_DimensionExtra::ToleranceLowerString() const
433 {
434 return m_lower_string;
435 }
436
437 ON_wString& ON_DimensionExtra::ToleranceLowerString()
438 {
439 return m_lower_string;
440 }
441
442 void ON_DimensionExtra::SetToleranceLowerString( const wchar_t* lower_string)
443 {
444 m_lower_string = lower_string;
445 }
446
447 void ON_DimensionExtra::SetToleranceLowerString( ON_wString& lower_string)
448 {
449 m_lower_string = lower_string;
450 }
451
452
453
454 const wchar_t* ON_DimensionExtra::AlternateString() const
455 {
456 return m_alt_string;
457 }
458
459 ON_wString& ON_DimensionExtra::AlternateString()
460 {
461 return m_alt_string;
462 }
463
464 void ON_DimensionExtra::SetAlternateString( const wchar_t* alt_string)
465 {
466 m_alt_string = alt_string;
467 }
468
469 void ON_DimensionExtra::SetAlternateString( ON_wString& alt_string)
470 {
471 m_alt_string = alt_string;
472 }
473
474 const wchar_t* ON_DimensionExtra::AlternateToleranceUpperString() const
475 {
476 return m_alt_upper_string;
477 }
478
479 ON_wString& ON_DimensionExtra::AlternateToleranceUpperString()
480 {
481 return m_alt_upper_string;
482 }
483
484 void ON_DimensionExtra::SetAlternateToleranceUpperString( const wchar_t* upper_string)
485 {
486 m_alt_upper_string = upper_string;
487 }
488
489 void ON_DimensionExtra::SetAlternateToleranceUpperString( ON_wString& upper_string)
490 {
491 m_alt_upper_string = upper_string;
492 }
493
494 const wchar_t* ON_DimensionExtra::AlternateToleranceLowerString() const
495 {
496 return m_alt_lower_string;
497 }
498
499 ON_wString& ON_DimensionExtra::AlternateToleranceLowerString()
500 {
501 return m_alt_lower_string;
502 }
503
504 void ON_DimensionExtra::SetAlternateToleranceLowerString( const wchar_t* lower_string)
505 {
506 m_alt_lower_string = lower_string;
507 }
508
509 void ON_DimensionExtra::SetAlternateToleranceLowerString( ON_wString& lower_string)
510 {
511 m_alt_lower_string = lower_string;
512 }
513 */
514
515 //--------------------
516
517
518 ON_VIRTUAL_OBJECT_IMPLEMENT( ON_Annotation2, ON_Geometry, "8D820224-BC6C-46b4-9066-BF39CC13AEFB");
519 ON_OBJECT_IMPLEMENT( ON_LinearDimension2, ON_Annotation2, "BD57F33B-A1B2-46e9-9C6E-AF09D30FFDDE");
520 ON_OBJECT_IMPLEMENT( ON_RadialDimension2, ON_Annotation2, "B2B683FC-7964-4e96-B1F9-9B356A76B08B");
521 ON_OBJECT_IMPLEMENT( ON_AngularDimension2, ON_Annotation2, "841BC40B-A971-4a8e-94E5-BBA26D67348E");
522 ON_OBJECT_IMPLEMENT( ON_TextEntity2, ON_Annotation2, "46F75541-F46B-48be-AA7E-B353BBE068A7");
523 ON_OBJECT_IMPLEMENT( ON_Leader2, ON_Annotation2, "14922B7A-5B65-4f11-8345-D415A9637129");
524 ON_OBJECT_IMPLEMENT( ON_TextDot, ON_Geometry, "74198302-CDF4-4f95-9609-6D684F22AB37");
525 ON_OBJECT_IMPLEMENT( ON_OrdinateDimension2,ON_Annotation2, "C8288D69-5BD8-4f50-9BAF-525A0086B0C3");
526
527 // class ON_Annotation2
528 //--------------------------------------------------------------------
529
Index() const530 int ON_Annotation2::Index() const
531 {
532 return m_index;
533 }
534
SetIndex(int index)535 void ON_Annotation2::SetIndex( int index)
536 {
537 m_index = index;
538 }
539
540
541
Create()542 void ON_Annotation2::Create()
543 {
544 m_textdisplaymode = ON::dtAboveLine;
545 m_index = -1;
546 m_textheight = 1.0;
547 Destroy();
548 }
549
Destroy()550 void ON_Annotation2::Destroy()
551 {
552 // 10-27-03 LW memory leak prevention
553 m_points.Empty();
554 SetTextValue(0);
555 SetTextFormula(0);
556 m_type = ON::dtNothing;
557 m_plane = ON_xy_plane;
558 m_userpositionedtext = false;
559 m_justification = 0;
560 m_annotative_scale = true;
561 }
562
EmergencyDestroy()563 void ON_Annotation2::EmergencyDestroy()
564 {
565 m_points.EmergencyDestroy();
566 m_usertext.EmergencyDestroy();
567 }
568
ON_Annotation2()569 ON_Annotation2::ON_Annotation2()
570 {
571 Create();
572 }
573
~ON_Annotation2()574 ON_Annotation2::~ON_Annotation2()
575 {
576 Destroy();
577 }
578
EvaluatePoint(const ON_ObjRef & objref,ON_3dPoint & P) const579 bool ON_Annotation2::EvaluatePoint( const ON_ObjRef& objref, ON_3dPoint& P) const
580 {
581 bool rc = false;
582 switch( objref.m_component_index.m_type )
583 {
584 case ON_COMPONENT_INDEX::dim_linear_point:
585 case ON_COMPONENT_INDEX::dim_radial_point:
586 case ON_COMPONENT_INDEX::dim_angular_point:
587 case ON_COMPONENT_INDEX::dim_ordinate_point:
588 case ON_COMPONENT_INDEX::dim_text_point:
589 {
590 ON_2dPoint uv = Point(objref.m_component_index.m_index);
591 if ( uv.IsValid() )
592 {
593 P = m_plane.PointAt(uv.x,uv.y);
594 rc = true;
595 }
596 }
597 break;
598 default:
599 // other enum values skipped on purpose
600 break;
601 }
602 if (!rc)
603 {
604 P = ON_UNSET_POINT;
605 }
606 return rc;
607 }
608
609 // convert from old style annotation
operator =(const ON_Annotation & src)610 ON_Annotation2& ON_Annotation2::operator=(const ON_Annotation& src)
611 {
612 // get a clean and empty "this"
613 Destroy();
614 Create();
615 ON_Geometry::operator=(src);
616
617 m_type = src.Type();
618 m_textdisplaymode = src.TextDisplayMode();
619 m_plane = src.Plane();
620
621 // 13 November 2006 Dale Lear
622 // Copying 5 points isn't always the right
623 // thing to do. Sometimes there should be
624 // no points or fewer points. I'm leaving
625 // this unchnaged for now and fixing the
626 // immediate bugs downstream. When we
627 // have a larger window (> 1 week before
628 // release) for beta testing, I'll change
629 // this to copy the number of points
630 // that actually exist in src
631 m_points.Reserve(5);
632 for( int i = 0; i < 5; i++)
633 SetPoint( 0, src.Point( i));
634
635
636 SetTextValue(src.UserText());
637 SetTextFormula(0);
638 m_userpositionedtext = src.UserPositionedText()?true:false;
639 m_index = 0;
640 m_textheight = 1.0;
641
642 return *this;
643 }
644
ON_Annotation2(const ON_Annotation & src)645 ON_Annotation2::ON_Annotation2(const ON_Annotation& src)
646 {
647 Create();
648 *this = src;
649 }
650
651
IsValid(ON_TextLog * text_log) const652 ON_BOOL32 ON_Annotation2::IsValid( ON_TextLog* text_log ) const
653 {
654 if ( !m_plane.IsValid() )
655 {
656 if ( text_log )
657 {
658 text_log->Print("ON_Annotation2 - m_plane is not valid\n");
659 }
660 return false;
661 }
662
663 const int points_count = m_points.Count();
664
665 int i;
666 for ( i = 0; i < points_count; i++ )
667 {
668 if ( !m_points[i].IsValid() )
669 {
670 if ( text_log )
671 {
672 text_log->Print("ON_Annotation2 - m_points[%d] is not valid.\n");
673 }
674 return false;
675 }
676 }
677
678 switch ( m_type )
679 {
680 case ON::dtDimLinear:
681 case ON::dtDimAligned:
682 case ON::dtDimAngular:
683 case ON::dtDimDiameter:
684 case ON::dtDimRadius:
685 case ON::dtLeader:
686 case ON::dtTextBlock:
687 case ON::dtDimOrdinate:
688 break;
689
690 default:
691 if ( text_log )
692 {
693 text_log->Print("ON_Annotation2 - m_type = %d is not a valid enum value\n",m_type);
694 }
695 return false;
696 break;
697 }
698
699 return true;
700 }
701
702 /*
703 bool ON_LinearDimension2::GetAnnotationBoundingBox(
704 const ON_DimStyle* dimstyle,
705 ON_2dPoint text0,
706 ON_2dPoint text1,
707 ON_BoundingBox& tight_bbox,
708 int bGrowBox,
709 const ON_Xform* xform
710 ) const
711 {
712 if ( 5 == m_points.Count() )
713 {
714 // Get 5 points that are always in the
715 ON_3dPointArray P(10);
716 ON_2dPoint uv0, uv1, uv2, uv3;
717
718 P.Append( m_plane.origin );
719
720 uv0 = m_points[0];
721 uv1 = uv0;
722 uv1.y = m_points[1].y;
723 uv2 = m_points[2];
724 uv3.x = uv2.x;
725 uv3.y = uv1.y;
726 P.Append( m_plane.PointAt(uv0.x,uv0.y) );
727 P.Append( m_plane.PointAt(uv1.x,uv1.y) );
728 P.Append( m_plane.PointAt(uv2.x,uv2.y) );
729 P.Append( m_plane.PointAt(uv3.x,uv3.y) );
730
731 if ( dimstyle )
732 {
733 // The ends of the displayed extension lines
734 // have their "y" values adjusted by the dimstyle.
735 const double el_offset = dimstyle->ExtOffset();
736 const double el_extension = dimstyle->ExtExtension();
737
738 const double v0 = (uv0.y < uv1.y) ? -1.0 : 1.0;
739 uv0.y += v0*el_offset;
740 uv1.y += v0*el_extension;
741
742 const double v1 = (uv2.y < uv3.y) ? -1.0 : 1.0;
743 uv2.y += v1*el_offset;
744 uv3.y += v1*el_extension;
745
746 P.Append( m_plane.PointAt(uv0.x,uv0.y) );
747 P.Append( m_plane.PointAt(uv1.x,uv1.y) );
748 P.Append( m_plane.PointAt(uv2.x,uv2.y) );
749 P.Append( m_plane.PointAt(uv3.x,uv3.y) );
750 }
751
752 ON_2dPoint corners[4];
753 if ( GetAnnotationText2dBoundingBox(dimstyle,text0,text1,corners) )
754 {
755 P.Append( m_plane.PointAt(corners[0].x,corners[0].y) );
756 P.Append( m_plane.PointAt(corners[1].x,corners[1].y) );
757 P.Append( m_plane.PointAt(corners[2].x,corners[2].y) );
758 P.Append( m_plane.PointAt(corners[3].x,corners[3].y) );
759 }
760
761 // TODO Add arrowheads
762 if ( P.GetTightBoundingBox( tight_bbox, bGrowBox, xform ) )
763 bGrowBox = true;
764 }
765 else if ( bGrowBox && !tight_bbox.IsValid() )
766 {
767 // invalid linear dimension
768 tight_bbox.Destroy();
769 bGrowBox = false;
770 }
771
772 return (0!=bGrowBox);
773 }
774 */
WriteAnnotation2UserText_V4(ON_BinaryArchive & file,const ON_wString & s)775 static bool WriteAnnotation2UserText_V4( ON_BinaryArchive& file, const ON_wString& s )
776 {
777 bool rc;
778 ON_wString s4;
779 int len = s.Length();
780
781 for(int i = 0; i < len; i++)
782 {
783 if(s[i] == '\r' || s[i] == '\n')
784 {
785 s4 += L'\r';
786 s4 += L'\n';
787
788 // May 24, 2012 Tim - Fix for RR 100260. If we use a while here we
789 // miss adding carriage returns where the user really meant to have a
790 // blank line. If we only check the next character and then continue on
791 // we preserve the blank lines.
792 if(i < len-1 && (s[i+1] == L'\r' || s[i+1] == L'\n'))
793 i++;
794 continue;
795 }
796 s4 += s[i];
797 }
798 rc = file.WriteString(s4);
799 return rc;
800 }
801
WriteAnnotation2UserText_V5(ON_BinaryArchive & file,const ON_wString & s)802 static bool WriteAnnotation2UserText_V5( ON_BinaryArchive& file, const ON_wString& s )
803 {
804 bool rc;
805 rc = file.WriteString( s);
806 return rc;
807 }
808
809 //static int CountTextLines(const ON_wString& text)
810 //{
811 // int len = text.Length();
812 // int lines = len > 0 ? 1 : 0;
813 // for(int i = 0; i < len; i++)
814 // {
815 // if(text[i] == L'\n' || text[i] == L'\r')
816 // {
817 // lines++;
818 // if(i < len-1 && text[i] == L'\r' && text[i+1] == L'\n')
819 // i++;
820 // }
821 // }
822 // return lines;
823 //}
824
Write(ON_BinaryArchive & file) const825 ON_BOOL32 ON_Annotation2::Write( ON_BinaryArchive& file ) const
826 {
827 int i;
828 bool rc = false;
829 bool bInChunk = (file.Archive3dmVersion() >= 5 );
830 if ( bInChunk )
831 {
832 // 18 October 2007 Dale Lear
833 // I modified this code so that V5 files can add
834 // information in ON_Annotation2 chunks without
835 // breaking past and future file IO.
836 // The opennurbs version number before this change was
837 // 20071017*. I changed the version to 20071018* when
838 // I checked in this IO change. The reason I can get
839 // away with this is that nobody except developers has
840 // a copy of V5 Rhino.
841 // 28 Aug, 2010 - Lowell - changed minor version 0->1 to write
842 // annotative scale flag
843 // 24 September 2010 Dale Lear
844 // I incremented chunk version to 1.2 and wrote the TextFormaula() string.
845 rc = file.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,2);
846 if (!rc)
847 return false;
848 }
849 else
850 {
851 // For archives with opennurbs version < 200710180
852 // The code before version 200710180 does not properly
853 // handle new additions to the ON_Annotation2 chunk.
854 rc = file.Write3dmChunkVersion( 1, 0 );
855 }
856
857 while(rc)
858 {
859 i = m_type;
860 rc = file.WriteInt( i);
861 if ( !rc) break;
862
863 i = m_textdisplaymode;
864 rc = file.WriteInt( i);
865 if ( !rc) break;
866
867 // June 17, 2010 - Lowell - Added adjustment to position text
868 // a little better in pre-v5 files.
869 // There's no adjustment for right/left justify becasue we don't
870 // know the width of the text here
871 // This doesn't change the size or position of any fields being
872 // written, but just adjusts the plane to tune up the alignment
873
874 // 16 Nov, 2011 - Lowell - Change text to bottom left justified for pre-v5 files rr94270
875 // This stuff is moved to CRhinoDoc::Write3DMHelper() so it will help with other file
876 // formats too
877 //ON_Plane plane = m_plane;
878 //if(file.Archive3dmVersion() <= 4 && m_type == ON::dtTextBlock)
879 //{
880 // double height = m_textheight;
881 // int lines = CountTextLines(m_usertext);
882 // double linefeed = ON_Font::m_default_linefeed_ratio;
883
884 // if(m_justification & tjBottom)
885 // {
886 // if(lines > 1)
887 // {
888 // ON_3dPoint p = plane.PointAt(0.0, -height * (lines-1) * linefeed);
889 // plane.SetOrigin(p);
890 // }
891 // }
892 // else if(m_justification & tjMiddle)
893 // {
894 // double h = height * (lines-1) * linefeed + height;
895 // ON_3dPoint p = plane.PointAt(0.0, h * 0.5);
896 // plane.SetOrigin(p);
897 // }
898 // else if(m_justification & tjTop)
899 // {
900 // ON_3dPoint p = plane.PointAt(0.0, -height);
901 // plane.SetOrigin(p);
902 // }
903 //}
904
905 rc = file.WritePlane(m_plane);
906 if ( !rc) break;
907
908 ON_2dPointArray points = m_points;
909 int bUserPositionedText = m_userpositionedtext?1:0;
910 switch( m_type )
911 {
912 case ON::dtDimAligned:
913 case ON::dtDimLinear:
914 if ( 4 == points.Count() )
915 {
916 // so old versions will read enough points.
917 points.AppendNew();
918 points[4].Set(0.5*(points[0].x + points[2].x),points[1].y);
919 bUserPositionedText = false;
920 }
921 break;
922
923 case ON::dtDimAngular:
924 //user positioned text is supported.
925 break;
926
927 case ON::dtDimRadius:
928 case ON::dtDimDiameter:
929 // 9 August 2005 Dale Lear - radial dimensions do
930 // not support user postioned text. The never have
931 // in Rhino, but the old files had 5 points in them.
932 if ( 4 == points.Count() )
933 {
934 // so old versions will read enough points.
935 points.AppendNew();
936 }
937 if ( points.Count() >= 5 )
938 {
939 points[4] = points[2];
940 }
941 bUserPositionedText = false;
942 break;
943
944 default:
945 bUserPositionedText = false;
946 break;
947 }
948
949 rc = file.WriteArray( points);
950 if ( !rc) break;
951
952 // June 17, 2010 - Lowell - Added support for writing word-wrapped text
953 // to pre-v5 files with hard returns in place of wrapping markers
954 rc = ( file.Archive3dmVersion() <= 4 )
955 ? WriteAnnotation2UserText_V4(file,m_usertext)
956 : WriteAnnotation2UserText_V5(file,m_usertext);
957 if ( !rc) break;
958 // 7-9-03 lw removed extra text string getting written
959
960 rc = file.WriteInt( bUserPositionedText );
961 if ( !rc) break;
962
963 rc = file.WriteInt( m_index); // font or dimstyle index
964 if ( !rc) break;
965
966 rc = file.WriteDouble( m_textheight);
967 if ( !rc) break;
968
969 if ( !bInChunk )
970 break;
971
972 // NOTE WELL - NEVER change the code in this function
973 // above this comment. If you do, you will
974 // break reading and writing V4 files.
975 // Ask Dale Lear if you have any questions.
976
977 // 18 October 2007 - Dale Lear added m_justification IO
978 rc = file.WriteInt(m_justification);
979 if ( !rc)
980 break;
981
982 // 28 Aug 2010 - Lowell - Added flag for whether text gets scaled in modelspace
983 rc = file.WriteBool(m_annotative_scale);
984 if(!rc)
985 break;
986
987 // 24 September 2010 Dale Lear
988 // I incremented chunk version to 1.2
989 ON_wString text_formula = TextFormula();
990 rc = file.WriteString(text_formula);
991 if(!rc)
992 break;
993
994 // To write more ON_Annotation2 fields, increment the minor version
995 // number and write the new information here.
996
997
998 // Finished writing ON_Annotation2 information
999 break;
1000 }
1001
1002 if ( bInChunk )
1003 {
1004 if ( !file.EndWrite3dmChunk() )
1005 rc = false;
1006 }
1007
1008 return rc;
1009 }
1010
Read(ON_BinaryArchive & file)1011 ON_BOOL32 ON_Annotation2::Read( ON_BinaryArchive& file )
1012 {
1013 // NOTE WELL - If you make any changes to this code,
1014 // you break file IO for some annotation
1015 // objects. Please discuss all changes
1016 // with Dale Lear BEFORE you check in any
1017 // changes.
1018
1019 Destroy();
1020
1021 // If annotation is read from old files that do not contain
1022 // the m_annotative_scale setting, then m_annotative_scale
1023 // must be false so the text behaves the way it did in old
1024 // files. The "Destroy()" function above can set m_annotative_scale
1025 // any way that makes sense for new objects.
1026 m_annotative_scale = false;
1027
1028 int major_version = 0;
1029 int minor_version = 0;
1030 bool rc = false;
1031
1032 bool bInChunk = (file.Archive3dmVersion() >= 5 && file.ArchiveOpenNURBSVersion() >= 200710180);
1033
1034 if ( bInChunk )
1035 {
1036 rc = file.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version);
1037 if ( !rc )
1038 return false;
1039 }
1040 else
1041 {
1042 rc = file.Read3dmChunkVersion(&major_version,&minor_version);
1043 }
1044
1045 while(rc)
1046 {
1047 if ( 1 != major_version )
1048 {
1049 rc = false;
1050 break;
1051 }
1052
1053 int i;
1054 rc = file.ReadInt( &i);
1055 if (!rc) break;
1056 m_type = ON::AnnotationType( i);
1057
1058 rc = file.ReadInt( &i);
1059 if (!rc) break;
1060 m_textdisplaymode = ON::eTextDisplayMode( i);
1061
1062 rc = file.ReadPlane( m_plane);
1063 if (!rc) break;
1064
1065 rc = file.ReadArray( m_points);
1066 if (!rc) break;
1067
1068 rc = file.ReadString( m_usertext);
1069 if (!rc) break;
1070
1071 i = 0;
1072 rc = file.ReadInt( &i );
1073 if (!rc) break;
1074 m_userpositionedtext = i ? true : false;
1075
1076 rc = file.ReadInt( &m_index);
1077 if (!rc) break;
1078
1079 rc = file.ReadDouble( &m_textheight);
1080 if (!rc) break;
1081
1082 switch( m_type )
1083 {
1084 case ON::dtDimAligned:
1085 case ON::dtDimLinear:
1086 if ( m_points.Count() < 5 )
1087 {
1088 m_userpositionedtext = false;
1089 }
1090 break;
1091
1092 case ON::dtDimAngular:
1093 if ( m_points.Count() <= 0 )
1094 {
1095 m_userpositionedtext = false;
1096 }
1097 break;
1098
1099 case ON::dtDimRadius:
1100 case ON::dtDimDiameter:
1101 // 9 August 2005 Dale Lear - radial dimensions do
1102 // not support user postioned text. The never have
1103 // in Rhino, but the old files had 5 points in them.
1104 if ( 5 == m_points.Count() )
1105 {
1106 m_points.SetCount(4);
1107 }
1108 m_userpositionedtext = false;
1109 break;
1110
1111 default:
1112 m_userpositionedtext = false;
1113 break;
1114 }
1115
1116 if ( !bInChunk )
1117 break;
1118
1119 // 18 October 2007 - Dale Lear added m_justification IO
1120 rc = file.ReadInt( &m_justification );
1121 if (!rc) break;
1122
1123 if ( minor_version <= 0 )
1124 break;
1125
1126 if(minor_version >= 1)
1127 {
1128 // 28 Aug, 2010 - Lowell - added reading annotative scale flag
1129 rc = file.ReadBool(&m_annotative_scale);
1130 if (!rc) break;
1131
1132 if ( minor_version >= 2 )
1133 {
1134 // 24 September 2010 Dale Lear
1135 // I incremented chunk version to 1.2
1136 ON_wString text_formula;
1137 rc = file.ReadString(text_formula);
1138 if(!rc) break;
1139 SetTextFormula(text_formula);
1140 }
1141
1142 }
1143
1144 // Read new additions to ON_Annotation2 here
1145
1146 break;
1147 }
1148
1149 if ( bInChunk )
1150 {
1151 if (!file.EndRead3dmChunk() )
1152 rc = false;
1153 }
1154
1155
1156 return rc;
1157 }
1158
ObjectType() const1159 ON::object_type ON_Annotation2::ObjectType() const
1160 {
1161 return ON::annotation_object;
1162 }
1163
Dimension() const1164 int ON_Annotation2::Dimension() const
1165 {
1166 return 3;
1167 }
1168
Transform(const ON_Xform & xform)1169 ON_BOOL32 ON_Annotation2::Transform( const ON_Xform& xform )
1170 {
1171 ON_Geometry::Transform(xform);
1172
1173 ON_2dPoint p;
1174 ON_Xform scalexf;
1175 double scale = xform.Determinant();
1176 scale = fabs( scale);
1177 if( fabs( scale - 1.0) > ON_SQRT_EPSILON && fabs( scale) > ON_SQRT_EPSILON)
1178 {
1179 scale = pow( scale, 1.0/3.0);
1180 scalexf.Scale( scale, scale, scale);
1181 for( int i = 0; i < m_points.Count(); i++)
1182 {
1183 p = Point( i);
1184 p.Transform( scalexf);
1185 SetPoint( i, p);
1186 }
1187 // This scales the text height on text but not on dimensions
1188 if( ON_Annotation2::IsText())
1189 {
1190 SetHeight( scale * Height());
1191 }
1192 }
1193
1194 return m_plane.Transform( xform );
1195
1196 }
1197
ON_Plane_Repair(ON_Plane & plane)1198 int ON_Plane_Repair(ON_Plane& plane)
1199 {
1200 int rc;
1201 if ( plane.IsValid() )
1202 {
1203 rc = 1;
1204 }
1205 else
1206 {
1207 rc = 2;
1208 if (!plane.origin.IsValid())
1209 {
1210 plane.origin.Set(0.0,0.0,0.0);
1211 }
1212
1213 bool bGoodX = (plane.xaxis.IsValid() && !plane.xaxis.IsZero() );
1214 bool bGoodY = (plane.yaxis.IsValid() && !plane.yaxis.IsZero() );
1215 bool bGoodZ = (plane.zaxis.IsValid() && !plane.zaxis.IsZero() );
1216 if ( bGoodX )
1217 {
1218 if ( fabs(plane.xaxis.Length()-1.0) > ON_SQRT_EPSILON )
1219 plane.xaxis.Unitize();
1220 }
1221 if ( bGoodY )
1222 {
1223 if ( fabs(plane.yaxis.Length()-1.0) > ON_SQRT_EPSILON )
1224 plane.yaxis.Unitize();
1225 }
1226 if ( bGoodZ )
1227 {
1228 if ( fabs(plane.zaxis.Length()-1.0) > ON_SQRT_EPSILON )
1229 plane.zaxis.Unitize();
1230 }
1231
1232 if ( bGoodZ )
1233 {
1234 double x = bGoodX ? fabs(plane.zaxis*plane.xaxis) : 99.0;
1235 double y = bGoodX ? fabs(plane.zaxis*plane.yaxis) : 99.0;
1236 if ( x <= ON_SQRT_EPSILON )
1237 {
1238 if ( y > ON_SQRT_EPSILON )
1239 {
1240 plane.yaxis = ON_CrossProduct(plane.zaxis,plane.xaxis);
1241 plane.yaxis.Unitize();
1242 }
1243 }
1244 else if ( y <= ON_SQRT_EPSILON )
1245 {
1246 plane.xaxis = ON_CrossProduct(plane.yaxis,plane.zaxis);
1247 plane.xaxis.Unitize();
1248 }
1249 else if ( x <= y && x < 1.0 )
1250 {
1251 plane.yaxis = ON_CrossProduct(plane.zaxis,plane.xaxis);
1252 if( plane.yaxis.Unitize() )
1253 {
1254 plane.xaxis = ON_CrossProduct(plane.yaxis,plane.zaxis);
1255 plane.xaxis.Unitize();
1256 }
1257 else if ( y < 1.0 )
1258 {
1259 plane.CreateFromNormal( plane.origin, plane.zaxis );
1260 }
1261 }
1262 else if ( y < 1.0 )
1263 {
1264 plane.xaxis = ON_CrossProduct(plane.yaxis,plane.zaxis);
1265 if( plane.xaxis.Unitize() )
1266 {
1267 plane.yaxis = ON_CrossProduct(plane.zaxis,plane.xaxis);
1268 plane.yaxis.Unitize();
1269 }
1270 else
1271 {
1272 plane.CreateFromNormal( plane.origin, plane.zaxis );
1273 }
1274 }
1275 }
1276 else if ( bGoodX )
1277 {
1278 if ( bGoodY )
1279 {
1280 plane.zaxis = ON_CrossProduct(plane.xaxis,plane.yaxis);
1281 if ( plane.zaxis.Unitize() )
1282 {
1283 if ( fabs(plane.yaxis*plane.xaxis) > ON_SQRT_EPSILON )
1284 {
1285 plane.yaxis = ON_CrossProduct(plane.zaxis,plane.xaxis);
1286 plane.yaxis.Unitize();
1287 }
1288 }
1289 else
1290 {
1291 plane.yaxis.PerpendicularTo(plane.xaxis);
1292 plane.yaxis.Unitize();
1293 plane.zaxis = ON_CrossProduct(plane.xaxis,plane.yaxis);
1294 plane.zaxis.Unitize();
1295 }
1296 }
1297 else
1298 {
1299 plane.yaxis.PerpendicularTo(plane.xaxis);
1300 plane.yaxis.Unitize();
1301 plane.zaxis = ON_CrossProduct(plane.xaxis,plane.yaxis);
1302 plane.zaxis.Unitize();
1303 }
1304 }
1305 else if ( bGoodY )
1306 {
1307 plane.zaxis.PerpendicularTo(plane.yaxis);
1308 plane.zaxis.Unitize();
1309 plane.xaxis = ON_CrossProduct(plane.yaxis,plane.zaxis);
1310 plane.xaxis.Unitize();
1311 }
1312 else
1313 {
1314 plane.xaxis.Set(1.0,0.0,0.0);
1315 plane.yaxis.Set(0.0,1.0,0.0);
1316 plane.zaxis.Set(0.0,0.0,1.0);
1317 }
1318 plane.UpdateEquation();
1319 }
1320 return rc;
1321 }
1322
1323 // overrides virtual ON_Geometry::Transform()
Transform(const ON_Xform & xform)1324 ON_BOOL32 ON_RadialDimension2::Transform( const ON_Xform& xform )
1325 {
1326 // TODO fill in something that works for non-rigid transforms
1327 return ON_Annotation2::Transform(xform);
1328 }
1329
Transform(const ON_Xform & xform)1330 ON_BOOL32 ON_Leader2::Transform( const ON_Xform& xform )
1331 {
1332 bool rc = xform.IsIdentity();
1333 if ( !rc)
1334 {
1335 ON_Plane plane = m_plane;
1336 rc = plane.Transform(xform);
1337 if ( rc )
1338 {
1339 int i;
1340 const int point_count = m_points.Count();
1341 ON_2dPointArray q(point_count);
1342 ON_2dPoint p2, q2;
1343 ON_3dPoint P, Q;
1344 bool bUpdatePoints = false;
1345 for ( i = 0; i < point_count && rc; i++ )
1346 {
1347 p2 = m_points[i];
1348 P = m_plane.PointAt( p2.x, p2.y );
1349 Q = xform*P;
1350 if( !plane.ClosestPointTo(Q,&q2.x,&q2.y) )
1351 rc = false;
1352 if ( fabs(p2.x - q2.x) <= ON_SQRT_EPSILON )
1353 q2.x = p2.x;
1354 else
1355 bUpdatePoints = true;
1356 if ( fabs(p2.y - q2.y) <= ON_SQRT_EPSILON )
1357 q2.y = p2.y;
1358 else
1359 bUpdatePoints = true;
1360 q.Append(q2);
1361 }
1362
1363 if(rc)
1364 {
1365 ON_Geometry::Transform(xform);
1366 m_plane = plane;
1367
1368 if ( bUpdatePoints )
1369 m_points = q;
1370
1371 if ( m_points[0].x != 0.0 || m_points[0].y != 0.0 )
1372 {
1373 ON_2dVector v = m_points[0];
1374 if ( !v.IsZero() )
1375 {
1376 m_plane.origin = m_plane.PointAt(v.x,v.y);
1377 m_plane.UpdateEquation();
1378 v.Reverse();
1379 for ( i = 1; i < point_count; i++ )
1380 {
1381 m_points[i] += v;
1382 }
1383 m_points[0].Set(0.0,0.0);
1384 }
1385 }
1386 }
1387 }
1388 }
1389 return rc;
1390 }
1391
Transform(const ON_Xform & xform)1392 ON_BOOL32 ON_AngularDimension2::Transform( const ON_Xform& xform )
1393 {
1394 // Dale Lear - this override fixes RR 11114 by correctly
1395 // handling non uniform scaling.
1396 bool rc = xform.IsIdentity();
1397 if ( !rc)
1398 {
1399 ON_Plane plane = m_plane;
1400 if ( dim_pt_count == m_points.Count() && plane.Transform( xform ) )
1401 {
1402 rc = true;
1403 ON_3dPoint P[dim_pt_count], Q[dim_pt_count], A[3], B[3];
1404 ON_2dVector p2[dim_pt_count], q2[dim_pt_count], a[3], b[3];
1405 double r[3];
1406 int i;
1407 bool bUpdatePoints = false;
1408 double a0 = 0.0;
1409 double a1 = m_angle;
1410 a[0].Set( m_radius*cos(a0), m_radius*sin(a0) );
1411 a[1].Set( m_radius*cos(0.5*(a0+a1)), m_radius*sin(0.5*(a0+a1)) );
1412 a[2].Set( m_radius*cos(a1), m_radius*sin(a1) );
1413 for ( i = 0; i < dim_pt_count && rc; i++ )
1414 {
1415 p2[i] = m_points[i];
1416 P[i] = m_plane.PointAt( p2[i].x, p2[i].y );
1417 Q[i] = xform*P[i];
1418 if( !plane.ClosestPointTo(Q[i],&q2[i].x,&q2[i].y) )
1419 rc = false;
1420 if ( fabs(p2[i].x - q2[i].x) > ON_SQRT_EPSILON
1421 || fabs(p2[i].y - q2[i].y) > ON_SQRT_EPSILON )
1422 {
1423 // transformation is not a rigid motion
1424 bUpdatePoints = true;
1425 }
1426 }
1427
1428 for ( i = 0; i < 3 && rc; i++ )
1429 {
1430 A[i] = m_plane.PointAt( a[i].x, a[i].y );
1431 B[i] = xform*A[i];
1432 if( !plane.ClosestPointTo(B[i],&b[i].x,&b[i].y) )
1433 rc = false;
1434 r[i] = B[i].DistanceTo(plane.origin);
1435 if ( fabs(a[i].x - b[i].x) > ON_SQRT_EPSILON
1436 || fabs(a[i].y - b[i].y) > ON_SQRT_EPSILON )
1437 {
1438 // transformation is not a rigid motion
1439 bUpdatePoints = true;
1440 }
1441 if ( r[i] < ON_SQRT_EPSILON )
1442 rc = false;
1443 else if ( r[i] > m_radius*(1.0+ON_SQRT_EPSILON) )
1444 bUpdatePoints = true;
1445 else if ( r[i] < m_radius*(1.0-ON_SQRT_EPSILON) )
1446 bUpdatePoints = true;
1447 }
1448
1449 if (rc)
1450 {
1451 if ( bUpdatePoints )
1452 {
1453 ON_3dVector X = B[0] - plane.origin;
1454 X.Unitize();
1455
1456 ON_3dVector Y1 = B[1] - plane.origin;
1457 Y1.Unitize();
1458 ON_3dVector Z1 = ON_CrossProduct(X,Y1);
1459 double z1 = Z1.Length();
1460 Z1.Unitize();
1461
1462 ON_3dVector Y2 = B[2] - plane.origin;
1463 Y2.Unitize();
1464 ON_3dVector Z2 = ON_CrossProduct(X,Y2);
1465 double z2 = Z2.Length();
1466 Z2.Unitize();
1467
1468 if ( z2 >= z1 && z2 >= 0.05 )
1469 {
1470 plane.xaxis = X;
1471 plane.zaxis = Z2;
1472 if ( Z1*Z2 < 0.0 )
1473 plane.zaxis.Reverse();
1474 plane.yaxis = ON_CrossProduct(plane.zaxis,plane.xaxis);
1475 plane.yaxis.Unitize();
1476 }
1477 else if ( z1 >= 0.05 )
1478 {
1479 plane.xaxis = X;
1480 plane.zaxis = Z1;
1481 plane.yaxis = ON_CrossProduct(plane.zaxis,plane.xaxis);
1482 plane.yaxis.Unitize();
1483 }
1484 else
1485 {
1486 rc = false;
1487 }
1488
1489 if (rc)
1490 {
1491 plane.UpdateEquation();
1492 ON_3dVector V = B[2] - plane.origin;
1493 double x = V*plane.xaxis;
1494 double y = V*plane.yaxis;
1495 double angle = atan2(y,x);
1496 if ( angle < 0.0 )
1497 angle += 2.0*ON_PI;
1498 double radius = (r[0]+r[1]+r[2])/3.0;
1499
1500 double arc_pt_angle = 1.0/3.0;
1501 if ( m_angle > 0.0 && m_points[arc_pt_index].IsValid() )
1502 {
1503 arc_pt_angle = atan2(m_points[arc_pt_index].y,m_points[arc_pt_index].x);
1504 if ( arc_pt_angle < 0.0 ) arc_pt_angle += 2.0*ON_PI;
1505 if ( arc_pt_angle > m_angle )
1506 arc_pt_angle = 1.0/3.0;
1507 else
1508 arc_pt_angle /= m_angle;
1509
1510 if ( arc_pt_angle < 0.0 )
1511 arc_pt_angle = 0.0;
1512 else if ( arc_pt_angle > 1.0 )
1513 arc_pt_angle = 1.0;
1514 }
1515 arc_pt_angle *= angle;
1516
1517
1518 ON_Geometry::Transform(xform);
1519 m_plane = plane;
1520 m_radius = radius;
1521 m_angle = angle;
1522 m_points[start_pt_index].Set(m_radius,0.0);
1523 m_points[end_pt_index].Set(m_radius*cos(m_angle),m_radius*sin(m_angle));
1524 m_points[arc_pt_index].Set(m_radius*cos(arc_pt_angle),m_radius*sin(arc_pt_angle));
1525 if ( m_userpositionedtext )
1526 {
1527 m_plane.ClosestPointTo(Q[userpositionedtext_pt_index],
1528 &m_points[userpositionedtext_pt_index].x,
1529 &m_points[userpositionedtext_pt_index].y
1530 );
1531 }
1532 else
1533 {
1534 m_points[userpositionedtext_pt_index].Set(m_radius*cos(0.5*m_angle),m_radius*sin(0.5*m_angle));
1535 }
1536
1537 }
1538 }
1539 else
1540 {
1541 ON_Geometry::Transform(xform);
1542 m_plane = plane;
1543 }
1544 }
1545 }
1546 }
1547
1548 return rc;
1549 }
1550
IsText() const1551 bool ON_Annotation2::IsText() const
1552 { return (ON::dtTextBlock == m_type); }
1553
IsLeader() const1554 bool ON_Annotation2::IsLeader() const
1555 { return (ON::dtLeader == m_type); }
1556
IsDimension() const1557 bool ON_Annotation2::IsDimension() const
1558 { return (ON::dtTextBlock != m_type && ON::dtLeader != m_type); }
1559
NumericValue() const1560 double ON_Annotation2::NumericValue() const
1561 { return ON_UNSET_VALUE; }
1562
SetHeight(double ht)1563 void ON_Annotation2::SetHeight( double ht)
1564 { if( ht > ON_SQRT_EPSILON) m_textheight = ht; }
1565
Height() const1566 double ON_Annotation2::Height() const
1567 { return m_textheight; }
1568
SetType(ON::eAnnotationType type)1569 void ON_Annotation2::SetType( ON::eAnnotationType type )
1570 {
1571 m_type = type;
1572 if(type == ON::dtDimRadius)
1573 SetTextValue(ON_RadialDimension2::DefaultRadiusText());
1574 else if(type == ON::dtDimDiameter)
1575 SetTextValue(ON_RadialDimension2::DefaultDiameterText());
1576 else
1577 SetTextValue(0);
1578
1579 SetTextFormula(0);
1580 }
1581
Type() const1582 ON::eAnnotationType ON_Annotation2::Type() const
1583 { return m_type; }
1584
SetPlane(const ON_Plane & plane)1585 void ON_Annotation2::SetPlane( const ON_Plane& plane )
1586 { m_plane = plane; }
1587
Plane() const1588 const ON_Plane& ON_Annotation2::Plane() const
1589 { return m_plane; }
1590
SetPointCount(int count)1591 void ON_Annotation2::SetPointCount( int count)
1592 {
1593 if( m_points.Count() < count)
1594 {
1595 m_points.Reserve( count);
1596 for( int i = m_points.Count(); i < count; i++)
1597 m_points.Append( ON_2dPoint());
1598 }
1599 }
1600
PointCount() const1601 int ON_Annotation2::PointCount() const
1602 { return m_points.Count(); }
1603
SetPoints(const ON_2dPointArray & points)1604 void ON_Annotation2::SetPoints( const ON_2dPointArray& points )
1605 { m_points = points; }
1606
Points() const1607 const ON_2dPointArray& ON_Annotation2::Points() const
1608 { return m_points; }
1609
SetPoint(int idx,const ON_2dPoint & point)1610 void ON_Annotation2::SetPoint( int idx, const ON_2dPoint& point )
1611 {
1612 if ( idx >= 0 )
1613 {
1614 if ( idx < m_points.Count() )
1615 m_points[idx] = point;
1616 else if ( idx == m_points.Count() )
1617 m_points.Append(point);
1618 }
1619 }
1620
Point(int idx) const1621 ON_2dPoint ON_Annotation2::Point( int idx ) const
1622 {
1623 return ( idx >= 0 && idx < m_points.Count() )
1624 ? m_points[idx]
1625 : ON_2dPoint( 0.0, 0.0 );
1626 }
1627
SetUserText(const wchar_t * text_value)1628 void ON_Annotation2::SetUserText( const wchar_t* text_value )
1629 // ON_Annotation2::SetUserText is OBSOLETE - use ON_Annotation2::SetTextValue();
1630 {
1631 SetTextValue( text_value );
1632 }
1633
UserText() const1634 const ON_wString& ON_Annotation2::UserText() const
1635 // ON_Annotation2::UserText() is OBSOLETE - use ON_Annotation2::TextValue();
1636 {
1637 return m_usertext;
1638 }
1639
SetUserPositionedText(int bMoved)1640 void ON_Annotation2::SetUserPositionedText( int bMoved )
1641 { m_userpositionedtext = bMoved?true:false; }
UserPositionedText() const1642 bool ON_Annotation2::UserPositionedText() const
1643 { return m_userpositionedtext; }
1644
1645
1646 // Converts 2d points in annotation to 3d WCS points
GetECStoWCSXform(ON_Xform & xform) const1647 ON_BOOL32 ON_Annotation2::GetECStoWCSXform( ON_Xform& xform ) const
1648 {
1649 ON_3dVector z = ON_CrossProduct( m_plane.xaxis, m_plane.yaxis );
1650 return xform.ChangeBasis( m_plane.origin, m_plane.xaxis, m_plane.yaxis, z,
1651 ON_origin, ON_xaxis, ON_yaxis, ON_zaxis );
1652 }
1653
1654 // Converts from WCS 3d points to 2d points in annotation
GetWCStoECSXform(ON_Xform & xform) const1655 ON_BOOL32 ON_Annotation2::GetWCStoECSXform( ON_Xform& xform ) const
1656 {
1657 ON_3dVector z = ON_CrossProduct( m_plane.xaxis, m_plane.yaxis );
1658 return xform.ChangeBasis( ON_origin, ON_xaxis, ON_yaxis, ON_zaxis,
1659 m_plane.origin, m_plane.xaxis, m_plane.yaxis, z );
1660 }
1661
ReservePoints(int count)1662 void ON_Annotation2::ReservePoints( int count)
1663 {
1664 m_points.SetCapacity( count);
1665 m_points.SetCount( count);
1666 }
1667
DefaultText()1668 const wchar_t* ON_Annotation2::DefaultText() { return L""; }
1669
1670
SetTextDisplayMode(ON::eTextDisplayMode mode)1671 void ON_Annotation2::SetTextDisplayMode( ON::eTextDisplayMode mode)
1672 {
1673 m_textdisplaymode = mode;
1674 }
1675
TextDisplayMode() const1676 ON::eTextDisplayMode ON_Annotation2::TextDisplayMode() const
1677 {
1678 return m_textdisplaymode;
1679 }
1680
1681
ConvertBack(ON_Annotation & target)1682 void ON_Annotation2::ConvertBack( ON_Annotation& target)
1683 {
1684 target.SetType( Type());
1685 target.SetTextDisplayMode( TextDisplayMode());
1686 target.SetPlane( Plane());
1687 target.SetPoints( Points());
1688 target.SetUserText( TextValue());
1689 target.SetDefaultText( DefaultText());
1690 target.SetUserPositionedText( UserPositionedText());
1691 }
1692
SetJustification(unsigned int justification)1693 void ON_Annotation2::SetJustification( unsigned int justification)
1694 {
1695 // SDKBREAK - move to ON_Leader virtual SetJustification
1696 if(this->IsLeader())
1697 m_justification = justification;
1698 }
1699
Justification()1700 unsigned int ON_Annotation2::Justification()
1701 {
1702 // SDKBREAK - move to ON_Leader virtual Justification
1703 if(this->IsLeader())
1704 return m_justification;
1705 else
1706 return 0;
1707 }
1708
1709
1710 //----- ON_LinearDimension2 ------------------------------------------
ON_LinearDimension2()1711 ON_LinearDimension2::ON_LinearDimension2()
1712 {
1713 //ON_DimensionExtra* pDE = new ON_DimensionExtra;
1714 //if( pDE)
1715 //{
1716 // if( !AttachUserData( pDE))
1717 // delete pDE;
1718 // else
1719 // pDE->SetDefaults();
1720 //}
1721
1722 m_type = ON::dtDimLinear;
1723 m_textdisplaymode = ON::dtAboveLine;
1724 m_plane = ON_xy_plane;
1725 SetTextValue(DefaultText());
1726 SetTextFormula(0);
1727 m_points.Reserve(ON_LinearDimension2::dim_pt_count);
1728 m_points.SetCount(ON_LinearDimension2::dim_pt_count);
1729 m_points.Zero();
1730 }
1731
~ON_LinearDimension2()1732 ON_LinearDimension2::~ON_LinearDimension2()
1733 {
1734 }
1735
IsValid(ON_TextLog * text_log) const1736 ON_BOOL32 ON_LinearDimension2::IsValid( ON_TextLog* text_log ) const
1737 {
1738 if ( m_type != ON::dtDimLinear && m_type != ON::dtDimAligned )
1739 {
1740 if ( text_log )
1741 {
1742 text_log->Print("ON_LinearDimension2 - m_type != ON::dtDimLinear or ON::dtDimAligned.\n");
1743 }
1744 return false;
1745 }
1746
1747 if ( !ON_Annotation2::IsValid( text_log ))
1748 {
1749 if ( text_log )
1750 {
1751 text_log->Print("ON_LinearDimension2 - invalid ON_Annotation2 base class.\n");
1752 }
1753 return false;
1754 }
1755
1756 if ( m_points.Count() != 5 )
1757 {
1758 if ( text_log )
1759 {
1760 text_log->Print("ON_LinearDimension2 - m_points.Count() = %d (should be 5).\n",m_points.Count());
1761 }
1762 return false;
1763 }
1764
1765 if ( m_points[1].x != m_points[0].x )
1766 {
1767 if ( text_log )
1768 {
1769 text_log->Print("ON_LinearDimension2 - m_points[1].x = %g != %g = m_points[0].x (should be equal)\n",
1770 m_points[1].x, m_points[0].x
1771 );
1772 }
1773 return false;
1774 }
1775
1776 if ( m_points[3].x != m_points[2].x )
1777 {
1778 if ( text_log )
1779 {
1780 text_log->Print("ON_LinearDimension2 - m_points[3].x = %g != %g = m_points[2].x\n",
1781 m_points[3].x, m_points[2].x
1782 );
1783 }
1784 return false;
1785 }
1786
1787 if ( m_points[3].y != m_points[1].y )
1788 {
1789 if ( text_log )
1790 {
1791 text_log->Print("ON_LinearDimension2 - m_points[3].y = %g != %g = m_points[1].y\n",
1792 m_points[3].y, m_points[1].y
1793 );
1794 }
1795 return false;
1796 }
1797
1798 return true;
1799 }
1800
Write(ON_BinaryArchive & archive) const1801 ON_BOOL32 ON_LinearDimension2::Write(ON_BinaryArchive& archive) const
1802 {
1803 // 18 October 2007 Dale Lear
1804 // I added the chunk wrapping so V5 and future versions can
1805 // add IO support for information specific to ON_LinearDimension2
1806 // V4 did not have a ON_LinearDimension2::Write and simply called
1807 // ON_Annotation2::Write.
1808 bool rc = false;
1809 bool bInChunk = (archive.Archive3dmVersion() >= 5);
1810 if ( bInChunk )
1811 {
1812 rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0);
1813 if ( !rc )
1814 return false;
1815 }
1816 else
1817 {
1818 rc = true;
1819 }
1820
1821 while(rc)
1822 {
1823 rc = ON_Annotation2::Write(archive)?true:false;
1824 if (!rc) break;
1825 if ( !bInChunk )
1826 break;
1827
1828 // To write new fields, increment minor version number
1829 // and write values here. Ask Dale Lear for help.
1830
1831 break;
1832 }
1833
1834 if ( bInChunk )
1835 {
1836 if (!archive.EndWrite3dmChunk())
1837 rc = false;
1838 }
1839 return rc;
1840 }
1841
Read(ON_BinaryArchive & archive)1842 ON_BOOL32 ON_LinearDimension2::Read(ON_BinaryArchive& archive)
1843 {
1844 // 18 October 2007 Dale Lear
1845 // I added the chunk wrapping so V5 and future versions can
1846 // add IO support for information specific to ON_LinearDimension2
1847 int major_version = 0;
1848 int minor_version = 0;
1849 bool rc = false;
1850 bool bInChunk = (archive.Archive3dmVersion() >= 5 && archive.ArchiveOpenNURBSVersion() >= 200710180);
1851 if ( bInChunk )
1852 {
1853 rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version);
1854 if ( !rc )
1855 return false;
1856 }
1857 else
1858 {
1859 rc = true;
1860 }
1861
1862 while(rc)
1863 {
1864 rc = ON_Annotation2::Read(archive)?true:false;
1865 if (!rc) break;
1866 if ( !bInChunk || minor_version <= 0 )
1867 break;
1868
1869 // read future addition here
1870
1871 break;
1872 }
1873
1874 if ( bInChunk )
1875 {
1876 if ( !archive.EndRead3dmChunk() )
1877 rc = false;
1878 }
1879 return rc;
1880 }
1881
GetBBox(double * boxmax,double * boxmin,ON_BOOL32 bGrowBox) const1882 ON_BOOL32 ON_LinearDimension2::GetBBox(
1883 double* boxmax,
1884 double* boxmin,
1885 ON_BOOL32 bGrowBox
1886 ) const
1887 {
1888 ON_BoundingBox bbox;
1889 if ( bGrowBox )
1890 {
1891 bbox.m_min.x = boxmin[0];
1892 bbox.m_min.y = boxmin[1];
1893 bbox.m_min.z = boxmin[2];
1894 bbox.m_max.x = boxmax[0];
1895 bbox.m_max.y = boxmax[1];
1896 bbox.m_max.z = boxmax[2];
1897 if ( !bbox.IsValid() )
1898 {
1899 bbox.Destroy();
1900 bGrowBox = false;
1901 }
1902 }
1903
1904 if ( 5 == m_points.Count() )
1905 {
1906 ON_3dPointArray P(5);
1907 ON_2dPoint uv;
1908 if ( m_userpositionedtext )
1909 {
1910 uv = m_points[0]; // point someplace in text
1911 P.Append( m_plane.PointAt(uv.x,uv.y) );
1912 }
1913
1914 P.Append( m_plane.origin );
1915
1916 uv.x = 0.0;
1917 uv.y = m_points[1].y;
1918 P.Append( m_plane.PointAt(uv.x,uv.y) );
1919
1920 uv = m_points[2];
1921 P.Append( m_plane.PointAt(uv.x,uv.y) );
1922
1923 uv.y = m_points[1].y;
1924 P.Append( m_plane.PointAt(uv.x,uv.y) );
1925 bGrowBox = P.GetBBox(&bbox.m_min.x, &bbox.m_max.x, bGrowBox);
1926 }
1927
1928 if ( bGrowBox )
1929 {
1930 boxmin[0] = bbox.m_min.x;
1931 boxmin[1] = bbox.m_min.y;
1932 boxmin[2] = bbox.m_min.z;
1933 boxmax[0] = bbox.m_max.x;
1934 boxmax[1] = bbox.m_max.y;
1935 boxmax[2] = bbox.m_max.z;
1936 }
1937
1938 return bGrowBox;
1939 }
1940
1941
1942
1943
GetTightBoundingBox(ON_BoundingBox & tight_bbox,int bGrowBox,const ON_Xform * xform) const1944 bool ON_LinearDimension2::GetTightBoundingBox(
1945 ON_BoundingBox& tight_bbox,
1946 int bGrowBox,
1947 const ON_Xform* xform
1948 ) const
1949 {
1950 if ( 5 == m_points.Count() )
1951 {
1952 ON_3dPointArray P(5);
1953 ON_2dPoint uv;
1954 if ( m_userpositionedtext )
1955 {
1956 uv = m_points[0]; // point someplace in text
1957 P.Append( m_plane.PointAt(uv.x,uv.y) );
1958 }
1959
1960 P.Append( m_plane.origin );
1961
1962 uv.x = 0.0;
1963 uv.y = m_points[1].y;
1964 P.Append( m_plane.PointAt(uv.x,uv.y) );
1965
1966 uv = m_points[2];
1967 P.Append( m_plane.PointAt(uv.x,uv.y) );
1968
1969 uv.y = m_points[1].y;
1970 P.Append( m_plane.PointAt(uv.x,uv.y) );
1971
1972 if ( P.GetTightBoundingBox( tight_bbox, bGrowBox, xform ) )
1973 bGrowBox = true;
1974 }
1975 else if ( bGrowBox && !tight_bbox.IsValid() )
1976 {
1977 tight_bbox.Destroy();
1978 bGrowBox = false;
1979 }
1980
1981 return (0!=bGrowBox);
1982 }
1983
Repair()1984 int ON_LinearDimension2::Repair()
1985 {
1986 // returns 0 = unable to repair
1987 // 1 = in perfect condtion
1988 // 2 == repaired.
1989
1990 const int ext0_pt_index = ON_LinearDimension2::ext0_pt_index;
1991 const int arrow0_pt_index = ON_LinearDimension2::arrow0_pt_index;
1992 const int ext1_pt_index = ON_LinearDimension2::ext1_pt_index;
1993 const int arrow1_pt_index = ON_LinearDimension2::arrow1_pt_index;
1994 const int userpositionedtext_pt_index = ON_LinearDimension2::userpositionedtext_pt_index;
1995 const int dim_pt_count = ON_LinearDimension2::dim_pt_count;
1996
1997 int rc = 0;
1998 if ( m_points.Count() >= dim_pt_count
1999 && m_points[ext0_pt_index].IsValid()
2000 && m_points[ext1_pt_index].IsValid() )
2001 {
2002 rc = 1;
2003 if ( !m_plane.IsValid() )
2004 {
2005 rc = ON_Plane_Repair(m_plane);
2006 }
2007
2008 if ( m_points.Count() > dim_pt_count )
2009 {
2010 rc = 2;
2011 m_points.SetCount(dim_pt_count);
2012 }
2013
2014 // m_points[ext0_pt_index] must be at (0,0)
2015 ON_2dVector v = m_points[ext0_pt_index];
2016 double d;
2017 int i;
2018 if ( !v.IsZero() )
2019 {
2020 rc = 2;
2021 m_plane.origin = m_plane.PointAt(v.x,v.y);
2022 m_plane.UpdateEquation();
2023 v.Reverse();
2024 for ( i = 0; i < dim_pt_count; i++ )
2025 {
2026 m_points[i] += v;
2027 }
2028 m_points[ext0_pt_index].Set(0.0,0.0);
2029 }
2030
2031 if ( ON::dtDimAligned == m_type && (m_points[ext1_pt_index].x < 0.0 || m_points[ext1_pt_index].y != 0.0) )
2032 {
2033 rc = 2;
2034 // Aligned dims must have m_points[ext1_pt_index].x = m_points[ext0_pt_index].x
2035 if ( m_points[ext1_pt_index].x > 100.0*ON_SQRT_EPSILON
2036 && fabs(m_points[ext1_pt_index].y) <= ON_SQRT_EPSILON )
2037 {
2038 m_points[ext1_pt_index].y = 0.0;
2039 }
2040 else
2041 {
2042 // Dimension line parallel to point0 -> point2
2043 // rotate the plane so p2 is on the x axis
2044 v = m_points[ext1_pt_index];
2045 d = v.Length();
2046 v.Unitize();
2047 m_plane.Rotate(v.y,v.x,m_plane.zaxis,m_plane.origin);
2048
2049 // rotate points in opposite direction
2050 v.y = -v.y;
2051 for ( i = 0; i < dim_pt_count; i++ )
2052 {
2053 ON_2dPoint p = m_points[i];
2054 m_points[i].Set( v.x*p.x - v.y*p.y, v.y*p.x + v.x*p.y );
2055 }
2056 m_points[ext0_pt_index].Set(0.0,0.0);
2057 m_points[ext1_pt_index].Set(d,0.0);
2058 }
2059 }
2060 else if ( ON::dtDimLinear != m_type )
2061 {
2062 rc = 2;
2063 m_type = ON::dtDimLinear;
2064 }
2065
2066 if ( m_points[arrow0_pt_index].x != m_points[ext0_pt_index].x )
2067 {
2068 rc = 2;
2069 m_points[arrow0_pt_index].x = m_points[ext0_pt_index].x;
2070 }
2071
2072 if ( m_points[arrow1_pt_index].x != m_points[ext1_pt_index].x )
2073 {
2074 rc = 2;
2075 m_points[arrow1_pt_index].x = m_points[ext1_pt_index].x;
2076 }
2077
2078 if ( !ON_IsValid(m_points[arrow0_pt_index].y) )
2079 {
2080 rc = 2;
2081 if ( !ON_IsValid(m_points[arrow1_pt_index].y) )
2082 m_points[arrow1_pt_index].y = 0.5*(m_points[ext0_pt_index].y + m_points[ext1_pt_index].y);
2083 m_points[arrow0_pt_index].y = m_points[arrow1_pt_index].y;
2084 }
2085 else if ( !ON_IsValid(m_points[arrow1_pt_index].y) )
2086 {
2087 rc = 2;
2088 m_points[arrow1_pt_index].y = m_points[arrow0_pt_index].y;
2089 }
2090 else if ( m_points[arrow0_pt_index].y != m_points[arrow1_pt_index].y )
2091 {
2092 rc = 2;
2093 d = 0.5*(m_points[arrow0_pt_index].y + m_points[arrow1_pt_index].y);
2094 m_points[arrow0_pt_index].y = d;
2095 m_points[arrow1_pt_index].y = d;
2096 }
2097
2098 if ( m_userpositionedtext )
2099 {
2100 if ( !m_points[userpositionedtext_pt_index].IsValid() )
2101 {
2102 rc = 2;
2103 m_userpositionedtext = false;
2104 }
2105 }
2106
2107 if ( !m_userpositionedtext )
2108 {
2109 if ( m_points[userpositionedtext_pt_index].y != m_points[arrow0_pt_index].y
2110 || m_points[userpositionedtext_pt_index].x != 0.5*(m_points[arrow0_pt_index].x + m_points[arrow1_pt_index].x) )
2111 {
2112 rc = 2;
2113 m_points[userpositionedtext_pt_index].y = m_points[arrow0_pt_index].y;
2114 m_points[userpositionedtext_pt_index].x = 0.5*(m_points[arrow0_pt_index].x + m_points[arrow1_pt_index].x);
2115 }
2116 }
2117
2118 if ( !m_plane.IsValid() )
2119 {
2120 rc = 2;
2121 ON_Plane_Repair(m_plane);
2122 }
2123 }
2124 return rc;
2125 }
2126
Transform(const ON_Xform & xform)2127 ON_BOOL32 ON_LinearDimension2::Transform( const ON_Xform& xform )
2128 {
2129 // Dale Lear - this override fixes RR 11114 by correctly
2130 // handling non uniform scaling.
2131 bool rc = xform.IsIdentity();
2132 if ( !rc)
2133 {
2134 ON_Plane plane = m_plane;
2135 if ( dim_pt_count == m_points.Count() && plane.Transform( xform ) )
2136 {
2137 rc = true;
2138 ON_3dPoint P[dim_pt_count], Q[dim_pt_count];
2139 ON_2dVector p2[dim_pt_count], q2[dim_pt_count];
2140 int i;
2141 bool bUpdatePoints = false;
2142 for ( i = 0; i < dim_pt_count && rc; i++ )
2143 {
2144 p2[i] = m_points[i];
2145 P[i] = m_plane.PointAt( p2[i].x, p2[i].y );
2146 Q[i] = xform*P[i];
2147 if( !plane.ClosestPointTo(Q[i],&q2[i].x,&q2[i].y) )
2148 rc = false;
2149 if ( fabs(p2[i].x - q2[i].x) > ON_SQRT_EPSILON
2150 || fabs(p2[i].y - q2[i].y) > ON_SQRT_EPSILON )
2151 {
2152 // transformation is not in SL3
2153 bUpdatePoints = true;
2154 }
2155 }
2156
2157 if (rc)
2158 {
2159 ON_Geometry::Transform(xform);
2160 m_plane = plane;
2161 if ( bUpdatePoints )
2162 {
2163 for ( i = 0; i < dim_pt_count && rc; i++ )
2164 {
2165 m_points[i] = q2[i];
2166 }
2167 // Repair() will properly align the arrow points, etc.
2168 Repair();
2169 }
2170 }
2171 }
2172 }
2173
2174 return rc;
2175 }
2176
NumericValue() const2177 double ON_LinearDimension2::NumericValue() const
2178 {
2179 // Use y coords of ext points instead of 3d distance
2180 // to reduce noise in the answer.
2181 return (m_points.Count() >= dim_pt_count)
2182 ? fabs(m_points[ext0_pt_index].x - m_points[ext1_pt_index].x)
2183 : 0.0;
2184 }
2185
StyleIndex() const2186 int ON_LinearDimension2::StyleIndex() const
2187 {
2188 return ON_Annotation2::Index();
2189 }
2190
SetStyleIndex(int i)2191 void ON_LinearDimension2::SetStyleIndex( int i)
2192 {
2193 ON_Annotation2::SetIndex( i);
2194 }
2195
2196 /*
2197
2198 ext0_pt_index = 0, // end of first extension line
2199 arrow0_pt_index = 1, // arrowhead tip on first extension line
2200 ext1_pt_index = 2, // end of second extension line
2201 arrow1_pt_index = 3, // arrowhead tip on second extension line
2202 dim_pt_count = 5, // number of m_points[] in an angular dim
2203
2204 // Points calculated from values in m_points[]
2205 text_pivot_pt = 10000 // center of dimension text
2206 dim_mid_pt = 10001 // midpoint of dimension line
2207
2208 */
2209
Dim2dPoint(int point_index) const2210 ON_2dPoint ON_LinearDimension2::Dim2dPoint( int point_index ) const
2211 {
2212 ON_2dPoint p2;
2213 if ( m_points.Count() < dim_pt_count )
2214 {
2215 p2.x = p2.y = ON_UNSET_VALUE;
2216 }
2217 else
2218 {
2219 if ( text_pivot_pt == point_index )
2220 {
2221 point_index = m_userpositionedtext ? userpositionedtext_pt_index : dim_mid_pt;
2222 }
2223
2224 const ON_2dPoint* points = m_points.Array();
2225 switch(point_index)
2226 {
2227 case ext0_pt_index:
2228 p2 = points[0];
2229 break;
2230
2231 case arrow0_pt_index:
2232 p2.x = points[0].x;
2233 p2.y = points[1].y;
2234 break;
2235
2236 case ext1_pt_index:
2237 p2 = points[2];
2238 break;
2239
2240 case arrow1_pt_index:
2241 p2.x = points[2].x;
2242 p2.y = points[1].y;
2243 break;
2244
2245 case userpositionedtext_pt_index:
2246 p2.x = points[4].x;
2247 p2.y = points[4].y;
2248 break;
2249
2250 case dim_mid_pt:
2251 p2.x = 0.5*(points[0].x + points[2].x);
2252 p2.y = points[1].y;
2253 break;
2254
2255 default:
2256 p2.x = p2.y = ON_UNSET_VALUE;
2257 break;
2258 }
2259 }
2260 return p2;
2261 }
2262
Dim3dPoint(int point_index) const2263 ON_3dPoint ON_LinearDimension2::Dim3dPoint( int point_index ) const
2264 {
2265 ON_2dPoint p2 = Dim2dPoint(point_index);
2266 return (ON_UNSET_VALUE == p2.x) ? ON_UNSET_POINT : m_plane.PointAt(p2.x,p2.y);
2267 }
2268
2269
2270 // 6-23-03 lw Added v2 file writing of annotation
GetV2Form(ON_LinearDimension & dim)2271 void ON_LinearDimension2::GetV2Form( ON_LinearDimension& dim)
2272 {
2273 ON_Annotation2::ConvertBack( dim);
2274 }
2275
2276
2277
CreateFromV2(const ON_Annotation & v2_ann,const ON_3dmAnnotationSettings & settings,int dimstyle_index)2278 bool ON_LinearDimension2::CreateFromV2(
2279 const ON_Annotation& v2_ann,
2280 const ON_3dmAnnotationSettings& settings,
2281 int dimstyle_index
2282 )
2283 {
2284 bool rc = false;
2285 if ( ON::dtDimLinear == v2_ann.m_type || ON::dtDimAligned == v2_ann.m_type )
2286 {
2287 if ( v2_ann.m_points.Count() >= ON_LinearDimension2::dim_pt_count )
2288 {
2289 m_points.Reserve(ON_LinearDimension2::dim_pt_count);
2290 m_points.SetCount(0);
2291 m_points.Append(ON_LinearDimension2::dim_pt_count,v2_ann.Points().Array());
2292 m_userpositionedtext = v2_ann.UserPositionedText();
2293 m_type = v2_ann.m_type;
2294 SetTextValue(v2_ann.UserText());
2295 SetTextFormula(0);
2296
2297 m_plane = v2_ann.m_plane;
2298 m_plane.UpdateEquation();
2299
2300 switch( settings.m_textalign)
2301 {
2302 case 1:
2303 m_textdisplaymode = ON::dtInLine;
2304 break;
2305 case 2:
2306 m_textdisplaymode = ON::dtHorizontal;
2307 break;
2308 default:
2309 m_textdisplaymode = ON::dtAboveLine;
2310 break;
2311 }
2312
2313 ON_2dVector v = m_points[0];
2314 if ( !v.IsZero() )
2315 {
2316 m_plane.origin = m_plane.PointAt(v.x,v.y);
2317 m_plane.UpdateEquation();
2318 m_points[0].Set(0.0,0.0);
2319 v.Reverse();
2320 int i;
2321 for ( i = 1; i < ON_LinearDimension2::dim_pt_count; i++ )
2322 {
2323 m_points[i] += v;
2324 }
2325 }
2326
2327 m_index = dimstyle_index;
2328 rc = true;
2329 }
2330 }
2331 return rc;
2332 }
2333
GetDimensionLineSegments(ON_RECT gdi_text_rect,int gdi_height_of_I,ON_Xform gdi_to_world,const ON_DimStyle & dimstyle,double dimscale,const ON_Viewport * vp,double x[6],bool & bInside) const2334 int ON_LinearDimension2::GetDimensionLineSegments(
2335 ON_RECT gdi_text_rect,
2336 int gdi_height_of_I,
2337 ON_Xform gdi_to_world,
2338 const ON_DimStyle& dimstyle,
2339 double dimscale,
2340 const ON_Viewport* vp,
2341 double x[6],
2342 bool& bInside
2343 ) const
2344 {
2345 int rc = 0;
2346
2347 x[0] = 0.0;
2348 x[1] = 0.0;
2349 x[2] = 0.0;
2350 x[3] = 0.0;
2351 x[4] = 0.0;
2352 x[5] = 0.0;
2353 bInside = true;
2354
2355 if ( m_points.Count() < 3 )
2356 return 0;
2357
2358 int i = (m_points[ext0_pt_index].x <= m_points[ext1_pt_index].x)
2359 ? ext0_pt_index
2360 : ext1_pt_index;
2361 const double x0 = m_points[i].x;
2362 const double x1 = m_points[(ext0_pt_index==i) ? ext1_pt_index : ext0_pt_index].x;
2363 x[0] = x0; // left end of first dimension line
2364 x[1] = x1; // right end of first dimension line
2365 x[2] = x0; // left end of second dimension line
2366 x[3] = x1; // right end of second dimension line
2367 x[4] = x0; // tip of first arrow
2368 x[5] = x1; // tip of second arrow
2369
2370 if ( 0 == gdi_height_of_I )
2371 {
2372 // Default to height of Ariel 'I'
2373 gdi_height_of_I = (165*ON_Font::normal_font_height)/256;
2374 }
2375
2376 if ( 0.0 == dimscale )
2377 {
2378 dimscale = 1.0;
2379 }
2380
2381 double t;
2382
2383 ON::eTextDisplayMode textdisplay = ON::TextDisplayMode(dimstyle.TextAlignment());
2384 if ( ON::dtHorizontal == textdisplay && !vp )
2385 textdisplay = ON::dtInLine;
2386
2387 const double text_height_of_I = dimscale*dimstyle.TextHeight();
2388 const double textgap = fabs(dimscale*dimstyle.TextGap());
2389 const double gdi_to_plane_scale = text_height_of_I/gdi_height_of_I;
2390 const double textwidth = fabs(gdi_to_plane_scale*(gdi_text_rect.right - gdi_text_rect.left));
2391 const double arrowwidth = dimscale*dimstyle.ArrowSize();
2392 const double tailwidth = 0.5*arrowwidth;
2393 const double dimwidth = x1 - x0;
2394 const double mindimwidth = (ON::dtInLine == textdisplay)
2395 ? (2.0*(arrowwidth + tailwidth + textgap) + textwidth)
2396 : (2.0*arrowwidth + tailwidth);
2397 const double dimextension = dimscale*dimstyle.DimExtension();
2398
2399 int ForceArrows = 0;
2400 const ON_DimensionExtra* pDE = ON_DimensionExtra::DimensionExtension(this,false);
2401 if( pDE)
2402 ForceArrows = pDE->ArrowPosition();
2403
2404 // 19 Apr 2012 - Lowell - Fixed so forcing arrows inside won't cause the dim line to
2405 // draw through InLine text rr103322
2406 if(ForceArrows == -1 || // force outside
2407 (dimwidth < mindimwidth && ForceArrows != 1)) // arrowheads have to be "outside" - they won't fit inside even without text
2408 {
2409 t = arrowwidth + tailwidth;
2410 x[0] = x0;
2411 x[1] = x0-t;
2412 x[2] = x1+t;
2413 x[3] = x1;
2414 x[4] = x0; // arrow tips
2415 x[5] = x1;
2416 if( dimextension != 0.0)
2417 {
2418 x[0] += dimextension;
2419 x[3] -= dimextension;
2420 }
2421 bInside = false;
2422 rc = 2;
2423 }
2424 // Horizontal text or Userpositioned text
2425 else if ( (ON::dtHorizontal == textdisplay && vp) || m_userpositionedtext )
2426 {
2427 // use projected rectangle to clip dimension line
2428 double xx0, xx1, xx, y0, y1, t;
2429 ON_3dPoint P, R;
2430 ON_2dPoint corners[4]; // corners of text rect in plane coords
2431 ON_Line ray;
2432
2433 ON_3dVector vp_zaxis = (ON::dtHorizontal == textdisplay && vp)
2434 ? vp->CameraZ()
2435 : m_plane.zaxis;
2436
2437 // 30 July 2012 - Lowell - Slightly shrink the text gap value
2438 // so that text + gap won't intersect the dim line if when text
2439 // is moved along the dim line. rr110504
2440 double gdi_gap = fabs(textgap/gdi_to_plane_scale)-12;
2441 if(gdi_gap < 0.0) gdi_gap = 0.0;
2442
2443 R.Set(gdi_text_rect.left-gdi_gap,gdi_text_rect.bottom+gdi_gap,0.0);
2444 ray.from = gdi_to_world*R; ray.to = ray.from + vp_zaxis;
2445 P = ( ON_Intersect(ray,m_plane,&t) ) ? ray.PointAt(t) : ray.from;
2446 m_plane.ClosestPointTo(P,&corners[0].x,&corners[0].y);
2447
2448 R.Set(gdi_text_rect.right+gdi_gap,gdi_text_rect.bottom+gdi_gap,0.0);
2449 ray.from = gdi_to_world*R; ray.to = ray.from + vp_zaxis;
2450 P = ( ON_Intersect(ray,m_plane,&t) ) ? ray.PointAt(t) : ray.from;
2451 m_plane.ClosestPointTo(P,&corners[1].x,&corners[1].y);
2452
2453 R.Set(gdi_text_rect.right+gdi_gap,gdi_text_rect.top-gdi_gap,0.0);
2454 ray.from = gdi_to_world*R; ray.to = ray.from + vp_zaxis;
2455 P = ( ON_Intersect(ray,m_plane,&t) ) ? ray.PointAt(t) : ray.from;
2456 m_plane.ClosestPointTo(P,&corners[2].x,&corners[2].y);
2457
2458 R.Set(gdi_text_rect.left-gdi_gap,gdi_text_rect.top-gdi_gap,0.0);
2459 ray.from = gdi_to_world*R; ray.to = ray.from + vp_zaxis;
2460 P = ( ON_Intersect(ray,m_plane,&t) ) ? ray.PointAt(t) : ray.from;
2461 m_plane.ClosestPointTo(P,&corners[3].x,&corners[3].y);
2462
2463 // Test if text rect intersects dimension line
2464 xx0 = xx1 = ON_UNSET_VALUE;
2465 for ( i = 0; i < 4; i++ )
2466 {
2467 y0 = corners[i].y - m_points[1].y; // vertical dist from corner to dimension line
2468 y1 = corners[(i+1)%4].y - m_points[1].y; // vertical dist from next corner to dimension line
2469 // if they're both above or both below, no intersection of this segment
2470 if ( (y0 > 0.0 && y1 > 0.0) || (y0 < 0.0 && y1 < 0.0) || y0 == y1 )
2471 continue;
2472
2473 // segment intersects dimension line.
2474 // find x-coord of intersection
2475 t = y0/(y0-y1);
2476 xx = (1.0-t)*corners[i].x + t*corners[(i+1)%4].x;
2477 if ( ON_UNSET_VALUE == xx0 )
2478 {
2479 xx0 = xx1 = xx;
2480 }
2481 else if ( xx < xx0 )
2482 {
2483 xx0 = xx;
2484 }
2485 else if ( xx > xx1 )
2486 {
2487 xx1 = xx;
2488 }
2489 }
2490
2491 // Nov 4 2009 - Lowell - Added test for no intersection of text with dimension line rr33003
2492 // Important for user positioned text that's moved out of the way of the dimension line
2493 if(xx0 != ON_UNSET_VALUE && xx1 != ON_UNSET_VALUE)
2494 {
2495 // xx0 is left edge of text rect
2496 // xx1 is right edge of text rect
2497 t = arrowwidth + tailwidth;
2498 if ( x0 + t <= xx0 && xx0 < xx1 && xx1 <= x1 - t )
2499 {
2500 // clip line, 2 segments arrows inside
2501 x[0] = x0;
2502 x[1] = xx0;
2503 x[2] = xx1;
2504 x[3] = x1;
2505 x[4] = x0;
2506 x[5] = x1;
2507 if( dimextension != 0.0)
2508 {
2509 x[0] -= dimextension;
2510 x[3] += dimextension;
2511 }
2512 rc = 2;
2513 }
2514 else // 2 segments, put the arrows outside the extension lines
2515 {
2516 x[0] = x0;
2517 x[1] = x0 - t;
2518 x[2] = x1 + t;
2519 x[3] = x1;
2520 x[4] = x0;
2521 x[5] = x1;
2522 if( dimextension != 0.0)
2523 {
2524 x[0] += dimextension;
2525 x[3] -= dimextension;
2526 }
2527 bInside = false;
2528 rc = 2;
2529 }
2530 }
2531 else
2532 {
2533 // 1 segment, arrows inside
2534 x[0] = x0;
2535 x[1] = x1;
2536 x[2] = x0;
2537 x[3] = x1;
2538 x[4] = x0;
2539 x[5] = x1;
2540 if( dimextension != 0.0)
2541 {
2542 x[0] -= dimextension;
2543 x[1] += dimextension;
2544 }
2545 rc = 1;
2546 }
2547 }
2548 // Above line text
2549 else if ( ON::dtAboveLine == textdisplay || m_userpositionedtext )
2550 {
2551 // 1 segment, arrows inside
2552 x[0] = x0;
2553 x[1] = x1;
2554 x[2] = x0;
2555 x[3] = x1;
2556 x[4] = x0;
2557 x[5] = x1;
2558 if( dimextension != 0.0)
2559 {
2560 x[0] -= dimextension;
2561 x[1] += dimextension;
2562 }
2563 rc = 1;
2564 }
2565 // In line text
2566 else if ( ON::dtInLine == textdisplay )
2567 {
2568 // 2 segments, arrows inside
2569 t = 0.5*(dimwidth - textwidth - 2.0*textgap);
2570 x[0] = x0;
2571 x[1] = x0+t;
2572 x[2] = x1-t;
2573 x[3] = x1;
2574 x[4] = x0;
2575 x[5] = x1;
2576 if( dimextension != 0.0)
2577 {
2578 x[0] -= dimextension;
2579 x[3] += dimextension;
2580 }
2581
2582 rc = 2;
2583 }
2584
2585 return rc;
2586 }
2587
2588
DefaultText()2589 const wchar_t* ON_LinearDimension2::DefaultText() { return L"<>"; }
2590
2591
2592
2593
2594 //----- ON_RadialDimension2 ------------------------------------------
ON_RadialDimension2()2595 ON_RadialDimension2::ON_RadialDimension2()
2596 {
2597 m_type = ON::dtDimDiameter;
2598 m_textdisplaymode = ON::dtInLine;
2599 SetTextValue(DefaultDiameterText());
2600 SetTextFormula(0);
2601 m_points.Reserve(ON_RadialDimension2::dim_pt_count);
2602 m_points.SetCount(ON_RadialDimension2::dim_pt_count);
2603 m_points.Zero();
2604 }
2605
~ON_RadialDimension2()2606 ON_RadialDimension2::~ON_RadialDimension2()
2607 {
2608 }
2609
IsValid(ON_TextLog * text_log) const2610 ON_BOOL32 ON_RadialDimension2::IsValid( ON_TextLog* text_log ) const
2611 {
2612 if ( m_type != ON::dtDimRadius && m_type != ON::dtDimDiameter )
2613 {
2614 if ( text_log )
2615 {
2616 text_log->Print("ON_RadialDimension2 - m_type != ON::dtDimRadius or ON::dtDimDiameter\n");
2617 }
2618 return false;
2619 }
2620
2621 if ( !ON_Annotation2::IsValid( text_log ))
2622 {
2623 if ( text_log )
2624 {
2625 text_log->Print("ON_RadialDimension2 - invalid ON_Annotation2 base class.\n");
2626 }
2627 return false;
2628 }
2629
2630 if ( 4 != m_points.Count() )
2631 {
2632 if ( text_log )
2633 {
2634 text_log->Print("ON_RadialDimension2 - m_points.Count() = %d (should be 4 or 5)\n", m_points.Count() );
2635 }
2636 return false;
2637 }
2638
2639 return true;
2640 }
2641
2642
Write(ON_BinaryArchive & archive) const2643 ON_BOOL32 ON_RadialDimension2::Write(ON_BinaryArchive& archive) const
2644 {
2645 // 18 October 2007 Dale Lear
2646 // I added the chunk wrapping so V5 and future versions can
2647 // add IO support for information specific to ON_RadialDimension2
2648 // V4 did not have a ON_RadialDimension2::Write and simply called
2649 // ON_Annotation2::Write.
2650 bool rc = false;
2651 bool bInChunk = (archive.Archive3dmVersion() >= 5);
2652 if ( bInChunk )
2653 {
2654 rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0);
2655 if ( !rc )
2656 return false;
2657 }
2658 else
2659 {
2660 rc = true;
2661 }
2662
2663 while(rc)
2664 {
2665 rc = ON_Annotation2::Write(archive)?true:false;
2666 if (!rc) break;
2667 if ( !bInChunk )
2668 break;
2669
2670 // To write new fields, increment minor version number
2671 // and write values here. Ask Dale Lear for help.
2672
2673 break;
2674 }
2675
2676 if ( bInChunk )
2677 {
2678 if (!archive.EndWrite3dmChunk())
2679 rc = false;
2680 }
2681 return rc;
2682 }
2683
Read(ON_BinaryArchive & archive)2684 ON_BOOL32 ON_RadialDimension2::Read(ON_BinaryArchive& archive)
2685 {
2686 // 18 October 2007 Dale Lear
2687 // I added the chunk wrapping so V5 and future versions can
2688 // add IO support for information specific to ON_RadialDimension2
2689 int major_version = 0;
2690 int minor_version = 0;
2691 bool rc = false;
2692 bool bInChunk = (archive.Archive3dmVersion() >= 5 && archive.ArchiveOpenNURBSVersion() >= 200710180);
2693 if ( bInChunk )
2694 {
2695 rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version);
2696 if ( !rc )
2697 return false;
2698 }
2699 else
2700 {
2701 rc = true;
2702 }
2703
2704 while(rc)
2705 {
2706 rc = ON_Annotation2::Read(archive)?true:false;
2707 if (!rc) break;
2708 if ( !bInChunk || minor_version <= 0 )
2709 break;
2710
2711 // read future addition here
2712
2713 break;
2714 }
2715
2716 if ( bInChunk )
2717 {
2718 if ( !archive.EndRead3dmChunk() )
2719 rc = false;
2720 }
2721 return rc;
2722 }
2723
2724
GetBBox(double * boxmax,double * boxmin,ON_BOOL32 bGrowBox) const2725 ON_BOOL32 ON_RadialDimension2::GetBBox(
2726 double* boxmax,
2727 double* boxmin,
2728 ON_BOOL32 bGrowBox
2729 ) const
2730 {
2731 ON_BoundingBox bbox;
2732 if ( bGrowBox )
2733 {
2734 bbox.m_min.x = boxmin[0];
2735 bbox.m_min.y = boxmin[1];
2736 bbox.m_min.z = boxmin[2];
2737 bbox.m_max.x = boxmax[0];
2738 bbox.m_max.y = boxmax[1];
2739 bbox.m_max.z = boxmax[2];
2740 if ( !bbox.IsValid() )
2741 {
2742 bbox.Destroy();
2743 bGrowBox = false;
2744 }
2745 }
2746
2747 if ( 4 == m_points.Count() )
2748 {
2749 ON_3dPointArray P(4);
2750 ON_2dPoint uv;
2751 if ( m_userpositionedtext )
2752 {
2753 uv = m_points[0]; // point someplace in text
2754 P.Append( m_plane.PointAt(uv.x,uv.y) );
2755 }
2756
2757 P.Append( m_plane.origin ); // + sign at center of dimension
2758
2759 uv = m_points[1];
2760 P.Append( m_plane.PointAt(uv.x,uv.y) );
2761
2762 uv = m_points[2];
2763 P.Append( m_plane.PointAt(uv.x,uv.y) );
2764
2765 uv = m_points[3];
2766 P.Append( m_plane.PointAt(uv.x,uv.y) );
2767 bGrowBox = P.GetBBox(&bbox.m_min.x, &bbox.m_max.x, bGrowBox);
2768 }
2769
2770 if ( bGrowBox )
2771 {
2772 boxmin[0] = bbox.m_min.x;
2773 boxmin[1] = bbox.m_min.y;
2774 boxmin[2] = bbox.m_min.z;
2775 boxmax[0] = bbox.m_max.x;
2776 boxmax[1] = bbox.m_max.y;
2777 boxmax[2] = bbox.m_max.z;
2778 }
2779
2780 return bGrowBox;
2781 }
2782
2783
2784
2785
2786
GetTightBoundingBox(ON_BoundingBox & tight_bbox,int bGrowBox,const ON_Xform * xform) const2787 bool ON_RadialDimension2::GetTightBoundingBox(
2788 ON_BoundingBox& tight_bbox,
2789 int bGrowBox,
2790 const ON_Xform* xform
2791 ) const
2792 {
2793 if ( 4 == m_points.Count() )
2794 {
2795 ON_3dPointArray P(4);
2796 ON_2dPoint uv;
2797
2798 uv = m_points[0]; // + sign at center of dimension (usually at (0,0)
2799 P.Append( m_plane.PointAt(uv.x,uv.y) );
2800
2801 uv = m_points[1];
2802 P.Append( m_plane.PointAt(uv.x,uv.y) );
2803
2804 uv = m_points[2];
2805 P.Append( m_plane.PointAt(uv.x,uv.y) );
2806
2807 uv = m_points[3];
2808 P.Append( m_plane.PointAt(uv.x,uv.y) );
2809
2810 if ( P.GetTightBoundingBox( tight_bbox, bGrowBox, xform ) )
2811 bGrowBox = true;
2812 }
2813 else if ( bGrowBox && !tight_bbox.IsValid() )
2814 {
2815 tight_bbox.Destroy();
2816 bGrowBox = false;
2817 }
2818
2819 return (0!=bGrowBox);
2820 }
2821
Dim2dPoint(int point_index) const2822 ON_2dPoint ON_RadialDimension2::Dim2dPoint(
2823 int point_index
2824 ) const
2825 {
2826 ON_2dPoint p2;
2827 if ( m_points.Count() < dim_pt_count || point_index < 0 )
2828 {
2829 p2.x = p2.y = ON_UNSET_VALUE;
2830 }
2831 else
2832 {
2833 if ( text_pivot_pt == point_index )
2834 {
2835 point_index = tail_pt_index;
2836 }
2837 if ( point_index < dim_pt_count )
2838 {
2839 p2 = m_points[point_index];
2840 }
2841 else
2842 {
2843 p2.x = p2.y = ON_UNSET_VALUE;
2844 }
2845 }
2846 return p2;
2847 }
2848
Dim3dPoint(int point_index) const2849 ON_3dPoint ON_RadialDimension2::Dim3dPoint(
2850 int point_index
2851 ) const
2852 {
2853 ON_2dPoint p2 = Dim2dPoint(point_index);
2854 return (ON_UNSET_VALUE == p2.x) ? ON_UNSET_POINT : m_plane.PointAt(p2.x,p2.y);
2855 }
2856
2857 // set the plane, center, and point on curve.
2858 // the rest will be set by the Rhino dimension
CreateFromPoints(ON_3dPoint center,ON_3dPoint arrowtip,ON_3dVector xaxis,ON_3dVector normal,double offset_distance)2859 bool ON_RadialDimension2::CreateFromPoints(
2860 ON_3dPoint center,
2861 ON_3dPoint arrowtip,
2862 ON_3dVector xaxis,
2863 ON_3dVector normal,
2864 double offset_distance)
2865 {
2866 if ( m_type != ON::dtDimDiameter )
2867 m_type = ON::dtDimRadius;
2868 bool rc = false;
2869 if ( center.IsValid() && arrowtip.IsValid() && normal.IsValid() && !normal.IsZero() && xaxis.IsValid() && !xaxis.IsZero() )
2870 {
2871 ON_Plane plane( center, normal);
2872 double c = xaxis*plane.xaxis;
2873 double s = xaxis*plane.yaxis;
2874 if ( c != 0.0 || s != 0.0 )
2875 {
2876 if ( c <= 0.0 || s != 0.0 )
2877 {
2878 plane.Rotate( s, c, plane.zaxis );
2879 }
2880 m_plane = plane;
2881 ON_2dVector tip;
2882 if ( m_plane.ClosestPointTo(arrowtip,&tip.x,&tip.y) )
2883 {
2884 //double r = tip.Length();
2885 m_points.SetCapacity(dim_pt_count);
2886 m_points.SetCount(dim_pt_count);
2887
2888 m_points[center_pt_index].Set(0.0,0.0);
2889 m_points[arrow_pt_index] = tip;
2890 tip.Unitize();
2891
2892 m_points[knee_pt_index] = m_points[arrow_pt_index] + offset_distance*tip;
2893 m_points[tail_pt_index] = m_points[knee_pt_index];
2894 if ( m_points[arrow_pt_index].x < 0.0 )
2895 m_points[tail_pt_index].x -= offset_distance;
2896 else
2897 m_points[tail_pt_index].x += offset_distance;
2898 m_plane = plane;
2899 m_userpositionedtext = false;
2900
2901 rc = true;
2902 }
2903 }
2904 }
2905 return rc;
2906 }
2907
2908
NumericValue() const2909 double ON_RadialDimension2::NumericValue() const
2910 {
2911 double d = 0.0;
2912 if ( m_points.Count() >= dim_pt_count )
2913 {
2914 d = (m_points[center_pt_index] - m_points[arrow_pt_index]).Length();
2915 if( ON::dtDimDiameter == m_type )
2916 d *= 2.0;
2917 }
2918 return d;
2919 }
2920
StyleIndex() const2921 int ON_RadialDimension2::StyleIndex() const
2922 {
2923 return ON_Annotation2::Index();
2924 }
2925
SetStyleIndex(int i)2926 void ON_RadialDimension2::SetStyleIndex( int i)
2927 {
2928 ON_Annotation2::SetIndex( i);
2929 }
2930
2931
DefaultRadiusText()2932 const wchar_t* ON_RadialDimension2::DefaultRadiusText()
2933 {
2934 static wchar_t defstr[4] = { radiussym,L'<',L'>',0 };
2935 return defstr;
2936 }
2937
DefaultDiameterText()2938 const wchar_t* ON_RadialDimension2::DefaultDiameterText()
2939 {
2940 static wchar_t defstr[4] = { diametersym,L'<',L'>',0 };
2941 return defstr;
2942 }
2943
2944 // 6-23-03 lw Added v2 file writing of annotation
GetV2Form(ON_RadialDimension & dim)2945 void ON_RadialDimension2::GetV2Form( ON_RadialDimension& dim)
2946 {
2947 ON_Annotation2::ConvertBack( dim);
2948 }
2949
2950
CreateFromV2(const ON_Annotation & v2_ann,const ON_3dmAnnotationSettings & settings,int dimstyle_index)2951 bool ON_RadialDimension2::CreateFromV2(
2952 const ON_Annotation& v2_ann,
2953 const ON_3dmAnnotationSettings& settings,
2954 int dimstyle_index
2955 )
2956 {
2957 bool rc = false;
2958 if( ON::dtDimRadius == v2_ann.m_type || ON::dtDimDiameter == v2_ann.m_type )
2959 {
2960 const ON_SimpleArray<ON_2dPoint>& points = v2_ann.Points();
2961 if ( points.Count() >= 4 )
2962 {
2963 m_points.Reserve(4);
2964 m_points.SetCount(0);
2965 m_points.Append(4,points.Array());
2966 m_plane = v2_ann.m_plane;
2967 m_plane.UpdateEquation();
2968 SetTextValue(v2_ann.UserText());
2969 SetTextFormula(0);
2970 m_userpositionedtext = false;
2971 m_type = v2_ann.Type();
2972 m_textdisplaymode = ( 2 == settings.m_textalign )
2973 ? ON::dtHorizontal
2974 : ON::dtInLine;
2975 m_index = dimstyle_index;
2976 ON_2dVector v = m_points[0];
2977 if ( !v.IsZero() )
2978 {
2979 m_plane.origin = m_plane.PointAt(v.x,v.y);
2980 m_plane.UpdateEquation();
2981 v.Reverse();
2982 m_points[0].Set(0.0,0.0);
2983 m_points[1] += v;
2984 m_points[2] += v;
2985 m_points[3] += v;
2986 }
2987
2988 rc = true;
2989 }
2990 }
2991 return rc;
2992 }
2993
2994
2995 //----- ON_AngularDimension2Extra -----------------------------------------
2996 // Additions to ON_AngularDimension2 class
2997
2998 class ON_AngularDimension2Extra : public ON_UserData
2999 {
3000 ON_OBJECT_DECLARE(ON_AngularDimension2Extra);
3001 public:
3002 static ON_AngularDimension2Extra* AngularDimensionExtra(ON_AngularDimension2* pDim/*, bool bCreate*/);
3003 static const ON_AngularDimension2Extra* AngularDimensionExtra(const ON_AngularDimension2* pDim/*, bool bCreate*/);
3004
3005 ON_AngularDimension2Extra();
3006 ~ON_AngularDimension2Extra();
3007
3008 // override virtual ON_Object::Dump function
3009 void Dump( ON_TextLog& text_log ) const;
3010
3011 // override virtual ON_Object::SizeOf function
3012 unsigned int SizeOf() const;
3013
3014 // override virtual ON_Object::Write function
3015 ON_BOOL32 Write(ON_BinaryArchive& binary_archive) const;
3016
3017 // override virtual ON_Object::Read function
3018 ON_BOOL32 Read(ON_BinaryArchive& binary_archive);
3019
3020 // override virtual ON_UserData::GetDescription function
3021 ON_BOOL32 GetDescription( ON_wString& description );
3022
3023 // override virtual ON_UserData::Archive function
3024 ON_BOOL32 Archive() const;
3025
3026 // Scale all of the length values
3027 void Scale( double scale);
3028
3029 //
3030 double DimpointOffset(int index) const;
3031 void SetDimpointOffset(int index, double offset);
3032
3033 // offsets from apex of dimension to point from which extension lines start
3034 // if these are < 0.0, they are ignored
3035 // Extension lines are drawn from theses points to the Arrow tip points
3036 // subject to dimexe & dimexo & dimse1 & dimse2
3037 double m_dimpoint_offset[2];
3038 };
3039
3040 ON_OBJECT_IMPLEMENT(ON_AngularDimension2Extra,ON_UserData,"A68B151F-C778-4a6e-BCB4-23DDD1835677");
3041
AngularDimensionExtra(ON_AngularDimension2 * pDim)3042 ON_AngularDimension2Extra* ON_AngularDimension2Extra::AngularDimensionExtra(ON_AngularDimension2* pDim)
3043 {
3044 ON_AngularDimension2Extra* pExtra = 0;
3045 if(pDim)
3046 {
3047 pExtra = ON_AngularDimension2Extra::Cast(pDim->GetUserData(ON_AngularDimension2Extra::m_ON_AngularDimension2Extra_class_id.Uuid()));
3048 if(pExtra == 0)
3049 {
3050 pExtra = new ON_AngularDimension2Extra;
3051 if( pExtra)
3052 {
3053 if(!pDim->AttachUserData(pExtra))
3054 {
3055 delete pExtra;
3056 pExtra = 0;
3057 }
3058 }
3059 }
3060 }
3061 return pExtra;
3062 }
3063
AngularDimensionExtra(const ON_AngularDimension2 * pDim)3064 const ON_AngularDimension2Extra* ON_AngularDimension2Extra::AngularDimensionExtra(const ON_AngularDimension2* pDim)
3065 {
3066 return AngularDimensionExtra((ON_AngularDimension2*)pDim);
3067 }
3068
ON_AngularDimension2Extra()3069 ON_AngularDimension2Extra::ON_AngularDimension2Extra()
3070 {
3071 m_userdata_uuid = ON_AngularDimension2Extra::m_ON_AngularDimension2Extra_class_id.Uuid();
3072 m_application_uuid = ON_opennurbs5_id; // opennurbs.dll reads/writes this userdata
3073 // The id must be the version 5 id because
3074 // V6 SaveAs V5 needs to work, but SaveAs
3075 // V4 should not write this userdata.
3076 m_userdata_copycount = 1;
3077
3078 m_dimpoint_offset[0] = 0;
3079 m_dimpoint_offset[1] = 0;
3080 }
3081
~ON_AngularDimension2Extra()3082 ON_AngularDimension2Extra::~ON_AngularDimension2Extra()
3083 {
3084 }
3085
Dump(ON_TextLog &) const3086 void ON_AngularDimension2Extra::Dump( ON_TextLog& ) const
3087 {
3088 // do nothing
3089 }
3090
SizeOf() const3091 unsigned int ON_AngularDimension2Extra::SizeOf() const
3092 {
3093 unsigned int sz = ON_UserData::SizeOf();
3094 sz += sizeof(*this) - sizeof(ON_UserData);
3095 return sz;
3096 }
3097
Write(ON_BinaryArchive & archive) const3098 ON_BOOL32 ON_AngularDimension2Extra::Write(ON_BinaryArchive& archive) const
3099 {
3100 int major_version = 1;
3101 int minor_version = 0;
3102 bool rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,major_version,minor_version);
3103
3104 if(rc) rc = archive.WriteDouble(m_dimpoint_offset[0]);
3105 if(rc) rc = archive.WriteDouble(m_dimpoint_offset[1]);
3106
3107 if(!archive.EndWrite3dmChunk())
3108 rc = false;
3109
3110 return rc;
3111 }
3112
Read(ON_BinaryArchive & archive)3113 ON_BOOL32 ON_AngularDimension2Extra::Read(ON_BinaryArchive& archive)
3114 {
3115 int major_version = 1;
3116 int minor_version = 0;
3117 bool rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version);
3118 if(major_version != 1)
3119 rc = false;
3120
3121 if(rc) rc = archive.ReadDouble(&m_dimpoint_offset[0]);
3122 if(rc) rc = archive.ReadDouble(&m_dimpoint_offset[1]);
3123
3124 if ( !archive.EndRead3dmChunk() )
3125 rc = false;
3126
3127 return rc;
3128 }
3129
GetDescription(ON_wString & description)3130 ON_BOOL32 ON_AngularDimension2Extra::GetDescription( ON_wString& description)
3131 {
3132 description.Format( "Userdata extension of ON_AngularDimension2");
3133 return true;
3134 }
3135
Archive() const3136 ON_BOOL32 ON_AngularDimension2Extra::Archive() const
3137 {
3138 // true to write to file
3139 return true;
3140 }
3141
Scale(double scale)3142 void ON_AngularDimension2Extra::Scale(double scale)
3143 {
3144 if( ON_IsValid(scale) && scale > ON_SQRT_EPSILON)
3145 {
3146 m_dimpoint_offset[0] *= scale;
3147 m_dimpoint_offset[1] *= scale;
3148 }
3149 }
3150
DimpointOffset(int index) const3151 double ON_AngularDimension2Extra::DimpointOffset(int index) const
3152 {
3153 if(index == 0)
3154 return m_dimpoint_offset[0];
3155 if(index == 1)
3156 return m_dimpoint_offset[1];
3157 return -1;
3158 }
SetDimpointOffset(int index,double offset)3159 void ON_AngularDimension2Extra::SetDimpointOffset(int index, double offset)
3160 {
3161 if(index >= 0 && index <= 1)
3162 m_dimpoint_offset[index] = offset;
3163 }
3164
3165 //----- ON_AngularDimension2 -----------------------------------------
ON_AngularDimension2()3166 ON_AngularDimension2::ON_AngularDimension2() : m_angle(0.0), m_radius(1.0)
3167 {
3168 m_type = ON::dtDimAngular;
3169 m_textdisplaymode = ON::dtAboveLine;
3170 SetTextValue(DefaultText());
3171 SetTextFormula(0);
3172 m_points.Reserve(ON_AngularDimension2::dim_pt_count);
3173 m_points.SetCount(ON_AngularDimension2::dim_pt_count);
3174 m_points.Zero();
3175
3176 // Add this userdata to every angular dimension
3177 // ON_AngularDimension2Extra* pDE = ON_AngularDimension2Extra::AngularDimensionExtra(this, true);
3178 // if(pDE)
3179 // {
3180 // pDE->SetDimpointOffset(0, -1);
3181 // pDE->SetDimpointOffset(1, -1);
3182 // }
3183 }
3184
~ON_AngularDimension2()3185 ON_AngularDimension2::~ON_AngularDimension2()
3186 {
3187 }
3188
3189
IsValid(ON_TextLog * text_log) const3190 ON_BOOL32 ON_AngularDimension2::IsValid( ON_TextLog* text_log ) const
3191 {
3192 if ( m_type != ON::dtDimAngular )
3193 {
3194 if ( text_log )
3195 {
3196 text_log->Print("ON_AngularDimension2 - m_type != ON::dtDimAngular\n");
3197 }
3198 return false;
3199 }
3200
3201 if ( !ON_Annotation2::IsValid( text_log ))
3202 {
3203 if ( text_log )
3204 {
3205 text_log->Print("ON_AngularDimension2 - invalid ON_Annotation2 base class.\n");
3206 }
3207 return false;
3208 }
3209
3210 if ( 4 != m_points.Count() )
3211 {
3212 if ( text_log )
3213 {
3214 text_log->Print("ON_AngularDimension2 - m_points.Count() = %d (should be 4)\n", m_points.Count() );
3215 }
3216 return false;
3217 }
3218
3219 if ( !ON_IsValid(m_angle) || m_angle <= 0.0 || m_angle > 2.0*ON_PI )
3220 {
3221 if ( text_log )
3222 {
3223 text_log->Print("ON_AngularDimension2 - bogus m_angle = %g\n",m_angle);
3224 }
3225 return false;
3226 }
3227
3228 if ( !ON_IsValid(m_radius) || m_radius <= 0.0 )
3229 {
3230 if ( text_log )
3231 {
3232 text_log->Print("ON_AngularDimension2 - bogus m_radius = %g\n",m_radius);
3233 }
3234 return false;
3235 }
3236
3237 if ( 0.0 == m_points[1].x && 0.0 == m_points[1].y )
3238 {
3239 if ( text_log )
3240 {
3241 text_log->Print("ON_AngularDimension2 - angle dim m_points[1] = center (should be on start ray).\n");
3242 }
3243 return false;
3244 }
3245
3246 if ( 0.0 == m_points[2].x && 0.0 == m_points[2].y )
3247 {
3248 if ( text_log )
3249 {
3250 text_log->Print("ON_AngularDimension2 - angle dim m_points[2] = center (should be on end ray).\n");
3251 }
3252 return false;
3253 }
3254
3255 if ( 0.0 == m_points[3].x && 0.0 == m_points[3].y )
3256 {
3257 if ( text_log )
3258 {
3259 text_log->Print("ON_AngularDimension2 - angle dim m_points[3] = center (should be on interior of arc).\n");
3260 }
3261 return false;
3262 }
3263
3264 double a1 = atan2(m_points[1].y, m_points[1].x);
3265 double a2 = atan2(m_points[2].y, m_points[2].x);
3266 double a3 = atan2(m_points[3].y, m_points[3].x);
3267 if ( a1 < 0.0 )
3268 a1 += 2.0*ON_PI;
3269 while ( a2 <= a1 )
3270 a2 += 2.0*ON_PI;
3271 while ( a3 < a1 ) // Oct 23 2009 LW changed from a3 <= a1 to allow point at end of arc rr53634
3272 a3 += 2.0*ON_PI;
3273
3274 if ( fabs(m_angle - (a2-a1)) > ON_ZERO_TOLERANCE + m_angle*ON_SQRT_EPSILON )
3275 {
3276 if ( text_log )
3277 {
3278 text_log->Print("ON_AngularDimension2 - m_angle = %g != %g = (end angle - start angle)\n",m_angle,a2-a1);
3279 }
3280 return false;
3281 }
3282
3283 double r = ON_2dVector(m_points[3]).Length();
3284 if ( fabs(r - m_radius) > ON_ZERO_TOLERANCE + m_radius*ON_SQRT_EPSILON )
3285 {
3286 if ( text_log )
3287 {
3288 text_log->Print("ON_AngularDimension2 - m_radius = %g != %g = |m_point[3])|\n",m_radius,r);
3289 }
3290 return false;
3291 }
3292
3293
3294 if ( a3 > a2 ) // Oct 23 2009 LW changed from a3 >= a2 to allow point at end of arc rr53634
3295 {
3296 if ( text_log )
3297 {
3298 text_log->Print("ON_AngularDimension2 - angle dim m_points[3] = not on arc interior.\n");
3299 }
3300 return false;
3301 }
3302
3303 return true;
3304 }
3305
3306
3307
GetBBox(double * boxmax,double * boxmin,ON_BOOL32 bGrowBox) const3308 ON_BOOL32 ON_AngularDimension2::GetBBox(
3309 double* boxmax,
3310 double* boxmin,
3311 ON_BOOL32 bGrowBox
3312 ) const
3313 {
3314 ON_BoundingBox bbox;
3315 if ( bGrowBox )
3316 {
3317 bbox.m_min.x = boxmin[0];
3318 bbox.m_min.y = boxmin[1];
3319 bbox.m_min.z = boxmin[2];
3320 bbox.m_max.x = boxmax[0];
3321 bbox.m_max.y = boxmax[1];
3322 bbox.m_max.z = boxmax[2];
3323 if ( !bbox.IsValid() )
3324 {
3325 bbox.Destroy();
3326 bGrowBox = false;
3327 }
3328 }
3329
3330 ON_Arc arc;
3331 if ( GetArc(arc) )
3332 {
3333 if ( arc.GetTightBoundingBox(bbox,bGrowBox?true:false,0) )
3334 bGrowBox = true;
3335 }
3336
3337 if ( bGrowBox )
3338 {
3339 boxmin[0] = bbox.m_min.x;
3340 boxmin[1] = bbox.m_min.y;
3341 boxmin[2] = bbox.m_min.z;
3342 boxmax[0] = bbox.m_max.x;
3343 boxmax[1] = bbox.m_max.y;
3344 boxmax[2] = bbox.m_max.z;
3345 }
3346
3347 return bGrowBox;
3348 }
3349
3350
3351
3352
3353
GetTightBoundingBox(ON_BoundingBox & tight_bbox,int bGrowBox,const ON_Xform * xform) const3354 bool ON_AngularDimension2::GetTightBoundingBox(
3355 ON_BoundingBox& tight_bbox,
3356 int bGrowBox,
3357 const ON_Xform* xform
3358 ) const
3359 {
3360 ON_Arc arc;
3361 if ( GetArc(arc) )
3362 {
3363 if ( arc.GetTightBoundingBox(tight_bbox,bGrowBox,xform) )
3364 bGrowBox = true;
3365 }
3366 else if ( bGrowBox && !tight_bbox.IsValid() )
3367 {
3368 tight_bbox.Destroy();
3369 bGrowBox = false;
3370 }
3371
3372 return (0!=bGrowBox);
3373
3374 }
3375
Dim2dPoint(int point_index) const3376 ON_2dPoint ON_AngularDimension2::Dim2dPoint( int point_index ) const
3377 {
3378 ON_2dPoint p2;
3379 if ( m_points.Count() < dim_pt_count || point_index < 0 )
3380 {
3381 p2.x = p2.y = ON_UNSET_VALUE;
3382 }
3383 else
3384 {
3385 if ( text_pivot_pt == point_index )
3386 {
3387 point_index = m_userpositionedtext
3388 ? userpositionedtext_pt_index
3389 : arcmid_pt;
3390 }
3391
3392 if ( point_index < dim_pt_count )
3393 {
3394 p2 = m_points[point_index];
3395 }
3396 else
3397 {
3398 switch(point_index)
3399 {
3400 case arcstart_pt:
3401 p2.x = m_radius;
3402 p2.y = 0.0;
3403 break;
3404 case arcend_pt:
3405 p2.x = m_radius*cos(m_angle);
3406 p2.y = m_radius*sin(m_angle);
3407 break;
3408 case arccenter_pt:
3409 p2.x = 0.0;
3410 p2.y = 0.0;
3411 break;
3412 case arcmid_pt:
3413 p2.x = m_radius*cos(0.5*m_angle);
3414 p2.y = m_radius*sin(0.5*m_angle);
3415 break;
3416 case extension0_pt:
3417 {
3418 p2 = m_points[start_pt_index];
3419 double dp0 = DimpointOffset(0);
3420 if(dp0 >= 0)
3421 {
3422 ON_2dVector v2 = (ON_2dVector)p2;
3423 v2.Unitize();
3424 p2 = (ON_2dPoint)v2 * dp0;
3425 }
3426 }
3427 break;
3428 case extension1_pt:
3429 {
3430 p2 = m_points[end_pt_index];
3431 double dp1 = DimpointOffset(1);
3432 if(dp1 >= 0)
3433 {
3434 ON_2dVector v2 = (ON_2dVector)p2;
3435 v2.Unitize();
3436 p2 = (ON_2dPoint)v2 * dp1;
3437 }
3438 }
3439 break;
3440 default:
3441 p2.x = p2.y = ON_UNSET_VALUE;
3442 break;
3443 }
3444 }
3445 }
3446 return p2;
3447 }
3448
Dim3dPoint(int point_index) const3449 ON_3dPoint ON_AngularDimension2::Dim3dPoint( int point_index ) const
3450 {
3451 ON_2dPoint p2 = Dim2dPoint(point_index);
3452 return (ON_UNSET_VALUE == p2.x) ? ON_UNSET_POINT : m_plane.PointAt(p2.x,p2.y);
3453 }
3454
3455
Write(ON_BinaryArchive & file) const3456 ON_BOOL32 ON_AngularDimension2::Write( ON_BinaryArchive& file ) const
3457 {
3458 // 18 October 2007 Dale Lear
3459 // I added the chunk wrapping so V5 and future versions can
3460 // add IO support for information specific to ON_LinearDimension2
3461 // V4 did not have a ON_LinearDimension2::Write and simply called
3462 // ON_Annotation2::Write.
3463 bool rc = false;
3464 bool bInChunk = (file.Archive3dmVersion() >= 5);
3465 if ( bInChunk )
3466 {
3467 rc = file.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0);
3468 if ( !rc )
3469 return false;
3470 }
3471 else
3472 {
3473 rc = true;
3474 }
3475
3476 while(rc)
3477 {
3478 rc = ON_Annotation2::Write(file)?true:false;
3479 if (!rc) break;
3480 rc = file.WriteDouble( m_angle);
3481 if (!rc) break;
3482 rc = file.WriteDouble( m_radius);
3483 if (!rc) break;
3484 if ( !bInChunk )
3485 break;
3486
3487 // to write new V5 fields, increment the minor
3488 // version number and write them below
3489
3490 break;
3491 }
3492
3493 if ( bInChunk )
3494 {
3495 if (!file.EndWrite3dmChunk())
3496 rc = false;
3497 }
3498
3499 return rc;
3500 }
3501
Read(ON_BinaryArchive & file)3502 ON_BOOL32 ON_AngularDimension2::Read( ON_BinaryArchive& file )
3503 {
3504 // 18 October 2007 Dale Lear
3505 // I added the chunk wrapping so V5 and future versions can
3506 // add IO support for information specific to ON_AngularDimension2
3507 int major_version = 0;
3508 int minor_version = 0;
3509 bool rc = false;
3510 bool bInChunk = (file.Archive3dmVersion() >= 5 && file.ArchiveOpenNURBSVersion() >= 200710180);
3511 if ( bInChunk )
3512 {
3513 rc = file.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version);
3514 if ( !rc )
3515 return false;
3516 }
3517 else
3518 {
3519 rc = true;
3520 }
3521
3522 while(rc)
3523 {
3524 rc = ON_Annotation2::Read(file)?true:false;
3525 if (!rc) break;
3526 rc = file.ReadDouble( &m_angle);
3527 if (!rc) break;
3528 rc = file.ReadDouble( &m_radius);
3529 if (!rc) break;
3530 if ( !bInChunk || minor_version <= 0 )
3531 break;
3532
3533 // Code to read any new ON_AngularDimension2 fields will
3534 // go here.
3535
3536 break;
3537 }
3538
3539 if ( bInChunk )
3540 {
3541 // To read new ON_AngularDimension2 specific additions,
3542 // examine the minor version number and read the information
3543 // here. Please ask Dale Lear for help.
3544
3545 if ( !file.EndRead3dmChunk() )
3546 rc = false;
3547 }
3548 return rc;
3549 }
3550
VectorAngle(const ON_2dVector & v,double & angle)3551 static ON_BOOL32 VectorAngle( const ON_2dVector& v, double& angle)
3552 {
3553 if( v.IsTiny())
3554 return false;
3555
3556 angle = atan2( v.y, v.x);
3557
3558 if( angle < 0.0)
3559 angle += 2.0 * ON_PI;
3560
3561 if( angle > 2.0 * ON_PI)
3562 angle -= 2.0 * ON_PI;
3563
3564 return true;
3565 }
3566
CreateFromV2(const ON_Annotation & v2_ann,const ON_3dmAnnotationSettings & settings,int dimstyle_index)3567 bool ON_AngularDimension2::CreateFromV2(
3568 const ON_Annotation& v2_ann,
3569 const ON_3dmAnnotationSettings& settings,
3570 int dimstyle_index
3571 )
3572 {
3573 if( ON::dtDimAngular != v2_ann.Type() )
3574 return false;
3575
3576 if ( v2_ann.m_points.Count() < 3 )
3577 return false;
3578
3579 ON_Plane plane = v2_ann.m_plane;
3580 plane.UpdateEquation();
3581 if ( !plane.IsValid() )
3582 return false;
3583
3584 ON_2dVector p0 = v2_ann.m_points[0]; // point on first line
3585 ON_2dVector p1 = v2_ann.m_points[1]; // point on second line
3586 ON_2dPoint tp = v2_ann.m_points[2]; // user positioned text point
3587 if ( !p0.IsValid() || !p1.IsValid() || p0.IsZero() || p1.IsZero() )
3588 return false;
3589
3590 bool bUserPositionedText = v2_ann.UserPositionedText() && tp.IsValid();
3591
3592 if ( p0.x <= 0.0 && 0.0 != p0.y )
3593 {
3594 bUserPositionedText = false;
3595 ON_3dPoint P0 = plane.PointAt(p0.x,p0.y);
3596 ON_3dPoint P1 = plane.PointAt(p1.x,p1.y);
3597 plane.xaxis = P0-plane.origin;
3598 if ( !plane.xaxis.Unitize() )
3599 return false;
3600 plane.yaxis = ON_CrossProduct( plane.zaxis, plane.xaxis );
3601 plane.yaxis.Unitize();
3602 if ( !plane.IsValid() )
3603 return false;
3604 p0.x = p0.Length();
3605 p0.y = 0.0;
3606 if ( !plane.ClosestPointTo(P1,&p1.x,&p1.y) )
3607 return false;
3608 }
3609
3610 if ( p1.x >= 0.0 && p1.y == 0.0 )
3611 return false;
3612
3613 double angle = atan2(p1.y,p1.x);
3614 if ( angle < 0.0 )
3615 angle += 2.0*ON_PI;
3616
3617 double radius = 0.5*(p0.Length() + p1.Length());
3618
3619 const ON_AngularDimension* v2_angdim = ON_AngularDimension::Cast(&v2_ann);
3620 if ( v2_angdim && v2_angdim->Radius() > 0.0 )
3621 radius = v2_angdim->Radius();
3622
3623 if ( !bUserPositionedText )
3624 {
3625 tp.x = radius*cos(0.5*angle);
3626 tp.y = radius*sin(0.5*angle);
3627 }
3628
3629 ON_2dPoint arcpt( radius*cos(angle/3.0), radius*sin(angle/3.0) );
3630
3631 m_plane = plane;
3632 m_points.SetCapacity(4);
3633 m_points.SetCount(4);
3634 m_points[0] = tp;
3635 m_points[1] = p0;
3636 m_points[2] = p1;
3637 m_points[3] = arcpt;
3638 m_angle = angle;
3639 m_radius = radius;
3640
3641 SetTextValue(v2_ann.UserText());
3642 SetTextFormula(0);
3643 m_userpositionedtext = bUserPositionedText;
3644
3645 switch( settings.m_textalign)
3646 {
3647 case 1:
3648 m_textdisplaymode = ON::dtInLine;
3649 break;
3650 case 2:
3651 m_textdisplaymode = ON::dtHorizontal;
3652 break;
3653 default:
3654 m_textdisplaymode = ON::dtAboveLine;
3655 break;
3656 }
3657
3658 m_index = dimstyle_index;
3659
3660 return true;
3661 }
3662
CreateFromArc(const ON_Arc & arc)3663 bool ON_AngularDimension2::CreateFromArc( const ON_Arc& arc )
3664 {
3665 // June 9, 2010 - Lowell - Changed to call CreateFromPoints()
3666 bool rc = arc.IsValid();
3667 if (rc)
3668 {
3669 ON_3dPoint C = arc.Center();
3670 ON_3dPoint S = arc.StartPoint();
3671 ON_3dPoint E = arc.EndPoint();
3672 ON_3dPoint M = arc.MidPoint();
3673 ON_3dVector N = arc.Plane().zaxis;
3674
3675 rc = CreateFromPoints(C, S, E, M, N);
3676 }
3677
3678 return rc;
3679 }
3680
GetArc(ON_Arc & arc) const3681 bool ON_AngularDimension2::GetArc( ON_Arc& arc ) const
3682 {
3683 bool rc = false;
3684 // Jan 25, 2007 - changed min radius from >0 to >ON_SQRT_EPSILON
3685 // to avoid domain problems trying to use very small arcs later
3686 if ( ON_IsValid(m_radius) && m_radius > ON_SQRT_EPSILON
3687 && ON_IsValid(m_angle) && m_angle > 0.0 && m_angle <= 2.0*ON_PI
3688 && m_plane.origin.IsValid()
3689 && m_plane.xaxis.IsValid()
3690 && m_plane.yaxis.IsValid()
3691 && m_plane.zaxis.IsValid()
3692 && fabs( m_plane.zaxis.Length() - 1.0 ) <= ON_SQRT_EPSILON
3693 && 4 == m_points.Count()
3694 )
3695 {
3696 ON_3dVector X = m_plane.PointAt( m_points[start_pt_index].x, m_points[start_pt_index].y ) - m_plane.origin;
3697 if ( fabs(X.Length()-1.0) <= ON_SQRT_EPSILON || X.Unitize() )
3698 {
3699 if ( fabs(X*m_plane.zaxis) <= ON_SQRT_EPSILON )
3700 {
3701 ON_3dVector Y = ON_CrossProduct( m_plane.zaxis, X );
3702 if ( fabs(Y.Length()-1.0) <= ON_SQRT_EPSILON || Y.Unitize() )
3703 {
3704 arc.plane = m_plane;
3705 arc.plane.xaxis = X;
3706 arc.plane.yaxis = Y;
3707 arc.plane.UpdateEquation();
3708 arc.SetAngleIntervalRadians( ON_Interval(0.0,m_angle) );
3709 arc.radius = m_radius;
3710 rc = true;
3711 }
3712 }
3713 }
3714 }
3715
3716 return rc;
3717 }
3718
GetExtensionLines(ON_Line extensions[2]) const3719 bool ON_AngularDimension2::GetExtensionLines(ON_Line extensions[2]) const
3720 {
3721 bool rc = false;
3722
3723 if ( ON_IsValid(m_radius) && m_radius > ON_SQRT_EPSILON
3724 && ON_IsValid(m_angle) && m_angle > 0.0 && m_angle <= 2.0*ON_PI
3725 && m_plane.origin.IsValid()
3726 && m_plane.xaxis.IsValid()
3727 && m_plane.yaxis.IsValid()
3728 && m_plane.zaxis.IsValid()
3729 && fabs( m_plane.zaxis.Length() - 1.0 ) <= ON_SQRT_EPSILON
3730 && 4 == m_points.Count()
3731 )
3732 {
3733 const ON_AngularDimension2Extra* pDE = ON_AngularDimension2Extra::AngularDimensionExtra(this);
3734 if(pDE != 0)
3735 {
3736 double exoffset0 = pDE->DimpointOffset(0);
3737 double exoffset1 = pDE->DimpointOffset(1);
3738 ON_3dPoint e00, e01, e10, e11;
3739 e00 = m_plane.PointAt(m_points[start_pt_index].x, m_points[start_pt_index].y);
3740 e10 = m_plane.PointAt(m_points[end_pt_index].x, m_points[end_pt_index].y);
3741 ON_3dVector X = e00 - m_plane.origin;
3742 ON_3dVector Y = e10 - m_plane.origin;
3743 if((fabs(X.Length()-1.0) <= ON_SQRT_EPSILON || X.Unitize()) &&
3744 (fabs(Y.Length()-1.0) <= ON_SQRT_EPSILON || Y.Unitize()))
3745 {
3746 if((fabs(X*m_plane.zaxis) <= ON_SQRT_EPSILON) &&
3747 (fabs(Y*m_plane.zaxis) <= ON_SQRT_EPSILON))
3748 {
3749 e00 = m_plane.origin + X * exoffset0;
3750 e10 = m_plane.origin + Y * exoffset1;
3751 e01 = m_plane.origin + X * m_radius;
3752 e11 = m_plane.origin + Y * m_radius;
3753
3754 extensions[0].from = e00;
3755 extensions[0].to = e01;
3756 extensions[1].from = e10;
3757 extensions[1].to = e11;
3758 rc = true;
3759 }
3760 }
3761 }
3762 }
3763 return rc;
3764 }
3765
3766
CreateFromPoints(const ON_3dPoint & pc,const ON_3dPoint & p0in,const ON_3dPoint & p1in,ON_3dPoint & arcpt,ON_3dVector & Normal)3767 bool ON_AngularDimension2::CreateFromPoints(
3768 const ON_3dPoint& pc,
3769 const ON_3dPoint& p0in,
3770 const ON_3dPoint& p1in,
3771 ON_3dPoint& arcpt,
3772 ON_3dVector& Normal)
3773 {
3774 ON_3dPoint p0, p1;
3775 p0 = p0in;
3776 p1 = p1in;
3777
3778 ON_Plane plane( pc, Normal);
3779
3780 ON_2dPoint pa, pp0, pp1;
3781
3782 if( !plane.ClosestPointTo( p0, &pp0.x, &pp0.y))
3783 return false;
3784
3785 // rotate so that p0 is on x-axis
3786 ON_2dVector v0( pp0);
3787 v0.Unitize();
3788 plane.Rotate( v0.y, v0.x, plane.Normal());
3789
3790 if( !plane.ClosestPointTo( p0, &pp0.x, &pp0.y))
3791 return false;
3792
3793 if( !plane.ClosestPointTo( arcpt, &pa.x, &pa.y))
3794 return false;
3795
3796 if( !plane.ClosestPointTo( p1, &pp1.x, &pp1.y))
3797 return false;
3798
3799 double a1, aa;
3800 if( !VectorAngle( ON_2dVector( pp1), a1) || !VectorAngle( ON_2dVector( pa), aa))
3801 return false;
3802
3803 if( aa > a1) // the angle is really the bigger one ( > 180)
3804 {
3805 // rotate so that p0 is on x-axis
3806 v0.Set( pp1.x, pp1.y);
3807 v0.Unitize();
3808 plane.Rotate( v0.y, v0.x, plane.Normal());
3809
3810 if( !plane.ClosestPointTo( arcpt, &pa.x, &pa.y))
3811 return false;
3812 if( !plane.ClosestPointTo( p1, &pp0.x, &pp0.y))
3813 return false;
3814 if( !plane.ClosestPointTo( p0, &pp1.x, &pp1.y))
3815 return false;
3816 }
3817
3818 VectorAngle( ON_2dVector( pp1), a1);
3819
3820 SetAngle( a1);
3821 SetRadius( ON_2dVector( pa).Length());
3822
3823 ON_AngularDimension2Extra* pDE = ON_AngularDimension2Extra::AngularDimensionExtra(this);
3824 if(pDE != 0)
3825 {
3826 double os = ((ON_2dVector)pp0).Length();
3827 pDE->SetDimpointOffset(0, os);
3828 os = ((ON_2dVector)pp1).Length();
3829 pDE->SetDimpointOffset(1, os);
3830 }
3831
3832 ReservePoints( 4);
3833 SetPlane( plane);
3834 SetPoint( 1, pp0);
3835 SetPoint( 2, pp1);
3836 SetPoint( 3, pa);
3837
3838
3839 return true;
3840 }
3841
SetAngle(double angle)3842 void ON_AngularDimension2::SetAngle( double angle)
3843 {
3844 m_angle = angle;
3845 }
3846
Angle() const3847 double ON_AngularDimension2::Angle() const
3848 {
3849 return m_angle;
3850 }
3851
SetRadius(double radius)3852 void ON_AngularDimension2::SetRadius( double radius)
3853 {
3854 m_radius = radius;
3855 }
3856
Radius() const3857 double ON_AngularDimension2::Radius() const
3858 {
3859 return m_radius;
3860 }
3861
NumericValue() const3862 double ON_AngularDimension2::NumericValue() const
3863 {
3864 // This returns degrees - if we get another angular unit system, add it
3865 return (m_angle*180.0/ON_PI);
3866 }
3867
StyleIndex() const3868 int ON_AngularDimension2::StyleIndex() const
3869 {
3870 return ON_Annotation2::Index();
3871 }
3872
SetStyleIndex(int i)3873 void ON_AngularDimension2::SetStyleIndex( int i)
3874 {
3875 ON_Annotation2::SetIndex( i);
3876 }
3877
DefaultText()3878 const wchar_t* ON_AngularDimension2::DefaultText()
3879 {
3880 return L"<>"; // Aug 31, 2009 - Lowell
3881 }
3882
ConvertBack(ON_AngularDimension2 &)3883 void ON_AngularDimension2::ConvertBack(
3884 ON_AngularDimension2& // target - formal parameter intentionally ignored in this virtual function
3885 )
3886 {
3887 }
3888
3889 // 6-23-03 lw Added v2 file writing of annotation
GetV2Form(ON_AngularDimension & dim)3890 void ON_AngularDimension2::GetV2Form( ON_AngularDimension& dim)
3891 {
3892 ON_Annotation2::ConvertBack( dim);
3893 dim.SetPoint(0, Point(1));
3894 dim.SetPoint(1, Point(2));
3895 dim.SetPoint(2, Point(3));
3896 dim.SetPoint(3, Point(0)); // text point or apex
3897 dim.SetAngle( Angle());
3898 dim.SetRadius( Radius());
3899 }
3900
3901
3902
OrientRectHelper(ON_2dVector corners[4])3903 static void OrientRectHelper( ON_2dVector corners[4] )
3904 {
3905 double twice_area = 0.0;
3906 ON_2dVector p0, p1;
3907 int i;
3908 p1 = corners[3];
3909 for ( i = 0; i < 4; i++ )
3910 {
3911 p0 = p1;
3912 p1 = corners[i];
3913 twice_area += (p0.x-p1.x)*(p0.y+p1.y);
3914 }
3915 if ( twice_area < 0.0 )
3916 {
3917 p1 = corners[1];
3918 corners[1] = corners[3];
3919 corners[3] = p1;
3920 }
3921 }
3922
GetDimensionArcSegments(ON_RECT gdi_text_rect,int gdi_height_of_I,ON_Xform gdi_to_world,const ON_DimStyle & dimstyle,double dimscale,const ON_Viewport * vp,double a[6],bool & bInside) const3923 int ON_AngularDimension2::GetDimensionArcSegments(
3924 ON_RECT gdi_text_rect,
3925 int gdi_height_of_I,
3926 ON_Xform gdi_to_world,
3927 const ON_DimStyle& dimstyle,
3928 double dimscale,
3929 const ON_Viewport* vp,
3930 double a[6],
3931 bool& bInside
3932 ) const
3933 {
3934 int rc = 0;
3935
3936 a[0] = 0.0;
3937 a[1] = 0.0;
3938
3939 if ( m_angle <= 0.0 || !ON_IsValid(m_angle) )
3940 return 0;
3941
3942 a[1] = m_angle;
3943
3944 if ( m_radius <= 0.0 || !ON_IsValid(m_radius) || m_angle >= 2.0*ON_PI )
3945 return 0;
3946
3947 if ( 0 == gdi_height_of_I )
3948 {
3949 // Default to height of Ariel 'I' (this code still works if ON_Font::normal_font_height != 256)
3950 gdi_height_of_I = (165*ON_Font::normal_font_height)/256;
3951 }
3952
3953 if ( 0.0 == dimscale )
3954 {
3955 dimscale = 1.0;
3956 }
3957
3958 double t;
3959
3960 ON::eTextDisplayMode textdisplay = ON::TextDisplayMode(dimstyle.TextAlignment());
3961 if ( ON::dtHorizontal == textdisplay && !vp )
3962 textdisplay = ON::dtInLine;
3963
3964 const double text_height_of_I = dimscale*dimstyle.TextHeight();
3965 const double textgap = dimscale*dimstyle.TextGap();
3966 const double gdi_to_plane_scale = text_height_of_I/gdi_height_of_I;
3967 const double textwidth = fabs(gdi_to_plane_scale*(gdi_text_rect.right - gdi_text_rect.left));
3968 const double arrowwidth = fabs(dimscale*dimstyle.ArrowSize());
3969 const double tailwidth = 0.5*arrowwidth;
3970 const double dimextension = fabs(dimscale*dimstyle.DimExtension());
3971 const double a0 = 0.0;
3972 const double a1 = m_angle;
3973
3974 double sin_angle = 0.5*dimextension/m_radius;
3975 if ( sin_angle > 1.0 ) sin_angle = 1.0; else if (sin_angle < -1.0) sin_angle = -1.0;
3976 const double dimextension_angle = 2.0*asin(sin_angle);
3977
3978 sin_angle = 0.5*arrowwidth/m_radius;
3979 if ( sin_angle > 1.0 ) sin_angle = 1.0; else if (sin_angle < -1.0) sin_angle = -1.0;
3980 const double arrowangle = 2.0*asin(sin_angle);
3981
3982 sin_angle = 0.5*tailwidth/m_radius;
3983 if ( sin_angle > 1.0 ) sin_angle = 1.0; else if (sin_angle < -1.0) sin_angle = -1.0;
3984 const double tailangle = 2.0*asin(sin_angle);
3985
3986 // June 7, 2010 - Lowell - Added some special handling for very small dimensions
3987 double arrow_angle = arrowangle + tailangle;
3988 if(arrow_angle > ON_PI * 0.5)
3989 arrow_angle = ON_PI * 0.5;
3990 if ( m_radius <= arrowwidth + tailwidth || m_radius*(a1-a0) < 2.0*(arrowwidth) + tailwidth )
3991 {
3992 // arc is tiny with respect to arrowhead size - arrowheads have to be "outside"
3993 // 2 arc segments, arrowheads outside
3994 a[0] = a0;
3995 a[1] = a0 - arrow_angle;
3996 a[2] = a1 + arrow_angle;
3997 a[3] = a1;
3998 a[4] = a0;
3999 a[5] = a1;
4000 if( dimextension_angle != 0.0)
4001 {
4002 a[0] += dimextension_angle;
4003 a[3] -= dimextension_angle;
4004 }
4005 bInside = false;
4006 return 2;
4007 }
4008
4009 if ( ON::dtInLine == textdisplay && m_radius <= 0.5*(textwidth+2.0*textgap) )
4010 {
4011 // 2 arc segments, arrowheads outside
4012 a[0] = a0;
4013 a[1] = a0 - arrow_angle;
4014 a[2] = a1 + arrow_angle;
4015 a[3] = a1;
4016 a[4] = a0;
4017 a[5] = a1;
4018 if( dimextension_angle != 0.0)
4019 {
4020 a[0] += dimextension_angle;
4021 a[3] -= dimextension_angle;
4022 }
4023 bInside = false;
4024 return 2;
4025 }
4026
4027 sin_angle = 0.5*(textwidth+2.0*textgap)/m_radius;
4028 if ( sin_angle > 1.0 ) sin_angle = 1.0; else if (sin_angle < -1.0) sin_angle = -1.0;
4029 const double textangle = (ON::dtInLine == textdisplay && !m_userpositionedtext )
4030 ? 2.0*asin(sin_angle)
4031 : 0.0;
4032
4033 if ( (a1-a0) <= 2.0*(arrow_angle) + textangle )
4034 {
4035 // 2 arc segments, arrowheads outside
4036 a[0] = a0;
4037 a[1] = a0 - arrow_angle;
4038 a[2] = a1 + arrow_angle;
4039 a[3] = a1;
4040 a[4] = a0;
4041 a[5] = a1;
4042 if( dimextension_angle != 0.0)
4043 {
4044 a[0] += dimextension_angle;
4045 a[3] -= dimextension_angle;
4046 }
4047 bInside = false;
4048 return 2;
4049 }
4050
4051 if ( (ON::dtHorizontal == textdisplay && vp) || m_userpositionedtext )
4052 {
4053 // use projected rectangle to clip dimension arc
4054 double aa0, aa1, aa, r0, r1, t, tt[2];
4055 ON_3dPoint P, R, c[2];
4056 ON_2dVector corners[4], N;
4057 ON_Line ray;
4058 int i,xi, xrc;
4059 const ON_Circle circle(ON_xy_plane,1.0);
4060
4061 ON_3dVector vp_zaxis = (ON::dtHorizontal == textdisplay && vp)
4062 ? vp->CameraZ()
4063 : m_plane.zaxis;
4064
4065 // 30 July 2012 - Lowell - Slightly shrink the text gap value
4066 // so that text + gap won't intersect the dim line if when text
4067 // is moved along the dim line. rr110504
4068 double gdi_gap = fabs(textgap/gdi_to_plane_scale)-12;
4069 if(gdi_gap < 0.0) gdi_gap = 0.0;
4070
4071 R.Set(gdi_text_rect.left-gdi_gap,gdi_text_rect.bottom+gdi_gap,0.0);
4072 ray.from = gdi_to_world*R; ray.to = ray.from + vp_zaxis;
4073 P = ( ON_Intersect(ray,m_plane,&t) ) ? ray.PointAt(t) : ray.from;
4074 m_plane.ClosestPointTo(P,&corners[0].x,&corners[0].y);
4075
4076 R.Set(gdi_text_rect.right+gdi_gap,gdi_text_rect.bottom+gdi_gap,0.0);
4077 ray.from = gdi_to_world*R; ray.to = ray.from + vp_zaxis;
4078 P = ( ON_Intersect(ray,m_plane,&t) ) ? ray.PointAt(t) : ray.from;
4079 m_plane.ClosestPointTo(P,&corners[1].x,&corners[1].y);
4080
4081 R.Set(gdi_text_rect.right+gdi_gap,gdi_text_rect.top-gdi_gap,0.0);
4082 ray.from = gdi_to_world*R; ray.to = ray.from + vp_zaxis;
4083 P = ( ON_Intersect(ray,m_plane,&t) ) ? ray.PointAt(t) : ray.from;
4084 m_plane.ClosestPointTo(P,&corners[2].x,&corners[2].y);
4085
4086 R.Set(gdi_text_rect.left-gdi_gap,gdi_text_rect.top-gdi_gap,0.0);
4087 ray.from = gdi_to_world*R; ray.to = ray.from + vp_zaxis;
4088 P = ( ON_Intersect(ray,m_plane,&t) ) ? ray.PointAt(t) : ray.from;
4089 m_plane.ClosestPointTo(P,&corners[3].x,&corners[3].y);
4090
4091 // orient projected rect so it is counter-clockwise
4092 OrientRectHelper(corners);
4093
4094 aa0 = a0;
4095 aa1 = a1;
4096 P.Set(cos(a0)*m_radius,sin(a0)*m_radius,0.0);
4097 R.Set(cos(a1)*m_radius,sin(a1)*m_radius,0.0);
4098 for ( i = 0; i < 4; i++ )
4099 {
4100 N.x = (corners[i].y-corners[(i+1)%4].y);
4101 N.y = (corners[(i+1)%4].x-corners[i].x);
4102 if ( !N.Unitize() )
4103 continue;
4104 if ( (P.x - corners[i].x)*N.x + (P.y - corners[i].y)*N.y < 0.0 )
4105 {
4106 // end point not in text box
4107 aa0 = ON_UNSET_VALUE;
4108 }
4109 if ( (R.x - corners[i].x)*N.x + (R.y - corners[i].y)*N.y < 0.0 )
4110 {
4111 // start point not in text box
4112 aa1 = ON_UNSET_VALUE;
4113 }
4114 }
4115
4116 if ( ON_UNSET_VALUE == aa0 )
4117 aa0 = aa1;
4118 else if ( ON_UNSET_VALUE == aa1 )
4119 aa1 = aa0;
4120
4121 r1 = corners[3].Length() - m_radius;
4122 ray.to.x = corners[3].x/m_radius; ray.to.y = corners[3].y/m_radius;
4123 ray.to.z = ray.from.z = 0.0;
4124 for ( i = 0; i < 4; i++ )
4125 {
4126 r0 = r1;
4127 r1 = corners[i].Length() - m_radius;
4128 ray.from = ray.to;
4129 ray.to.x = corners[i].x/m_radius; ray.to.y = corners[i].y/m_radius;
4130 if ( r0 < 0.0 && r1 < 0.0 )
4131 {
4132 continue; // ray is inside circle
4133 }
4134 if ( r0 > 0.0 && r1 > 0.0 )
4135 {
4136 if ( !ray.ClosestPointTo(ON_2dPoint(0.0,0.0),&t ) )
4137 continue;
4138 R = ray.PointAt(t);
4139 if ( R.x*R.x + R.y*R.y >= 1.0 )
4140 continue; // ray is outside circle
4141 }
4142
4143
4144 xrc = 0;
4145 if ( 0.0 == r0 )
4146 tt[xrc++] = 0.0;
4147
4148 if ( 0.0 == r1 )
4149 tt[xrc++] = 1.0;
4150
4151 if ( 0 == xrc )
4152 xrc = ON_Intersect(ray,circle,&tt[0],c[0],&tt[1],c[1]);
4153
4154 if ( xrc < 1 || xrc > 2 )
4155 continue; // ray does not intersect circle;
4156
4157 for ( xi = 0; xi < xrc; xi++ )
4158 {
4159 if ( tt[xi] < 0.0 || tt[xi] > 1.0 )
4160 continue; // intersection point not on segment
4161
4162 P = ray.PointAt(tt[xi]);
4163 if ( 0.0 == P.x && 0.0 == P.y )
4164 continue; // bogus
4165
4166 aa = atan2(P.y,P.x);
4167 if ( aa < a0 ) aa += 2.0*ON_PI; else if ( aa > a1 ) aa -= 2.0*ON_PI;
4168 if ( aa < a0 || aa > a1 )
4169 {
4170 continue;
4171 }
4172 if ( ON_UNSET_VALUE == aa0 )
4173 aa0 = aa1 = aa;
4174 else if ( aa < aa0 )
4175 aa0 = aa;
4176 else if ( aa > aa1 )
4177 aa1 = aa;
4178 }
4179 }
4180 if ( ON_UNSET_VALUE != aa0 && ON_UNSET_VALUE != aa1
4181 && a0 <= aa0 && aa0 < aa1 && aa1 <= a1 )
4182 {
4183 t = arrow_angle;
4184 if ( aa0 < a0+t && aa1 > a1-t )
4185 {
4186 // text box hits both arrowheads
4187 // 2 arc segments, arrowheads outside
4188 a[0] = a0;
4189 a[1] = a0 - arrow_angle;
4190 a[2] = a1 + arrow_angle;
4191 a[3] = a1;
4192 a[4] = a0;
4193 a[5] = a1;
4194 if( dimextension_angle != 0.0)
4195 {
4196 a[0] += dimextension_angle;
4197 a[3] -= dimextension_angle;
4198 }
4199 bInside = false;
4200 rc = 2;
4201 }
4202 else
4203 {
4204 if ( aa0 < a0+t ) aa0 = a0+t;
4205 if ( aa1 > a1-t ) aa1 = a1-t;
4206 if ( a0 < aa0 && aa0 < aa1 && aa1 < a1 )
4207 {
4208 // clip arc to text rectangle
4209 // 2 arc segments, arrowheads inside
4210 a[0] = a0;
4211 a[1] = aa0;
4212 a[2] = aa1;
4213 a[3] = a1;
4214 a[4] = a0;
4215 a[5] = a1;
4216 if( dimextension_angle != 0.0)
4217 {
4218 a[0] -= dimextension_angle;
4219 a[3] += dimextension_angle;
4220 }
4221 bInside = true;
4222 rc = 2;
4223 }
4224 else
4225 {
4226 // nasty case - don't bother clipping
4227 // 1 segment, arrows inside
4228 a[0] = a0;
4229 a[1] = a1;
4230 a[2] = a0;
4231 a[3] = a1;
4232 a[4] = a0;
4233 a[5] = a1;
4234 if( dimextension_angle != 0.0)
4235 {
4236 a[0] -= dimextension_angle;
4237 a[1] += dimextension_angle;
4238 }
4239 bInside = true;
4240 rc = 1;
4241 }
4242 }
4243 }
4244 else
4245 {
4246 // 1 segment, arrows inside
4247 a[0] = a0;
4248 a[1] = a1;
4249 a[2] = a0;
4250 a[3] = a1;
4251 a[4] = a0;
4252 a[5] = a1;
4253 if( dimextension_angle != 0.0)
4254 {
4255 a[0] -= dimextension_angle;
4256 a[1] += dimextension_angle;
4257 }
4258 bInside = true;
4259 rc = 1;
4260 }
4261 }
4262 else if ( ON::dtAboveLine == textdisplay || m_userpositionedtext )
4263 {
4264 // 1 segment, arrows inside
4265 a[0] = a0;
4266 a[1] = a1;
4267 a[2] = a0;
4268 a[3] = a1;
4269 a[4] = a0;
4270 a[5] = a1;
4271 if( dimextension_angle != 0.0)
4272 {
4273 a[0] -= dimextension_angle;
4274 a[1] += dimextension_angle;
4275 }
4276 bInside = true;
4277 rc = 1;
4278 }
4279 else if ( ON::dtInLine == textdisplay )
4280 {
4281 // 2 segments, arrows inside
4282 t = 0.5*((a1-a0) - textangle);
4283 a[0] = a0;
4284 a[1] = a0+t;
4285 a[2] = a1-t;
4286 a[3] = a1;
4287 a[4] = a0;
4288 a[5] = a1;
4289 if( dimextension_angle != 0.0)
4290 {
4291 a[0] -= dimextension_angle;
4292 a[3] += dimextension_angle;
4293 }
4294 bInside = true;
4295 rc = 2;
4296 }
4297
4298 return rc;
4299 }
4300
DimpointOffset(int index) const4301 double ON_AngularDimension2::DimpointOffset(int index) const
4302 {
4303 const ON_AngularDimension2Extra* pDE = ON_AngularDimension2Extra::AngularDimensionExtra(this);
4304 if(pDE != 0)
4305 return pDE->DimpointOffset(index);
4306 return -1.0;
4307 }
SetDimpointOffset(int index,double offset)4308 void ON_AngularDimension2::SetDimpointOffset(int index, double offset)
4309 {
4310 ON_AngularDimension2Extra* pDE = ON_AngularDimension2Extra::AngularDimensionExtra(this);
4311 if(pDE != 0)
4312 pDE->SetDimpointOffset(index, offset);
4313 }
4314
4315
4316 //----- ON_OrdinateDimension2 -----------------------------------------
ON_OrdinateDimension2()4317 ON_OrdinateDimension2::ON_OrdinateDimension2()
4318 {
4319 m_type = ON::dtDimOrdinate;
4320 SetTextValue(DefaultText());
4321 SetTextFormula(0);
4322 m_direction = -1; // undetermined direction
4323 m_points.Reserve(ON_OrdinateDimension2::dim_pt_count);
4324 m_points.SetCount(ON_OrdinateDimension2::dim_pt_count);
4325 m_points.Zero();
4326 m_kink_offset_0 = ON_UNSET_VALUE;
4327 m_kink_offset_1 = ON_UNSET_VALUE;
4328 }
4329
~ON_OrdinateDimension2()4330 ON_OrdinateDimension2::~ON_OrdinateDimension2()
4331 {
4332 }
4333
Transform(const ON_Xform & xform)4334 ON_BOOL32 ON_OrdinateDimension2::Transform( const ON_Xform& xform )
4335 {
4336 bool rc = xform.IsIdentity();
4337 if ( !rc)
4338 {
4339 return ON_Annotation2::Transform(xform);
4340 }
4341 return rc;
4342 }
4343
Dim2dPoint(int point_index,double default_offset) const4344 ON_2dPoint ON_OrdinateDimension2::Dim2dPoint( int point_index, double default_offset) const
4345 {
4346 ON_2dPoint p2( ON_UNSET_VALUE, ON_UNSET_VALUE);
4347 int dir = m_direction;
4348 if( dir == -1 && ( point_index == offset_pt_0 || point_index == offset_pt_1))
4349 {
4350 if( fabs( m_points[definition_pt_index].y - m_points[leader_end_pt_index].y) >
4351 fabs( m_points[definition_pt_index].x - m_points[leader_end_pt_index].x))
4352 dir = 0;
4353 else
4354 dir = 1;
4355 }
4356
4357 if( point_index >= 0 && point_index < dim_pt_count && m_points.Count() == dim_pt_count)
4358 {
4359 p2 = m_points[point_index];
4360 }
4361 else if( point_index == text_pivot_pt)
4362 {
4363 // ON_UNSET_POINT
4364 }
4365 else if( point_index == offset_pt_0)
4366 {
4367 double offset;
4368 if( m_kink_offset_0 == ON_UNSET_VALUE)
4369 offset = default_offset;
4370 else
4371 offset = m_kink_offset_0;
4372
4373 if( dir == x)
4374 {
4375 p2 = m_points[leader_end_pt_index];
4376 if( p2.y > m_points[definition_pt_index].y)
4377 p2.y -= offset;
4378 else
4379 p2.y += offset;
4380 }
4381 else if( dir == y)
4382 {
4383 p2 = m_points[leader_end_pt_index];
4384 if( p2.x > m_points[definition_pt_index].x)
4385 p2.x -= offset;
4386 else
4387 p2.x += offset;
4388 }
4389 }
4390 else if( point_index == offset_pt_1)
4391 {
4392 double offset0;
4393 if( m_kink_offset_0 == ON_UNSET_VALUE)
4394 offset0 = default_offset;
4395 else
4396 offset0 = m_kink_offset_0;
4397
4398 double offset1;
4399 if( m_kink_offset_1 == ON_UNSET_VALUE)
4400 offset1 = default_offset;
4401 else
4402 offset1 = m_kink_offset_1;
4403
4404 if( dir == x)
4405 {
4406 p2.x = m_points[definition_pt_index].x;
4407 if( m_points[leader_end_pt_index].y > m_points[definition_pt_index].y)
4408 p2.y = m_points[leader_end_pt_index].y - offset0 - offset1;
4409 else
4410 p2.y = m_points[leader_end_pt_index].y + offset0 + offset1;
4411 }
4412 else if( dir == y)
4413 {
4414 p2.y = m_points[definition_pt_index].y;
4415 if( m_points[leader_end_pt_index].x > m_points[definition_pt_index].x)
4416 p2.x = m_points[leader_end_pt_index].x - offset0 - offset1;
4417 else
4418 p2.x = m_points[leader_end_pt_index].x + offset0 + offset1;
4419 }
4420 }
4421 return p2;
4422 }
4423
Dim3dPoint(int point_index,double default_offset) const4424 ON_3dPoint ON_OrdinateDimension2::Dim3dPoint( int point_index, double default_offset) const
4425 {
4426 ON_2dPoint p2 = Dim2dPoint(point_index, default_offset);
4427 return (ON_UNSET_VALUE == p2.x) ? ON_UNSET_POINT : m_plane.PointAt(p2.x,p2.y);
4428 }
4429
IsValid(ON_TextLog * text_log) const4430 ON_BOOL32 ON_OrdinateDimension2::IsValid( ON_TextLog* text_log) const
4431 {
4432 if ( m_type != ON::dtDimOrdinate)
4433 {
4434 if ( text_log )
4435 {
4436 text_log->Print("ON_OrdinateDimension2 - m_type != ON::dtDimOrdinate.\n");
4437 }
4438 return false;
4439 }
4440
4441 if ( !ON_Annotation2::IsValid( text_log ))
4442 {
4443 if ( text_log )
4444 {
4445 text_log->Print("ON_OrdinateDimension2 - invalid ON_Annotation2 base class.\n");
4446 }
4447 return false;
4448 }
4449
4450 if ( m_points.Count() != 2 )
4451 {
4452 if ( text_log )
4453 {
4454 text_log->Print("ON_OrdinateDimension2 - m_points.Count() = %d (should be 2).\n",m_points.Count());
4455 }
4456 return false;
4457 }
4458
4459 return true;
4460
4461 }
4462
Write(ON_BinaryArchive & file) const4463 ON_BOOL32 ON_OrdinateDimension2::Write( ON_BinaryArchive& file ) const
4464 {
4465 // put the entire ON_OrdinateDimension2 in a chunk so we can
4466 // add fields without breaking the file IO for old product.
4467 bool rc = file.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,1);
4468 if (rc)
4469 {
4470 rc = file.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0);
4471 if (rc)
4472 {
4473 // As of 18 October 2007, the following comment is out of date.
4474 // But, we still need to write this "extra" chunk so we don't
4475 // break V4 file writing.
4476 //
4477 // The output of ON_Annotation2::Write must be wrapped
4478 // in an additional chunk because it does not put
4479 // itself in a chunk. If you don't put it in a chunk,
4480 // the versioning in the ON_Annotation2::Write is useless and
4481 // will cause serious IO bugs if fields are ever added.
4482 rc = ON_Annotation2::Write( file) ? true : false;
4483 if (!file.EndWrite3dmChunk() )
4484 rc = false;
4485 }
4486 if (rc)
4487 rc = file.WriteInt( m_direction);
4488 // kink offsets, ver 1.1 added 2-4-06
4489 if (rc)
4490 rc = file.WriteDouble( m_kink_offset_0);
4491 if (rc)
4492 rc = file.WriteDouble( m_kink_offset_1);
4493
4494 // end of ON_OrdinateDimension2 chunk
4495 if (!file.EndWrite3dmChunk() )
4496 rc = false;
4497 }
4498
4499 return rc;
4500 }
4501
Read(ON_BinaryArchive & file)4502 ON_BOOL32 ON_OrdinateDimension2::Read( ON_BinaryArchive& file )
4503 {
4504 int major_version=0, minor_version=0;
4505 bool rc = file.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version);
4506 if (rc)
4507 {
4508 if ( 1 != major_version )
4509 {
4510 rc = false;
4511 }
4512 else
4513 {
4514 int submajor_version=0, subminor_version=0;
4515
4516 // subchunk wraps ON_Annotation2 field so this
4517 // function won't break if ON_Annotation2 changes.
4518 rc = file.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&submajor_version,&subminor_version);
4519 if (rc)
4520 {
4521 if ( 1 != submajor_version )
4522 rc = false;
4523 else
4524 {
4525 rc = ON_Annotation2::Read( file) ? true : false;
4526 }
4527 if ( !file.EndRead3dmChunk() )
4528 rc = false;
4529 }
4530
4531 if( rc)
4532 rc = file.ReadInt( &m_direction);
4533
4534 if( minor_version > 0)
4535 {
4536 if( rc)
4537 rc = file.ReadDouble( &m_kink_offset_0);
4538 if( rc)
4539 rc = file.ReadDouble( &m_kink_offset_1);
4540 }
4541 }
4542
4543 if (!file.EndRead3dmChunk())
4544 rc = false;
4545 }
4546 return rc;
4547 }
4548
NumericValue() const4549 double ON_OrdinateDimension2::NumericValue() const
4550 {
4551 if( m_direction == 0)
4552 return m_points[1].x - m_points[0].x;
4553 else
4554 return m_points[1].y - m_points[0].y;
4555 }
4556
StyleIndex() const4557 int ON_OrdinateDimension2::StyleIndex() const
4558 {
4559 return ON_Annotation2::Index();
4560 }
4561
SetStyleIndex(int i)4562 void ON_OrdinateDimension2::SetStyleIndex( int i)
4563 {
4564 ON_Annotation2::SetIndex( i);
4565 }
4566
GetBBox(double * boxmin,double * boxmax,ON_BOOL32 bGrowBox) const4567 ON_BOOL32 ON_OrdinateDimension2::GetBBox( double* boxmin,
4568 double* boxmax,
4569 ON_BOOL32 bGrowBox) const
4570 {
4571 ON_BoundingBox bbox;
4572 if ( bGrowBox )
4573 {
4574 bbox.m_min.x = boxmin[0];
4575 bbox.m_min.y = boxmin[1];
4576 bbox.m_min.z = boxmin[2];
4577 bbox.m_max.x = boxmax[0];
4578 bbox.m_max.y = boxmax[1];
4579 bbox.m_max.z = boxmax[2];
4580 if ( !bbox.IsValid() )
4581 {
4582 bbox.Destroy();
4583 bGrowBox = false;
4584 }
4585 }
4586
4587 if( m_points.Count() == 2)
4588 {
4589 ON_3dPointArray P( 2);
4590
4591 P.Append( m_plane.PointAt( m_points[0].x, m_points[0].y));
4592 P.Append( m_plane.PointAt( m_points[1].x, m_points[1].y));
4593 bGrowBox = P.GetBBox(&bbox.m_min.x, &bbox.m_max.x, bGrowBox);
4594 }
4595
4596 if ( bGrowBox )
4597 {
4598 boxmin[0] = bbox.m_min.x;
4599 boxmin[1] = bbox.m_min.y;
4600 boxmin[2] = bbox.m_min.z;
4601 boxmax[0] = bbox.m_max.x;
4602 boxmax[1] = bbox.m_max.y;
4603 boxmax[2] = bbox.m_max.z;
4604 }
4605
4606 return bGrowBox;
4607 }
4608
GetTightBoundingBox(ON_BoundingBox & tight_bbox,int bGrowBox,const ON_Xform * xform) const4609 bool ON_OrdinateDimension2::GetTightBoundingBox( ON_BoundingBox& tight_bbox,
4610 int bGrowBox,
4611 const ON_Xform* xform) const
4612 {
4613 if( m_points.Count() == 2)
4614 {
4615 ON_3dPointArray P(2);
4616
4617 P.Append( m_plane.PointAt( m_points[0].x, m_points[0].y));
4618 P.Append( m_plane.PointAt( m_points[1].x, m_points[1].y));
4619
4620 if ( P.GetTightBoundingBox( tight_bbox, bGrowBox, xform))
4621 bGrowBox = true;
4622 }
4623 else if( bGrowBox && !tight_bbox.IsValid())
4624 {
4625 tight_bbox.Destroy();
4626 bGrowBox = false;
4627 }
4628
4629 return( 0 != bGrowBox);
4630 }
4631
ImpliedDirection() const4632 int ON_OrdinateDimension2::ImpliedDirection() const
4633 {
4634 int direction = -1;
4635 const ON_2dPoint& p0 = m_points[definition_pt_index];
4636 const ON_2dPoint& p1 = m_points[leader_end_pt_index];
4637 if( fabs( p1.x - p0.x) <= fabs( p1.y - p0.y))
4638 direction = 0; // measures along x axis
4639 else
4640 direction = 1; // measures along y axis
4641
4642 return direction;
4643 }
4644
Direction() const4645 int ON_OrdinateDimension2::Direction() const
4646 {
4647 return m_direction;
4648 }
4649
SetDirection(int direction)4650 void ON_OrdinateDimension2::SetDirection( int direction)
4651 {
4652 m_direction = direction;
4653 }
4654
DefaultText()4655 const wchar_t* ON_OrdinateDimension2::DefaultText() { return L"<>"; }
4656
KinkOffset(int index) const4657 double ON_OrdinateDimension2::KinkOffset( int index) const
4658 {
4659 if( index == 0)
4660 return m_kink_offset_0;
4661 else if( index == 1)
4662 return m_kink_offset_1;
4663 else
4664 return ON_UNSET_VALUE;
4665 }
4666
SetKinkOffset(int index,double offset)4667 void ON_OrdinateDimension2::SetKinkOffset( int index, double offset)
4668 {
4669 if( index == 0)
4670 m_kink_offset_0 = offset;
4671 else if( index == 1)
4672 m_kink_offset_1 = offset;
4673 }
4674
CalcKinkPoints(ON_2dPoint p0,ON_2dPoint p1,int direction,double default_offset,ON_2dPoint & k0,ON_2dPoint & k1) const4675 void ON_OrdinateDimension2::CalcKinkPoints( ON_2dPoint p0, ON_2dPoint p1,
4676 int direction, double default_offset,
4677 ON_2dPoint& k0, ON_2dPoint& k1) const
4678 {
4679 double offset0 = KinkOffset( 0);
4680 double offset1 = KinkOffset( 1);
4681
4682 // if these haven't been set by dragging the offset points
4683 // use 2*textheight
4684 if( offset0 == ON_UNSET_VALUE)
4685 offset0 = default_offset;
4686 if( offset1 == ON_UNSET_VALUE)
4687 offset1 = default_offset;
4688
4689 if( p0[1-direction] > p1[1-direction])
4690 {
4691 offset0 = -offset0;
4692 offset1 = -offset1;
4693 }
4694
4695 //double d = fabs( p0[1-direction] - p1[1-direction]);
4696
4697 if( direction == 0)
4698 {
4699 //if( d - fabs( offset0) > default_offset)
4700 //{
4701 k1.x = p0.x;
4702 k1.y = p1.y - offset0 - offset1;
4703 //}
4704 //else
4705 //{
4706 // k1.x = p0.x;
4707 // k1.y = p1.y + offset0 - offset1;
4708 //}
4709
4710 k0.x = p1.x;
4711 k0.y = p1.y - offset0;
4712 }
4713 else
4714 {
4715 //if( d - fabs( offset0) > default_offset)
4716 //{
4717 k1.x = p1.x - offset0 - offset1;
4718 k1.y = p0.y;
4719 //}
4720 //else
4721 //{
4722 // k1.x = p1.x + offset0 - offset1;
4723 // k1.y = p0.y;
4724 //}
4725
4726 k0.x = p1.x - offset0;
4727 k0.y = p1.y;
4728 }
4729 }
4730
4731
4732
4733 //----- ON_TextEntity2 -----------------------------------------------
ON_TextEntity2()4734 ON_TextEntity2::ON_TextEntity2()
4735 {
4736 m_type = ON::dtTextBlock;
4737 m_textdisplaymode = ON::dtNormal;
4738 }
4739
~ON_TextEntity2()4740 ON_TextEntity2::~ON_TextEntity2()
4741 {
4742 }
4743
IsValid(ON_TextLog * text_log) const4744 ON_BOOL32 ON_TextEntity2::IsValid( ON_TextLog* text_log ) const
4745 {
4746 if ( m_type != ON::dtTextBlock )
4747 {
4748 if ( text_log )
4749 {
4750 text_log->Print("ON_TextEntity2 - m_type != ON::dtTextBlock\n");
4751 }
4752 return false;
4753 }
4754
4755 // 05 March 2009 S. Baer
4756 // Text blocks with no "printable" characters are considered invalid. Any
4757 // character with a value greater than 32 (the value of space) is "printable."
4758 int count = m_usertext.Length();
4759 bool bValidText = false;
4760 for( int i=0; i<count; i++ )
4761 {
4762 wchar_t c = m_usertext[i];
4763 // all characters <= space are nonprintable
4764 if( c > L' ' )
4765 {
4766 bValidText = true;
4767 break;
4768 }
4769 }
4770 // 9 Oct 2010 S. Baer
4771 // With the addition of text formulas, the user text can be 0 length
4772 if( !bValidText && count<1 )
4773 {
4774 const wchar_t* formula = TextFormula();
4775 if( formula && formula[0] )
4776 bValidText = true;
4777 }
4778
4779 if( !bValidText )
4780 {
4781 if( text_log )
4782 {
4783 text_log->Print("ON_TextEntity2 - m_usertext does not contain printable characters.\n");
4784 }
4785 return false;
4786 }
4787
4788
4789 if ( !ON_Annotation2::IsValid( text_log ))
4790 {
4791 if ( text_log )
4792 {
4793 text_log->Print("ON_TextEntity2 - invalid ON_Annotation2 base class.\n");
4794 }
4795 return false;
4796 }
4797
4798 if ( 0 != m_points.Count() )
4799 {
4800 if ( text_log )
4801 {
4802 text_log->Print("ON_TextEntity2 - m_points.Count() = %d (should be 0)\n", m_points.Count() );
4803 }
4804 return false;
4805 }
4806
4807 return true;
4808 }
4809
4810
Write(ON_BinaryArchive & archive) const4811 ON_BOOL32 ON_TextEntity2::Write(ON_BinaryArchive& archive) const
4812 {
4813 // 18 October 2007 Dale Lear
4814 // I added the chunk wrapping so V5 and future versions can
4815 // add IO support for information specific to ON_TextEntity2
4816 // V4 did not have a ON_TextEntity2::Write and simply called
4817 // ON_Annotation2::Write.
4818 bool rc = false;
4819 bool bInChunk = (archive.Archive3dmVersion() >= 5);
4820 if ( bInChunk )
4821 {
4822 rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0);
4823 if ( !rc )
4824 return false;
4825 }
4826 else
4827 {
4828 rc = true;
4829 }
4830
4831 while(rc)
4832 {
4833 rc = ON_Annotation2::Write(archive)?true:false;
4834 if (!rc) break;
4835 if ( !bInChunk )
4836 break;
4837
4838 // To write new fields, increment minor version number
4839 // and write values here. Ask Dale Lear for help.
4840
4841 break;
4842 }
4843
4844 if ( bInChunk )
4845 {
4846 if (!archive.EndWrite3dmChunk())
4847 rc = false;
4848 }
4849 return rc;
4850 }
4851
Read(ON_BinaryArchive & archive)4852 ON_BOOL32 ON_TextEntity2::Read(ON_BinaryArchive& archive)
4853 {
4854 // 18 October 2007 Dale Lear
4855 // I added the chunk wrapping so V5 and future versions can
4856 // add IO support for information specific to ON_TextEntity2
4857 int major_version = 0;
4858 int minor_version = 0;
4859 bool rc = false;
4860 bool bInChunk = (archive.Archive3dmVersion() >= 5 && archive.ArchiveOpenNURBSVersion() >= 200710180);
4861 if ( bInChunk )
4862 {
4863 rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version);
4864 if ( !rc )
4865 return false;
4866 }
4867 else
4868 {
4869 rc = true;
4870 }
4871
4872 while(rc)
4873 {
4874 rc = ON_Annotation2::Read(archive)?true:false;
4875 if (!rc) break;
4876 if ( !bInChunk || minor_version <= 0 )
4877 break;
4878
4879 // read future addition here
4880
4881 break;
4882 }
4883
4884 if ( bInChunk )
4885 {
4886 // To read new ON_TextEntity2 specific additions,
4887 // examine the minor version number and read the information
4888 // here. Please ask Dale Lear for help.
4889
4890 if ( !archive.EndRead3dmChunk() )
4891 rc = false;
4892 }
4893 return rc;
4894 }
4895
4896
GetBBox(double * boxmax,double * boxmin,ON_BOOL32 bGrowBox) const4897 ON_BOOL32 ON_TextEntity2::GetBBox(
4898 double* boxmax,
4899 double* boxmin,
4900 ON_BOOL32 bGrowBox
4901 ) const
4902 {
4903 ON_BoundingBox bbox;
4904 if ( bGrowBox )
4905 {
4906 bbox.m_min.x = boxmin[0];
4907 bbox.m_min.y = boxmin[1];
4908 bbox.m_min.z = boxmin[2];
4909 bbox.m_max.x = boxmax[0];
4910 bbox.m_max.y = boxmax[1];
4911 bbox.m_max.z = boxmax[2];
4912 if ( !bbox.IsValid() )
4913 {
4914 bbox.Destroy();
4915 bGrowBox = false;
4916 }
4917 }
4918
4919 if ( 1 == m_points.Count() )
4920 {
4921 ON_2dPoint uv = m_points[0];
4922 bbox.Set( m_plane.PointAt(uv.x,uv.y), bGrowBox );
4923 bGrowBox = true;
4924 }
4925 else if ( 0 == m_points.Count() )
4926 {
4927 bbox.Set( m_plane.origin, bGrowBox );
4928 bGrowBox = true;
4929 }
4930
4931 if ( bGrowBox )
4932 {
4933 boxmin[0] = bbox.m_min.x;
4934 boxmin[1] = bbox.m_min.y;
4935 boxmin[2] = bbox.m_min.z;
4936 boxmax[0] = bbox.m_max.x;
4937 boxmax[1] = bbox.m_max.y;
4938 boxmax[2] = bbox.m_max.z;
4939 }
4940
4941 return bGrowBox;
4942 }
4943
4944
4945
4946
4947
GetTightBoundingBox(ON_BoundingBox & tight_bbox,int bGrowBox,const ON_Xform * xform) const4948 bool ON_TextEntity2::GetTightBoundingBox(
4949 ON_BoundingBox& tight_bbox,
4950 int bGrowBox,
4951 const ON_Xform* xform
4952 ) const
4953 {
4954 if ( 1 == m_points.Count() )
4955 {
4956 ON_3dPointArray P(1);
4957 P.Append( m_plane.PointAt(m_points[0].x,m_points[0].y) );
4958 if ( P.GetTightBoundingBox( tight_bbox, bGrowBox, xform ) )
4959 bGrowBox = true;
4960 }
4961 else if ( bGrowBox && !tight_bbox.IsValid() )
4962 {
4963 tight_bbox.Destroy();
4964 bGrowBox = false;
4965 }
4966
4967 return (0!=bGrowBox);
4968 }
4969
FontIndex() const4970 int ON_TextEntity2::FontIndex() const
4971 {
4972 return m_index;
4973 }
4974
SetFontIndex(int i)4975 void ON_TextEntity2::SetFontIndex( int i)
4976 {
4977 m_index = i;
4978 }
4979
Transform(const ON_Xform & xform)4980 ON_BOOL32 ON_TextEntity2::Transform( const ON_Xform& xform )
4981 {
4982 // Dale Lear - this override fixes RR 11114 by correctly
4983 // handling non uniform scaling.
4984 bool rc = xform.IsIdentity();
4985 if ( !rc)
4986 {
4987 ON_Plane xformed_plane = m_plane;
4988 rc = xformed_plane.Transform(xform);
4989 if (rc)
4990 rc = ON_Geometry::Transform(xform)?true:false;
4991 if (rc)
4992 {
4993 ON_3dPoint P0 = xform*m_plane.origin;
4994 ON_3dPoint P1 = xform*(m_plane.origin + m_plane.xaxis);
4995 double s = P0.DistanceTo(P1);
4996 if ( s <= ON_ZERO_TOLERANCE )
4997 {
4998 P1 = xform*(m_plane.origin + m_plane.yaxis);
4999 s = P0.DistanceTo(P1);
5000 }
5001 m_plane = xformed_plane;
5002 if ( s > ON_ZERO_TOLERANCE && fabs(s-1.0) > ON_SQRT_EPSILON )
5003 {
5004 s *= m_textheight;
5005 if ( s > ON_SQRT_EPSILON )
5006 m_textheight = s;
5007 }
5008 }
5009 }
5010
5011 return rc;
5012 }
5013
5014
5015
5016 // 6-23-03 lw Added v2 file writing of annotation
GetV2Form(ON_TextEntity & text)5017 void ON_TextEntity2::GetV2Form( ON_TextEntity& text)
5018 {
5019 ON_Annotation2::ConvertBack( text);
5020 text.SetHeight( Height());
5021 // 8-20-03 lw convert from lower-left to upper-left reference point
5022 ON_Plane plane = Plane();
5023 plane.origin += plane.yaxis * 1.1 * m_textheight;
5024 plane.UpdateEquation();
5025 text.SetPlane( plane);
5026 }
5027
SetJustification(unsigned int justification)5028 void ON_TextEntity2::SetJustification( unsigned int justification)
5029 {
5030 m_justification = justification;
5031 }
5032
Justification()5033 unsigned int ON_TextEntity2::Justification()
5034 {
5035 return m_justification;
5036 }
5037
DrawTextMask() const5038 bool ON_TextEntity2::DrawTextMask() const
5039 {
5040 const ON_TextExtra* pTE = ON_TextExtra::TextExtension(this, false);
5041 if(pTE)
5042 return pTE->DrawTextMask();
5043 else
5044 return false;
5045 }
5046
SetDrawTextMask(bool bDraw)5047 void ON_TextEntity2::SetDrawTextMask(bool bDraw)
5048 {
5049 ON_TextExtra* pTE = ON_TextExtra::TextExtension(this, true);
5050 if(pTE)
5051 pTE->SetDrawTextMask(bDraw);
5052 }
5053
MaskColorSource() const5054 int ON_TextEntity2::MaskColorSource() const
5055 {
5056 const ON_TextExtra* pTE = ON_TextExtra::TextExtension(this, false);
5057 if(pTE)
5058 return pTE->MaskColorSource();
5059 else
5060 return 0;
5061 }
5062
SetMaskColorSource(int source)5063 void ON_TextEntity2::SetMaskColorSource(int source)
5064 {
5065 ON_TextExtra* pTE = ON_TextExtra::TextExtension(this, true);
5066 if(pTE)
5067 pTE->SetMaskColorSource(source);
5068 }
5069
MaskColor() const5070 ON_Color ON_TextEntity2::MaskColor() const
5071 {
5072 const ON_TextExtra* pTE = ON_TextExtra::TextExtension(this, false);
5073 if(pTE)
5074 return pTE->MaskColor();
5075 else
5076 return 0;
5077 }
5078
SetMaskColor(ON_Color color)5079 void ON_TextEntity2::SetMaskColor(ON_Color color)
5080 {
5081 ON_TextExtra* pTE = ON_TextExtra::TextExtension(this, true);
5082 if(pTE)
5083 pTE->SetMaskColor(color);
5084 }
5085
MaskOffsetFactor() const5086 double ON_TextEntity2::MaskOffsetFactor() const
5087 {
5088 const ON_TextExtra* pTE = ON_TextExtra::TextExtension(this, false);
5089 if(pTE)
5090 return pTE->MaskOffsetFactor();
5091 else
5092 return 0;
5093 }
5094
SetMaskOffsetFactor(double offset)5095 void ON_TextEntity2::SetMaskOffsetFactor(double offset)
5096 {
5097 ON_TextExtra* pTE = ON_TextExtra::TextExtension(this, true);
5098 if(pTE)
5099 pTE->SetMaskOffsetFactor(offset);
5100 }
5101
AnnotativeScaling() const5102 bool ON_TextEntity2::AnnotativeScaling() const
5103 {
5104 return m_annotative_scale;
5105 }
5106
SetAnnotativeScaling(bool b)5107 void ON_TextEntity2::SetAnnotativeScaling(bool b)
5108 {
5109 m_annotative_scale = b;
5110 }
5111
5112
5113
5114 //----- ON_Leader2 ------------------------------------------
ON_Leader2()5115 ON_Leader2::ON_Leader2()
5116 {
5117 m_type = ON::dtLeader;
5118 m_textdisplaymode = ON::dtInLine;
5119 }
5120
~ON_Leader2()5121 ON_Leader2::~ON_Leader2()
5122 {
5123 }
5124
IsValid(ON_TextLog * text_log) const5125 ON_BOOL32 ON_Leader2::IsValid( ON_TextLog* text_log ) const
5126 {
5127 if ( m_type != ON::dtLeader )
5128 {
5129 if ( text_log )
5130 {
5131 text_log->Print("ON_Leader2 - m_type != ON::dtLeader\n");
5132 }
5133 return false;
5134 }
5135
5136 if ( !ON_Annotation2::IsValid( text_log ))
5137 {
5138 if ( text_log )
5139 {
5140 text_log->Print("ON_Leader2 - invalid ON_Annotation2 base class.\n");
5141 }
5142 return false;
5143 }
5144
5145 if ( m_points.Count() < 2 )
5146 {
5147 if ( text_log )
5148 {
5149 text_log->Print("ON_Leader2 - m_points.Count() = %d (should be >= 2)\n", m_points.Count() );
5150 }
5151 return false;
5152 }
5153
5154 return true;
5155 }
5156
Write(ON_BinaryArchive & archive) const5157 ON_BOOL32 ON_Leader2::Write(ON_BinaryArchive& archive) const
5158 {
5159 // 18 October 2007 Dale Lear
5160 // I added the chunk wrapping so V5 and future versions can
5161 // add IO support for information specific to ON_Leader2
5162 // V4 did not have a ON_Leader2::Write and simply called
5163 // ON_Leader2::Write.
5164 bool rc = false;
5165 bool bInChunk = (archive.Archive3dmVersion() >= 5);
5166 if ( bInChunk )
5167 {
5168 rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0);
5169 if ( !rc )
5170 return false;
5171 }
5172 else
5173 {
5174 rc = true;
5175 }
5176
5177 while(rc)
5178 {
5179 rc = ON_Annotation2::Write(archive)?true:false;
5180 if (!rc) break;
5181 if ( !bInChunk )
5182 break;
5183
5184 // To write new fields, increment minor version number
5185 // and write values here. Ask Dale Lear for help.
5186
5187 break;
5188 }
5189
5190 if ( bInChunk )
5191 {
5192 if (!archive.EndWrite3dmChunk())
5193 rc = false;
5194 }
5195 return rc;
5196 }
5197
Read(ON_BinaryArchive & archive)5198 ON_BOOL32 ON_Leader2::Read(ON_BinaryArchive& archive)
5199 {
5200 // 18 October 2007 Dale Lear
5201 // I added the chunk wrapping so V5 and future versions can
5202 // add IO support for information specific to ON_Leader2
5203 int major_version = 0;
5204 int minor_version = 0;
5205 bool rc = false;
5206 bool bInChunk = (archive.Archive3dmVersion() >= 5 && archive.ArchiveOpenNURBSVersion() >= 200710180);
5207 if ( bInChunk )
5208 {
5209 rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version);
5210 if ( !rc )
5211 return false;
5212 }
5213 else
5214 {
5215 rc = true;
5216 }
5217
5218 while(rc)
5219 {
5220 rc = ON_Annotation2::Read(archive)?true:false;
5221 if (!rc) break;
5222 if ( !bInChunk || minor_version <= 0 )
5223 break;
5224
5225 // read future addition here
5226
5227 break;
5228 }
5229
5230 if ( bInChunk )
5231 {
5232 if ( !archive.EndRead3dmChunk() )
5233 rc = false;
5234 }
5235 return rc;
5236 }
5237
GetBBox(double * boxmax,double * boxmin,ON_BOOL32 bGrowBox) const5238 ON_BOOL32 ON_Leader2::GetBBox(
5239 double* boxmax,
5240 double* boxmin,
5241 ON_BOOL32 bGrowBox
5242 ) const
5243 {
5244 ON_BoundingBox bbox;
5245 if ( bGrowBox )
5246 {
5247 bbox.m_min.x = boxmin[0];
5248 bbox.m_min.y = boxmin[1];
5249 bbox.m_min.z = boxmin[2];
5250 bbox.m_max.x = boxmax[0];
5251 bbox.m_max.y = boxmax[1];
5252 bbox.m_max.z = boxmax[2];
5253 if ( !bbox.IsValid() )
5254 {
5255 bbox.Destroy();
5256 bGrowBox = false;
5257 }
5258 }
5259
5260 const int point_count = m_points.Count();
5261 if ( point_count > 0 )
5262 {
5263 ON_3dPointArray P(point_count);
5264 int i;
5265 for ( i = 0; i < point_count; i++ )
5266 {
5267 ON_2dPoint uv = m_points[i];
5268 P.Append( m_plane.PointAt(uv.x,uv.y));
5269 }
5270 if ( P.GetBoundingBox(bbox,bGrowBox?true:false) )
5271 bGrowBox = true;
5272 }
5273
5274 if ( bGrowBox )
5275 {
5276 boxmin[0] = bbox.m_min.x;
5277 boxmin[1] = bbox.m_min.y;
5278 boxmin[2] = bbox.m_min.z;
5279 boxmax[0] = bbox.m_max.x;
5280 boxmax[1] = bbox.m_max.y;
5281 boxmax[2] = bbox.m_max.z;
5282 }
5283
5284 return bGrowBox;
5285 }
5286
5287
5288
GetTightBoundingBox(ON_BoundingBox & tight_bbox,int bGrowBox,const ON_Xform * xform) const5289 bool ON_Leader2::GetTightBoundingBox(
5290 ON_BoundingBox& tight_bbox,
5291 int bGrowBox,
5292 const ON_Xform* xform
5293 ) const
5294 {
5295 const int point_count = m_points.Count();
5296 if ( point_count >= 2 )
5297 {
5298 ON_3dPointArray P(point_count);
5299 int i;
5300 for ( i = 0; i < point_count; i++ )
5301 {
5302 ON_2dPoint uv = m_points[i];
5303 P.Append( m_plane.PointAt(uv.x,uv.y));
5304 }
5305 if ( P.GetTightBoundingBox( tight_bbox, bGrowBox, xform ) )
5306 bGrowBox = true;
5307 }
5308 else if ( bGrowBox && !tight_bbox.IsValid() )
5309 {
5310 tight_bbox.Destroy();
5311 bGrowBox = false;
5312 }
5313
5314 return (0!=bGrowBox);
5315 }
5316
Dim2dPoint(int point_index) const5317 ON_2dPoint ON_Leader2::Dim2dPoint(
5318 int point_index
5319 ) const
5320 {
5321 ON_2dPoint p2;
5322 int point_count = m_points.Count();
5323 if ( point_index < 0 || point_count < 1 )
5324 {
5325 p2.x = p2.y = ON_UNSET_VALUE;
5326 }
5327 else
5328 {
5329 switch(point_index)
5330 {
5331 case arrow_pt_index:
5332 p2 = m_points[0];
5333 break;
5334
5335 case text_pivot_pt:
5336 case tail_pt:
5337 p2 = *m_points.Last();
5338 break;
5339
5340 default:
5341 if ( point_index < point_count )
5342 {
5343 p2 = m_points[point_index];
5344 }
5345 else
5346 {
5347 p2.x = p2.y = ON_UNSET_VALUE;
5348 }
5349 break;
5350 }
5351 }
5352 return p2;
5353 }
5354
Dim3dPoint(int point_index) const5355 ON_3dPoint ON_Leader2::Dim3dPoint(
5356 int point_index
5357 ) const
5358 {
5359 ON_2dPoint p2 = Dim2dPoint(point_index);
5360 return (ON_UNSET_VALUE == p2.x) ? ON_UNSET_POINT : m_plane.PointAt(p2.x,p2.y);
5361 }
5362
5363
AddPoint(const ON_2dPoint & point)5364 void ON_Leader2::AddPoint( const ON_2dPoint& point )
5365 {
5366 m_points.Append( point);
5367
5368 }
5369
RemovePoint(int idx)5370 bool ON_Leader2::RemovePoint( int idx )
5371 {
5372 bool rc = true;
5373 if( idx == -1) // -1 removes the last point
5374 {
5375 m_points.Remove();
5376 }
5377 else if( idx >= 0 && idx < m_points.Count())
5378 {
5379 m_points.Remove( idx);
5380 }
5381 else
5382 {
5383 rc = false;
5384 }
5385
5386 return rc;
5387 }
5388
5389 // April 22, 2010 Lowell - Added to support right justified text on left pointing leader tails rr64292
GetTextDirection(ON_2dVector & text_dir) const5390 bool ON_Leader2::GetTextDirection( ON_2dVector& text_dir ) const
5391 {
5392 bool rc = false;
5393 const int point_count = m_points.Count();
5394 if ( point_count < 2 )
5395 {
5396 text_dir.Set(-1.0,0.0);
5397 }
5398 else
5399 {
5400 int i; // 20 June 2011 Fixed textdir for leaders with 2 points. rr86801
5401 for(i = point_count-1; i >= 1; i--)
5402 {
5403 text_dir = m_points[point_count-1] - m_points[i-1];
5404 if(text_dir.Unitize())
5405 {
5406 rc = true;
5407 break;
5408 }
5409 text_dir.Set(-1.0,0.0);
5410 }
5411 }
5412 return rc;
5413 }
5414
GetArrowHeadDirection(ON_2dVector & arrowhead_dir) const5415 bool ON_Leader2::GetArrowHeadDirection( ON_2dVector& arrowhead_dir ) const
5416 {
5417 bool rc = false;
5418 const int point_count = m_points.Count();
5419 if ( point_count < 2 )
5420 {
5421 arrowhead_dir.Set(-1.0,0.0);
5422 }
5423 else
5424 {
5425 int i;
5426 for ( i = 1; i < point_count; i++ )
5427 {
5428 arrowhead_dir = m_points[0] - m_points[i];
5429 if ( arrowhead_dir.Unitize() )
5430 {
5431 rc = true;
5432 break;
5433 }
5434 arrowhead_dir.Set(-1.0,0.0);
5435 }
5436 }
5437 return rc;
5438 }
5439
GetArrowHeadTip(ON_2dPoint & arrowhead_tip) const5440 bool ON_Leader2::GetArrowHeadTip( ON_2dPoint& arrowhead_tip ) const
5441 {
5442 bool rc = false;
5443 switch( m_points.Count())
5444 {
5445 case 0:
5446 arrowhead_tip.Set(0.0,0.0);
5447 break;
5448 case 1:
5449 arrowhead_tip = m_points[0];
5450 break;
5451 default:
5452 arrowhead_tip = m_points[0];
5453 rc = true;
5454 break;
5455 }
5456 return rc;
5457 }
5458
5459
5460
GetArrowHeadDirection(ON_2dVector & arrowhead_dir) const5461 bool ON_RadialDimension2::GetArrowHeadDirection( ON_2dVector& arrowhead_dir ) const
5462 {
5463 bool rc = false;
5464 if ( m_points.Count() < 4 )
5465 {
5466 arrowhead_dir.Set(-1.0,0.0);
5467 }
5468 else
5469 {
5470 arrowhead_dir = m_points[1] - m_points[3];
5471 if ( 0 == (rc=arrowhead_dir.Unitize()) )
5472 {
5473 arrowhead_dir = m_points[1] - m_points[2];
5474 if ( 0 == (rc=arrowhead_dir.Unitize()) )
5475 {
5476 arrowhead_dir = m_points[0] - m_points[1];
5477 rc = arrowhead_dir.Unitize();
5478 }
5479 }
5480 }
5481 return rc;
5482 }
5483
GetArrowHeadTip(ON_2dPoint & arrowhead_tip) const5484 bool ON_RadialDimension2::GetArrowHeadTip( ON_2dPoint& arrowhead_tip ) const
5485 {
5486 bool rc = false;
5487 if ( m_points.Count() >= 2 )
5488 {
5489 arrowhead_tip = m_points[1];
5490 rc = true;
5491 }
5492 else
5493 {
5494 arrowhead_tip.Set(0.0,0.0);
5495 rc = false;
5496 }
5497 return rc;
5498 }
5499
5500 // 6-23-03 lw Added v2 file writing of annotation
GetV2Form(ON_Leader & leader)5501 void ON_Leader2::GetV2Form( ON_Leader& leader)
5502 {
5503 ON_Annotation2::ConvertBack( leader);
5504 }
5505
5506
CreateFromV2(const ON_Annotation & v2_ann,const ON_3dmAnnotationSettings & settings,int dimstyle_index)5507 bool ON_Leader2::CreateFromV2(
5508 const ON_Annotation& v2_ann,
5509 const ON_3dmAnnotationSettings& settings,
5510 int dimstyle_index
5511 )
5512 {
5513 bool rc = false;
5514 if( ON::dtLeader == v2_ann.m_type && v2_ann.m_points.Count() >= 2 )
5515 {
5516 m_plane = v2_ann.m_plane;
5517 m_plane.UpdateEquation();
5518 m_points.Reserve(v2_ann.m_points.Count());
5519 m_points.SetCount(0);
5520 m_points.Append(v2_ann.m_points.Count(),v2_ann.m_points.Array());
5521 ON_2dVector v = m_points[0];
5522 SetTextValue(v2_ann.UserText());
5523 SetTextFormula(0);
5524 m_userpositionedtext = false;
5525 m_textdisplaymode = ( 2 == settings.m_textalign )
5526 ? ON::dtHorizontal
5527 : ON::dtInLine;
5528 m_type = ON::dtLeader;
5529 m_index = dimstyle_index;
5530
5531 if ( !v.IsZero() )
5532 {
5533 m_plane.origin = m_plane.PointAt(v.x,v.y);
5534 m_plane.UpdateEquation();
5535 v.Reverse();
5536 int i;
5537 for ( i = 1; i < m_points.Count(); i++ )
5538 {
5539 m_points[i] += v;
5540 }
5541 m_points[0].Set(0.0,0.0);
5542 }
5543 rc = true;
5544 }
5545 return rc;
5546 }
5547
5548
5549 // class ON_TextDot
5550 //--------------------------------------------------------------------
ON_TextDot()5551 ON_TextDot::ON_TextDot() :
5552 m_point( ON_origin), m_height( 14), m_text( L'1'),
5553 m_fontface( L"Arial bold"), m_display( 0)
5554 {
5555 }
5556
~ON_TextDot()5557 ON_TextDot::~ON_TextDot()
5558 {
5559 }
5560
EmergencyDestroy()5561 void ON_TextDot::EmergencyDestroy()
5562 {
5563 m_text.EmergencyDestroy();
5564 m_fontface.EmergencyDestroy();
5565 m_point = ON_origin;
5566 m_height = 0;
5567 m_display = 0;
5568 }
5569
IsValid(ON_TextLog * text_log) const5570 ON_BOOL32 ON_TextDot::IsValid(
5571 ON_TextLog* text_log
5572 ) const
5573 {
5574 // 5/6/03 LW made dots with no text valid.
5575 if ( !m_point.IsValid() )
5576 {
5577 if ( 0 != text_log )
5578 {
5579 text_log->Print("ON_TextDot m_point is not valid\n");
5580 }
5581 return false;
5582 }
5583 return true;
5584 }
5585
Dump(ON_TextLog & log) const5586 void ON_TextDot::Dump( ON_TextLog& log) const
5587 {
5588 log.Print("ON_TextDot \"%ls\" at ",m_text.Array());
5589 log.Print( m_point); // ON_Geometry 3d location
5590 log.Print("\n");
5591 }
5592
Write(ON_BinaryArchive & file) const5593 ON_BOOL32 ON_TextDot::Write( ON_BinaryArchive& file) const
5594 {
5595 ON_BOOL32 rc = file.Write3dmChunkVersion(1,0);
5596 if (rc) rc = file.WritePoint( m_point );
5597 if (rc) rc = file.WriteInt( m_height);
5598 if (rc) rc = file.WriteString( m_text);
5599 if (rc) rc = file.WriteString( m_fontface);
5600 if (rc) rc = file.WriteInt( m_display);
5601
5602 return rc;
5603 }
5604
Read(ON_BinaryArchive & file)5605 ON_BOOL32 ON_TextDot::Read( ON_BinaryArchive& file)
5606 {
5607 m_text.Empty();
5608 int major_version = 0;
5609 int minor_version = 0;
5610 ON_BOOL32 rc = file.Read3dmChunkVersion(&major_version,&minor_version);
5611 if ( major_version == 1 ) {
5612 if (rc) rc = file.ReadPoint( m_point);
5613 if (rc) rc = file.ReadInt( &m_height);
5614 if (rc) rc = file.ReadString( m_text);
5615 if (rc) rc = file.ReadString( m_fontface);
5616 if (rc) rc = file.ReadInt( &m_display);
5617 }
5618 else {
5619 rc = false;
5620 }
5621 return rc;
5622 }
5623
ObjectType() const5624 ON::object_type ON_TextDot::ObjectType() const
5625 {
5626 return ON::text_dot;
5627 }
5628
Dimension() const5629 int ON_TextDot::Dimension() const
5630 {
5631 return 3;
5632 }
5633
GetBBox(double * box_min,double * box_max,ON_BOOL32 grow_box) const5634 ON_BOOL32 ON_TextDot::GetBBox( double* box_min, double* box_max, ON_BOOL32 grow_box /*= false*/) const
5635 {
5636 return ON_GetPointListBoundingBox( 3, 0, 1, 3, &m_point.x, box_min, box_max, grow_box?true:false );
5637 }
5638
Transform(const ON_Xform & xform)5639 ON_BOOL32 ON_TextDot::Transform( const ON_Xform& xform)
5640 {
5641 TransformUserData( xform);
5642 return ON_TransformPointList( 3, 0, 1, 3, &m_point.x, xform);
5643 }
5644
IsDeformable() const5645 bool ON_TextDot::IsDeformable() const
5646 {
5647 return true;
5648 }
5649
MakeDeformable()5650 bool ON_TextDot::MakeDeformable()
5651 {
5652 return true;
5653 }
5654
Point() const5655 const ON_3dPoint& ON_TextDot::Point() const
5656 {
5657 return m_point;
5658 }
5659
SetPoint(const ON_3dPoint & point)5660 void ON_TextDot::SetPoint( const ON_3dPoint& point)
5661 {
5662 m_point = point;
5663 }
5664
Height() const5665 int ON_TextDot::Height() const
5666 {
5667 return m_height;
5668 }
5669
SetHeight(int height)5670 void ON_TextDot::SetHeight( int height)
5671 {
5672 if( height > 2)
5673 m_height = height;
5674 }
5675
TextString() const5676 const wchar_t* ON_TextDot::TextString() const
5677 {
5678 if( m_text.IsEmpty())
5679 return L"";
5680 else
5681 return m_text;
5682 }
5683
SetTextString(const wchar_t * string)5684 void ON_TextDot::SetTextString( const wchar_t* string)
5685 {
5686 m_text.Empty();
5687 if( string)
5688 {
5689 int len = (int)wcslen(string);
5690 wchar_t* str = 0;
5691 if(len > 0 && string[len-1] <= L' ')
5692 {
5693 // trim off trailing white space
5694 str = (wchar_t*)onmalloc((len+1)*sizeof(wchar_t));
5695 int j = 0;
5696 for(int i = 0; i < len; i++)
5697 {
5698 if(string[i] == L'\r' || string[i] == L'\n')
5699 continue;
5700 str[j++] = string[i];
5701 }
5702 str[j] = 0;
5703 // wcscpy(str, string);
5704
5705 for(int i = len-1; i >= 0 && str[i] <= L' '; i--)
5706 str[i] = 0;
5707 }
5708 if(str)
5709 {
5710 if(wcslen(str) > 0)
5711 m_text = str;
5712 onfree(str);
5713 }
5714 else
5715 m_text = string;
5716 }
5717 }
5718
FontFace() const5719 const wchar_t* ON_TextDot::FontFace() const
5720 {
5721 if( m_fontface.IsEmpty())
5722 return L"";
5723 else
5724 return m_fontface;
5725 }
5726
SetFontFace(const wchar_t * face)5727 void ON_TextDot::SetFontFace( const wchar_t* face)
5728 {
5729 if( face)
5730 m_fontface = face;
5731 else
5732 m_fontface.Empty();
5733 }
5734
SetAlwaysOnTop(bool bTop)5735 void ON_TextDot::SetAlwaysOnTop(bool bTop)
5736 {
5737 if(bTop)
5738 m_display |= 1;
5739 else
5740 m_display &= (~1);
5741 }
5742
AlwaysOnTop() const5743 bool ON_TextDot::AlwaysOnTop() const
5744 {
5745 return (m_display & 1) == 1;
5746 }
5747
SetTransparent(bool bTransparent)5748 void ON_TextDot::SetTransparent(bool bTransparent)
5749 {
5750 if(bTransparent)
5751 m_display |= 2;
5752 else
5753 m_display &= (~2);
5754 }
5755
Transparent() const5756 bool ON_TextDot::Transparent() const
5757 {
5758 return (m_display & 2) == 2;
5759 }
5760
SetBold(bool bBold)5761 void ON_TextDot::SetBold(bool bBold)
5762 {
5763 if(bBold)
5764 m_display |= 4;
5765 else
5766 m_display &= (~4);
5767 }
5768
Bold() const5769 bool ON_TextDot::Bold() const
5770 {
5771 return (m_display & 4) == 4;
5772 }
5773
SetItalic(bool bItalic)5774 void ON_TextDot::SetItalic(bool bItalic)
5775 {
5776 if(bItalic)
5777 m_display |= 8;
5778 else
5779 m_display &= (~8);
5780 }
5781
Italic() const5782 bool ON_TextDot::Italic() const
5783 {
5784 return (m_display & 8) == 8;
5785 }
5786
5787
5788
5789
ON_Annotation2Text()5790 ON_Annotation2Text::ON_Annotation2Text()
5791 {
5792 memset(&m_rect,0,sizeof(m_rect));
5793 }
5794
~ON_Annotation2Text()5795 ON_Annotation2Text::~ON_Annotation2Text()
5796 {
5797 }
5798
operator =(const char * s)5799 ON_Annotation2Text& ON_Annotation2Text::operator=(const char* s)
5800 {
5801 SetText(s);
5802 return *this;
5803 }
5804
operator =(const wchar_t * s)5805 ON_Annotation2Text& ON_Annotation2Text::operator=(const wchar_t* s)
5806 {
5807 SetText(s);
5808 return *this;
5809 }
5810
SetText(const char * s)5811 void ON_Annotation2Text::SetText(const char* s)
5812 {
5813 ON_wString::operator=(s);
5814 memset(&m_rect,0,sizeof(m_rect));
5815 }
5816
SetText(const wchar_t * s)5817 void ON_Annotation2Text::SetText(const wchar_t* s)
5818 {
5819 ON_wString::operator=(s);
5820 memset(&m_rect,0,sizeof(m_rect));
5821 }
5822
GetTextXform(ON_RECT gdi_text_rect,const ON_Font & font,const ON_DimStyle * dimstyle,double dimscale,const ON_Viewport * vp,const ON_Xform * model_xform,ON_Xform & xform) const5823 bool ON_Annotation2::GetTextXform(
5824 ON_RECT gdi_text_rect,
5825 const ON_Font& font,
5826 const ON_DimStyle* dimstyle,
5827 double dimscale,
5828 const ON_Viewport* vp,
5829 const ON_Xform* model_xform,
5830 ON_Xform& xform
5831 ) const
5832 {
5833 int gdi_height_of_I = font.HeightOfI();
5834 const double textheight = dimstyle ? dimstyle->TextHeight() : m_textheight;
5835 double textgap = dimstyle ? dimstyle->TextGap() : 0.0;
5836 const ON::eTextDisplayMode textalignment = dimstyle ? ON::TextDisplayMode(dimstyle->TextAlignment()) : ON::dtNormal;
5837 const ON_3dVector cameraX = (vp) ? vp->CameraX() : m_plane.xaxis;
5838 const ON_3dVector cameraY = (vp) ? vp->CameraY() : m_plane.yaxis;
5839 if(dimstyle)
5840 {
5841 // SDKBREAK - Oct 4, 07 LW Get correct text gap using
5842 // multi-line tolerance text since GetTextXform doesn't do that.
5843 if(( dimstyle->ToleranceStyle() == 2 || dimstyle->ToleranceStyle() == 3) &&
5844 ( Type() == ON::dtDimLinear || Type() == ON::dtDimAligned))
5845 textgap += textheight * 0.5;
5846 }
5847 return GetTextXform(
5848 gdi_text_rect,
5849 gdi_height_of_I,
5850 textheight, textgap, textalignment,
5851 dimscale,
5852 cameraX, cameraY,
5853 model_xform,
5854 xform
5855 );
5856 }
5857
5858
5859
GetLeaderEndAndDirection(const ON_Annotation2 * pAnn,ON_2dPoint & E,ON_2dVector & R)5860 static bool GetLeaderEndAndDirection( const ON_Annotation2* pAnn,
5861 ON_2dPoint& E,
5862 ON_2dVector& R )
5863 {
5864 bool rc = false;
5865
5866 ON::eAnnotationType ann_type = pAnn->m_type;
5867 const ON_2dPointArray& ann_m_points = pAnn->m_points;
5868
5869
5870 R.Set(1.0,0.0); // unit vector points to end
5871 E.Set(0.0,0.0); // end point
5872
5873 if ( ann_m_points.Count() >= 4 && (ON::dtDimDiameter == ann_type || ON::dtDimRadius == ann_type) )
5874 {
5875 E = ann_m_points[2]; // end of radial dimension
5876 R = E - ann_m_points[3];
5877 if ( !R.Unitize() )
5878 {
5879 R = E - ann_m_points[1];
5880 if ( !R.Unitize() )
5881 {
5882 R = E - ann_m_points[0];
5883 if ( !R.Unitize() )
5884 {
5885 R.Set(1.0,0.0);
5886 }
5887 }
5888 }
5889 rc = true;
5890 }
5891 else if ( ann_m_points.Count() >= 2 && ON::dtLeader == ann_type )
5892 {
5893 int i;
5894 E = *ann_m_points.Last();
5895 for (i = ann_m_points.Count()-2; i >= 0; i-- )
5896 {
5897 R = E - ann_m_points[i];
5898 if ( R.Unitize() )
5899 {
5900 break;
5901 }
5902 R.Set(1.0,0.0);
5903 }
5904 rc = true;
5905 }
5906 else if ( ann_m_points.Count() >= 2 && ON::dtDimOrdinate == ann_type )
5907 {
5908 E = ann_m_points[1];
5909
5910 int direction = (( ON_OrdinateDimension2*)pAnn)->Direction();
5911 if( direction == -1)
5912 {
5913 if( fabs( ann_m_points[1].x - ann_m_points[0].x)
5914 <= fabs( ann_m_points[1].y - ann_m_points[0].y))
5915 direction = 0;
5916 else
5917 direction = 1;
5918 }
5919
5920 if( direction == 0)
5921 R.Set( 0.0, ann_m_points[1].y - ann_m_points[0].y);
5922 else
5923 R.Set( ann_m_points[1].x - ann_m_points[0].x, 0.0);
5924
5925 if( !R.Unitize())
5926 R.Set(1.0,0.0);
5927
5928 rc = true;
5929 }
5930
5931 return rc;
5932 }
5933
5934 //static bool do_plane_translation = true;
5935 //static bool do_text_centering_xform = true;
5936 //static bool do_text_centering_rotation = true;
5937 //static bool do_text_centering_translation = true;
5938 //static bool do_mirror_flip = true;
5939 //static bool do_flip_x = true;
5940 //static bool do_flip_y = true;
5941
5942 // New function added Oct 30, 07 - LW
5943 // To use model xform to draw annotation in blocks correctly
GetTextXform(ON_RECT gdi_text_rect,int gdi_height_of_I,double dimstyle_textheight,double dimstyle_textgap,ON::eTextDisplayMode dimstyle_textalignment,double dimscale,ON_3dVector cameraX,ON_3dVector cameraY,const ON_Xform * model_xform,ON_Xform & xform) const5944 bool ON_Annotation2::GetTextXform(
5945 ON_RECT gdi_text_rect,
5946 int gdi_height_of_I,
5947 double dimstyle_textheight,
5948 double dimstyle_textgap,
5949 ON::eTextDisplayMode dimstyle_textalignment,
5950 double dimscale,
5951 ON_3dVector cameraX,
5952 ON_3dVector cameraY,
5953 const ON_Xform* model_xform,
5954 ON_Xform& xform
5955 ) const
5956 {
5957 ON_Xform mxi;
5958 if( model_xform)
5959 {
5960 mxi = model_xform->Inverse();
5961 cameraX.Transform( mxi);
5962 cameraY.Transform( mxi);
5963 }
5964 const ON_Annotation2* ann = this;
5965
5966 const ON::eAnnotationType ann_type = ann->m_type;
5967
5968 if ( 0 == gdi_height_of_I )
5969 {
5970 // Default to height of Ariel 'I'
5971 gdi_height_of_I = (165*ON_Font::normal_font_height)/256;
5972 }
5973
5974 if ( 0.0 == dimscale )
5975 {
5976 dimscale = 1.0;
5977 }
5978
5979 dimstyle_textheight *= dimscale;
5980 dimstyle_textgap *= dimscale;
5981
5982 double textheight = ( ON::dtTextBlock == ann_type )
5983 ? m_textheight*dimscale
5984 : dimstyle_textheight;
5985 if ( 0.0 == textheight )
5986 textheight = 1.0;
5987
5988 ON_3dVector cameraZ = ON_CrossProduct( cameraX, cameraY );
5989 if ( fabs( 1.0 - cameraZ.Length() ) > ON_SQRT_EPSILON )
5990 {
5991 cameraZ.Unitize();
5992 }
5993
5994 // This xform is a scale from Windows gdi coordinates
5995 // to annotation plane coordinates.
5996 const double gdi_to_plane_scale = textheight/gdi_height_of_I;
5997 ON_Xform gdi_to_plane(1.0);
5998 gdi_to_plane.m_xform[0][0] = gdi_to_plane_scale;
5999 gdi_to_plane.m_xform[1][1] = -gdi_to_plane_scale;
6000
6001 // width and height of text line in Rhino units.
6002 const double text_line_width = gdi_to_plane_scale*(gdi_text_rect.right - gdi_text_rect.left);
6003 //const double text_line_height = gdi_to_plane_scale*(gdi_text_rect.bottom - gdi_text_rect.top);
6004
6005 if ( ON::dtTextBlock == ann_type )
6006 {
6007 // The orientation of the text is text blocks
6008 // does not depend on the view or text alignment
6009 // settings. The position and orientation of
6010 // the text in every other annotation depends on
6011 // the view and text alignment settings.
6012 //
6013 // It simplifies the code for the rest of the
6014 // annotation settings to quickly deal with text
6015 // blocks here.
6016 ON_Xform plane_to_world(1.0);
6017 plane_to_world.Rotation(ON_xy_plane,ann->m_plane);
6018 xform = plane_to_world*gdi_to_plane;
6019 return true;
6020 }
6021
6022 // text_position_mode
6023 // 1 = linear, aligned, or anglular dimension
6024 // (dimension definition determines center point of text box)
6025 // 2 = radial, diameter, leader
6026 // (dimension definition determined end point of text box)
6027 int position_style = 0;
6028 switch( ann_type )
6029 {
6030 case ON::dtDimAligned:
6031 case ON::dtDimLinear:
6032 case ON::dtDimAngular:
6033 // dimension definition determines center point of text box
6034 position_style = 1;
6035 break;
6036
6037 case ON::dtLeader:
6038 if(ON::dtHorizontal == dimstyle_textalignment)
6039 position_style = 1;
6040 else
6041 position_style = 2;
6042 break;
6043
6044 case ON::dtDimRadius:
6045 case ON::dtDimDiameter:
6046 case ON::dtDimOrdinate:
6047 // dimension definition determines end of text box
6048 position_style = 2;
6049 break;
6050
6051 case ON::dtTextBlock:
6052 case ON::dtNothing:
6053 break;
6054 }
6055
6056 // This translation puts the center of the fist line of text at
6057 // (0,0) in the annotation's plane.
6058 if ( ON::dtHorizontal != dimstyle_textalignment || 1 == position_style )
6059 {
6060 if((m_justification & tjRight) == tjRight)
6061 gdi_to_plane.m_xform[0][3] = 0.5*text_line_width;
6062 else
6063 gdi_to_plane.m_xform[0][3] = -0.5*text_line_width;
6064 }
6065 gdi_to_plane.m_xform[1][3] = -0.5*textheight;
6066
6067 if ( ON::dtHorizontal != dimstyle_textalignment )
6068 {
6069 if ( ((cameraZ*m_plane.zaxis) < -ON_SQRT_EPSILON) )
6070 {
6071 // Viewing dimension from the backside
6072 ON_Xform flip(1.0);
6073 switch ( position_style )
6074 {
6075 case 1: // ON::dtDimLinear, ON::dtDimAligned, ON::dtDimAngular
6076 flip.m_xform[0][0] = -1.0;
6077 flip.m_xform[0][3] = gdi_text_rect.left + gdi_text_rect.right;
6078 break;
6079
6080 case 2: // ON::dtDimDiameter, ON::dtDimRadius, ON::dtLeader
6081 //flip.m_xform[1][1] = -1.0;
6082 //flip.m_xform[1][3] = -(gdi_text_rect.top + gdi_text_rect.bottom);
6083 break;
6084 }
6085 gdi_to_plane = gdi_to_plane*flip;
6086 }
6087 }
6088
6089 // text_centering_rotation rotates about the "center". Angular,
6090 // radial, and leader dimensions use this rotation.
6091 ON_2dVector text_centering_rotation(1.0,0.0);
6092
6093 // text_centering_translation is a small translation deals with
6094 // text that is above or to the right of the "center" point.
6095 // It is no larger than dimstyle_gap + 1/2 the size of the
6096 // text's bounding box.
6097 ON_2dVector text_centering_translation(0.0,0.0);
6098 bool text_y_flip = false;
6099 double x, y;
6100
6101 if ( ON::dtHorizontal != dimstyle_textalignment )
6102 {
6103 if ( ON::dtDimLinear == ann_type || ON::dtDimAligned == ann_type )
6104 {
6105 if ( ON::dtAboveLine == dimstyle_textalignment )
6106 {
6107 text_centering_translation.y = 0.5*textheight+dimstyle_textgap;
6108 }
6109 y = ann->m_plane.yaxis*cameraY;
6110 x = -ann->m_plane.yaxis*cameraX;
6111 if ( fabs(y) <= ON_SQRT_EPSILON && fabs(x) > ON_SQRT_EPSILON )
6112 {
6113 y = x;
6114 }
6115 if ( y < 0.0 )
6116 {
6117 text_centering_translation.Reverse();
6118 text_centering_rotation.Reverse(); // rotate 180 degrees
6119 }
6120 }
6121 else if ( ON::dtDimAngular == ann_type )
6122 {
6123 // This transform rotates the text in the annotation plane.
6124 const ON_AngularDimension2* angular_dim = ON_AngularDimension2::Cast(ann);
6125 if ( 0 != angular_dim )
6126 {
6127 double a = 0.5*angular_dim->m_angle;
6128 ON_2dVector R(cos(a),sin(a));
6129 a -= 0.5*ON_PI;
6130 text_centering_rotation.x = cos(a);
6131 text_centering_rotation.y = sin(a);
6132 ON_3dVector V = R.x*m_plane.xaxis + R.y*m_plane.yaxis;
6133 x = V*cameraX;
6134 y = V*cameraY;
6135 if ( fabs(y) <= ON_SQRT_EPSILON && fabs(x) > ON_SQRT_EPSILON )
6136 {
6137 y = -x;
6138 }
6139 if ( y < 0.0 )
6140 {
6141 text_centering_rotation.Reverse(); // add another 180 degrees of rotation
6142 }
6143
6144 if ( ON::dtAboveLine == dimstyle_textalignment )
6145 {
6146 y = 0.5*textheight + dimstyle_textgap;
6147 text_centering_translation.x = -y*text_centering_rotation.y;
6148 text_centering_translation.y = y*text_centering_rotation.x;
6149 }
6150 }
6151 }
6152 else if ( ON::dtDimDiameter == ann_type
6153 || ON::dtDimRadius == ann_type
6154 || ON::dtLeader == ann_type
6155 || ON::dtDimOrdinate == ann_type)
6156 {
6157 ON_2dPoint E(0.0,0.0); // end point
6158 ON_2dVector R(1.0,0.0); // unit vector from penultimate point to end point
6159 GetLeaderEndAndDirection( this, E, R );
6160
6161 text_centering_rotation = R;
6162
6163 text_centering_translation = (dimstyle_textgap + 0.5*text_line_width)*text_centering_rotation;
6164
6165 ON_3dVector V = text_centering_rotation.x*m_plane.xaxis + text_centering_rotation.y*m_plane.yaxis;
6166 x = V*cameraX;
6167 y = V*cameraY;
6168 if ( fabs(x) <= ON_SQRT_EPSILON && fabs(y) > ON_SQRT_EPSILON )
6169 {
6170 x = y;
6171 }
6172 if ( x < 0.0 )
6173 text_centering_rotation.Reverse(); // rotate 180 degrees
6174
6175 if(cameraZ * m_plane.zaxis < 0.0)
6176 text_y_flip = true;
6177 }
6178 }
6179 else if(ann_type == ON::dtLeader)
6180 {
6181 if((m_justification & tjRight) == tjRight)
6182 text_centering_translation.Set(-(dimstyle_textgap + 0.5*text_line_width), 0.0);
6183 else if((m_justification & tjLeft) == tjLeft)
6184 text_centering_translation.Set(dimstyle_textgap + 0.5*text_line_width, 0.0);
6185
6186 }
6187
6188 ON_Xform text_centering_xform(1.0);
6189 text_centering_xform.m_xform[0][0] = text_centering_rotation.x;
6190 text_centering_xform.m_xform[0][1] = -text_centering_rotation.y;
6191 text_centering_xform.m_xform[1][0] = text_centering_rotation.y;
6192 if(text_y_flip)
6193 text_centering_xform.m_xform[1][1] = -text_centering_rotation.x;
6194 else
6195 text_centering_xform.m_xform[1][1] = text_centering_rotation.x;
6196
6197
6198 // Since the translation happens after the rotation about (0,0),
6199 // we can just tack it on here.
6200 text_centering_xform.m_xform[0][3] = text_centering_translation.x;
6201 text_centering_xform.m_xform[1][3] = text_centering_translation.y;
6202
6203 // This transform translates the text in the annotation plane
6204 // from the plane origin to the final location of the annotation text
6205 // It can be a large translation
6206 ON_2dVector text_offset_translation(0.0,0.0); // CRhinoText::Offset() = text->Offset()
6207 switch( ann_type )
6208 {
6209 case ON::dtDimLinear:
6210 case ON::dtDimAligned:
6211 if ( m_points.Count() >= ON_LinearDimension2::dim_pt_count )
6212 {
6213 const ON_LinearDimension2* linear_dim = ON_LinearDimension2::Cast(ann);
6214 if ( linear_dim )
6215 {
6216 text_offset_translation = linear_dim->Dim2dPoint(ON_LinearDimension2::text_pivot_pt);
6217 }
6218 }
6219 break;
6220
6221 case ON::dtDimAngular:
6222 if ( m_points.Count() >= ON_AngularDimension2::dim_pt_count )
6223 {
6224 const ON_AngularDimension2* angular_dim = ON_AngularDimension2::Cast(ann);
6225 if ( angular_dim )
6226 {
6227 text_offset_translation = angular_dim->Dim2dPoint(ON_AngularDimension2::text_pivot_pt);
6228 }
6229 }
6230 break;
6231
6232 case ON::dtDimDiameter:
6233 case ON::dtDimRadius:
6234 if ( m_points.Count() >= ON_RadialDimension2::dim_pt_count )
6235 {
6236 // No user positioned text on radial dimensions.
6237 text_offset_translation = m_points[ON_RadialDimension2::tail_pt_index];
6238 }
6239 break;
6240
6241 case ON::dtLeader:
6242 if ( m_points.Count() > 0 )
6243 {
6244 // No user positioned text on leaders.
6245 text_offset_translation = *m_points.Last();
6246 }
6247 break;
6248
6249 case ON::dtDimOrdinate:
6250 if ( m_points.Count() == 2 )
6251 {
6252 // No user positioned text on leaders.
6253 text_offset_translation = m_points[1];
6254 }
6255 break;
6256
6257 case ON::dtTextBlock:
6258 case ON::dtNothing:
6259 break;
6260 }
6261
6262 ON_Xform plane_translation(1.0);
6263 plane_translation.m_xform[0][3] = text_offset_translation.x;
6264 plane_translation.m_xform[1][3] = text_offset_translation.y;
6265
6266 // this transform maps a point in the annotation plane to world coordinates
6267 ON_Xform plane_to_world(1.0);
6268 plane_to_world.Rotation(ON_xy_plane,ann->m_plane);
6269
6270 ON_Xform horizonal_xform(1.0);
6271 if ( ON::dtHorizontal == dimstyle_textalignment )
6272 {
6273 ON_3dPoint fixed_point = ann->m_plane.PointAt(text_offset_translation.x,text_offset_translation.y);
6274 horizonal_xform.Rotation(
6275 fixed_point,
6276 ann->m_plane.xaxis,
6277 ann->m_plane.yaxis,
6278 ann->m_plane.zaxis,
6279 fixed_point,
6280 cameraX,
6281 cameraY,
6282 cameraZ
6283 );
6284
6285 if ( 2 == position_style )
6286 {
6287 // leaders, radial, and diameter
6288 ON_2dPoint E(0.0,0.0); // end point
6289 ON_2dVector R(1.0,0.0); // unit vector from penultimate point to end point
6290 GetLeaderEndAndDirection( this, E, R );
6291 ON_3dVector V = R.x*m_plane.xaxis + R.y*m_plane.yaxis;
6292 x = V*cameraX;
6293 y = ( x > -ON_SQRT_EPSILON )
6294 ? dimstyle_textgap
6295 : -(dimstyle_textgap + text_line_width);
6296 V = y*cameraX;
6297 horizonal_xform.m_xform[0][3] += V.x;
6298 horizonal_xform.m_xform[1][3] += V.y;
6299 horizonal_xform.m_xform[2][3] += V.z;
6300 }
6301 }
6302
6303 ON_Xform gdi_to_world;
6304
6305 gdi_to_world = horizonal_xform
6306 * plane_to_world
6307 * plane_translation
6308 * text_centering_xform
6309 * gdi_to_plane;
6310
6311 xform = gdi_to_world;
6312
6313 return true;
6314 }
6315
GetTextPoint(ON_2dPoint & text_2d_point) const6316 bool ON_Annotation2::GetTextPoint( ON_2dPoint& text_2d_point ) const
6317 {
6318 bool rc = false;
6319 switch ( m_type )
6320 {
6321 case ON::dtTextBlock:
6322 text_2d_point.Set(0.0,0.0);
6323 rc = true;
6324 break;
6325
6326 case ON::dtDimLinear:
6327 case ON::dtDimAligned:
6328 if ( m_userpositionedtext )
6329 {
6330 if ( m_points.Count() >= 5 )
6331 {
6332 text_2d_point = m_points[4];
6333 rc = true;
6334 }
6335 }
6336 else if ( m_points.Count() >= 3 )
6337 {
6338 text_2d_point.x = 0.5*(m_points[0].x + m_points[2].x);
6339 text_2d_point.y = m_points[2].y;
6340 rc = true;
6341 }
6342 break;
6343
6344 case ON::dtLeader:
6345 if ( m_points.Count() > 0 )
6346 {
6347 text_2d_point = *m_points.Last();
6348 rc = true;
6349 }
6350 break;
6351
6352 case ON::dtDimAngular:
6353 {
6354 const ON_AngularDimension2* angular_dim = ON_AngularDimension2::Cast(this);
6355 if ( angular_dim )
6356 {
6357 if ( m_userpositionedtext )
6358 {
6359 if ( m_points.Count() >= 0 )
6360 {
6361 text_2d_point = m_points[0];
6362 }
6363 }
6364 else
6365 {
6366 text_2d_point.x = angular_dim->m_radius*cos(angular_dim->m_angle);
6367 text_2d_point.y = angular_dim->m_radius*sin(angular_dim->m_angle);
6368 rc = true;
6369 }
6370 }
6371 }
6372 break;
6373
6374 case ON::dtDimRadius:
6375 case ON::dtDimDiameter:
6376 // no user positioned text
6377 if ( m_points.Count() >= 3 )
6378 {
6379 text_2d_point = m_points[2];
6380 rc = true;
6381 }
6382
6383 break;
6384
6385 case ON::dtDimOrdinate:
6386 case ON::dtNothing:
6387 break;
6388 }
6389 return rc;
6390 }
6391
6392
6393 ////////////////////////////////////////////////////////////
6394 //
6395 // do not copy or export this class definition.
6396 //
6397 class /*NEVER PUT THIS CLASS IN THE SDK*/ ON_AnnotationTextFormula : public ON_UserData
6398 {
6399 #if !defined(BOZO_VACCINE_699FCC4262D4488c9109F1B7A37CE926)
6400 #error Never copy this class definition or put this definition in a header file!
6401 #endif
6402 ON_OBJECT_DECLARE(ON_AnnotationTextFormula);
6403 public:
6404 ON_AnnotationTextFormula();
6405 ~ON_AnnotationTextFormula();
6406 // NO! - do not add IO support to this userdata! // ON_BOOL32 Write(ON_BinaryArchive&) const;
6407 // NO! - do not add IO support to this userdata! // ON_BOOL32 Read(ON_BinaryArchive&);
6408 ON_BOOL32 GetDescription(ON_wString&);
6409 // NO! - do not add IO support to this userdata! // ON_BOOL32 Archive() const;
6410 static ON_AnnotationTextFormula* Get(const ON_Annotation2*);
6411 static void Set(ON_Annotation2*,const wchar_t* text_formula);
6412
6413 ON_wString m_text_formula;
6414 };
6415
6416 #undef BOZO_VACCINE_699FCC4262D4488c9109F1B7A37CE926
6417
6418 ON_OBJECT_IMPLEMENT(ON_AnnotationTextFormula,ON_UserData,"699FCC42-62D4-488c-9109-F1B7A37CE926");
6419
~ON_AnnotationTextFormula()6420 ON_AnnotationTextFormula::~ON_AnnotationTextFormula()
6421 {}
6422
ON_AnnotationTextFormula()6423 ON_AnnotationTextFormula::ON_AnnotationTextFormula()
6424 {
6425 m_userdata_uuid = ON_AnnotationTextFormula::m_ON_AnnotationTextFormula_class_id.Uuid();
6426 m_application_uuid = ON_opennurbs5_id;
6427 m_userdata_copycount = 1;
6428 }
6429
GetDescription(ON_wString & description)6430 ON_BOOL32 ON_AnnotationTextFormula::GetDescription( ON_wString& description )
6431 {
6432 description = "Annotation Text Formula";
6433 return true;
6434 }
6435
Get(const ON_Annotation2 * p)6436 ON_AnnotationTextFormula* ON_AnnotationTextFormula::Get(const ON_Annotation2* p)
6437 {
6438 return (0 != p)
6439 ? ON_AnnotationTextFormula::Cast(p->GetUserData(ON_AnnotationTextFormula::m_ON_AnnotationTextFormula_class_id.Uuid()))
6440 : 0;
6441 }
6442
Set(ON_Annotation2 * p,const wchar_t * text_formula)6443 void ON_AnnotationTextFormula::Set(ON_Annotation2* p,const wchar_t* text_formula)
6444 {
6445 if ( 0 != p )
6446 {
6447 ON_AnnotationTextFormula* tf = Get(p);
6448 if ( 0 == text_formula || 0 == text_formula[0] )
6449 {
6450 if (0 != tf )
6451 delete tf;
6452 }
6453 else
6454 {
6455 if ( 0 == tf )
6456 {
6457 tf = new ON_AnnotationTextFormula();
6458 p->AttachUserData(tf);
6459 }
6460 tf->m_text_formula = text_formula;
6461 }
6462 }
6463 }
6464 //
6465 // do not copy or export this class definition.
6466 //
6467 ////////////////////////////////////////////////////////////
6468
SetTextValue(const wchar_t * text_value)6469 void ON_Annotation2::SetTextValue( const wchar_t* text_value )
6470 {
6471 m_usertext = text_value;
6472 }
6473
TextValue() const6474 const wchar_t* ON_Annotation2::TextValue() const
6475 {
6476 return ((const wchar_t*)m_usertext);
6477 }
6478
SetTextFormula(const wchar_t * text_formula)6479 void ON_Annotation2::SetTextFormula( const wchar_t* text_formula )
6480 {
6481 ON_AnnotationTextFormula::Set(this,text_formula);
6482 }
6483
TextFormula() const6484 const wchar_t* ON_Annotation2::TextFormula() const
6485 {
6486 const ON_AnnotationTextFormula* tf = ON_AnnotationTextFormula::Get(this);
6487 return (0 != tf) ? ((const wchar_t*)tf->m_text_formula) : 0;
6488 }
6489
6490