KiCad PCB EDA Suite
Loading...
Searching...
No Matches
reference_image.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2024 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
24#include "reference_image.h"
25
26#include <wx/debug.h>
27
28#include <bitmap_base.h>
30
31
33 m_iuScale( aIuScale ), m_pos( 0, 0 ), m_transformOriginOffset( 0, 0 ),
34 m_bitmapBase( std::make_unique<BITMAP_BASE>() )
35{
37}
38
39
41 m_iuScale( aOther.m_iuScale ), m_pos( aOther.m_pos ),
42 m_transformOriginOffset( aOther.m_transformOriginOffset ),
43 m_bitmapBase( std::make_unique<BITMAP_BASE>( *aOther.m_bitmapBase ) )
44{
46}
47
48
50{
51}
52
53
55{
56 const double pixelSizeIu = (double) m_iuScale.MilsToIU( 1000 ) / m_bitmapBase->GetPPI();
57 m_bitmapBase->SetPixelSizeIu( pixelSizeIu );
58}
59
60
62{
63 wxASSERT( m_iuScale.IU_PER_MILS == aOther.m_iuScale.IU_PER_MILS );
64
65 if( &aOther != this )
66 {
67 if( aOther.m_bitmapBase )
68 {
69 m_bitmapBase = std::make_unique<BITMAP_BASE>( *aOther.m_bitmapBase );
70 }
71 m_pos = aOther.m_pos;
74 }
75
76 return *this;
77}
78
79
81{
82 if( m_pos != aOther.m_pos )
83 return false;
84
86 return false;
87
88 if( m_bitmapBase->GetSize() != aOther.m_bitmapBase->GetSize() )
89 return false;
90
91 if( m_bitmapBase->GetPPI() != aOther.m_bitmapBase->GetPPI() )
92 return false;
93
94 if( m_bitmapBase->GetScale() != aOther.m_bitmapBase->GetScale() )
95 return false;
96
97 if( m_bitmapBase->GetImageID() != aOther.m_bitmapBase->GetImageID() )
98 return false;
99
100 if( m_bitmapBase->GetImageData() != aOther.m_bitmapBase->GetImageData() )
101 return false;
102
103 return true;
104}
105
106
107double REFERENCE_IMAGE::Similarity( const REFERENCE_IMAGE& aOther ) const
108{
109 double similarity = 1.0;
110
111 if( m_pos != aOther.m_pos )
112 similarity *= 0.9;
113
114 if( m_bitmapBase->GetSize() != aOther.m_bitmapBase->GetSize() )
115 similarity *= 0.9;
116
117 if( m_bitmapBase->GetPPI() != aOther.m_bitmapBase->GetPPI() )
118 similarity *= 0.9;
119
120 if( m_bitmapBase->GetScale() != aOther.m_bitmapBase->GetScale() )
121 similarity *= 0.9;
122
123 if( m_bitmapBase->GetImageID() != aOther.m_bitmapBase->GetImageID() )
124 similarity *= 0.9;
125
126 if( m_bitmapBase->GetImageData() != aOther.m_bitmapBase->GetImageData() )
127 similarity *= 0.9;
128
129 return similarity;
130}
131
132
134{
135 return BOX2I::ByCenter( m_pos, m_bitmapBase->GetSize() );
136}
137
138
140{
141 return m_pos;
142}
143
144
146{
147 const BOX2D newBox = BOX2D::ByCenter( aPos, m_bitmapBase->GetSize() );
148
149 if( !IsBOX2Safe( newBox ) )
150 return;
151
152 m_pos = aPos;
153}
154
155
157{
159}
160
161
163{
164 m_transformOriginOffset = aCenter;
165}
166
167
169{
170 return m_bitmapBase->GetSize();
171}
172
173
175{
176 if( aWidth <= 0 )
177 return;
178
179 const double ratio = aWidth / (double) m_bitmapBase->GetSize().x;
180 scaleBy( ratio );
181}
182
183
184void REFERENCE_IMAGE::SetHeight( int aHeight )
185{
186 if( aHeight <= 0 )
187 return;
188
189 const double ratio = aHeight / (double) m_bitmapBase->GetSize().y;
190 scaleBy( ratio );
191}
192
193
195{
196 return m_bitmapBase->GetScale();
197}
198
199
201{
202 if( aScale <= 0 )
203 return;
204
205 const double ratio = aScale / m_bitmapBase->GetScale();
206 scaleBy( ratio );
207}
208
209
210void REFERENCE_IMAGE::scaleBy( double aRatio )
211{
212 if( aRatio <= 0 )
213 return;
214
215 const VECTOR2D currentOrigin = m_pos + m_transformOriginOffset;
216 const VECTOR2D newOffset = m_transformOriginOffset * aRatio;
217 const VECTOR2D newCenter = currentOrigin - newOffset;
218 const VECTOR2D newSize = m_bitmapBase->GetSize() * aRatio;
219
220 // The span of the image is limited to the size of the coordinate system
221 if( !IsVec2SafeXY( newSize ) )
222 return;
223
224 const BOX2D newBox = BOX2D::ByCenter( newCenter, newSize );
225
226 // Any overflow, just reject the call
227 if( !IsBOX2Safe( newBox ) )
228 return;
229
230 m_bitmapBase->SetScale( m_bitmapBase->GetScale() * aRatio );
231 SetTransformOriginOffset( KiROUND( newOffset ) );
232 // Don't need to recheck the box, we just did that
233 m_pos = KiROUND( newCenter );
234}
235
236
237void REFERENCE_IMAGE::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
238{
239 VECTOR2I newPos = m_pos;
240 MIRROR( newPos, aCentre, aFlipDirection );
241
242 const BOX2D newBox = BOX2D::ByCenter( newPos, m_bitmapBase->GetSize() );
243
244 if( !IsBOX2Safe( newBox ) )
245 return;
246
247 m_pos = newPos;
248 m_bitmapBase->Mirror( aFlipDirection );
249}
250
251
252void REFERENCE_IMAGE::Rotate( const VECTOR2I& aCenter, const EDA_ANGLE& aAngle )
253{
254 EDA_ANGLE norm( aAngle.AsDegrees(), DEGREES_T );
255
256 RotatePoint( m_pos, aCenter, aAngle );
257
258 norm.Normalize();
259
260 // each call to m_bitmapBase->Rotate() rotates 90 degrees CCW
261 for( double ang = 45.0; ang < norm.AsDegrees(); ang += 90.0 )
262 m_bitmapBase->Rotate( false );
263}
264
265
266bool REFERENCE_IMAGE::ReadImageFile( const wxString& aFullFilename )
267{
268 if( m_bitmapBase->ReadImageFile( aFullFilename ) )
269 {
271 return true;
272 }
273
274 return false;
275}
276
277
278bool REFERENCE_IMAGE::ReadImageFile( wxMemoryBuffer& aBuffer )
279{
280 if( m_bitmapBase->ReadImageFile( aBuffer ) )
281 {
283 return true;
284 }
285
286 return false;
287}
288
289
290bool REFERENCE_IMAGE::SetImage( const wxImage& aImage )
291{
292 if( m_bitmapBase->SetImage( aImage ) )
293 {
295 return true;
296 }
297
298 return false;
299}
300
301
303{
304 // This cannot be null after construction
305 return *m_bitmapBase;
306}
307
308
310{
311 return *m_bitmapBase;
312}
313
314
316{
317 std::swap( m_pos, aOther.m_pos );
319 std::swap( m_bitmapBase, aOther.m_bitmapBase );
320}
constexpr bool IsBOX2Safe(const BOX2< Vec > &aInput)
Check if a BOX2 is safe for use with BOX2D (probably BOX2D or BOX2L)
Definition: box2.h:949
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition: box2.h:990
This class handle bitmap images in KiCad.
Definition: bitmap_base.h:49
static constexpr BOX2< VECTOR2I > ByCenter(const VECTOR2I &aCenter, const SizeVec &aSize)
Definition: box2.h:75
EDA_ANGLE Normalize()
Definition: eda_angle.h:221
double AsDegrees() const
Definition: eda_angle.h:113
A REFERENCE_IMAGE is a wrapper around a BITMAP_IMAGE that is displayed in an editor as a reference fo...
BITMAP_BASE & MutableImage() const
Only use this if you really need to modify the underlying image.
const EDA_IU_SCALE & m_iuScale
void SwapData(REFERENCE_IMAGE &aItem)
void Rotate(const VECTOR2I &aCenter, const EDA_ANGLE &aAngle)
void SetTransformOriginOffset(const VECTOR2I &aCenter)
bool ReadImageFile(const wxString &aFullFilename)
Read and store an image file.
VECTOR2I GetTransformOriginOffset() const
Get the center of scaling, etc, relative to the image center (GetPosition()).
VECTOR2I GetPosition() const
void Flip(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection)
bool SetImage(const wxImage &aImage)
Set the image from an existing wxImage.
std::unique_ptr< BITMAP_BASE > m_bitmapBase
REFERENCE_IMAGE & operator=(const REFERENCE_IMAGE &aOther)
void SetHeight(int aHeight)
VECTOR2I GetSize() const
VECTOR2I m_transformOriginOffset
< Center of scaling, etc, relative to the image center
void SetPosition(const VECTOR2I &aPos)
void SetWidth(int aWidth)
const BITMAP_BASE & GetImage() const
Get the underlying image.
double Similarity(const REFERENCE_IMAGE &aOther) const
double GetImageScale() const
void SetImageScale(double aScale)
Set the image "zoom" value.
REFERENCE_IMAGE(const EDA_IU_SCALE &aIuScale)
BOX2I GetBoundingBox() const
void scaleBy(double ratio)
bool operator==(const REFERENCE_IMAGE &aOther) const
@ DEGREES_T
Definition: eda_angle.h:31
a few functions useful in geometry calculations.
bool IsVec2SafeXY(const VECTOR2< T > &aVec)
Check if both coordinates of a vector are within the limits of the integer type.
constexpr void MIRROR(T &aPoint, const T &aMirrorRef)
Updates aPoint with the mirror of aPoint relative to the aMirrorRef.
Definition: mirror.h:45
FLIP_DIRECTION
Definition: mirror.h:27
STL namespace.
const double IU_PER_MILS
Definition: base_units.h:77
constexpr int MilsToIU(int mils) const
Definition: base_units.h:93
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition: trigo.cpp:229