opennurbs_hatch.cpp
Go to the documentation of this file.
00001 /* $NoKeywords: $ */
00002 /*
00003 //
00004 // Copyright (c) 1993-2012 Robert McNeel & Associates. All rights reserved.
00005 // OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
00006 // McNeel & Associates.
00007 //
00008 // THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
00009 // ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
00010 // MERCHANTABILITY ARE HEREBY DISCLAIMED.
00011 //                              
00012 // For complete openNURBS copyright information see <http://www.opennurbs.org>.
00013 //
00015 */
00016 #include "pcl/surface/3rdparty/opennurbs/opennurbs.h"
00017 
00018 //March 23, 2008 - LW
00019 //Adding ON_HatchExtra class to support movable base point for hatches
00020 //This should be combined with the ON_Hatch class next time that is possible
00021 // Don't put this extension class in a header file or export it.
00022 
00023 class ON_HatchExtra : public ON_UserData
00024 {
00025   ON_OBJECT_DECLARE(ON_HatchExtra);
00026 public:
00027   static ON_HatchExtra* HatchExtension(ON_Hatch* pHatch, bool bCreate);
00028   static const ON_HatchExtra* HatchExtension(const ON_Hatch* pHatch, bool bCreate);
00029 
00030   ON_HatchExtra();
00031   ~ON_HatchExtra();
00032 
00033   void SetDefaults();
00034 
00035   // override virtual ON_Object::Dump function
00036   void Dump( ON_TextLog& text_log ) const;
00037 
00038   // override virtual ON_Object::SizeOf function
00039   unsigned int SizeOf() const;
00040 
00041   // override virtual ON_Object::Write function
00042   ON_BOOL32 Write(ON_BinaryArchive& binary_archive) const;
00043 
00044   // override virtual ON_Object::Read function
00045   ON_BOOL32 Read(ON_BinaryArchive& binary_archive);
00046 
00047   // override virtual ON_UserData::GetDescription function
00048   ON_BOOL32 GetDescription( ON_wString& description );
00049 
00050   // override virtual ON_UserData::Archive function
00051   ON_BOOL32 Archive() const; 
00052 
00053   // Get and set a 2d point in the hatch's ECS coordinates
00054   void SetBasePoint(ON_2dPoint& basepoint);
00055   ON_2dPoint BasePoint() const;
00056 
00057   ON_UUID    m_parent_hatch; // Hatch this extends or ON_nil_uuid
00058   ON_2dPoint m_basepoint;    // Base point in hatch's ECS
00059   
00060 };
00061 
00062 ON_OBJECT_IMPLEMENT(ON_HatchExtra,ON_UserData,"3FF7007C-3D04-463f-84E3-132ACEB91062");
00063 
00064 ON_HatchExtra* ON_HatchExtra::HatchExtension(ON_Hatch* pHatch, bool bCreate)
00065 {
00066   ON_HatchExtra* pExtra = 0;
00067   if(pHatch)
00068   {
00069     pExtra = ON_HatchExtra::Cast(pHatch->GetUserData(ON_HatchExtra::m_ON_HatchExtra_class_id.Uuid()));
00070     if(pExtra == 0 && bCreate)
00071     {
00072       pExtra = new ON_HatchExtra;
00073       if(pExtra)
00074       {
00075         if(!pHatch->AttachUserData(pExtra))
00076         {
00077           delete pExtra;
00078           pExtra = 0;
00079         }
00080       }  
00081     }
00082   }
00083   return pExtra;
00084 }
00085 
00086 const ON_HatchExtra* ON_HatchExtra::HatchExtension(const ON_Hatch* pHatch, bool bCreate)
00087 {
00088   return HatchExtension((ON_Hatch*)pHatch, bCreate);
00089 }
00090 
00091 ON_HatchExtra::ON_HatchExtra()
00092 {
00093   m_userdata_uuid = ON_HatchExtra::m_ON_HatchExtra_class_id.Uuid();
00094   m_application_uuid = ON_opennurbs5_id; // opennurbs.dll reads/writes this userdata
00095                                          // The id must be the version 5 id because
00096                                          // V6 SaveAs V5 needs to work, but SaveAs
00097                                          // V4 should not write this userdata.   
00098   m_userdata_copycount = 1;
00099   SetDefaults();
00100 }
00101 
00102 ON_HatchExtra::~ON_HatchExtra()
00103 {
00104 }
00105 
00106 void ON_HatchExtra::SetDefaults()
00107 {
00108   m_parent_hatch = ON_nil_uuid;
00109   m_basepoint.Set(0.0,0.0);
00110 }
00111 
00112 void ON_HatchExtra::Dump(ON_TextLog& text_log) const
00113 {
00114 }
00115 
00116 unsigned int ON_HatchExtra::SizeOf() const
00117 {
00118   unsigned int sz = ON_UserData::SizeOf();
00119   sz += sizeof(*this)-sizeof(ON_UserData);
00120   return sz;
00121 }
00122 
00123 ON_BOOL32 ON_HatchExtra::Write(ON_BinaryArchive& archive) const
00124 {
00125   bool rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0);
00126 
00127   if(rc) rc = archive.WriteUuid( m_parent_hatch);
00128   if(rc) rc = archive.WritePoint(m_basepoint);
00129 
00130   if(!archive.EndWrite3dmChunk())
00131     rc = false;
00132 
00133   return rc;
00134 }
00135 
00136 ON_BOOL32 ON_HatchExtra::Read(ON_BinaryArchive& archive)
00137 {
00138   int major_version = 0;
00139   int minor_version = 0;
00140   bool rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version);
00141 
00142   if(major_version != 1)
00143       rc = false;
00144 
00145   m_basepoint.Set(0.0,0.0);
00146   if(rc) rc = archive.ReadUuid(m_parent_hatch);
00147   if(rc) rc = archive.ReadPoint(m_basepoint);
00148 
00149   if(!archive.EndRead3dmChunk())
00150     rc = false;
00151 
00152   return rc;
00153 }
00154 
00155 ON_BOOL32 ON_HatchExtra::GetDescription( ON_wString& description)
00156 {
00157   description.Format( "Userdata extension of ON_Hatch (contains basepoint)");
00158   return true;
00159 }
00160 
00161 ON_BOOL32 ON_HatchExtra::Archive() const
00162 {
00163   return true;
00164 }
00165 
00166 void ON_HatchExtra::SetBasePoint(ON_2dPoint& point)
00167 {
00168   if(point.IsValid())
00169     m_basepoint = point;
00170 }
00171 
00172 ON_2dPoint ON_HatchExtra::BasePoint() const
00173 {
00174   return m_basepoint;
00175 }
00176 
00178 //  class ON_HatchLine
00180 
00181 ON_HatchLine::ON_HatchLine()
00182 : m_angle( 0.0), m_base( 0.0,0.0), m_offset( 0.0, 1.0)
00183 {
00184 }
00185 
00186 ON_HatchLine::ON_HatchLine(double angle, 
00187                            const ON_2dPoint& base, 
00188                            const ON_2dVector& offset,
00189                            const ON_SimpleArray<double> dashes)
00190 : m_angle( angle), m_base( base), m_offset( offset), m_dashes( dashes)
00191 {
00192 }
00193 
00194 bool ON_HatchLine::operator==(const ON_HatchLine& src) const
00195 {
00196   return( m_angle == src.m_angle && 
00197           m_base == src.m_base &&
00198           m_offset == src.m_offset && 
00199           m_dashes == src.m_dashes);
00200 }
00201 
00202 bool ON_HatchLine::operator!=(const ON_HatchLine& src) const
00203 {
00204   return !operator==( src);
00205 }
00206 
00207 ON_BOOL32 ON_HatchLine::IsValid( ON_TextLog* text_log) const
00208 {
00209   bool rc = m_angle >= 0.0;
00210   if( !rc)
00211   {
00212     if( text_log)
00213       text_log->Print( "Angle ( %lf) must be >= 0.0\n", m_angle);
00214     return false;
00215   }
00216   rc = m_angle < ON_PI * 2.0;
00217   if( !rc)
00218   {
00219     if( text_log)
00220       text_log->Print( "Angle ( %lf) must be < 2*Pi.\n", m_angle);
00221     return false;
00222   }
00223   rc = m_base != ON_2dPoint( ON_UNSET_VALUE, ON_UNSET_VALUE);
00224   if( !rc)
00225   {
00226     if( text_log)
00227       text_log->Print( "Base is not a valid point.\n");
00228     return false;
00229   }
00230   rc = m_offset.x != ON_UNSET_VALUE;
00231   if( !rc)
00232   {
00233     if( text_log)
00234       text_log->Print( "Offset is not a valid vector.\n");
00235     return false;
00236   }
00237   rc = m_offset.y > ON_SQRT_EPSILON;
00238   if( !rc)
00239   {
00240     if( text_log)
00241       text_log->Print( "Offset.y ( %lf) must be > 0.0", m_offset.y);
00242     return false;
00243   }
00244   return true;
00245 }
00246 
00247 void ON_HatchLine::Dump( ON_TextLog& dump) const
00248 {
00249   dump.Print( "ON_HatchLine: angle = %lf radians ( %lf degrees) ", 
00250     Angle(), ON_RADIANS_TO_DEGREES * Angle());
00251   dump.Print( " base = ");
00252   dump.Print( m_base);
00253   dump.Print( " offset = ");
00254   dump.Print( m_offset);
00255   int count = m_dashes.Count();
00256   dump.Print( "\nDash count = %d: ", count);
00257   for( int i = 0; i < count; i++)
00258   {
00259     dump.Print( "%lf", Dash( i));
00260     if( i < count-1)
00261       dump.Print( ", ");
00262   }
00263   dump.Print( "\n");
00264 }
00265 
00266 ON_BOOL32 ON_HatchLine::Write( ON_BinaryArchive& ar) const
00267 {
00268   ON_BOOL32 rc = ar.Write3dmChunkVersion(1,1);
00269 
00270   if (rc) rc = ar.WriteDouble( m_angle);
00271   if (rc) rc = ar.WritePoint( m_base);
00272   if (rc) rc = ar.WriteVector( m_offset);
00273   if (rc) rc = ar.WriteArray( m_dashes);
00274 
00275   return rc;
00276 }
00277 
00278 ON_BOOL32 ON_HatchLine::Read( ON_BinaryArchive& ar)
00279 {
00280   m_angle = 0.0;
00281   m_base.Set( 0.0, 0.0);
00282   m_offset.Set( 0.0, 1.0);
00283   m_dashes.Empty();
00284   int major_version = 0;
00285   int minor_version = 0;
00286   ON_BOOL32 rc = ar.Read3dmChunkVersion( &major_version, &minor_version);
00287   if ( major_version == 1 ) 
00288   {
00289     if ( rc) rc = ar.ReadDouble( &m_angle);
00290     if ( rc) rc = ar.ReadPoint( m_base);
00291     if ( rc) rc = ar.ReadVector( m_offset);
00292     if ( rc) rc = ar.ReadArray( m_dashes);
00293   }
00294   return rc;
00295 }
00296 
00297 // ON_HatchLine Interface
00298 double ON_HatchLine::Angle() const
00299 {
00300   return m_angle;
00301 }
00302 
00303 void ON_HatchLine::SetAngle( double angle)
00304 {
00305   m_angle = angle;
00306   double twopi = ON_PI * 2.0;
00307 
00308   // clamp between [0  2pi)
00309   while( m_angle < 0.0)
00310     m_angle += twopi;
00311   while( m_angle > twopi)
00312     m_angle -= twopi;
00313 }
00314 
00315 ON_2dPoint ON_HatchLine::Base() const
00316 {
00317   return m_base;
00318 }
00319 
00320 void ON_HatchLine::SetBase( const ON_2dPoint& base)
00321 {
00322   m_base = base;
00323 }
00324 
00325 ON_2dVector ON_HatchLine::Offset() const
00326 {
00327   return m_offset;
00328 }
00329 
00330 void ON_HatchLine::SetOffset( const ON_2dVector& offset)
00331 {
00332   m_offset = offset;
00333 }
00334 
00335 int ON_HatchLine::DashCount() const
00336 {
00337   return m_dashes.Count();
00338 }
00339 
00340 double ON_HatchLine::Dash( int index) const
00341 {
00342   if( index >= 0 && index < m_dashes.Count())
00343     return m_dashes[index];
00344   return 0.0;
00345 }
00346 
00347 void ON_HatchLine::AppendDash( double dash)
00348 {
00349 //  if( fabs( dash) > ON_SQRT_EPSILON)
00350     m_dashes.Append( dash);
00351 }
00352 
00353 void ON_HatchLine::SetPattern( const ON_SimpleArray<double>& dashes)
00354 {
00355   m_dashes = dashes;
00356 }
00357 
00358 void ON_HatchLine::GetLineData( double& angle, 
00359                                 ON_2dPoint& base, 
00360                                 ON_2dVector& offset, 
00361                                 ON_SimpleArray<double>& dashes) const
00362 {
00363   angle = m_angle;
00364   base = m_base;
00365   offset = m_offset;  dashes = m_dashes;
00366 }
00367 
00368 double ON_HatchLine::GetPatternLength() const
00369 {
00370   int i;
00371   double length = 0.0;
00372   for( i = 0; i < m_dashes.Count(); i++)
00373     length += fabs( m_dashes[i]);
00374 
00375   return length;
00376 }
00377 
00378 
00379 //  class ON_HatchPattern
00381 ON_OBJECT_IMPLEMENT( ON_HatchPattern, ON_Object, "064E7C91-35F6-4734-A446-79FF7CD659E1" );
00382 
00383 ON_HatchPattern::ON_HatchPattern()
00384 : m_hatchpattern_index(-1)
00385 , m_hatchpattern_id(ON_nil_uuid)
00386 , m_type(ON_HatchPattern::ftSolid)
00387 {
00388 }
00389 
00390 ON_HatchPattern::~ON_HatchPattern()
00391 {
00392 }
00393 
00394 ON_BOOL32 ON_HatchPattern::IsValid( ON_TextLog* text_log) const
00395 {
00396   eFillType type = FillType();
00397   ON_BOOL32 rc = true;
00398   if( type != ftSolid && type != ftLines && type != ftGradient)
00399   {
00400     if( text_log)
00401       text_log->Print( "Type field not set correctly.\n");
00402     rc = false;
00403   }
00404   if( type == ftLines)
00405   {
00406     int count = m_lines.Count();
00407     if( count < 1)
00408     {
00409       if( text_log)
00410         text_log->Print( "Line type patetern with no lines.\n");
00411       return false;
00412     }
00413     for( int i = 0; i < count; i++)
00414     {
00415       if( !m_lines[i].IsValid())
00416       {
00417         if( text_log)
00418           text_log->Print( "Line[%d] is not valid.\n", i);
00419         return false;
00420       }
00421     }
00422     return true;
00423   }
00424   return rc;
00425 }
00426 
00427 void ON_HatchPattern::Dump( ON_TextLog& dump) const
00428 {
00429   dump.Print( "Hatch pattern - ");
00430   switch( m_type)
00431   {
00432   case ftSolid:
00433     dump.Print( "fill type: Solid");
00434     break;
00435   case ftLines:
00436     dump.Print( "fill type: Lines");
00437     break;
00438   case ftGradient:
00439     dump.Print( "fill type: Gradient");
00440     break;
00441   case ftLast:
00442     // no action, but this keeps gcc happy
00443     break;
00444   }
00445   dump.Print( "\n");
00446 
00447   const wchar_t* wsHatchPatternName = m_hatchpattern_name;
00448   if ( 0 == wsHatchPatternName )
00449     wsHatchPatternName = L"";
00450   dump.Print( "Name: %ls\n", wsHatchPatternName);
00451 
00452   const wchar_t* wsDescription =  m_description;
00453   if ( 0 == wsDescription )
00454     wsDescription = L"";
00455   dump.Print( "Description: %ls\n", wsDescription);
00456 
00457   if( m_type == ftLines)
00458   {
00459     int count = m_lines.Count();
00460     dump.Print( "Line count = %d\n", count);
00461     for( int i = 0; i < count; i++)
00462     {
00463       m_lines[i].Dump( dump);
00464     }
00465     dump.Print( "\n");
00466   }
00467 }
00468 
00469 ON_BOOL32 ON_HatchPattern::Write( ON_BinaryArchive& ar) const
00470 {
00471   ON_BOOL32 rc = ar.Write3dmChunkVersion(1,2);
00472 
00473   if (rc) rc = ar.WriteInt( m_hatchpattern_index);
00474   if (rc) rc = ar.WriteInt( m_type);
00475   if (rc) rc = ar.WriteString( m_hatchpattern_name);
00476   if (rc) rc = ar.WriteString( m_description);
00477   if( rc)
00478   {
00479     if( m_type == ftLines)
00480     {
00481       int i, count = m_lines.Count();
00482       if ( count < 0 )
00483         count = 0;
00484       rc = ar.WriteInt( count );
00485       for( i = 0; i < count && rc; i++)
00486         rc = m_lines[i].Write( ar);
00487     }
00488   }
00489   // version 1.2 field
00490   if (rc) rc = ar.WriteUuid(m_hatchpattern_id);
00491 
00492   return rc;
00493 }
00494 
00495 ON_BOOL32 ON_HatchPattern::Read( ON_BinaryArchive& ar)
00496 {
00497   m_hatchpattern_index = -1;
00498   memset(&m_hatchpattern_id,0,sizeof(m_hatchpattern_id));
00499   m_type = ftSolid;
00500   m_hatchpattern_name.Empty();
00501   m_description.Empty();
00502   m_lines.Empty();
00503   int i;
00504 
00505   int major_version = 0;
00506   int minor_version = 0;
00507   ON_BOOL32 rc = ar.Read3dmChunkVersion( &major_version, &minor_version);
00508   if ( major_version == 1 ) 
00509   {
00510     if( rc) rc = ar.ReadInt( &m_hatchpattern_index);
00511     i = 0;
00512     if( rc) rc = ar.ReadInt( &i);
00513     if( rc) 
00514     {
00515       switch( i)
00516       {
00517       case 0:  m_type = ftSolid;    break;
00518       case 1:  m_type = ftLines;    break;
00519       case 2:  m_type = ftGradient; break;
00520       default: rc = false;          break;
00521       }
00522     }
00523     if( rc) rc = ar.ReadString( m_hatchpattern_name);
00524     if( rc) rc = ar.ReadString( m_description);
00525     if( rc)
00526     {
00527       if( m_type == ftLines)
00528       {
00529         m_lines.Empty();
00530         int count = 0;
00531         rc = ar.ReadInt( &count);
00532         if( rc && count > 0 ) 
00533         {
00534           m_lines.SetCapacity( count);
00535           int i;
00536           for( i = 0; rc && i < count; i++)
00537           {
00538             ON_HatchLine& line = m_lines.AppendNew();
00539             rc = line.Read( ar);
00540           }
00541         }
00542       }
00543     }
00544     if ( minor_version >= 2 )
00545     {
00546       rc = ar.ReadUuid(m_hatchpattern_id);
00547     }
00548   }
00549   return rc;
00550 }
00551 
00552 ON_HatchPattern::eFillType ON_HatchPattern::FillType() const
00553 {
00554   if( m_type >= ftSolid && m_type < ftLast)
00555     return m_type;
00556 
00557   return ftLast;
00558 }
00559 
00560 void ON_HatchPattern::SetFillType( eFillType type)
00561 {
00562   m_type = type;
00563 }
00564 
00565 void ON_HatchPattern::SetName( const wchar_t* pName)
00566 {
00567   m_hatchpattern_name = pName;
00568   m_hatchpattern_name.TrimLeftAndRight();
00569 }
00570 
00571 void ON_HatchPattern::SetName( const char* pName)
00572 {
00573   m_hatchpattern_name = pName;
00574   m_hatchpattern_name.TrimLeftAndRight();
00575 }
00576 
00577 void ON_HatchPattern::GetName( ON_wString& string) const
00578 {
00579   string = m_hatchpattern_name;
00580 }
00581 
00582 const wchar_t* ON_HatchPattern::Name() const
00583 {
00584   return m_hatchpattern_name;
00585 }
00586 
00587 
00588 void ON_HatchPattern::SetDescription( const wchar_t* pDescription)
00589 {
00590   m_description = pDescription;
00591 }
00592 
00593 void ON_HatchPattern::SetDescription( const char* pDescription)
00594 {
00595   m_description = pDescription;
00596 }
00597 
00598 void ON_HatchPattern::GetDescription( ON_wString& string) const
00599 {
00600   string = m_description;
00601 }
00602 
00603 const wchar_t* ON_HatchPattern::Description() const
00604 {
00605   return m_description;
00606 }
00607 
00608 
00609 void ON_HatchPattern::SetIndex( int i)
00610 {
00611   m_hatchpattern_index = i;
00612 }
00613 
00614 int ON_HatchPattern::Index() const
00615 {
00616   return m_hatchpattern_index;
00617 }
00618 
00619 
00620 //  Line HatchPattern functions
00621 
00622 int ON_HatchPattern::HatchLineCount() const
00623 {
00624   return m_lines.Count();
00625 }
00626 
00627 int ON_HatchPattern::AddHatchLine( const ON_HatchLine& line)
00628 {
00629   m_lines.Append( line);
00630   return m_lines.Count()-1;
00631 }
00632 
00633 const ON_HatchLine* ON_HatchPattern::HatchLine( int index) const
00634 {
00635   if( index >= 0 && index < m_lines.Count())
00636     return &m_lines[index];
00637   else
00638     return NULL;
00639 }
00640 
00641 bool ON_HatchPattern::RemoveHatchLine( int index)
00642 {
00643   if( index >= 0 && index < m_lines.Count())
00644   {
00645     m_lines.Remove( index);
00646     return true;
00647   }
00648   return false;
00649 }
00650 
00651 void ON_HatchPattern::RemoveAllHatchLines()
00652 {
00653   m_lines.Empty();
00654 }
00655 
00656 int ON_HatchPattern::SetHatchLines( const ON_ClassArray<ON_HatchLine> lines)
00657 {
00658   m_lines = lines;
00659   return m_lines.Count();
00660 }
00661 
00662 
00663 
00664 
00665 //  class ON_HatchLoop
00667 
00668 #if defined(ON_DLL_EXPORTS)
00669 
00670 // When the Microsoft CRT(s) is/are used, this is the best
00671 // way to prevent crashes that happen when a hatch loop is
00672 // allocated with new in one DLL and deallocated with
00673 // delete in another DLL.
00674 
00675 void* ON_HatchLoop::operator new(size_t sz)
00676 {
00677   // ON_HatchLoop new
00678   return onmalloc(sz);
00679 }
00680 
00681 void ON_HatchLoop::operator delete(void* p)
00682 {
00683   // ON_HatchLoop delete
00684   onfree(p);
00685 }
00686 
00687 void* ON_HatchLoop::operator new[] (size_t sz)
00688 {
00689   // ON_HatchLoop array new
00690   return onmalloc(sz);
00691 }
00692 
00693 void ON_HatchLoop::operator delete[] (void* p)
00694 {
00695   // ON_HatchLoop array delete
00696   onfree(p);
00697 }
00698 
00699 void* ON_HatchLoop::operator new(size_t, void* p)
00700 {
00701   // ON_HatchLoop placement new
00702   return p;
00703 }
00704 
00705 void ON_HatchLoop::operator delete(void*, void*)
00706 {
00707   // ON_HatchLoop placement delete
00708   return;
00709 }
00710 
00711 #endif
00712 
00713 
00714 ON_HatchLoop::ON_HatchLoop()
00715 : m_type( ON_HatchLoop::ltOuter), m_p2dCurve( NULL)
00716 {
00717 }
00718 
00719 ON_HatchLoop::ON_HatchLoop( ON_Curve* pCurve2d, eLoopType type)
00720 : m_type( type), m_p2dCurve( pCurve2d)
00721 {
00722 }
00723 
00724 ON_HatchLoop::ON_HatchLoop( const ON_HatchLoop& src)
00725 : m_type( src.m_type), m_p2dCurve( NULL)
00726 { 
00727   if( src.m_p2dCurve)
00728     m_p2dCurve = src.m_p2dCurve->DuplicateCurve();
00729 }
00730 
00731 ON_HatchLoop::~ON_HatchLoop()
00732 {
00733   delete m_p2dCurve;
00734 }
00735 
00736 ON_HatchLoop& ON_HatchLoop::operator=( const ON_HatchLoop& src)
00737 {
00738   if( this != &src)
00739   {
00740     if( m_p2dCurve)
00741       delete m_p2dCurve;
00742     m_p2dCurve = src.m_p2dCurve->DuplicateCurve();
00743 
00744     m_type = src.m_type;
00745   }
00746   return *this;
00747 }
00748 
00749 ON_BOOL32 ON_HatchLoop::IsValid( ON_TextLog* text_log) const
00750 {
00751   ON_BOOL32 rc = m_p2dCurve != NULL;
00752   if( !rc)
00753   {
00754     if( text_log)
00755       text_log->Print( "2d loop curve is NULL\n");
00756   }
00757   if( rc)
00758   {
00759     rc = m_p2dCurve->IsValid( text_log);
00760     if( !rc)
00761     {
00762       if( text_log)
00763         text_log->Print( "Loop curve is not valid\n");
00764     }
00765   }
00766 
00767   if( rc)
00768   {
00769     ON_BoundingBox box;
00770     m_p2dCurve->GetBoundingBox( box);
00771     rc = ( box.Max().z == box.Min().z && box.Max().z == 0.0);
00772     if( !rc)
00773     {
00774       if( text_log)
00775         text_log->Print( "2d loop curve has non-zero z coordinates\n");
00776     }
00777   }
00778 
00779   if( rc && m_type != ltOuter && m_type != ltInner)
00780   {
00781     if( text_log)
00782       text_log->Print( "Loop type is invalid.\n");
00783     rc = false;
00784   }
00785 
00786   return rc;
00787 }
00788 
00789 void ON_HatchLoop::Dump( ON_TextLog& dump) const
00790 {
00791   if( m_type == ltOuter)
00792     dump.Print( "Outer hatch loop\n");
00793   if( m_type == ltInner)
00794     dump.Print( "Inner hatch loop\n");
00795 
00796   if ( 0 == m_p2dCurve )
00797   {
00798     dump.Print( "2d curve: null pointer\n");
00799   }
00800   else
00801   {
00802     dump.Print( "2d curve:\n");
00803     m_p2dCurve->Dump(dump);
00804   }
00805 
00806 }
00807 
00808 ON_BOOL32 ON_HatchLoop::Write( ON_BinaryArchive& ar) const
00809 {
00810   ON_BOOL32 rc = ar.Write3dmChunkVersion(1,1);
00811   if( rc) rc = ar.WriteInt( m_type);
00812   if( rc) rc = ar.WriteObject( m_p2dCurve);
00813   return rc;
00814 }
00815 
00816 ON_BOOL32 ON_HatchLoop::Read( ON_BinaryArchive& ar)
00817 {
00818   m_type = ltOuter;
00819   delete m_p2dCurve;
00820   m_p2dCurve = NULL;
00821   int major_version = 0;
00822   int minor_version = 0;
00823   ON_BOOL32 rc = ar.Read3dmChunkVersion( &major_version, &minor_version);
00824   if ( major_version == 1 ) 
00825   {
00826     int type = 0;
00827     if( rc) rc = ar.ReadInt( &type);
00828     if( rc) 
00829     {
00830       switch( type)
00831       {
00832       case ltOuter:  m_type = ltOuter; break;
00833       case ltInner:  m_type = ltInner; break;
00834       default: rc = false; break;
00835       }
00836     }
00837     if( rc)
00838     {
00839       ON_Object* pObj = NULL;
00840       rc = ar.ReadObject( &pObj);
00841       if( pObj)
00842       {
00843         m_p2dCurve = ON_Curve::Cast( pObj);
00844         if( !m_p2dCurve) // read something, but it wasn't right
00845         {
00846           rc = false;
00847           delete pObj;
00848         }
00849       }
00850     }
00851   }
00852   return rc;
00853 }
00854 
00855 const ON_Curve* ON_HatchLoop::Curve() const
00856 {
00857   return m_p2dCurve;
00858 }
00859 
00860 bool ON_HatchLoop::SetCurve( const ON_Curve& curve)
00861 {
00862   ON_Curve* pC = curve.DuplicateCurve();
00863   if( pC)
00864   {
00865     if(pC->Dimension() == 3 && !pC->ChangeDimension(2))
00866       return false;
00867 
00868     if( m_p2dCurve)
00869       delete m_p2dCurve;
00870     m_p2dCurve = pC;
00871   }
00872   return true;
00873 }
00874 ON_HatchLoop::eLoopType ON_HatchLoop::Type() const
00875 {
00876   return m_type;
00877 }
00878 
00879 void ON_HatchLoop::SetType( eLoopType type)
00880 {
00881   m_type = type;
00882 }
00883 
00884 //  class ON_Hatch
00886 ON_OBJECT_IMPLEMENT( ON_Hatch, ON_Geometry, "0559733B-5332-49d1-A936-0532AC76ADE5");
00887 
00888 
00889 ON_Hatch::ON_Hatch()
00890 : m_pattern_scale( 1.0),
00891   m_pattern_rotation( 0.0),
00892   m_pattern_index( -1)
00893 {
00894 }
00895 
00896 ON_Hatch::ON_Hatch( const ON_Hatch& src)
00897 :  ON_Geometry(src),
00898    m_plane( src.m_plane), 
00899    m_pattern_scale( src.m_pattern_scale),
00900    m_pattern_rotation( src.m_pattern_rotation),
00901    m_pattern_index( src.m_pattern_index)
00902 {
00903   m_loops.Reserve( src.m_loops.Count());
00904   for( int i = 0; i < src.m_loops.Count(); i++)
00905   {
00906     ON_HatchLoop* pL = new ON_HatchLoop( *src.m_loops[i]);
00907     m_loops.Append( pL);
00908   }
00909 }
00910 
00911 ON_Hatch& ON_Hatch::operator=( const ON_Hatch& src)
00912 {
00913   if( this != &src)
00914   {
00915     // Nov 3 2004 Dale Lear:
00916     //   Delete existing loops so we don't leak the memory;
00917     int i;
00918     for ( i = 0; i < m_loops.Count(); i++ )
00919     {
00920       ON_HatchLoop* pL = m_loops[i];
00921       if ( pL )
00922       {
00923         m_loops[i] = 0;
00924         delete pL;
00925       }
00926     }
00927     m_loops.SetCount(0);
00928 
00929     ON_Geometry::operator =(src);
00930 
00931     m_plane = src.m_plane;
00932     m_pattern_index = src.m_pattern_index;
00933     m_pattern_scale = src.m_pattern_scale;
00934     m_pattern_rotation = src.m_pattern_rotation;
00935     m_loops.Reserve( src.m_loops.Count());
00936     for( i = 0; i < src.m_loops.Count(); i++)
00937     {
00938       ON_HatchLoop* pL = new ON_HatchLoop( *src.m_loops[i]);
00939       m_loops.Append( pL);
00940     }
00941   }
00942   return *this;
00943 }
00944 
00945 ON_Hatch::~ON_Hatch()
00946 {
00947   int i;
00948   for ( i = 0; i < m_loops.Count(); i++ )
00949   {
00950     ON_HatchLoop* pL = m_loops[i];
00951     if ( pL )
00952     {
00953       m_loops[i] = 0;
00954       delete pL;
00955     }
00956   }
00957 }
00958 
00959 
00960 ON_Hatch* ON_Hatch::DuplicateHatch() const
00961 {
00962   return Duplicate();
00963 }
00964 
00965 ON_BOOL32 ON_Hatch::IsValid( ON_TextLog* text_log) const
00966 {
00967   ON_BOOL32 rc = m_plane.IsValid();
00968   if( !rc)
00969   {
00970     if( text_log)
00971       text_log->Print( "Plane is not valid\n");
00972     return false;
00973   }
00974   // 18 June 2012 - Lowell - Added loop self-intersection and 
00975   // intersecting other loops tests
00976   int count = m_loops.Count();
00977   for(int i = 0; i < count; i++)
00978   {
00979     if(m_loops[i] == 0)
00980     {
00981       if( text_log)
00982         text_log->Print( "Loop[%d] is NULL\n", i);
00983       return false;
00984     }
00985     if(rc)
00986       rc = m_loops[i]->IsValid( text_log);
00987     if( !rc)
00988     {
00989       if( text_log)
00990         text_log->Print( "Loop[%d] is not valid\n", i);
00991       return false;
00992     }
00993   }
00994   
00995   return true;
00996 }
00997 
00998 void ON_Hatch::Dump( ON_TextLog& dump) const
00999 {
01000   dump.Print("Hatch: Pattern index: %d\n", PatternIndex());
01001   dump.Print("Pattern rotation: %g\n", PatternRotation());
01002   dump.Print("Pattern scale: %g\n", PatternScale());
01003   ON_3dPoint p = this->BasePoint();
01004   dump.Print("Base point: %g, %g, %g\n", p.x, p.y, p.z);
01005   dump.Print("Plane origin: %g, %g, %g\n", m_plane.origin.x, m_plane.origin.y, m_plane.origin.z);
01006   dump.Print("Plane x axis: %g, %g, %g\n", m_plane.xaxis.x, m_plane.xaxis.y, m_plane.xaxis.z);
01007   dump.Print("Plane y axis: %g, %g, %g\n", m_plane.yaxis.x, m_plane.yaxis.y, m_plane.yaxis.z);
01008   dump.Print("Plane z axis: %g, %g, %g\n", m_plane.zaxis.x, m_plane.zaxis.y, m_plane.zaxis.z);
01009   int count = m_loops.Count();
01010   dump.Print("Loop count = %d\n", count);
01011   for( int i = 0; i < count; i++)
01012     m_loops[i]->Dump( dump);
01013 }
01014 
01015 ON_BOOL32 ON_Hatch::Write( ON_BinaryArchive& ar) const
01016 {
01017   ON_BOOL32 rc = ar.Write3dmChunkVersion(1,1);
01018   if (rc) rc = ar.WritePlane( m_plane);
01019   if (rc) rc = ar.WriteDouble( m_pattern_scale);
01020   if (rc) rc = ar.WriteDouble( m_pattern_rotation);
01021   if (rc) rc = ar.WriteInt( m_pattern_index);
01022   if (rc)
01023   {
01024     int i, count = m_loops.Count();
01025     if( count < 0 )
01026       count = 0;
01027     ON_BOOL32 rc = ar.WriteInt( count);
01028     for( i = 0; i < count && rc; i++)
01029       rc = m_loops[i]->Write( ar);
01030   }
01031   return rc;
01032 }
01033 
01034 ON_BOOL32 ON_Hatch::Read( ON_BinaryArchive& ar)
01035 {
01036   m_plane.CreateFromNormal( ON_origin, ON_zaxis);
01037   m_pattern_scale = 1.0;
01038   m_pattern_rotation = 0.0;
01039   m_pattern_index = -1;
01040   m_loops.Empty();
01041   int major_version = 0;
01042   int minor_version = 0;
01043   ON_BOOL32 rc = ar.Read3dmChunkVersion( &major_version, &minor_version);
01044   if ( major_version == 1 ) 
01045   {
01046     if( rc) rc = ar.ReadPlane( m_plane);
01047     if( rc) rc = ar.ReadDouble( &m_pattern_scale);
01048     if( rc) rc = ar.ReadDouble( &m_pattern_rotation);
01049     if( rc) rc = ar.ReadInt( &m_pattern_index);
01050     if( rc)
01051     {
01052       m_loops.Empty();
01053       int i, count = 0;
01054       rc = ar.ReadInt( &count);
01055       if( rc && count > 0)
01056       {
01057         m_loops.SetCapacity( count );
01058         for( i = 0; rc && i < count; i++)
01059         {
01060           ON_HatchLoop*& pLoop = m_loops.AppendNew();
01061           pLoop = new ON_HatchLoop;
01062           if( pLoop)
01063             rc = pLoop->Read( ar);
01064           else
01065             rc = false;
01066         }
01067       }
01068     }
01069   }
01070   return rc;
01071 }
01072 
01073 ON::object_type ON_Hatch::ObjectType() const
01074 {
01075   return ON::hatch_object;
01076 }
01077 
01078 int ON_Hatch::Dimension() const
01079 {
01080   return 3;
01081 }
01082 
01083 // Copy the 2d curve, make it 3d, and transform it 
01084 // to the 3d plane position
01085 ON_Curve* ON_Hatch::LoopCurve3d( int index) const
01086 {
01087   int count = m_loops.Count();
01088   ON_Curve* pC = NULL;
01089 
01090   if( index >= 0 && index < count)
01091   {
01092     if( m_loops[index]->Curve())
01093     {
01094       pC = m_loops[index]->Curve()->DuplicateCurve();
01095       if( pC)
01096       {
01097         pC->ChangeDimension( 3);
01098 
01099         ON_Xform xf;
01100         xf.Rotation( ON_xy_plane, m_plane);
01101 
01102         pC->Transform( xf);
01103       }
01104     }
01105   }
01106   return pC;
01107 }
01108 
01109 
01110 int ON_Hatch::PatternIndex() const
01111 {
01112   return m_pattern_index;
01113 }
01114 
01115 void ON_Hatch::SetPatternIndex( int index)
01116 {
01117   m_pattern_index = index;
01118 }
01119 
01120 
01121 ON_BOOL32 ON_Hatch::GetBBox( double* bmin, double* bmax, ON_BOOL32 bGrowBox) const
01122 {
01123   int i;
01124   int count = m_loops.Count();
01125   ON_BOOL32 rc = true;
01126   ON_Curve* pC;
01127   for( i = 0; rc && i < count; i++)
01128   {
01129     pC = LoopCurve3d( i);
01130     if( pC)
01131     {
01132       rc = pC->GetBBox( bmin, bmax, i?true:bGrowBox);
01133       delete pC;
01134     }
01135   }
01136   return rc;
01137 }
01138 
01139 bool ON_Hatch::GetTightBoundingBox( ON_BoundingBox& tight_bbox, int bGrowBox, const ON_Xform* xform) const
01140 {
01141   int i;
01142   int count = m_loops.Count();
01143   ON_CurveArray curves(count);
01144   for( i = 0; i < count; i++)
01145   {
01146     curves.Append( LoopCurve3d(i) );
01147   }
01148   return curves.GetTightBoundingBox(tight_bbox,bGrowBox,xform);
01149 }
01150 
01151 static double Angle3d(const ON_3dVector& axis, ON_3dVector& from, const ON_3dVector& to)
01152 {
01153   ON_3dVector x = from, a = to;
01154   x.Unitize();
01155   a.Unitize();
01156 
01157   ON_3dVector y = ON_CrossProduct(axis, from);
01158   y.Unitize();
01159 
01160   double cosa = x * a;
01161 
01162   if(cosa > 1.0 - ON_SQRT_EPSILON)
01163     return 0.0;
01164   if(cosa < ON_SQRT_EPSILON - 1.0)
01165     return ON_PI;
01166 
01167   double sina = a * y;
01168 
01169   return atan2(sina, cosa);
01170 }
01171 
01172 
01173 #define ARBBOUND  0.015625
01174 void arbaxis(const ON_3dVector& givenaxis, ON_3dVector& newaxis)
01175 {
01176   if(fabs(givenaxis[0]) < ARBBOUND && fabs(givenaxis[1]) < ARBBOUND) // near world z
01177     newaxis = ON_CrossProduct(ON_yaxis, givenaxis);
01178   else
01179     newaxis = ON_CrossProduct(ON_zaxis, givenaxis);
01180 
01181   newaxis.Unitize();
01182 }
01183 
01184 double arbaxisRotation(const ON_Plane& plane)
01185 {
01186   // get arbaxis frame and angle of rotation from it
01187   ON_3dVector arbXaxis;
01188   arbaxis(plane.zaxis, arbXaxis);
01189   return Angle3d(plane.zaxis, arbXaxis, plane.xaxis);
01190 }
01191 
01192 // 20 June 2012 - Lowell - rr44706, 68320
01193 // This will find A, the arbaxis direction for the hatch plane
01194 // and rotate the hatch plane by -A and rotate the hatch boundaries
01195 // by A and add A to the hatch rotation.
01196 // The picture will be the same after that, but the way the
01197 // angle is represented will match the way AutoCAD does it
01198 // so hatches can be round-tripped with acad files.
01199 // In addition, after several hatches are rotated by different amounts
01200 // the hatch angles can be set to look the same by setting them all
01201 // to the same pattern rotation
01202  
01203 static void UnrotateHatch(ON_Hatch* hatch)
01204 {
01205   double a = arbaxisRotation(hatch->Plane());
01206   ON_Plane& plane = *(ON_Plane*)(&hatch->Plane());
01207   if(fabs(a) > ON_ZERO_TOLERANCE)
01208   {
01209     plane.Rotate(-a, plane.zaxis);
01210     for(int i = 0; i < hatch->LoopCount(); i++)
01211     {
01212       ON_Curve* pC = (ON_Curve*)hatch->Loop(i)->Curve();
01213       pC->Rotate(a, ON_zaxis, ON_origin);
01214     }
01215     hatch->SetPatternRotation(hatch->PatternRotation()+a);
01216   }
01217   ON_3dPoint P;
01218   plane.ClosestPointTo(ON_origin, &P.x, &P.y);
01219 
01220   if(fabs(P.x) > ON_ZERO_TOLERANCE ||fabs(P.y) > ON_ZERO_TOLERANCE ||fabs(P.z) > ON_ZERO_TOLERANCE)
01221   {
01222     ON_2dVector V(-P.x, -P.y);
01223     for(int i = 0; i < hatch->LoopCount(); i++)
01224     {
01225       ON_Curve* pC = (ON_Curve*)hatch->Loop(i)->Curve();
01226       pC->Translate(V);
01227     }
01228     P = plane.PointAt(P.x, P.y);
01229     plane.origin = P;
01230   }
01231 }
01232 
01233 ON_BOOL32 ON_Hatch::Transform( const ON_Xform& xform)
01234 {
01235   if( fabs( fabs( xform.Determinant()) - 1.0) > 1.0e-4)
01236   {
01237     // xform has a scale component
01238     ON_Plane tmp( m_plane);
01239     tmp.Transform( xform);
01240     ON_Xform A, B, T;
01241     A.Rotation( ON_xy_plane, m_plane);
01242     B.Rotation( tmp, ON_xy_plane);
01243     T = B * xform * A;
01244 
01245     // kill translation and z-scaling
01246     T[0][2] = T[0][3] = 0.0;
01247     T[1][2] = T[1][3] = 0.0;
01248     T[2][0] = T[2][1] = 0.0; T[2][2] = 1.0; T[2][3] = 0.0; 
01249     T[3][0] = T[3][1] = T[3][2] = 0.0; T[3][3] = 1.0;
01250 
01251     for( int i = 0; i < LoopCount(); i++)
01252       m_loops[i]->m_p2dCurve->Transform( T);
01253   }
01254   int rc = m_plane.Transform( xform);
01255 
01256   UnrotateHatch(this);
01257 
01258   TransformUserData(xform);
01259 
01260 
01261 
01262 
01263   return rc;
01264 }
01265 
01266 bool ON_Hatch::Create( const ON_Plane& plane,
01267                        const ON_SimpleArray<const ON_Curve*> loops, 
01268                        int pattern_index, 
01269                        double pattern_rotation, 
01270                        double pattern_scale)
01271 {
01272   if( loops.Count() < 1)
01273     return false;
01274   if( pattern_index < 0)
01275     return false;
01276   SetPlane( plane);
01277   for( int i = 0; i < loops.Count(); i++)
01278   {
01279     ON_HatchLoop* pLoop = new ON_HatchLoop;
01280     pLoop->SetCurve( *loops[i]);
01281     pLoop->SetType( i?ON_HatchLoop::ltInner:ON_HatchLoop::ltOuter);
01282     AddLoop( pLoop);
01283   }
01284   SetPatternIndex( pattern_index);
01285   SetPatternRotation( pattern_rotation);
01286   SetPatternScale( pattern_scale);
01287   return true;
01288 }
01289 
01290 const ON_Plane& ON_Hatch::Plane() const
01291 {
01292   return m_plane;
01293 }
01294 
01295 void ON_Hatch::SetPlane( const ON_Plane& plane)
01296 {
01297   m_plane = plane;
01298 }
01299 
01300 double ON_Hatch::PatternRotation() const
01301 {
01302   return m_pattern_rotation;
01303 }
01304 
01305 void ON_Hatch::SetPatternRotation( double rotation)
01306 {
01307   m_pattern_rotation = rotation;
01308 }
01309 
01310 double ON_Hatch::PatternScale() const
01311 {
01312   return m_pattern_scale;
01313 }
01314 
01315 void ON_Hatch::SetPatternScale( double scale)
01316 {
01317   if( scale > 0.001) // Changed May 13, 2009 - Lowell - rr39185
01318     m_pattern_scale = scale;
01319 }
01320 
01321 int ON_Hatch::LoopCount() const
01322 {
01323   return m_loops.Count();
01324 }
01325 
01326 void ON_Hatch::AddLoop( ON_HatchLoop* pLoop)
01327 {
01328   m_loops.Append( pLoop);
01329 }
01330 
01331 bool ON_Hatch::InsertLoop( int index, ON_HatchLoop* loop)
01332 {
01333   if( index >= 0 && index <= m_loops.Count()) // 26 June 2012 - Lowell - Changed ndex < to ndex <= 
01334   {
01335     m_loops.Insert(index, loop);
01336         return true;
01337   }
01338 
01339   return false;
01340 }
01341 
01342 bool ON_Hatch::RemoveLoop( int index)
01343 {
01344   if( index >= 0 && index < m_loops.Count())
01345   {
01346     delete m_loops[index];
01347     m_loops.Remove(index);
01348     return true;
01349   }
01350   
01351   return false;
01352 }
01353 
01354 
01355 bool ON_Hatch::ReplaceLoops(ON_SimpleArray<const ON_Curve*> loop_curves)
01356 {
01357   if(loop_curves.Count() < 1)
01358     return false;
01359 
01360   bool rc = true;
01361   ON_Xform xf;
01362   bool flat = false;
01363   ON_SimpleArray<ON_HatchLoop*> loops;
01364 
01365   for(int i = 0; i < loop_curves.Count(); i++)
01366   {
01367     if(loop_curves[i] == 0)
01368     {
01369       rc = false;
01370       break;
01371     }
01372     ON_Curve* p2d = loop_curves[i]->Duplicate();
01373     if(p2d == 0)
01374     {
01375       rc = false;
01376       break;
01377     }
01378     if(p2d->Dimension() == 3)
01379     {
01380       if(!flat)
01381       {
01382         xf.PlanarProjection(m_plane);
01383         flat = true;
01384       }
01385       if(!p2d->Transform(xf) ||
01386          !p2d->ChangeDimension(2))
01387       {
01388         delete p2d;
01389         rc = false;
01390         break;
01391       }
01392     }
01393     ON_HatchLoop* loop = new ON_HatchLoop(p2d,loops.Count()?ON_HatchLoop::ltInner:ON_HatchLoop::ltOuter);
01394     if(loop)
01395       loops.Append(loop);
01396     else
01397       delete p2d;
01398   }
01399   if(!rc)
01400   {
01401     for(int i = 0; i < loops.Count(); i++)
01402       delete loops[i];
01403 
01404     loops.Empty();
01405   }
01406 
01407   if(loops.Count() < 1)
01408     return false;
01409 
01410   for(int i = 0; i < m_loops.Count(); i++)
01411     delete m_loops[i];
01412   m_loops.Empty();
01413   for(int i = 0; i < loops.Count(); i++)
01414     m_loops.Append(loops[i]);
01415   return true;
01416 }
01417 
01418 const ON_HatchLoop* ON_Hatch::Loop( int index) const
01419 {
01420   if( index >= 0 && index < m_loops.Count())
01421     return m_loops[index];
01422   
01423   return NULL;
01424 }
01425 
01426 // Basepoint functions added March 23, 2008 -LW
01427 void ON_Hatch::SetBasePoint(ON_2dPoint basepoint)
01428 {
01429   ON_HatchExtra* pE = ON_HatchExtra::HatchExtension(this,true);
01430   if(pE)
01431   {
01432     pE->SetBasePoint(basepoint);
01433   }
01434 }
01435 
01436 void ON_Hatch::SetBasePoint(ON_3dPoint point)
01437 {
01438   ON_HatchExtra* pE = ON_HatchExtra::HatchExtension(this,true);
01439   if(pE)
01440   {
01441     ON_2dPoint base;
01442     if(m_plane.ClosestPointTo(point, &base.x, &base.y))
01443       pE->SetBasePoint(base);
01444   }
01445 }
01446 
01447 ON_3dPoint ON_Hatch::BasePoint() const
01448 {
01449   ON_3dPoint point(ON_origin);
01450   const ON_HatchExtra* pE = ON_HatchExtra::HatchExtension(this,false);
01451   if(pE)
01452   {
01453     ON_2dPoint base = pE->BasePoint();
01454     point = m_plane.PointAt(base.x, base.y);
01455   }
01456   return point;
01457 }
01458 
01459 ON_2dPoint ON_Hatch::BasePoint2d() const
01460 {
01461   ON_2dPoint basepoint(0.0,0.0);
01462   const ON_HatchExtra* pE = ON_HatchExtra::HatchExtension(this,false);
01463   if(pE)
01464     basepoint = pE->BasePoint();
01465 
01466   return basepoint;
01467 }
01468 
01469 // Added March 23, 2008 -LW
01470 // This function is temporary and will be removed next time the SDK can be modified.
01471 class ON_HatchExtra* ON_Hatch::HatchExtension()
01472 {
01473   ON_HatchExtra* pExtra = ON_HatchExtra::Cast( GetUserData( ON_HatchExtra::m_ON_HatchExtra_class_id.Uuid()));
01474   return pExtra;
01475 }


pcl
Author(s): Open Perception
autogenerated on Wed Aug 26 2015 15:27:01