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 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, see <https://www.gnu.org/licenses/>.
18 */
19
20#include "reference_image.h"
21
22#include <string>
23
24#include <wx/debug.h>
25#include <wx/mstream.h>
26
27#include <bitmap_base.h>
29
30
31static bool compareImages( const BITMAP_BASE& aLeft, const BITMAP_BASE& aRight )
32{
33 const wxImage* leftImage = aLeft.GetImageData();
34 const wxImage* rightImage = aRight.GetImageData();
35
36 if( !leftImage || !rightImage )
37 return leftImage == rightImage;
38
39 wxMemoryOutputStream leftStream;
40 wxMemoryOutputStream rightStream;
41
42 if( !aLeft.SaveImageData( leftStream ) || !aRight.SaveImageData( rightStream ) )
43 return false;
44
45 size_t leftSize = leftStream.GetSize();
46 size_t rightSize = rightStream.GetSize();
47
48 if( leftSize != rightSize )
49 return false;
50
51 if( leftSize == 0 )
52 return true;
53
54 std::string leftData( leftSize, '\0' );
55 std::string rightData( rightSize, '\0' );
56
57 leftStream.CopyTo( leftData.data(), leftSize );
58 rightStream.CopyTo( rightData.data(), rightSize );
59
60 return leftData == rightData;
61}
62
63
65 m_iuScale( aIuScale ), m_pos( 0, 0 ), m_transformOriginOffset( 0, 0 ),
66 m_bitmapBase( std::make_unique<BITMAP_BASE>() )
67{
69}
70
71
79
80
84
85
87{
88 const double pixelSizeIu = (double) m_iuScale.MilsToIU( 1000 ) / m_bitmapBase->GetPPI();
89 m_bitmapBase->SetPixelSizeIu( pixelSizeIu );
90}
91
92
94{
95 wxASSERT( m_iuScale.IU_PER_MILS == aOther.m_iuScale.IU_PER_MILS );
96
97 if( &aOther != this )
98 {
99 if( aOther.m_bitmapBase )
100 {
101 m_bitmapBase = std::make_unique<BITMAP_BASE>( *aOther.m_bitmapBase );
102 }
103 m_pos = aOther.m_pos;
106 }
107
108 return *this;
109}
110
111
113{
114 if( m_pos != aOther.m_pos )
115 return false;
116
118 return false;
119
120 if( m_bitmapBase->GetSize() != aOther.m_bitmapBase->GetSize() )
121 return false;
122
123 if( m_bitmapBase->GetPPI() != aOther.m_bitmapBase->GetPPI() )
124 return false;
125
126 if( m_bitmapBase->GetScale() != aOther.m_bitmapBase->GetScale() )
127 return false;
128
129 if( !compareImages( *m_bitmapBase, *aOther.m_bitmapBase ) )
130 return false;
131
132 return true;
133}
134
135
136double REFERENCE_IMAGE::Similarity( const REFERENCE_IMAGE& aOther ) const
137{
138 double similarity = 1.0;
139
140 if( m_pos != aOther.m_pos )
141 similarity *= 0.9;
142
143 if( m_bitmapBase->GetSize() != aOther.m_bitmapBase->GetSize() )
144 similarity *= 0.9;
145
146 if( m_bitmapBase->GetPPI() != aOther.m_bitmapBase->GetPPI() )
147 similarity *= 0.9;
148
149 if( m_bitmapBase->GetScale() != aOther.m_bitmapBase->GetScale() )
150 similarity *= 0.9;
151
152 if( !compareImages( *m_bitmapBase, *aOther.m_bitmapBase ) )
153 similarity *= 0.9;
154
155 return similarity;
156}
157
158
160{
161 return BOX2I::ByCenter( m_pos, m_bitmapBase->GetSize() );
162}
163
164
166{
167 return m_pos;
168}
169
170
172{
173 const BOX2D newBox = BOX2D::ByCenter( aPos, m_bitmapBase->GetSize() );
174
175 if( !IsBOX2Safe( newBox ) )
176 return;
177
178 m_pos = aPos;
179}
180
181
186
187
189{
190 m_transformOriginOffset = aCenter;
191}
192
193
195{
196 return m_bitmapBase->GetSize();
197}
198
199
201{
202 if( aWidth <= 0 )
203 return;
204
205 const double ratio = aWidth / (double) m_bitmapBase->GetSize().x;
206 scaleBy( ratio );
207}
208
209
210void REFERENCE_IMAGE::SetHeight( int aHeight )
211{
212 if( aHeight <= 0 )
213 return;
214
215 const double ratio = aHeight / (double) m_bitmapBase->GetSize().y;
216 scaleBy( ratio );
217}
218
219
221{
222 return m_bitmapBase->GetScale();
223}
224
225
227{
228 if( aScale <= 0 )
229 return;
230
231 const double ratio = aScale / m_bitmapBase->GetScale();
232 scaleBy( ratio );
233}
234
235
236void REFERENCE_IMAGE::scaleBy( double aRatio )
237{
238 if( aRatio <= 0 )
239 return;
240
241 const VECTOR2D currentOrigin = m_pos + m_transformOriginOffset;
242 const VECTOR2D newOffset = m_transformOriginOffset * aRatio;
243 const VECTOR2D newCenter = currentOrigin - newOffset;
244 const VECTOR2D newSize = m_bitmapBase->GetSize() * aRatio;
245
246 // The span of the image is limited to the size of the coordinate system
247 if( !IsVec2SafeXY( newSize ) )
248 return;
249
250 const BOX2D newBox = BOX2D::ByCenter( newCenter, newSize );
251
252 // Any overflow, just reject the call
253 if( !IsBOX2Safe( newBox ) )
254 return;
255
256 m_bitmapBase->SetScale( m_bitmapBase->GetScale() * aRatio );
257 SetTransformOriginOffset( KiROUND( newOffset ) );
258
259 // Don't need to recheck the box, we just did that
260 m_pos = KiROUND( newCenter );
261}
262
263
264void REFERENCE_IMAGE::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
265{
266 VECTOR2I newPos = m_pos;
267 MIRROR( newPos, aCentre, aFlipDirection );
268
269 const BOX2D newBox = BOX2D::ByCenter( newPos, m_bitmapBase->GetSize() );
270
271 if( !IsBOX2Safe( newBox ) )
272 return;
273
274 m_pos = newPos;
275 m_bitmapBase->Mirror( aFlipDirection );
276}
277
278
279void REFERENCE_IMAGE::Rotate( const VECTOR2I& aCenter, const EDA_ANGLE& aAngle )
280{
281 EDA_ANGLE norm( aAngle.AsDegrees(), DEGREES_T );
282
283 RotatePoint( m_pos, aCenter, aAngle );
284
285 norm.Normalize();
286
287 // each call to m_bitmapBase->Rotate() rotates 90 degrees
288 for( double ang = 45.0; ang < norm.AsDegrees(); ang += 90.0 )
289 m_bitmapBase->Rotate( true );
290}
291
292
293bool REFERENCE_IMAGE::ReadImageFile( const wxString& aFullFilename )
294{
295 if( m_bitmapBase->ReadImageFile( aFullFilename ) )
296 {
298 return true;
299 }
300
301 return false;
302}
303
304
305bool REFERENCE_IMAGE::ReadImageFile( wxMemoryBuffer& aBuffer )
306{
307 if( m_bitmapBase->ReadImageFile( aBuffer ) )
308 {
310 return true;
311 }
312
313 return false;
314}
315
316
317bool REFERENCE_IMAGE::SetImage( const wxImage& aImage )
318{
319 if( m_bitmapBase->SetImage( aImage ) )
320 {
322 return true;
323 }
324
325 return false;
326}
327
328
329void REFERENCE_IMAGE::PackToBytes( std::string& aOutputBytes ) const
330{
331 wxMemoryOutputStream imageStream;
332
333 if( m_bitmapBase->GetImageData() && m_bitmapBase->SaveImageData( imageStream ) )
334 {
335 size_t size = imageStream.GetSize();
336
337 if( size > 0 )
338 {
339 aOutputBytes.resize( size );
340 imageStream.CopyTo( aOutputBytes.data(), size );
341 }
342 }
343}
344
345
346bool REFERENCE_IMAGE::UnpackFromBytes( const std::string& aInputBytes )
347{
348 if( aInputBytes.empty() )
349 return false;
350
351 wxMemoryBuffer imageBuffer;
352 imageBuffer.AppendData( aInputBytes.data(), aInputBytes.size() );
353
354 return ReadImageFile( imageBuffer );
355}
356
357
359{
360 // This cannot be null after construction
361 return *m_bitmapBase;
362}
363
364
369
370
372{
373 std::swap( m_pos, aOther.m_pos );
375 std::swap( m_bitmapBase, aOther.m_bitmapBase );
376}
constexpr bool IsBOX2Safe(const BOX2< Vec > &aInput)
Check if a BOX2 is safe for use with BOX2D (probably BOX2D or BOX2L)
Definition box2.h:945
BOX2< VECTOR2I > BOX2I
Definition box2.h:918
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:986
BOX2< VECTOR2D > BOX2D
Definition box2.h:919
This class handle bitmap images in KiCad.
Definition bitmap_base.h:45
double GetScale() const
Definition bitmap_base.h:69
bool SaveImageData(wxOutputStream &aOutStream) const
Write the bitmap data to aOutStream.
int GetPPI() const
wxImage * GetImageData()
Definition bitmap_base.h:64
VECTOR2I GetSize() const
static constexpr BOX2< VECTOR2I > ByCenter(const VECTOR2I &aCenter, const SizeVec &aSize)
Definition box2.h:71
EDA_ANGLE Normalize()
Definition eda_angle.h:229
double AsDegrees() const
Definition eda_angle.h:116
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)
VECTOR2I m_pos
XY coordinates of center of the bitmap.
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.
bool UnpackFromBytes(const std::string &aInputBytes)
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)
void PackToBytes(std::string &aOutputBytes) const
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:41
FLIP_DIRECTION
Definition mirror.h:23
STL namespace.
static bool compareImages(const BITMAP_BASE &aLeft, const BITMAP_BASE &aRight)
const double IU_PER_MILS
Definition base_units.h:75
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:225
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
VECTOR2< double > VECTOR2D
Definition vector2d.h:682