You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

321 lines
7.6 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, you may find one here:
  18. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  19. * or you may search the http://www.gnu.org website for the version 2 license,
  20. * or you may write to the Free Software Foundation, Inc.,
  21. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  22. */
  23. #include "reference_image.h"
  24. #include <wx/debug.h>
  25. #include <bitmap_base.h>
  26. #include <geometry/geometry_utils.h>
  27. REFERENCE_IMAGE::REFERENCE_IMAGE( const EDA_IU_SCALE& aIuScale ) :
  28. m_iuScale( aIuScale ), m_pos( 0, 0 ), m_transformOriginOffset( 0, 0 ),
  29. m_bitmapBase( std::make_unique<BITMAP_BASE>() )
  30. {
  31. updatePixelSizeInIU();
  32. }
  33. REFERENCE_IMAGE::REFERENCE_IMAGE( const REFERENCE_IMAGE& aOther ) :
  34. m_iuScale( aOther.m_iuScale ), m_pos( aOther.m_pos ),
  35. m_transformOriginOffset( aOther.m_transformOriginOffset ),
  36. m_bitmapBase( std::make_unique<BITMAP_BASE>( *aOther.m_bitmapBase ) )
  37. {
  38. updatePixelSizeInIU();
  39. }
  40. REFERENCE_IMAGE::~REFERENCE_IMAGE()
  41. {
  42. }
  43. void REFERENCE_IMAGE::updatePixelSizeInIU()
  44. {
  45. const double pixelSizeIu = (double) m_iuScale.MilsToIU( 1000 ) / m_bitmapBase->GetPPI();
  46. m_bitmapBase->SetPixelSizeIu( pixelSizeIu );
  47. }
  48. REFERENCE_IMAGE& REFERENCE_IMAGE::operator=( const REFERENCE_IMAGE& aOther )
  49. {
  50. wxASSERT( m_iuScale.IU_PER_MILS == aOther.m_iuScale.IU_PER_MILS );
  51. if( &aOther != this )
  52. {
  53. if( aOther.m_bitmapBase )
  54. {
  55. m_bitmapBase = std::make_unique<BITMAP_BASE>( *aOther.m_bitmapBase );
  56. }
  57. m_pos = aOther.m_pos;
  58. m_transformOriginOffset = aOther.m_transformOriginOffset;
  59. updatePixelSizeInIU();
  60. }
  61. return *this;
  62. }
  63. bool REFERENCE_IMAGE::operator==( const REFERENCE_IMAGE& aOther ) const
  64. {
  65. if( m_pos != aOther.m_pos )
  66. return false;
  67. if( m_transformOriginOffset != aOther.m_transformOriginOffset )
  68. return false;
  69. if( m_bitmapBase->GetSize() != aOther.m_bitmapBase->GetSize() )
  70. return false;
  71. if( m_bitmapBase->GetPPI() != aOther.m_bitmapBase->GetPPI() )
  72. return false;
  73. if( m_bitmapBase->GetScale() != aOther.m_bitmapBase->GetScale() )
  74. return false;
  75. if( m_bitmapBase->GetImageID() != aOther.m_bitmapBase->GetImageID() )
  76. return false;
  77. if( m_bitmapBase->GetImageData() != aOther.m_bitmapBase->GetImageData() )
  78. return false;
  79. return true;
  80. }
  81. double REFERENCE_IMAGE::Similarity( const REFERENCE_IMAGE& aOther ) const
  82. {
  83. double similarity = 1.0;
  84. if( m_pos != aOther.m_pos )
  85. similarity *= 0.9;
  86. if( m_bitmapBase->GetSize() != aOther.m_bitmapBase->GetSize() )
  87. similarity *= 0.9;
  88. if( m_bitmapBase->GetPPI() != aOther.m_bitmapBase->GetPPI() )
  89. similarity *= 0.9;
  90. if( m_bitmapBase->GetScale() != aOther.m_bitmapBase->GetScale() )
  91. similarity *= 0.9;
  92. if( m_bitmapBase->GetImageID() != aOther.m_bitmapBase->GetImageID() )
  93. similarity *= 0.9;
  94. if( m_bitmapBase->GetImageData() != aOther.m_bitmapBase->GetImageData() )
  95. similarity *= 0.9;
  96. return similarity;
  97. }
  98. BOX2I REFERENCE_IMAGE::GetBoundingBox() const
  99. {
  100. return BOX2I::ByCenter( m_pos, m_bitmapBase->GetSize() );
  101. }
  102. VECTOR2I REFERENCE_IMAGE::GetPosition() const
  103. {
  104. return m_pos;
  105. }
  106. void REFERENCE_IMAGE::SetPosition( const VECTOR2I& aPos )
  107. {
  108. const BOX2D newBox = BOX2D::ByCenter( aPos, m_bitmapBase->GetSize() );
  109. if( !IsBOX2Safe( newBox ) )
  110. return;
  111. m_pos = aPos;
  112. }
  113. VECTOR2I REFERENCE_IMAGE::GetTransformOriginOffset() const
  114. {
  115. return m_transformOriginOffset;
  116. }
  117. void REFERENCE_IMAGE::SetTransformOriginOffset( const VECTOR2I& aCenter )
  118. {
  119. m_transformOriginOffset = aCenter;
  120. }
  121. VECTOR2I REFERENCE_IMAGE::GetSize() const
  122. {
  123. return m_bitmapBase->GetSize();
  124. }
  125. void REFERENCE_IMAGE::SetWidth( int aWidth )
  126. {
  127. if( aWidth <= 0 )
  128. return;
  129. const double ratio = aWidth / (double) m_bitmapBase->GetSize().x;
  130. scaleBy( ratio );
  131. }
  132. void REFERENCE_IMAGE::SetHeight( int aHeight )
  133. {
  134. if( aHeight <= 0 )
  135. return;
  136. const double ratio = aHeight / (double) m_bitmapBase->GetSize().y;
  137. scaleBy( ratio );
  138. }
  139. double REFERENCE_IMAGE::GetImageScale() const
  140. {
  141. return m_bitmapBase->GetScale();
  142. }
  143. void REFERENCE_IMAGE::SetImageScale( double aScale )
  144. {
  145. if( aScale <= 0 )
  146. return;
  147. const double ratio = aScale / m_bitmapBase->GetScale();
  148. scaleBy( ratio );
  149. }
  150. void REFERENCE_IMAGE::scaleBy( double aRatio )
  151. {
  152. if( aRatio <= 0 )
  153. return;
  154. const VECTOR2D currentOrigin = m_pos + m_transformOriginOffset;
  155. const VECTOR2D newOffset = m_transformOriginOffset * aRatio;
  156. const VECTOR2D newCenter = currentOrigin - newOffset;
  157. const VECTOR2D newSize = m_bitmapBase->GetSize() * aRatio;
  158. // The span of the image is limited to the size of the coordinate system
  159. if( !IsVec2SafeXY( newSize ) )
  160. return;
  161. const BOX2D newBox = BOX2D::ByCenter( newCenter, newSize );
  162. // Any overflow, just reject the call
  163. if( !IsBOX2Safe( newBox ) )
  164. return;
  165. m_bitmapBase->SetScale( m_bitmapBase->GetScale() * aRatio );
  166. SetTransformOriginOffset( KiROUND( newOffset ) );
  167. // Don't need to recheck the box, we just did that
  168. m_pos = KiROUND( newCenter );
  169. }
  170. void REFERENCE_IMAGE::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
  171. {
  172. VECTOR2I newPos = m_pos;
  173. MIRROR( newPos, aCentre, aFlipDirection );
  174. const BOX2D newBox = BOX2D::ByCenter( newPos, m_bitmapBase->GetSize() );
  175. if( !IsBOX2Safe( newBox ) )
  176. return;
  177. m_pos = newPos;
  178. m_bitmapBase->Mirror( aFlipDirection );
  179. }
  180. void REFERENCE_IMAGE::Rotate( const VECTOR2I& aCenter, const EDA_ANGLE& aAngle )
  181. {
  182. EDA_ANGLE norm( aAngle.AsDegrees(), DEGREES_T );
  183. RotatePoint( m_pos, aCenter, aAngle );
  184. norm.Normalize();
  185. // each call to m_bitmapBase->Rotate() rotates 90 degrees CCW
  186. for( double ang = 45.0; ang < norm.AsDegrees(); ang += 90.0 )
  187. m_bitmapBase->Rotate( false );
  188. }
  189. bool REFERENCE_IMAGE::ReadImageFile( const wxString& aFullFilename )
  190. {
  191. if( m_bitmapBase->ReadImageFile( aFullFilename ) )
  192. {
  193. updatePixelSizeInIU();
  194. return true;
  195. }
  196. return false;
  197. }
  198. bool REFERENCE_IMAGE::ReadImageFile( wxMemoryBuffer& aBuffer )
  199. {
  200. if( m_bitmapBase->ReadImageFile( aBuffer ) )
  201. {
  202. updatePixelSizeInIU();
  203. return true;
  204. }
  205. return false;
  206. }
  207. bool REFERENCE_IMAGE::SetImage( const wxImage& aImage )
  208. {
  209. if( m_bitmapBase->SetImage( aImage ) )
  210. {
  211. updatePixelSizeInIU();
  212. return true;
  213. }
  214. return false;
  215. }
  216. const BITMAP_BASE& REFERENCE_IMAGE::GetImage() const
  217. {
  218. // This cannot be null after construction
  219. return *m_bitmapBase;
  220. }
  221. BITMAP_BASE& REFERENCE_IMAGE::MutableImage() const
  222. {
  223. return *m_bitmapBase;
  224. }
  225. void REFERENCE_IMAGE::SwapData( REFERENCE_IMAGE& aOther )
  226. {
  227. std::swap( m_pos, aOther.m_pos );
  228. std::swap( m_transformOriginOffset, aOther.m_transformOriginOffset );
  229. std::swap( m_bitmapBase, aOther.m_bitmapBase );
  230. }