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 #include "opennurbs.h"
17
18 //March 23, 2008 - LW
19 //Adding ON_HatchExtra class to support movable base point for hatches
20 //This should be combined with the ON_Hatch class next time that is possible
21 // Don't put this extension class in a header file or export it.
22
23 class ON_HatchExtra : public ON_UserData
24 {
25 ON_OBJECT_DECLARE(ON_HatchExtra);
26 public:
27 static ON_HatchExtra* HatchExtension(ON_Hatch* pHatch, bool bCreate);
28 static const ON_HatchExtra* HatchExtension(const ON_Hatch* pHatch, bool bCreate);
29
30 ON_HatchExtra();
31 ~ON_HatchExtra();
32
33 void SetDefaults();
34
35 // override virtual ON_Object::Dump function
36 void Dump( ON_TextLog& text_log ) const;
37
38 // override virtual ON_Object::SizeOf function
39 unsigned int SizeOf() const;
40
41 // override virtual ON_Object::Write function
42 ON_BOOL32 Write(ON_BinaryArchive& binary_archive) const;
43
44 // override virtual ON_Object::Read function
45 ON_BOOL32 Read(ON_BinaryArchive& binary_archive);
46
47 // override virtual ON_UserData::GetDescription function
48 ON_BOOL32 GetDescription( ON_wString& description );
49
50 // override virtual ON_UserData::Archive function
51 ON_BOOL32 Archive() const;
52
53 // Get and set a 2d point in the hatch's ECS coordinates
54 void SetBasePoint(ON_2dPoint& basepoint);
55 ON_2dPoint BasePoint() const;
56
57 ON_UUID m_parent_hatch; // Hatch this extends or ON_nil_uuid
58 ON_2dPoint m_basepoint; // Base point in hatch's ECS
59
60 };
61
62 ON_OBJECT_IMPLEMENT(ON_HatchExtra,ON_UserData,"3FF7007C-3D04-463f-84E3-132ACEB91062");
63
HatchExtension(ON_Hatch * pHatch,bool bCreate)64 ON_HatchExtra* ON_HatchExtra::HatchExtension(ON_Hatch* pHatch, bool bCreate)
65 {
66 ON_HatchExtra* pExtra = 0;
67 if(pHatch)
68 {
69 pExtra = ON_HatchExtra::Cast(pHatch->GetUserData(ON_HatchExtra::m_ON_HatchExtra_class_id.Uuid()));
70 if(pExtra == 0 && bCreate)
71 {
72 pExtra = new ON_HatchExtra;
73 if(pExtra)
74 {
75 if(!pHatch->AttachUserData(pExtra))
76 {
77 delete pExtra;
78 pExtra = 0;
79 }
80 }
81 }
82 }
83 return pExtra;
84 }
85
HatchExtension(const ON_Hatch * pHatch,bool bCreate)86 const ON_HatchExtra* ON_HatchExtra::HatchExtension(const ON_Hatch* pHatch, bool bCreate)
87 {
88 return HatchExtension((ON_Hatch*)pHatch, bCreate);
89 }
90
ON_HatchExtra()91 ON_HatchExtra::ON_HatchExtra()
92 {
93 m_userdata_uuid = ON_HatchExtra::m_ON_HatchExtra_class_id.Uuid();
94 m_application_uuid = ON_opennurbs5_id; // opennurbs.dll reads/writes this userdata
95 // The id must be the version 5 id because
96 // V6 SaveAs V5 needs to work, but SaveAs
97 // V4 should not write this userdata.
98 m_userdata_copycount = 1;
99 SetDefaults();
100 }
101
~ON_HatchExtra()102 ON_HatchExtra::~ON_HatchExtra()
103 {
104 }
105
SetDefaults()106 void ON_HatchExtra::SetDefaults()
107 {
108 m_parent_hatch = ON_nil_uuid;
109 m_basepoint.Set(0.0,0.0);
110 }
111
Dump(ON_TextLog & text_log) const112 void ON_HatchExtra::Dump(ON_TextLog& text_log) const
113 {
114 }
115
SizeOf() const116 unsigned int ON_HatchExtra::SizeOf() const
117 {
118 unsigned int sz = ON_UserData::SizeOf();
119 sz += sizeof(*this)-sizeof(ON_UserData);
120 return sz;
121 }
122
Write(ON_BinaryArchive & archive) const123 ON_BOOL32 ON_HatchExtra::Write(ON_BinaryArchive& archive) const
124 {
125 bool rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0);
126
127 if(rc) rc = archive.WriteUuid( m_parent_hatch);
128 if(rc) rc = archive.WritePoint(m_basepoint);
129
130 if(!archive.EndWrite3dmChunk())
131 rc = false;
132
133 return rc;
134 }
135
Read(ON_BinaryArchive & archive)136 ON_BOOL32 ON_HatchExtra::Read(ON_BinaryArchive& archive)
137 {
138 int major_version = 0;
139 int minor_version = 0;
140 bool rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version);
141
142 if(major_version != 1)
143 rc = false;
144
145 m_basepoint.Set(0.0,0.0);
146 if(rc) rc = archive.ReadUuid(m_parent_hatch);
147 if(rc) rc = archive.ReadPoint(m_basepoint);
148
149 if(!archive.EndRead3dmChunk())
150 rc = false;
151
152 return rc;
153 }
154
GetDescription(ON_wString & description)155 ON_BOOL32 ON_HatchExtra::GetDescription( ON_wString& description)
156 {
157 description.Format( "Userdata extension of ON_Hatch (contains basepoint)");
158 return true;
159 }
160
Archive() const161 ON_BOOL32 ON_HatchExtra::Archive() const
162 {
163 return true;
164 }
165
SetBasePoint(ON_2dPoint & point)166 void ON_HatchExtra::SetBasePoint(ON_2dPoint& point)
167 {
168 if(point.IsValid())
169 m_basepoint = point;
170 }
171
BasePoint() const172 ON_2dPoint ON_HatchExtra::BasePoint() const
173 {
174 return m_basepoint;
175 }
176
177 /////////////////////////////////////////////////////////////////
178 // class ON_HatchLine
179 /////////////////////////////////////////////////////////////////
180
ON_HatchLine()181 ON_HatchLine::ON_HatchLine()
182 : m_angle( 0.0), m_base( 0.0,0.0), m_offset( 0.0, 1.0)
183 {
184 }
185
ON_HatchLine(double angle,const ON_2dPoint & base,const ON_2dVector & offset,const ON_SimpleArray<double> dashes)186 ON_HatchLine::ON_HatchLine(double angle,
187 const ON_2dPoint& base,
188 const ON_2dVector& offset,
189 const ON_SimpleArray<double> dashes)
190 : m_angle( angle), m_base( base), m_offset( offset), m_dashes( dashes)
191 {
192 }
193
operator ==(const ON_HatchLine & src) const194 bool ON_HatchLine::operator==(const ON_HatchLine& src) const
195 {
196 return( m_angle == src.m_angle &&
197 m_base == src.m_base &&
198 m_offset == src.m_offset &&
199 m_dashes == src.m_dashes);
200 }
201
operator !=(const ON_HatchLine & src) const202 bool ON_HatchLine::operator!=(const ON_HatchLine& src) const
203 {
204 return !operator==( src);
205 }
206
IsValid(ON_TextLog * text_log) const207 ON_BOOL32 ON_HatchLine::IsValid( ON_TextLog* text_log) const
208 {
209 bool rc = m_angle >= 0.0;
210 if( !rc)
211 {
212 if( text_log)
213 text_log->Print( "Angle ( %lf) must be >= 0.0\n", m_angle);
214 return false;
215 }
216 rc = m_angle < ON_PI * 2.0;
217 if( !rc)
218 {
219 if( text_log)
220 text_log->Print( "Angle ( %lf) must be < 2*Pi.\n", m_angle);
221 return false;
222 }
223 rc = m_base != ON_2dPoint( ON_UNSET_VALUE, ON_UNSET_VALUE);
224 if( !rc)
225 {
226 if( text_log)
227 text_log->Print( "Base is not a valid point.\n");
228 return false;
229 }
230 rc = m_offset.x != ON_UNSET_VALUE;
231 if( !rc)
232 {
233 if( text_log)
234 text_log->Print( "Offset is not a valid vector.\n");
235 return false;
236 }
237 rc = m_offset.y > ON_SQRT_EPSILON;
238 if( !rc)
239 {
240 if( text_log)
241 text_log->Print( "Offset.y ( %lf) must be > 0.0", m_offset.y);
242 return false;
243 }
244 return true;
245 }
246
Dump(ON_TextLog & dump) const247 void ON_HatchLine::Dump( ON_TextLog& dump) const
248 {
249 dump.Print( "ON_HatchLine: angle = %lf radians ( %lf degrees) ",
250 Angle(), ON_RADIANS_TO_DEGREES * Angle());
251 dump.Print( " base = ");
252 dump.Print( m_base);
253 dump.Print( " offset = ");
254 dump.Print( m_offset);
255 int count = m_dashes.Count();
256 dump.Print( "\nDash count = %d: ", count);
257 for( int i = 0; i < count; i++)
258 {
259 dump.Print( "%lf", Dash( i));
260 if( i < count-1)
261 dump.Print( ", ");
262 }
263 dump.Print( "\n");
264 }
265
Write(ON_BinaryArchive & ar) const266 ON_BOOL32 ON_HatchLine::Write( ON_BinaryArchive& ar) const
267 {
268 ON_BOOL32 rc = ar.Write3dmChunkVersion(1,1);
269
270 if (rc) rc = ar.WriteDouble( m_angle);
271 if (rc) rc = ar.WritePoint( m_base);
272 if (rc) rc = ar.WriteVector( m_offset);
273 if (rc) rc = ar.WriteArray( m_dashes);
274
275 return rc;
276 }
277
Read(ON_BinaryArchive & ar)278 ON_BOOL32 ON_HatchLine::Read( ON_BinaryArchive& ar)
279 {
280 m_angle = 0.0;
281 m_base.Set( 0.0, 0.0);
282 m_offset.Set( 0.0, 1.0);
283 m_dashes.Empty();
284 int major_version = 0;
285 int minor_version = 0;
286 ON_BOOL32 rc = ar.Read3dmChunkVersion( &major_version, &minor_version);
287 if ( major_version == 1 )
288 {
289 if ( rc) rc = ar.ReadDouble( &m_angle);
290 if ( rc) rc = ar.ReadPoint( m_base);
291 if ( rc) rc = ar.ReadVector( m_offset);
292 if ( rc) rc = ar.ReadArray( m_dashes);
293 }
294 return rc;
295 }
296
297 // ON_HatchLine Interface
Angle() const298 double ON_HatchLine::Angle() const
299 {
300 return m_angle;
301 }
302
SetAngle(double angle)303 void ON_HatchLine::SetAngle( double angle)
304 {
305 m_angle = angle;
306 double twopi = ON_PI * 2.0;
307
308 // clamp between [0 2pi)
309 while( m_angle < 0.0)
310 m_angle += twopi;
311 while( m_angle > twopi)
312 m_angle -= twopi;
313 }
314
Base() const315 ON_2dPoint ON_HatchLine::Base() const
316 {
317 return m_base;
318 }
319
SetBase(const ON_2dPoint & base)320 void ON_HatchLine::SetBase( const ON_2dPoint& base)
321 {
322 m_base = base;
323 }
324
Offset() const325 ON_2dVector ON_HatchLine::Offset() const
326 {
327 return m_offset;
328 }
329
SetOffset(const ON_2dVector & offset)330 void ON_HatchLine::SetOffset( const ON_2dVector& offset)
331 {
332 m_offset = offset;
333 }
334
DashCount() const335 int ON_HatchLine::DashCount() const
336 {
337 return m_dashes.Count();
338 }
339
Dash(int index) const340 double ON_HatchLine::Dash( int index) const
341 {
342 if( index >= 0 && index < m_dashes.Count())
343 return m_dashes[index];
344 return 0.0;
345 }
346
AppendDash(double dash)347 void ON_HatchLine::AppendDash( double dash)
348 {
349 // if( fabs( dash) > ON_SQRT_EPSILON)
350 m_dashes.Append( dash);
351 }
352
SetPattern(const ON_SimpleArray<double> & dashes)353 void ON_HatchLine::SetPattern( const ON_SimpleArray<double>& dashes)
354 {
355 m_dashes = dashes;
356 }
357
GetLineData(double & angle,ON_2dPoint & base,ON_2dVector & offset,ON_SimpleArray<double> & dashes) const358 void ON_HatchLine::GetLineData( double& angle,
359 ON_2dPoint& base,
360 ON_2dVector& offset,
361 ON_SimpleArray<double>& dashes) const
362 {
363 angle = m_angle;
364 base = m_base;
365 offset = m_offset; dashes = m_dashes;
366 }
367
GetPatternLength() const368 double ON_HatchLine::GetPatternLength() const
369 {
370 int i;
371 double length = 0.0;
372 for( i = 0; i < m_dashes.Count(); i++)
373 length += fabs( m_dashes[i]);
374
375 return length;
376 }
377
378
379 // class ON_HatchPattern
380 /////////////////////////////////////////////////////////////////
381 ON_OBJECT_IMPLEMENT( ON_HatchPattern, ON_Object, "064E7C91-35F6-4734-A446-79FF7CD659E1" );
382
ON_HatchPattern()383 ON_HatchPattern::ON_HatchPattern()
384 : m_hatchpattern_index(-1)
385 , m_hatchpattern_id(ON_nil_uuid)
386 , m_type(ON_HatchPattern::ftSolid)
387 {
388 }
389
~ON_HatchPattern()390 ON_HatchPattern::~ON_HatchPattern()
391 {
392 }
393
IsValid(ON_TextLog * text_log) const394 ON_BOOL32 ON_HatchPattern::IsValid( ON_TextLog* text_log) const
395 {
396 eFillType type = FillType();
397 ON_BOOL32 rc = true;
398 if( type != ftSolid && type != ftLines && type != ftGradient)
399 {
400 if( text_log)
401 text_log->Print( "Type field not set correctly.\n");
402 rc = false;
403 }
404 if( type == ftLines)
405 {
406 int count = m_lines.Count();
407 if( count < 1)
408 {
409 if( text_log)
410 text_log->Print( "Line type patetern with no lines.\n");
411 return false;
412 }
413 for( int i = 0; i < count; i++)
414 {
415 if( !m_lines[i].IsValid())
416 {
417 if( text_log)
418 text_log->Print( "Line[%d] is not valid.\n", i);
419 return false;
420 }
421 }
422 return true;
423 }
424 return rc;
425 }
426
Dump(ON_TextLog & dump) const427 void ON_HatchPattern::Dump( ON_TextLog& dump) const
428 {
429 dump.Print( "Hatch pattern - ");
430 switch( m_type)
431 {
432 case ftSolid:
433 dump.Print( "fill type: Solid");
434 break;
435 case ftLines:
436 dump.Print( "fill type: Lines");
437 break;
438 case ftGradient:
439 dump.Print( "fill type: Gradient");
440 break;
441 case ftLast:
442 // no action, but this keeps gcc happy
443 break;
444 }
445 dump.Print( "\n");
446
447 const wchar_t* wsHatchPatternName = m_hatchpattern_name;
448 if ( 0 == wsHatchPatternName )
449 wsHatchPatternName = L"";
450 dump.Print( "Name: %ls\n", wsHatchPatternName);
451
452 const wchar_t* wsDescription = m_description;
453 if ( 0 == wsDescription )
454 wsDescription = L"";
455 dump.Print( "Description: %ls\n", wsDescription);
456
457 if( m_type == ftLines)
458 {
459 int count = m_lines.Count();
460 dump.Print( "Line count = %d\n", count);
461 for( int i = 0; i < count; i++)
462 {
463 m_lines[i].Dump( dump);
464 }
465 dump.Print( "\n");
466 }
467 }
468
Write(ON_BinaryArchive & ar) const469 ON_BOOL32 ON_HatchPattern::Write( ON_BinaryArchive& ar) const
470 {
471 ON_BOOL32 rc = ar.Write3dmChunkVersion(1,2);
472
473 if (rc) rc = ar.WriteInt( m_hatchpattern_index);
474 if (rc) rc = ar.WriteInt( m_type);
475 if (rc) rc = ar.WriteString( m_hatchpattern_name);
476 if (rc) rc = ar.WriteString( m_description);
477 if( rc)
478 {
479 if( m_type == ftLines)
480 {
481 int i, count = m_lines.Count();
482 if ( count < 0 )
483 count = 0;
484 rc = ar.WriteInt( count );
485 for( i = 0; i < count && rc; i++)
486 rc = m_lines[i].Write( ar);
487 }
488 }
489 // version 1.2 field
490 if (rc) rc = ar.WriteUuid(m_hatchpattern_id);
491
492 return rc;
493 }
494
Read(ON_BinaryArchive & ar)495 ON_BOOL32 ON_HatchPattern::Read( ON_BinaryArchive& ar)
496 {
497 m_hatchpattern_index = -1;
498 memset(&m_hatchpattern_id,0,sizeof(m_hatchpattern_id));
499 m_type = ftSolid;
500 m_hatchpattern_name.Empty();
501 m_description.Empty();
502 m_lines.Empty();
503 int i;
504
505 int major_version = 0;
506 int minor_version = 0;
507 ON_BOOL32 rc = ar.Read3dmChunkVersion( &major_version, &minor_version);
508 if ( major_version == 1 )
509 {
510 if( rc) rc = ar.ReadInt( &m_hatchpattern_index);
511 i = 0;
512 if( rc) rc = ar.ReadInt( &i);
513 if( rc)
514 {
515 switch( i)
516 {
517 case 0: m_type = ftSolid; break;
518 case 1: m_type = ftLines; break;
519 case 2: m_type = ftGradient; break;
520 default: rc = false; break;
521 }
522 }
523 if( rc) rc = ar.ReadString( m_hatchpattern_name);
524 if( rc) rc = ar.ReadString( m_description);
525 if( rc)
526 {
527 if( m_type == ftLines)
528 {
529 m_lines.Empty();
530 int count = 0;
531 rc = ar.ReadInt( &count);
532 if( rc && count > 0 )
533 {
534 m_lines.SetCapacity( count);
535 int i;
536 for( i = 0; rc && i < count; i++)
537 {
538 ON_HatchLine& line = m_lines.AppendNew();
539 rc = line.Read( ar);
540 }
541 }
542 }
543 }
544 if ( minor_version >= 2 )
545 {
546 rc = ar.ReadUuid(m_hatchpattern_id);
547 }
548 }
549 return rc;
550 }
551
FillType() const552 ON_HatchPattern::eFillType ON_HatchPattern::FillType() const
553 {
554 if( m_type >= ftSolid && m_type < ftLast)
555 return m_type;
556
557 return ftLast;
558 }
559
SetFillType(eFillType type)560 void ON_HatchPattern::SetFillType( eFillType type)
561 {
562 m_type = type;
563 }
564
SetName(const wchar_t * pName)565 void ON_HatchPattern::SetName( const wchar_t* pName)
566 {
567 m_hatchpattern_name = pName;
568 m_hatchpattern_name.TrimLeftAndRight();
569 }
570
SetName(const char * pName)571 void ON_HatchPattern::SetName( const char* pName)
572 {
573 m_hatchpattern_name = pName;
574 m_hatchpattern_name.TrimLeftAndRight();
575 }
576
GetName(ON_wString & string) const577 void ON_HatchPattern::GetName( ON_wString& string) const
578 {
579 string = m_hatchpattern_name;
580 }
581
Name() const582 const wchar_t* ON_HatchPattern::Name() const
583 {
584 return m_hatchpattern_name;
585 }
586
587
SetDescription(const wchar_t * pDescription)588 void ON_HatchPattern::SetDescription( const wchar_t* pDescription)
589 {
590 m_description = pDescription;
591 }
592
SetDescription(const char * pDescription)593 void ON_HatchPattern::SetDescription( const char* pDescription)
594 {
595 m_description = pDescription;
596 }
597
GetDescription(ON_wString & string) const598 void ON_HatchPattern::GetDescription( ON_wString& string) const
599 {
600 string = m_description;
601 }
602
Description() const603 const wchar_t* ON_HatchPattern::Description() const
604 {
605 return m_description;
606 }
607
608
SetIndex(int i)609 void ON_HatchPattern::SetIndex( int i)
610 {
611 m_hatchpattern_index = i;
612 }
613
Index() const614 int ON_HatchPattern::Index() const
615 {
616 return m_hatchpattern_index;
617 }
618
619
620 // Line HatchPattern functions
621
HatchLineCount() const622 int ON_HatchPattern::HatchLineCount() const
623 {
624 return m_lines.Count();
625 }
626
AddHatchLine(const ON_HatchLine & line)627 int ON_HatchPattern::AddHatchLine( const ON_HatchLine& line)
628 {
629 m_lines.Append( line);
630 return m_lines.Count()-1;
631 }
632
HatchLine(int index) const633 const ON_HatchLine* ON_HatchPattern::HatchLine( int index) const
634 {
635 if( index >= 0 && index < m_lines.Count())
636 return &m_lines[index];
637 else
638 return NULL;
639 }
640
RemoveHatchLine(int index)641 bool ON_HatchPattern::RemoveHatchLine( int index)
642 {
643 if( index >= 0 && index < m_lines.Count())
644 {
645 m_lines.Remove( index);
646 return true;
647 }
648 return false;
649 }
650
RemoveAllHatchLines()651 void ON_HatchPattern::RemoveAllHatchLines()
652 {
653 m_lines.Empty();
654 }
655
SetHatchLines(const ON_ClassArray<ON_HatchLine> lines)656 int ON_HatchPattern::SetHatchLines( const ON_ClassArray<ON_HatchLine> lines)
657 {
658 m_lines = lines;
659 return m_lines.Count();
660 }
661
662
663
664
665 // class ON_HatchLoop
666 /////////////////////////////////////////////////////////////////
667
668 #if defined(ON_DLL_EXPORTS)
669
670 // When the Microsoft CRT(s) is/are used, this is the best
671 // way to prevent crashes that happen when a hatch loop is
672 // allocated with new in one DLL and deallocated with
673 // delete in another DLL.
674
operator new(size_t sz)675 void* ON_HatchLoop::operator new(size_t sz)
676 {
677 // ON_HatchLoop new
678 return onmalloc(sz);
679 }
680
operator delete(void * p)681 void ON_HatchLoop::operator delete(void* p)
682 {
683 // ON_HatchLoop delete
684 onfree(p);
685 }
686
operator new[](size_t sz)687 void* ON_HatchLoop::operator new[] (size_t sz)
688 {
689 // ON_HatchLoop array new
690 return onmalloc(sz);
691 }
692
operator delete[](void * p)693 void ON_HatchLoop::operator delete[] (void* p)
694 {
695 // ON_HatchLoop array delete
696 onfree(p);
697 }
698
operator new(size_t,void * p)699 void* ON_HatchLoop::operator new(size_t, void* p)
700 {
701 // ON_HatchLoop placement new
702 return p;
703 }
704
operator delete(void *,void *)705 void ON_HatchLoop::operator delete(void*, void*)
706 {
707 // ON_HatchLoop placement delete
708 return;
709 }
710
711 #endif
712
713
ON_HatchLoop()714 ON_HatchLoop::ON_HatchLoop()
715 : m_type( ON_HatchLoop::ltOuter), m_p2dCurve( NULL)
716 {
717 }
718
ON_HatchLoop(ON_Curve * pCurve2d,eLoopType type)719 ON_HatchLoop::ON_HatchLoop( ON_Curve* pCurve2d, eLoopType type)
720 : m_type( type), m_p2dCurve( pCurve2d)
721 {
722 }
723
ON_HatchLoop(const ON_HatchLoop & src)724 ON_HatchLoop::ON_HatchLoop( const ON_HatchLoop& src)
725 : m_type( src.m_type), m_p2dCurve( NULL)
726 {
727 if( src.m_p2dCurve)
728 m_p2dCurve = src.m_p2dCurve->DuplicateCurve();
729 }
730
~ON_HatchLoop()731 ON_HatchLoop::~ON_HatchLoop()
732 {
733 delete m_p2dCurve;
734 }
735
operator =(const ON_HatchLoop & src)736 ON_HatchLoop& ON_HatchLoop::operator=( const ON_HatchLoop& src)
737 {
738 if( this != &src)
739 {
740 if( m_p2dCurve)
741 delete m_p2dCurve;
742 m_p2dCurve = src.m_p2dCurve->DuplicateCurve();
743
744 m_type = src.m_type;
745 }
746 return *this;
747 }
748
IsValid(ON_TextLog * text_log) const749 ON_BOOL32 ON_HatchLoop::IsValid( ON_TextLog* text_log) const
750 {
751 ON_BOOL32 rc = m_p2dCurve != NULL;
752 if( !rc)
753 {
754 if( text_log)
755 text_log->Print( "2d loop curve is NULL\n");
756 }
757 if( rc)
758 {
759 rc = m_p2dCurve->IsValid( text_log);
760 if( !rc)
761 {
762 if( text_log)
763 text_log->Print( "Loop curve is not valid\n");
764 }
765 }
766
767 if( rc)
768 {
769 ON_BoundingBox box;
770 m_p2dCurve->GetBoundingBox( box);
771 rc = ( box.Max().z == box.Min().z && box.Max().z == 0.0);
772 if( !rc)
773 {
774 if( text_log)
775 text_log->Print( "2d loop curve has non-zero z coordinates\n");
776 }
777 }
778
779 if( rc && m_type != ltOuter && m_type != ltInner)
780 {
781 if( text_log)
782 text_log->Print( "Loop type is invalid.\n");
783 rc = false;
784 }
785
786 return rc;
787 }
788
Dump(ON_TextLog & dump) const789 void ON_HatchLoop::Dump( ON_TextLog& dump) const
790 {
791 if( m_type == ltOuter)
792 dump.Print( "Outer hatch loop\n");
793 if( m_type == ltInner)
794 dump.Print( "Inner hatch loop\n");
795
796 if ( 0 == m_p2dCurve )
797 {
798 dump.Print( "2d curve: null pointer\n");
799 }
800 else
801 {
802 dump.Print( "2d curve:\n");
803 m_p2dCurve->Dump(dump);
804 }
805
806 }
807
Write(ON_BinaryArchive & ar) const808 ON_BOOL32 ON_HatchLoop::Write( ON_BinaryArchive& ar) const
809 {
810 ON_BOOL32 rc = ar.Write3dmChunkVersion(1,1);
811 if( rc) rc = ar.WriteInt( m_type);
812 if( rc) rc = ar.WriteObject( m_p2dCurve);
813 return rc;
814 }
815
Read(ON_BinaryArchive & ar)816 ON_BOOL32 ON_HatchLoop::Read( ON_BinaryArchive& ar)
817 {
818 m_type = ltOuter;
819 delete m_p2dCurve;
820 m_p2dCurve = NULL;
821 int major_version = 0;
822 int minor_version = 0;
823 ON_BOOL32 rc = ar.Read3dmChunkVersion( &major_version, &minor_version);
824 if ( major_version == 1 )
825 {
826 int type = 0;
827 if( rc) rc = ar.ReadInt( &type);
828 if( rc)
829 {
830 switch( type)
831 {
832 case ltOuter: m_type = ltOuter; break;
833 case ltInner: m_type = ltInner; break;
834 default: rc = false; break;
835 }
836 }
837 if( rc)
838 {
839 ON_Object* pObj = NULL;
840 rc = ar.ReadObject( &pObj);
841 if( pObj)
842 {
843 m_p2dCurve = ON_Curve::Cast( pObj);
844 if( !m_p2dCurve) // read something, but it wasn't right
845 {
846 rc = false;
847 delete pObj;
848 }
849 }
850 }
851 }
852 return rc;
853 }
854
Curve() const855 const ON_Curve* ON_HatchLoop::Curve() const
856 {
857 return m_p2dCurve;
858 }
859
SetCurve(const ON_Curve & curve)860 bool ON_HatchLoop::SetCurve( const ON_Curve& curve)
861 {
862 ON_Curve* pC = curve.DuplicateCurve();
863 if( pC)
864 {
865 if(pC->Dimension() == 3 && !pC->ChangeDimension(2))
866 return false;
867
868 if( m_p2dCurve)
869 delete m_p2dCurve;
870 m_p2dCurve = pC;
871 }
872 return true;
873 }
Type() const874 ON_HatchLoop::eLoopType ON_HatchLoop::Type() const
875 {
876 return m_type;
877 }
878
SetType(eLoopType type)879 void ON_HatchLoop::SetType( eLoopType type)
880 {
881 m_type = type;
882 }
883
884 // class ON_Hatch
885 /////////////////////////////////////////////////////////////////
886 ON_OBJECT_IMPLEMENT( ON_Hatch, ON_Geometry, "0559733B-5332-49d1-A936-0532AC76ADE5");
887
888
ON_Hatch()889 ON_Hatch::ON_Hatch()
890 : m_pattern_scale( 1.0),
891 m_pattern_rotation( 0.0),
892 m_pattern_index( -1)
893 {
894 }
895
ON_Hatch(const ON_Hatch & src)896 ON_Hatch::ON_Hatch( const ON_Hatch& src)
897 : ON_Geometry(src),
898 m_plane( src.m_plane),
899 m_pattern_scale( src.m_pattern_scale),
900 m_pattern_rotation( src.m_pattern_rotation),
901 m_pattern_index( src.m_pattern_index)
902 {
903 m_loops.Reserve( src.m_loops.Count());
904 for( int i = 0; i < src.m_loops.Count(); i++)
905 {
906 ON_HatchLoop* pL = new ON_HatchLoop( *src.m_loops[i]);
907 m_loops.Append( pL);
908 }
909 }
910
operator =(const ON_Hatch & src)911 ON_Hatch& ON_Hatch::operator=( const ON_Hatch& src)
912 {
913 if( this != &src)
914 {
915 // Nov 3 2004 Dale Lear:
916 // Delete existing loops so we don't leak the memory;
917 int i;
918 for ( i = 0; i < m_loops.Count(); i++ )
919 {
920 ON_HatchLoop* pL = m_loops[i];
921 if ( pL )
922 {
923 m_loops[i] = 0;
924 delete pL;
925 }
926 }
927 m_loops.SetCount(0);
928
929 ON_Geometry::operator =(src);
930
931 m_plane = src.m_plane;
932 m_pattern_index = src.m_pattern_index;
933 m_pattern_scale = src.m_pattern_scale;
934 m_pattern_rotation = src.m_pattern_rotation;
935 m_loops.Reserve( src.m_loops.Count());
936 for( i = 0; i < src.m_loops.Count(); i++)
937 {
938 ON_HatchLoop* pL = new ON_HatchLoop( *src.m_loops[i]);
939 m_loops.Append( pL);
940 }
941 }
942 return *this;
943 }
944
~ON_Hatch()945 ON_Hatch::~ON_Hatch()
946 {
947 int i;
948 for ( i = 0; i < m_loops.Count(); i++ )
949 {
950 ON_HatchLoop* pL = m_loops[i];
951 if ( pL )
952 {
953 m_loops[i] = 0;
954 delete pL;
955 }
956 }
957 }
958
959
DuplicateHatch() const960 ON_Hatch* ON_Hatch::DuplicateHatch() const
961 {
962 return Duplicate();
963 }
964
IsValid(ON_TextLog * text_log) const965 ON_BOOL32 ON_Hatch::IsValid( ON_TextLog* text_log) const
966 {
967 ON_BOOL32 rc = m_plane.IsValid();
968 if( !rc)
969 {
970 if( text_log)
971 text_log->Print( "Plane is not valid\n");
972 return false;
973 }
974 // 18 June 2012 - Lowell - Added loop self-intersection and
975 // intersecting other loops tests
976 int count = m_loops.Count();
977 for(int i = 0; i < count; i++)
978 {
979 if(m_loops[i] == 0)
980 {
981 if( text_log)
982 text_log->Print( "Loop[%d] is NULL\n", i);
983 return false;
984 }
985 if(rc)
986 rc = m_loops[i]->IsValid( text_log);
987 if( !rc)
988 {
989 if( text_log)
990 text_log->Print( "Loop[%d] is not valid\n", i);
991 return false;
992 }
993 }
994
995 return true;
996 }
997
Dump(ON_TextLog & dump) const998 void ON_Hatch::Dump( ON_TextLog& dump) const
999 {
1000 dump.Print("Hatch: Pattern index: %d\n", PatternIndex());
1001 dump.Print("Pattern rotation: %g\n", PatternRotation());
1002 dump.Print("Pattern scale: %g\n", PatternScale());
1003 ON_3dPoint p = this->BasePoint();
1004 dump.Print("Base point: %g, %g, %g\n", p.x, p.y, p.z);
1005 dump.Print("Plane origin: %g, %g, %g\n", m_plane.origin.x, m_plane.origin.y, m_plane.origin.z);
1006 dump.Print("Plane x axis: %g, %g, %g\n", m_plane.xaxis.x, m_plane.xaxis.y, m_plane.xaxis.z);
1007 dump.Print("Plane y axis: %g, %g, %g\n", m_plane.yaxis.x, m_plane.yaxis.y, m_plane.yaxis.z);
1008 dump.Print("Plane z axis: %g, %g, %g\n", m_plane.zaxis.x, m_plane.zaxis.y, m_plane.zaxis.z);
1009 int count = m_loops.Count();
1010 dump.Print("Loop count = %d\n", count);
1011 for( int i = 0; i < count; i++)
1012 m_loops[i]->Dump( dump);
1013 }
1014
Write(ON_BinaryArchive & ar) const1015 ON_BOOL32 ON_Hatch::Write( ON_BinaryArchive& ar) const
1016 {
1017 ON_BOOL32 rc = ar.Write3dmChunkVersion(1,1);
1018 if (rc) rc = ar.WritePlane( m_plane);
1019 if (rc) rc = ar.WriteDouble( m_pattern_scale);
1020 if (rc) rc = ar.WriteDouble( m_pattern_rotation);
1021 if (rc) rc = ar.WriteInt( m_pattern_index);
1022 if (rc)
1023 {
1024 int i, count = m_loops.Count();
1025 if( count < 0 )
1026 count = 0;
1027 ON_BOOL32 rc = ar.WriteInt( count);
1028 for( i = 0; i < count && rc; i++)
1029 rc = m_loops[i]->Write( ar);
1030 }
1031 return rc;
1032 }
1033
Read(ON_BinaryArchive & ar)1034 ON_BOOL32 ON_Hatch::Read( ON_BinaryArchive& ar)
1035 {
1036 m_plane.CreateFromNormal( ON_origin, ON_zaxis);
1037 m_pattern_scale = 1.0;
1038 m_pattern_rotation = 0.0;
1039 m_pattern_index = -1;
1040 m_loops.Empty();
1041 int major_version = 0;
1042 int minor_version = 0;
1043 ON_BOOL32 rc = ar.Read3dmChunkVersion( &major_version, &minor_version);
1044 if ( major_version == 1 )
1045 {
1046 if( rc) rc = ar.ReadPlane( m_plane);
1047 if( rc) rc = ar.ReadDouble( &m_pattern_scale);
1048 if( rc) rc = ar.ReadDouble( &m_pattern_rotation);
1049 if( rc) rc = ar.ReadInt( &m_pattern_index);
1050 if( rc)
1051 {
1052 m_loops.Empty();
1053 int i, count = 0;
1054 rc = ar.ReadInt( &count);
1055 if( rc && count > 0)
1056 {
1057 m_loops.SetCapacity( count );
1058 for( i = 0; rc && i < count; i++)
1059 {
1060 ON_HatchLoop*& pLoop = m_loops.AppendNew();
1061 pLoop = new ON_HatchLoop;
1062 if( pLoop)
1063 rc = pLoop->Read( ar);
1064 else
1065 rc = false;
1066 }
1067 }
1068 }
1069 }
1070 return rc;
1071 }
1072
ObjectType() const1073 ON::object_type ON_Hatch::ObjectType() const
1074 {
1075 return ON::hatch_object;
1076 }
1077
Dimension() const1078 int ON_Hatch::Dimension() const
1079 {
1080 return 3;
1081 }
1082
1083 // Copy the 2d curve, make it 3d, and transform it
1084 // to the 3d plane position
LoopCurve3d(int index) const1085 ON_Curve* ON_Hatch::LoopCurve3d( int index) const
1086 {
1087 int count = m_loops.Count();
1088 ON_Curve* pC = NULL;
1089
1090 if( index >= 0 && index < count)
1091 {
1092 if( m_loops[index]->Curve())
1093 {
1094 pC = m_loops[index]->Curve()->DuplicateCurve();
1095 if( pC)
1096 {
1097 pC->ChangeDimension( 3);
1098
1099 ON_Xform xf;
1100 xf.Rotation( ON_xy_plane, m_plane);
1101
1102 pC->Transform( xf);
1103 }
1104 }
1105 }
1106 return pC;
1107 }
1108
1109
PatternIndex() const1110 int ON_Hatch::PatternIndex() const
1111 {
1112 return m_pattern_index;
1113 }
1114
SetPatternIndex(int index)1115 void ON_Hatch::SetPatternIndex( int index)
1116 {
1117 m_pattern_index = index;
1118 }
1119
1120
GetBBox(double * bmin,double * bmax,ON_BOOL32 bGrowBox) const1121 ON_BOOL32 ON_Hatch::GetBBox( double* bmin, double* bmax, ON_BOOL32 bGrowBox) const
1122 {
1123 int i;
1124 int count = m_loops.Count();
1125 ON_BOOL32 rc = true;
1126 ON_Curve* pC;
1127 for( i = 0; rc && i < count; i++)
1128 {
1129 pC = LoopCurve3d( i);
1130 if( pC)
1131 {
1132 rc = pC->GetBBox( bmin, bmax, i?true:bGrowBox);
1133 delete pC;
1134 }
1135 }
1136 return rc;
1137 }
1138
GetTightBoundingBox(ON_BoundingBox & tight_bbox,int bGrowBox,const ON_Xform * xform) const1139 bool ON_Hatch::GetTightBoundingBox( ON_BoundingBox& tight_bbox, int bGrowBox, const ON_Xform* xform) const
1140 {
1141 int i;
1142 int count = m_loops.Count();
1143 ON_CurveArray curves(count);
1144 for( i = 0; i < count; i++)
1145 {
1146 curves.Append( LoopCurve3d(i) );
1147 }
1148 return curves.GetTightBoundingBox(tight_bbox,bGrowBox,xform);
1149 }
1150
Angle3d(const ON_3dVector & axis,ON_3dVector & from,const ON_3dVector & to)1151 static double Angle3d(const ON_3dVector& axis, ON_3dVector& from, const ON_3dVector& to)
1152 {
1153 ON_3dVector x = from, a = to;
1154 x.Unitize();
1155 a.Unitize();
1156
1157 ON_3dVector y = ON_CrossProduct(axis, from);
1158 y.Unitize();
1159
1160 double cosa = x * a;
1161
1162 if(cosa > 1.0 - ON_SQRT_EPSILON)
1163 return 0.0;
1164 if(cosa < ON_SQRT_EPSILON - 1.0)
1165 return ON_PI;
1166
1167 double sina = a * y;
1168
1169 return atan2(sina, cosa);
1170 }
1171
1172
1173 #define ARBBOUND 0.015625
arbaxis(const ON_3dVector & givenaxis,ON_3dVector & newaxis)1174 void arbaxis(const ON_3dVector& givenaxis, ON_3dVector& newaxis)
1175 {
1176 if(fabs(givenaxis[0]) < ARBBOUND && fabs(givenaxis[1]) < ARBBOUND) // near world z
1177 newaxis = ON_CrossProduct(ON_yaxis, givenaxis);
1178 else
1179 newaxis = ON_CrossProduct(ON_zaxis, givenaxis);
1180
1181 newaxis.Unitize();
1182 }
1183
arbaxisRotation(const ON_Plane & plane)1184 double arbaxisRotation(const ON_Plane& plane)
1185 {
1186 // get arbaxis frame and angle of rotation from it
1187 ON_3dVector arbXaxis;
1188 arbaxis(plane.zaxis, arbXaxis);
1189 return Angle3d(plane.zaxis, arbXaxis, plane.xaxis);
1190 }
1191
1192 // 20 June 2012 - Lowell - rr44706, 68320
1193 // This will find A, the arbaxis direction for the hatch plane
1194 // and rotate the hatch plane by -A and rotate the hatch boundaries
1195 // by A and add A to the hatch rotation.
1196 // The picture will be the same after that, but the way the
1197 // angle is represented will match the way AutoCAD does it
1198 // so hatches can be round-tripped with acad files.
1199 // In addition, after several hatches are rotated by different amounts
1200 // the hatch angles can be set to look the same by setting them all
1201 // to the same pattern rotation
1202
UnrotateHatch(ON_Hatch * hatch)1203 static void UnrotateHatch(ON_Hatch* hatch)
1204 {
1205 double a = arbaxisRotation(hatch->Plane());
1206 ON_Plane& plane = *(ON_Plane*)(&hatch->Plane());
1207 if(fabs(a) > ON_ZERO_TOLERANCE)
1208 {
1209 plane.Rotate(-a, plane.zaxis);
1210 for(int i = 0; i < hatch->LoopCount(); i++)
1211 {
1212 ON_Curve* pC = (ON_Curve*)hatch->Loop(i)->Curve();
1213 pC->Rotate(a, ON_zaxis, ON_origin);
1214 }
1215 hatch->SetPatternRotation(hatch->PatternRotation()+a);
1216 }
1217 ON_3dPoint P;
1218 plane.ClosestPointTo(ON_origin, &P.x, &P.y);
1219
1220 if(fabs(P.x) > ON_ZERO_TOLERANCE ||fabs(P.y) > ON_ZERO_TOLERANCE ||fabs(P.z) > ON_ZERO_TOLERANCE)
1221 {
1222 ON_2dVector V(-P.x, -P.y);
1223 for(int i = 0; i < hatch->LoopCount(); i++)
1224 {
1225 ON_Curve* pC = (ON_Curve*)hatch->Loop(i)->Curve();
1226 pC->Translate(V);
1227 }
1228 P = plane.PointAt(P.x, P.y);
1229 plane.origin = P;
1230 }
1231 }
1232
Transform(const ON_Xform & xform)1233 ON_BOOL32 ON_Hatch::Transform( const ON_Xform& xform)
1234 {
1235 if( fabs( fabs( xform.Determinant()) - 1.0) > 1.0e-4)
1236 {
1237 // xform has a scale component
1238 ON_Plane tmp( m_plane);
1239 tmp.Transform( xform);
1240 ON_Xform A, B, T;
1241 A.Rotation( ON_xy_plane, m_plane);
1242 B.Rotation( tmp, ON_xy_plane);
1243 T = B * xform * A;
1244
1245 // kill translation and z-scaling
1246 T[0][2] = T[0][3] = 0.0;
1247 T[1][2] = T[1][3] = 0.0;
1248 T[2][0] = T[2][1] = 0.0; T[2][2] = 1.0; T[2][3] = 0.0;
1249 T[3][0] = T[3][1] = T[3][2] = 0.0; T[3][3] = 1.0;
1250
1251 for( int i = 0; i < LoopCount(); i++)
1252 m_loops[i]->m_p2dCurve->Transform( T);
1253 }
1254 int rc = m_plane.Transform( xform);
1255
1256 UnrotateHatch(this);
1257
1258 TransformUserData(xform);
1259
1260
1261
1262
1263 return rc;
1264 }
1265
Create(const ON_Plane & plane,const ON_SimpleArray<const ON_Curve * > loops,int pattern_index,double pattern_rotation,double pattern_scale)1266 bool ON_Hatch::Create( const ON_Plane& plane,
1267 const ON_SimpleArray<const ON_Curve*> loops,
1268 int pattern_index,
1269 double pattern_rotation,
1270 double pattern_scale)
1271 {
1272 if( loops.Count() < 1)
1273 return false;
1274 if( pattern_index < 0)
1275 return false;
1276 SetPlane( plane);
1277 for( int i = 0; i < loops.Count(); i++)
1278 {
1279 ON_HatchLoop* pLoop = new ON_HatchLoop;
1280 pLoop->SetCurve( *loops[i]);
1281 pLoop->SetType( i?ON_HatchLoop::ltInner:ON_HatchLoop::ltOuter);
1282 AddLoop( pLoop);
1283 }
1284 SetPatternIndex( pattern_index);
1285 SetPatternRotation( pattern_rotation);
1286 SetPatternScale( pattern_scale);
1287 return true;
1288 }
1289
Plane() const1290 const ON_Plane& ON_Hatch::Plane() const
1291 {
1292 return m_plane;
1293 }
1294
SetPlane(const ON_Plane & plane)1295 void ON_Hatch::SetPlane( const ON_Plane& plane)
1296 {
1297 m_plane = plane;
1298 }
1299
PatternRotation() const1300 double ON_Hatch::PatternRotation() const
1301 {
1302 return m_pattern_rotation;
1303 }
1304
SetPatternRotation(double rotation)1305 void ON_Hatch::SetPatternRotation( double rotation)
1306 {
1307 m_pattern_rotation = rotation;
1308 }
1309
PatternScale() const1310 double ON_Hatch::PatternScale() const
1311 {
1312 return m_pattern_scale;
1313 }
1314
SetPatternScale(double scale)1315 void ON_Hatch::SetPatternScale( double scale)
1316 {
1317 if( scale > 0.001) // Changed May 13, 2009 - Lowell - rr39185
1318 m_pattern_scale = scale;
1319 }
1320
LoopCount() const1321 int ON_Hatch::LoopCount() const
1322 {
1323 return m_loops.Count();
1324 }
1325
AddLoop(ON_HatchLoop * pLoop)1326 void ON_Hatch::AddLoop( ON_HatchLoop* pLoop)
1327 {
1328 m_loops.Append( pLoop);
1329 }
1330
InsertLoop(int index,ON_HatchLoop * loop)1331 bool ON_Hatch::InsertLoop( int index, ON_HatchLoop* loop)
1332 {
1333 if( index >= 0 && index <= m_loops.Count()) // 26 June 2012 - Lowell - Changed ndex < to ndex <=
1334 {
1335 m_loops.Insert(index, loop);
1336 return true;
1337 }
1338
1339 return false;
1340 }
1341
RemoveLoop(int index)1342 bool ON_Hatch::RemoveLoop( int index)
1343 {
1344 if( index >= 0 && index < m_loops.Count())
1345 {
1346 delete m_loops[index];
1347 m_loops.Remove(index);
1348 return true;
1349 }
1350
1351 return false;
1352 }
1353
1354
ReplaceLoops(ON_SimpleArray<const ON_Curve * > loop_curves)1355 bool ON_Hatch::ReplaceLoops(ON_SimpleArray<const ON_Curve*> loop_curves)
1356 {
1357 if(loop_curves.Count() < 1)
1358 return false;
1359
1360 bool rc = true;
1361 ON_Xform xf;
1362 bool flat = false;
1363 ON_SimpleArray<ON_HatchLoop*> loops;
1364
1365 for(int i = 0; i < loop_curves.Count(); i++)
1366 {
1367 if(loop_curves[i] == 0)
1368 {
1369 rc = false;
1370 break;
1371 }
1372 ON_Curve* p2d = loop_curves[i]->Duplicate();
1373 if(p2d == 0)
1374 {
1375 rc = false;
1376 break;
1377 }
1378 if(p2d->Dimension() == 3)
1379 {
1380 if(!flat)
1381 {
1382 xf.PlanarProjection(m_plane);
1383 flat = true;
1384 }
1385 if(!p2d->Transform(xf) ||
1386 !p2d->ChangeDimension(2))
1387 {
1388 delete p2d;
1389 rc = false;
1390 break;
1391 }
1392 }
1393 ON_HatchLoop* loop = new ON_HatchLoop(p2d,loops.Count()?ON_HatchLoop::ltInner:ON_HatchLoop::ltOuter);
1394 if(loop)
1395 loops.Append(loop);
1396 else
1397 delete p2d;
1398 }
1399 if(!rc)
1400 {
1401 for(int i = 0; i < loops.Count(); i++)
1402 delete loops[i];
1403
1404 loops.Empty();
1405 }
1406
1407 if(loops.Count() < 1)
1408 return false;
1409
1410 for(int i = 0; i < m_loops.Count(); i++)
1411 delete m_loops[i];
1412 m_loops.Empty();
1413 for(int i = 0; i < loops.Count(); i++)
1414 m_loops.Append(loops[i]);
1415 return true;
1416 }
1417
Loop(int index) const1418 const ON_HatchLoop* ON_Hatch::Loop( int index) const
1419 {
1420 if( index >= 0 && index < m_loops.Count())
1421 return m_loops[index];
1422
1423 return NULL;
1424 }
1425
1426 // Basepoint functions added March 23, 2008 -LW
SetBasePoint(ON_2dPoint basepoint)1427 void ON_Hatch::SetBasePoint(ON_2dPoint basepoint)
1428 {
1429 ON_HatchExtra* pE = ON_HatchExtra::HatchExtension(this,true);
1430 if(pE)
1431 {
1432 pE->SetBasePoint(basepoint);
1433 }
1434 }
1435
SetBasePoint(ON_3dPoint point)1436 void ON_Hatch::SetBasePoint(ON_3dPoint point)
1437 {
1438 ON_HatchExtra* pE = ON_HatchExtra::HatchExtension(this,true);
1439 if(pE)
1440 {
1441 ON_2dPoint base;
1442 if(m_plane.ClosestPointTo(point, &base.x, &base.y))
1443 pE->SetBasePoint(base);
1444 }
1445 }
1446
BasePoint() const1447 ON_3dPoint ON_Hatch::BasePoint() const
1448 {
1449 ON_3dPoint point(ON_origin);
1450 const ON_HatchExtra* pE = ON_HatchExtra::HatchExtension(this,false);
1451 if(pE)
1452 {
1453 ON_2dPoint base = pE->BasePoint();
1454 point = m_plane.PointAt(base.x, base.y);
1455 }
1456 return point;
1457 }
1458
BasePoint2d() const1459 ON_2dPoint ON_Hatch::BasePoint2d() const
1460 {
1461 ON_2dPoint basepoint(0.0,0.0);
1462 const ON_HatchExtra* pE = ON_HatchExtra::HatchExtension(this,false);
1463 if(pE)
1464 basepoint = pE->BasePoint();
1465
1466 return basepoint;
1467 }
1468
1469 // Added March 23, 2008 -LW
1470 // This function is temporary and will be removed next time the SDK can be modified.
HatchExtension()1471 class ON_HatchExtra* ON_Hatch::HatchExtension()
1472 {
1473 ON_HatchExtra* pExtra = ON_HatchExtra::Cast( GetUserData( ON_HatchExtra::m_ON_HatchExtra_class_id.Uuid()));
1474 return pExtra;
1475 }
1476