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