7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-04-19 23:31:40 +00:00

Abstract REFERENCE_IMAGE to a separate class

Break the non-PCB-specfic parts of PCB_REFERENCE_IMAGE out
to a common REFERENCE_IMAGE class, which is then composed into
the PCB_REFERENCE_IMAGE. This will make it easier to bring the
transform origin logic to eeschema without repetition.
This commit is contained in:
John Beard 2024-09-29 22:03:53 +01:00
parent 4a0f111fd6
commit 3f131e2011
21 changed files with 676 additions and 352 deletions

View File

@ -586,6 +586,7 @@ set( COMMON_SRCS
ptree.cpp
rc_item.cpp
refdes_utils.cpp
reference_image.cpp
render_settings.cpp
scintilla_tricks.cpp
status_popup.cpp

View File

@ -107,20 +107,20 @@ void BITMAP_BASE::updatePPI()
}
void BITMAP_BASE::ImportData( BITMAP_BASE* aItem )
void BITMAP_BASE::ImportData( BITMAP_BASE& aItem )
{
*m_image = *aItem->m_image;
*m_bitmap = *aItem->m_bitmap;
*m_originalImage = *aItem->m_originalImage;
m_imageId = aItem->m_imageId;
m_scale = aItem->m_scale;
m_ppi = aItem->m_ppi;
m_pixelSizeIu = aItem->m_pixelSizeIu;
m_isMirroredX = aItem->m_isMirroredX;
m_isMirroredY = aItem->m_isMirroredY;
m_rotation = aItem->m_rotation;
m_imageType = aItem->m_imageType;
m_imageData = aItem->m_imageData;
*m_image = *aItem.m_image;
*m_bitmap = *aItem.m_bitmap;
*m_originalImage = *aItem.m_originalImage;
m_imageId = aItem.m_imageId;
m_scale = aItem.m_scale;
m_ppi = aItem.m_ppi;
m_pixelSizeIu = aItem.m_pixelSizeIu;
m_isMirroredX = aItem.m_isMirroredX;
m_isMirroredY = aItem.m_isMirroredY;
m_rotation = aItem.m_rotation;
m_imageType = aItem.m_imageType;
m_imageData = aItem.m_imageData;
}

View File

@ -35,11 +35,10 @@
#include <algorithm>
PANEL_IMAGE_EDITOR::PANEL_IMAGE_EDITOR( wxWindow* aParent, BITMAP_BASE* aItem ) :
PANEL_IMAGE_EDITOR_BASE( aParent )
PANEL_IMAGE_EDITOR::PANEL_IMAGE_EDITOR( wxWindow* aParent, const BITMAP_BASE& aItem ) :
PANEL_IMAGE_EDITOR_BASE( aParent ),
m_workingImage( std::make_unique<BITMAP_BASE>( aItem ) )
{
m_workingImage = new BITMAP_BASE( *aItem );
wxString msg;
msg.Printf( wxT( "%f" ), m_workingImage->GetScale() );
m_textCtrlScale->SetValue( msg );
@ -49,6 +48,11 @@ PANEL_IMAGE_EDITOR::PANEL_IMAGE_EDITOR( wxWindow* aParent, BITMAP_BASE* aItem )
}
PANEL_IMAGE_EDITOR::~PANEL_IMAGE_EDITOR()
{
}
void PANEL_IMAGE_EDITOR::OnGreyScaleConvert( wxCommandEvent& event )
{
m_workingImage->ConvertToGreyscale();
@ -132,11 +136,11 @@ void PANEL_IMAGE_EDITOR::OnRedrawPanel( wxPaintEvent& event )
}
void PANEL_IMAGE_EDITOR::TransferToImage( BITMAP_BASE* aItem )
void PANEL_IMAGE_EDITOR::TransferToImage( BITMAP_BASE& aItem )
{
wxString msg = m_textCtrlScale->GetValue();
double scale = 1.0;
msg.ToDouble( &scale );
m_workingImage->SetScale( scale );
aItem->ImportData( m_workingImage );
aItem.ImportData( *m_workingImage );
}

280
common/reference_image.cpp Normal file
View File

@ -0,0 +1,280 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "reference_image.h"
#include <wx/debug.h>
#include <bitmap_base.h>
#include <geometry/geometry_utils.h>
REFERENCE_IMAGE::REFERENCE_IMAGE( const EDA_IU_SCALE& aIuScale ) :
m_iuScale( aIuScale ), m_pos( 0, 0 ), m_transformOriginOffset( 0, 0 ),
m_bitmapBase( std::make_unique<BITMAP_BASE>() )
{
updatePixelSizeInIU();
}
REFERENCE_IMAGE::REFERENCE_IMAGE( const REFERENCE_IMAGE& aOther ) :
m_iuScale( aOther.m_iuScale ), m_pos( aOther.m_pos ),
m_transformOriginOffset( aOther.m_transformOriginOffset ),
m_bitmapBase( std::make_unique<BITMAP_BASE>( *aOther.m_bitmapBase ) )
{
updatePixelSizeInIU();
}
REFERENCE_IMAGE::~REFERENCE_IMAGE()
{
}
void REFERENCE_IMAGE::updatePixelSizeInIU()
{
const double pixelSizeIu = (double) m_iuScale.MilsToIU( 1000 ) / m_bitmapBase->GetPPI();
m_bitmapBase->SetPixelSizeIu( pixelSizeIu );
}
REFERENCE_IMAGE& REFERENCE_IMAGE::operator=( const REFERENCE_IMAGE& aOther )
{
wxASSERT( m_iuScale.IU_PER_MILS == aOther.m_iuScale.IU_PER_MILS );
if( &aOther != this )
{
if( aOther.m_bitmapBase )
{
m_bitmapBase = std::make_unique<BITMAP_BASE>( *aOther.m_bitmapBase );
}
m_pos = aOther.m_pos;
m_transformOriginOffset = aOther.m_transformOriginOffset;
updatePixelSizeInIU();
}
return *this;
}
bool REFERENCE_IMAGE::operator==( const REFERENCE_IMAGE& aOther ) const
{
if( m_pos != aOther.m_pos )
return false;
if( m_transformOriginOffset != aOther.m_transformOriginOffset )
return false;
if( m_bitmapBase->GetSize() != aOther.m_bitmapBase->GetSize() )
return false;
if( m_bitmapBase->GetPPI() != aOther.m_bitmapBase->GetPPI() )
return false;
if( m_bitmapBase->GetScale() != aOther.m_bitmapBase->GetScale() )
return false;
if( m_bitmapBase->GetImageID() != aOther.m_bitmapBase->GetImageID() )
return false;
if( m_bitmapBase->GetImageData() != aOther.m_bitmapBase->GetImageData() )
return false;
return true;
}
double REFERENCE_IMAGE::Similarity( const REFERENCE_IMAGE& aOther ) const
{
double similarity = 1.0;
if( m_pos != aOther.m_pos )
similarity *= 0.9;
if( m_bitmapBase->GetSize() != aOther.m_bitmapBase->GetSize() )
similarity *= 0.9;
if( m_bitmapBase->GetPPI() != aOther.m_bitmapBase->GetPPI() )
similarity *= 0.9;
if( m_bitmapBase->GetScale() != aOther.m_bitmapBase->GetScale() )
similarity *= 0.9;
if( m_bitmapBase->GetImageID() != aOther.m_bitmapBase->GetImageID() )
similarity *= 0.9;
if( m_bitmapBase->GetImageData() != aOther.m_bitmapBase->GetImageData() )
similarity *= 0.9;
return similarity;
}
BOX2I REFERENCE_IMAGE::GetBoundingBox() const
{
return BOX2I::ByCenter( m_pos, m_bitmapBase->GetSize() );
}
VECTOR2I REFERENCE_IMAGE::GetPosition() const
{
return m_pos;
}
void REFERENCE_IMAGE::SetPosition( const VECTOR2I& aPos )
{
const BOX2D newBox = BOX2D::ByCenter( aPos, m_bitmapBase->GetSize() );
if( !IsBOX2Safe( newBox ) )
return;
m_pos = aPos;
}
VECTOR2I REFERENCE_IMAGE::GetTransformOriginOffset() const
{
return m_transformOriginOffset;
}
void REFERENCE_IMAGE::SetTransformOriginOffset( const VECTOR2I& aCenter )
{
m_transformOriginOffset = aCenter;
}
VECTOR2I REFERENCE_IMAGE::GetSize() const
{
return m_bitmapBase->GetSize();
}
double REFERENCE_IMAGE::GetImageScale() const
{
return m_bitmapBase->GetScale();
}
void REFERENCE_IMAGE::SetImageScale( double aScale )
{
if( aScale < 0 )
return;
const double ratio = aScale / m_bitmapBase->GetScale();
const VECTOR2D currentOrigin = m_pos + m_transformOriginOffset;
const VECTOR2D newOffset = m_transformOriginOffset * ratio;
const VECTOR2D newCenter = currentOrigin - newOffset;
const VECTOR2D newSize = m_bitmapBase->GetSize() * ratio;
// The span of the image is limited to the size of the coordinate system
if( !IsVec2SafeXY( newSize ) )
return;
const BOX2D newBox = BOX2D::ByCenter( newCenter, newSize );
// Any overflow, just reject the call
if( !IsBOX2Safe( newBox ) )
return;
m_bitmapBase->SetScale( aScale );
SetTransformOriginOffset( KiROUND( newOffset ) );
// Don't need to recheck the box, we just did that
m_pos = KiROUND( newCenter );
}
void REFERENCE_IMAGE::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
{
VECTOR2I newPos = m_pos;
MIRROR( newPos, aCentre, aFlipDirection );
const BOX2D newBox = BOX2D::ByCenter( newPos, m_bitmapBase->GetSize() );
if( !IsBOX2Safe( newBox ) )
return;
m_pos = newPos;
m_bitmapBase->Mirror( aFlipDirection );
}
void REFERENCE_IMAGE::Rotate( const VECTOR2I& aCenter, const EDA_ANGLE& aAngle )
{
EDA_ANGLE norm( aAngle.AsDegrees(), DEGREES_T );
RotatePoint( m_pos, aCenter, aAngle );
norm.Normalize();
// each call to m_bitmapBase->Rotate() rotates 90 degrees CCW
for( double ang = 45.0; ang < norm.AsDegrees(); ang += 90.0 )
m_bitmapBase->Rotate( false );
}
bool REFERENCE_IMAGE::ReadImageFile( const wxString& aFullFilename )
{
if( m_bitmapBase->ReadImageFile( aFullFilename ) )
{
updatePixelSizeInIU();
return true;
}
return false;
}
bool REFERENCE_IMAGE::ReadImageFile( wxMemoryBuffer& aBuffer )
{
if( m_bitmapBase->ReadImageFile( aBuffer ) )
{
updatePixelSizeInIU();
return true;
}
return false;
}
const BITMAP_BASE& REFERENCE_IMAGE::GetImage() const
{
// This cannot be null after construction
return *m_bitmapBase;
}
BITMAP_BASE& REFERENCE_IMAGE::MutableImage() const
{
return *m_bitmapBase;
}
void REFERENCE_IMAGE::SwapData( REFERENCE_IMAGE& aOther )
{
std::swap( m_pos, aOther.m_pos );
std::swap( m_transformOriginOffset, aOther.m_transformOriginOffset );
std::swap( m_bitmapBase, aOther.m_bitmapBase );
}

View File

@ -78,7 +78,7 @@ public:
/**
* Copy aItem image to this object and update #m_bitmap.
*/
void ImportData( BITMAP_BASE* aItem );
void ImportData( BITMAP_BASE& aItem );
/**
* This scaling factor depends on #m_pixelSizeIu and #m_scale.

View File

@ -2,7 +2,7 @@
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2018 jean-pierre.charras
* Copyright (C) 2018 Kicad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2018-2024 Kicad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -22,22 +22,20 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef PANEL_IMAGE_EDITOR_H
#define PANEL_IMAGE_EDITOR_H
#pragma once
#include <bitmap_base.h>
#include <panel_image_editor_base.h>
#include <memory>
class BITMAP_BASE;
class PANEL_IMAGE_EDITOR : public PANEL_IMAGE_EDITOR_BASE
{
private:
BITMAP_BASE* m_workingImage; // The copy of BITMAP_BASE to be edited
public:
PANEL_IMAGE_EDITOR( wxWindow* aParent, BITMAP_BASE* aItem );
~PANEL_IMAGE_EDITOR() { delete m_workingImage; }
PANEL_IMAGE_EDITOR( wxWindow* aParent, const BITMAP_BASE& aItem );
~PANEL_IMAGE_EDITOR();
public:
bool TransferDataFromWindow() override;
@ -46,13 +44,14 @@ public:
* Function TransferToImage
* copy edited image to aItem
*/
void TransferToImage( BITMAP_BASE* aItem );
void TransferToImage( BITMAP_BASE& aItem );
private:
void OnGreyScaleConvert( wxCommandEvent& event ) override;
void OnRedrawPanel( wxPaintEvent& event ) override;
bool CheckValues();
};
#endif
// A copy of BITMAP_BASE to be edited
std::unique_ptr<BITMAP_BASE> m_workingImage;
};

137
include/reference_image.h Normal file
View File

@ -0,0 +1,137 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#pragma once
#include <memory>
#include <base_units.h>
#include <core/mirror.h>
#include <math/box2.h>
#include <math/vector2d.h>
class BITMAP_BASE;
class wxMemoryBuffer;
/**
* A REFERENCE_IMAGE is a wrapper around a BITMAP_IMAGE that is
* displayed in an editor as a reference for the user.
*/
class REFERENCE_IMAGE
{
public:
REFERENCE_IMAGE( const EDA_IU_SCALE& aIuScale );
REFERENCE_IMAGE( const REFERENCE_IMAGE& aOther );
~REFERENCE_IMAGE();
REFERENCE_IMAGE& operator=( const REFERENCE_IMAGE& aOther );
bool operator==( const REFERENCE_IMAGE& aOther ) const;
double Similarity( const REFERENCE_IMAGE& aOther ) const;
BOX2I GetBoundingBox() const;
bool HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const;
VECTOR2I GetPosition() const;
void SetPosition( const VECTOR2I& aPos );
VECTOR2I GetSize() const;
/**
* @return the image "zoom" value.
* scale = 1.0 = original size of bitmap.
* scale < 1.0 = the bitmap is drawn smaller than its original size.
* scale > 1.0 = the bitmap is drawn bigger than its original size.
*/
double GetImageScale() const;
/**
* Set the image "zoom" value.
*
* The image is scaled such that the position of the image's
* transform origin is unchanged.
*
* If the scale is negative or the image would overflow the
* the coordinate system, nothing is updated.
*/
void SetImageScale( double aScale );
void Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection );
void Rotate( const VECTOR2I& aCenter, const EDA_ANGLE& aAngle );
/**
* Read and store an image file.
*
* Initialize the bitmap used to draw this item format.
*
* @param aFullFilename is the full filename of the image file to read.
* @return true if success reading else false.
*/
bool ReadImageFile( const wxString& aFullFilename );
/**
* Read and store an image file.
*
* Initialize the bitmap used to draw this item format.
*
* @param aBuf is the memory buffer containing the image file to read.
* @return true if success reading else false.
*/
bool ReadImageFile( wxMemoryBuffer& aBuf );
void SwapData( REFERENCE_IMAGE& aItem );
/**
* Get the underlying image.
*
* This will always return a valid reference, but it may be to an empty image.
*/
const BITMAP_BASE& GetImage() const;
/**
* Only use this if you really need to modify the underlying image
*/
BITMAP_BASE& MutableImage() const;
/**
* Get the center of scaling, etc, relative to the image center (GetPosition()).
*/
VECTOR2I GetTransformOriginOffset() const;
void SetTransformOriginOffset( const VECTOR2I& aCenter );
private:
void updatePixelSizeInIU();
const EDA_IU_SCALE& m_iuScale;
VECTOR2I m_pos; // XY coordinates of center of the bitmap
///< Center of scaling, etc, relative to the image center
VECTOR2I m_transformOriginOffset;
std::unique_ptr<BITMAP_BASE> m_bitmapBase;
};

View File

@ -27,8 +27,7 @@
* @brief a few functions useful in geometry calculations.
*/
#ifndef GEOMETRY_UTILS_H
#define GEOMETRY_UTILS_H
#pragma once
#include <algorithm>
#include <math.h> // for copysign
@ -203,4 +202,26 @@ inline bool IsVec2SafeXY( const VECTOR2<T>& aVec )
bool ClipLine( const BOX2I *aClipBox, int &x1, int &y1, int &x2, int &y2 );
#endif // #ifndef GEOMETRY_UTILS_H
namespace KIGEOM
{
/**
* Perform a point-to-box hit test.
*
* @param aHitPoint - The point that is hitting the box
* @param aHittee - The box that is tested for hit.
* @param aAccuracy - The accuracy of the hit test.
*/
bool BoxHitTest( const VECTOR2I& aHitPoint, const BOX2I& aHittee, int aAccuracy );
/**
* Perform a box-to-box hit test.
*
* @param aHitter - The box that is either hitting or containing the hittee.
* @param aHittee - The box that is either being hit or contained by the hitter
* (this is possibly an object's bounding box).
* @param aHitteeContained - True if the hittee is tested for total containment,
* false if it is tested for intersection.
* @param aAccuracy - The accuracy of the hit test.
*/
bool BoxHitTest( const BOX2I& aHitter, const BOX2I& aHittee, bool aHitteeContained, int aAccuracy );
}; // namespace KIGEOM

View File

@ -198,3 +198,21 @@ bool ClipLine( const BOX2I *aClipBox, int &x1, int &y1, int &x2, int &y2 )
return false;
}
bool KIGEOM::BoxHitTest( const VECTOR2I& aHitter, const BOX2I& aHittee, int aAccuracy )
{
const BOX2I hittee = aHittee.GetInflated( aAccuracy );
return hittee.Contains( aHitter );
}
bool KIGEOM::BoxHitTest( const BOX2I& aHitter, const BOX2I& aHittee, bool aHitteeContained,
int aAccuracy )
{
const BOX2I hitter = aHitter.GetInflated( aAccuracy );
if( aHitteeContained )
return hitter.Contains( aHittee );
return hitter.Intersects( aHittee );
}

View File

@ -33,7 +33,7 @@
DIALOG_REFERENCE_IMAGE_PROPERTIES::DIALOG_REFERENCE_IMAGE_PROPERTIES( PCB_BASE_FRAME* aParent,
PCB_REFERENCE_IMAGE* aBitmap ) :
PCB_REFERENCE_IMAGE& aBitmap ) :
DIALOG_REFERENCE_IMAGE_PROPERTIES_BASE( aParent ),
m_frame( aParent ),
m_bitmap( aBitmap ),
@ -41,14 +41,15 @@ DIALOG_REFERENCE_IMAGE_PROPERTIES::DIALOG_REFERENCE_IMAGE_PROPERTIES( PCB_BASE_F
m_posY( aParent, m_YPosLabel, m_ModPositionY, m_YPosUnit )
{
// Create the image editor page
m_imageEditor = new PANEL_IMAGE_EDITOR( m_Notebook, aBitmap->MutableImage() );
m_imageEditor =
new PANEL_IMAGE_EDITOR( m_Notebook, aBitmap.GetReferenceImage().MutableImage() );
m_Notebook->AddPage( m_imageEditor, _( "Image" ), false );
m_posX.SetCoordType( ORIGIN_TRANSFORMS::ABS_X_COORD );
m_posY.SetCoordType( ORIGIN_TRANSFORMS::ABS_Y_COORD );
// Only show unactivated board layers if the bitmap is on one of them
if( !m_frame->GetBoard()->IsLayerEnabled( m_bitmap->GetLayer() ) )
if( !m_frame->GetBoard()->IsLayerEnabled( m_bitmap.GetLayer() ) )
m_LayerSelectionCtrl->ShowNonActivatedLayers( true );
m_LayerSelectionCtrl->SetLayersHotkeys( false );
@ -63,7 +64,7 @@ DIALOG_REFERENCE_IMAGE_PROPERTIES::DIALOG_REFERENCE_IMAGE_PROPERTIES( PCB_BASE_F
void PCB_BASE_EDIT_FRAME::ShowReferenceImagePropertiesDialog( BOARD_ITEM* aBitmap )
{
PCB_REFERENCE_IMAGE* bitmap = static_cast<PCB_REFERENCE_IMAGE*>( aBitmap );
PCB_REFERENCE_IMAGE& bitmap = static_cast<PCB_REFERENCE_IMAGE&>( *aBitmap );
DIALOG_REFERENCE_IMAGE_PROPERTIES dlg( this, bitmap );
if( dlg.ShowModal() == wxID_OK )
@ -78,12 +79,12 @@ void PCB_BASE_EDIT_FRAME::ShowReferenceImagePropertiesDialog( BOARD_ITEM* aBitma
bool DIALOG_REFERENCE_IMAGE_PROPERTIES::TransferDataToWindow()
{
m_posX.SetValue( m_bitmap->GetPosition().x );
m_posY.SetValue( m_bitmap->GetPosition().y );
m_posX.SetValue( m_bitmap.GetPosition().x );
m_posY.SetValue( m_bitmap.GetPosition().y );
m_LayerSelectionCtrl->SetLayerSelection( m_bitmap->GetLayer() );
m_LayerSelectionCtrl->SetLayerSelection( m_bitmap.GetLayer() );
m_cbLocked->SetValue( m_bitmap->IsLocked() );
m_cbLocked->SetValue( m_bitmap.IsLocked() );
m_cbLocked->SetToolTip( _( "Locked items cannot be freely moved and oriented on the canvas "
"and can only be selected when the 'Locked items' checkbox is "
"checked in the selection filter." ) );
@ -97,16 +98,16 @@ bool DIALOG_REFERENCE_IMAGE_PROPERTIES::TransferDataFromWindow()
if( m_imageEditor->TransferDataFromWindow() )
{
// Save old image in undo list if not already in edit
if( m_bitmap->GetEditFlags() == 0 )
m_frame->SaveCopyInUndoList( m_bitmap, UNDO_REDO::CHANGED );
if( m_bitmap.GetEditFlags() == 0 )
m_frame->SaveCopyInUndoList( &m_bitmap, UNDO_REDO::CHANGED );
// Update our bitmap from the editor
m_imageEditor->TransferToImage( m_bitmap->MutableImage() );
m_imageEditor->TransferToImage( m_bitmap.GetReferenceImage().MutableImage() );
// Set position, etc.
m_bitmap->SetPosition( VECTOR2I( m_posX.GetValue(), m_posY.GetValue() ) );
m_bitmap->SetLayer( ToLAYER_ID( m_LayerSelectionCtrl->GetLayerSelection() ) );
m_bitmap->SetLocked( m_cbLocked->GetValue() );
m_bitmap.SetPosition( VECTOR2I( m_posX.GetValue(), m_posY.GetValue() ) );
m_bitmap.SetLayer( ToLAYER_ID( m_LayerSelectionCtrl->GetLayerSelection() ) );
m_bitmap.SetLocked( m_cbLocked->GetValue() );
return true;
}

View File

@ -1,7 +1,7 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2018-2023 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2018-2024 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -21,8 +21,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef DIALOG_REFERENCE_IMAGE_PROPERTIES_H
#define DIALOG_REFERENCE_IMAGE_PROPERTIES_H
#pragma once
#include <dialogs/dialog_reference_image_properties_base.h>
#include <widgets/unit_binder.h>
@ -36,7 +35,7 @@ class PANEL_IMAGE_EDITOR;
class DIALOG_REFERENCE_IMAGE_PROPERTIES : public DIALOG_REFERENCE_IMAGE_PROPERTIES_BASE
{
public:
DIALOG_REFERENCE_IMAGE_PROPERTIES( PCB_BASE_FRAME* aParent, PCB_REFERENCE_IMAGE* aBitmap );
DIALOG_REFERENCE_IMAGE_PROPERTIES( PCB_BASE_FRAME* aParent, PCB_REFERENCE_IMAGE& aBitmap );
~DIALOG_REFERENCE_IMAGE_PROPERTIES() override {}
private:
@ -45,11 +44,10 @@ private:
private:
PCB_BASE_FRAME* m_frame;
PCB_REFERENCE_IMAGE* m_bitmap;
///< The reference image being edited
PCB_REFERENCE_IMAGE& m_bitmap;
PANEL_IMAGE_EDITOR* m_imageEditor;
UNIT_BINDER m_posX;
UNIT_BINDER m_posY;
};
#endif // DIALOG_REFERENCE_IMAGE_PROPERTIES_H

View File

@ -1466,14 +1466,15 @@ void PCB_IO_EASYEDAPRO_PARSER::ParseBoard(
std::unique_ptr<PCB_REFERENCE_IMAGE> bitmap =
std::make_unique<PCB_REFERENCE_IMAGE>( aBoard, kcenter, klayer );
REFERENCE_IMAGE& refImage = bitmap->GetReferenceImage();
wxImage::SetDefaultLoadFlags( wxImage::GetDefaultLoadFlags()
& ~wxImage::Load_Verbose );
if( bitmap->ReadImageFile( buf ) )
if( refImage.ReadImageFile( buf ) )
{
double scaleFactor = ScaleSize( size.x ) / bitmap->GetSize().x;
bitmap->SetImageScale( scaleFactor );
double scaleFactor = ScaleSize( size.x ) / refImage.GetSize().x;
refImage.SetImageScale( scaleFactor );
// TODO: support non-90-deg angles
bitmap->Rotate( kstart, EDA_ANGLE( angle, DEGREES_T ) );
@ -1484,7 +1485,7 @@ void PCB_IO_EASYEDAPRO_PARSER::ParseBoard(
MIRROR( x, KiROUND( kstart.x ) );
bitmap->SetX( x );
bitmap->MutableImage()->Mirror( FLIP_DIRECTION::LEFT_RIGHT );
refImage.MutableImage().Mirror( FLIP_DIRECTION::LEFT_RIGHT );
}
aBoard->Add( bitmap.release(), ADD_MODE::APPEND );

View File

@ -1072,7 +1072,9 @@ void PCB_IO_KICAD_SEXPR::format( const PCB_REFERENCE_IMAGE* aBitmap, int aNestLe
{
wxCHECK_RET( aBitmap != nullptr && m_out != nullptr, "" );
const wxImage* image = aBitmap->GetImage()->GetImageData();
const REFERENCE_IMAGE& refImage = aBitmap->GetReferenceImage();
const wxImage* image = refImage.GetImage().GetImageData();
wxCHECK_RET( image != nullptr, "wxImage* is NULL" );
@ -1082,15 +1084,15 @@ void PCB_IO_KICAD_SEXPR::format( const PCB_REFERENCE_IMAGE* aBitmap, int aNestLe
formatLayer( aBitmap->GetLayer() );
if( aBitmap->GetImage()->GetScale() != 1.0 )
m_out->Print( 0, "(scale %g)", aBitmap->GetImage()->GetScale() );
if( refImage.GetImageScale() != 1.0 )
m_out->Print( 0, "(scale %g)", refImage.GetImageScale() );
if( const bool locked = aBitmap->IsLocked() )
KICAD_FORMAT::FormatBool( m_out, 0, "locked", locked );
m_out->Print( aNestLevel + 1, "(data" );
wxString out = wxBase64Encode( aBitmap->GetImage()->GetImageDataBuffer() );
wxString out = wxBase64Encode( refImage.GetImage().GetImageDataBuffer() );
// Apparently the MIME standard character width for base64 encoding is 76 (unconfirmed)
// so use it in a vain attempt to be standard like.

View File

@ -3195,14 +3195,16 @@ PCB_REFERENCE_IMAGE* PCB_IO_KICAD_SEXPR_PARSER::parsePCB_REFERENCE_IMAGE( BOARD_
break;
case T_scale:
bitmap->SetImageScale( parseDouble( "image scale factor" ) );
{
REFERENCE_IMAGE& refImage = bitmap->GetReferenceImage();
refImage.SetImageScale( parseDouble( "image scale factor" ) );
if( !std::isnormal( bitmap->GetImage()->GetScale() ) )
bitmap->SetImageScale( 1.0 );
if( !std::isnormal( refImage.GetImageScale() ) )
refImage.SetImageScale( 1.0 );
NeedRIGHT();
break;
}
case T_data:
{
token = NextTok();
@ -3222,9 +3224,10 @@ PCB_REFERENCE_IMAGE* PCB_IO_KICAD_SEXPR_PARSER::parsePCB_REFERENCE_IMAGE( BOARD_
token = NextTok();
}
wxMemoryBuffer buffer = wxBase64Decode( data );
wxMemoryBuffer buffer = wxBase64Decode( data );
if( !bitmap->ReadImageFile( buffer ) )
REFERENCE_IMAGE& refImage = bitmap->GetReferenceImage();
if( !refImage.ReadImageFile( buffer ) )
THROW_IO_ERROR( _( "Failed to read image data." ) );
break;

View File

@ -2062,11 +2062,13 @@ void PCB_PAINTER::strokeText( const wxString& aText, const VECTOR2I& aPosition,
void PCB_PAINTER::draw( const PCB_REFERENCE_IMAGE* aBitmap, int aLayer )
{
m_gal->Save();
m_gal->Translate( aBitmap->GetPosition() );
const REFERENCE_IMAGE& refImg = aBitmap->GetReferenceImage();
m_gal->Translate( refImg.GetPosition() );
// When the image scale factor is not 1.0, we need to modify the actual as the image scale
// factor is similar to a local zoom
double img_scale = aBitmap->GetImageScale();
const double img_scale = refImg.GetImageScale();
if( img_scale != 1.0 )
m_gal->Scale( VECTOR2D( img_scale, img_scale ) );
@ -2080,7 +2082,7 @@ void PCB_PAINTER::draw( const PCB_REFERENCE_IMAGE* aBitmap, int aLayer )
m_gal->SetIsFill( false );
// Draws a bounding box.
VECTOR2D bm_size( aBitmap->GetSize() );
VECTOR2D bm_size( refImg.GetSize() );
// bm_size is the actual image size in UI.
// but m_gal scale was previously set to img_scale
// so recalculate size relative to this image size.
@ -2094,13 +2096,12 @@ void PCB_PAINTER::draw( const PCB_REFERENCE_IMAGE* aBitmap, int aLayer )
// Hard code reference images as opaque when selected. Otherwise cached layers will
// not be rendered under the selected image because cached layers are rendered after
// non-cached layers (e.g. bitmaps), which will have a closer Z order.
m_gal->DrawBitmap( *aBitmap->GetImage(), 1.0 );
m_gal->DrawBitmap( refImg.GetImage(), 1.0 );
}
else
m_gal->DrawBitmap( *aBitmap->GetImage(),
m_gal->DrawBitmap( refImg.GetImage(),
m_pcbSettings.GetColor( aBitmap, aBitmap->GetLayer() ).a );
m_gal->Restore();
}

View File

@ -25,19 +25,19 @@
#include "pcb_reference_image.h"
#include <pcb_draw_panel_gal.h>
#include <plotters/plotter.h>
#include <settings/color_settings.h>
#include <pcb_painter.h>
#include <bitmaps.h>
#include <base_units.h>
#include <common.h>
#include <eda_draw_frame.h>
#include <core/mirror.h>
#include <bitmaps.h>
#include <board.h>
#include <trigo.h>
#include <common.h>
#include <core/mirror.h>
#include <eda_draw_frame.h>
#include <pcb_draw_panel_gal.h>
#include <pcb_painter.h>
#include <plotters/plotter.h>
#include <geometry/geometry_utils.h>
#include <geometry/shape_rect.h>
#include <settings/color_settings.h>
#include <trigo.h>
#include <wx/mstream.h>
@ -47,26 +47,20 @@ using KIGFX::PCB_RENDER_SETTINGS;
PCB_REFERENCE_IMAGE::PCB_REFERENCE_IMAGE( BOARD_ITEM* aParent, const VECTOR2I& aPos,
PCB_LAYER_ID aLayer ) :
BOARD_ITEM( aParent, PCB_REFERENCE_IMAGE_T, aLayer ), m_pos( aPos ),
m_transformOriginOffset( 0, 0 )
BOARD_ITEM( aParent, PCB_REFERENCE_IMAGE_T, aLayer ), m_referenceImage( pcbIUScale )
{
m_bitmapBase = new BITMAP_BASE();
m_bitmapBase->SetPixelSizeIu( (float) pcbIUScale.MilsToIU( 1000 ) / m_bitmapBase->GetPPI() );
m_referenceImage.SetPosition( aPos );
}
PCB_REFERENCE_IMAGE::PCB_REFERENCE_IMAGE( const PCB_REFERENCE_IMAGE& aPCBBitmap ) :
BOARD_ITEM( aPCBBitmap ), m_pos( aPCBBitmap.m_pos ),
m_transformOriginOffset( aPCBBitmap.m_transformOriginOffset )
BOARD_ITEM( aPCBBitmap ), m_referenceImage( aPCBBitmap.m_referenceImage )
{
m_bitmapBase = new BITMAP_BASE( *aPCBBitmap.m_bitmapBase );
m_bitmapBase->SetPixelSizeIu( (float) pcbIUScale.MilsToIU( 1000 ) / m_bitmapBase->GetPPI() );
}
PCB_REFERENCE_IMAGE::~PCB_REFERENCE_IMAGE()
{
delete m_bitmapBase;
}
@ -79,43 +73,14 @@ PCB_REFERENCE_IMAGE& PCB_REFERENCE_IMAGE::operator=( const BOARD_ITEM& aItem )
if( &aItem != this )
{
BOARD_ITEM::operator=( aItem );
PCB_REFERENCE_IMAGE* bitmap = (PCB_REFERENCE_IMAGE*) &aItem;
delete m_bitmapBase;
m_bitmapBase = new BITMAP_BASE( *bitmap->m_bitmapBase );
m_pos = bitmap->m_pos;
m_bitmapBase->SetPixelSizeIu( (float) pcbIUScale.MilsToIU( 1000 ) / m_bitmapBase->GetPPI() );
const PCB_REFERENCE_IMAGE& refImg = static_cast<const PCB_REFERENCE_IMAGE&>( aItem );
m_referenceImage = refImg.m_referenceImage;
}
return *this;
}
bool PCB_REFERENCE_IMAGE::ReadImageFile( const wxString& aFullFilename )
{
if( m_bitmapBase->ReadImageFile( aFullFilename ) )
{
m_bitmapBase->SetPixelSizeIu( (float) pcbIUScale.MilsToIU( 1000 ) / m_bitmapBase->GetPPI() );
return true;
}
return false;
}
bool PCB_REFERENCE_IMAGE::ReadImageFile( wxMemoryBuffer& aBuffer )
{
if( m_bitmapBase->ReadImageFile( aBuffer ) )
{
m_bitmapBase->SetPixelSizeIu( (float) pcbIUScale.MilsToIU( 1000 ) / m_bitmapBase->GetPPI() );
return true;
}
return false;
}
EDA_ITEM* PCB_REFERENCE_IMAGE::Clone() const
{
return new PCB_REFERENCE_IMAGE( *this );
@ -135,8 +100,7 @@ void PCB_REFERENCE_IMAGE::swapData( BOARD_ITEM* aItem )
std::swap( m_flags, item->m_flags );
std::swap( m_parent, item->m_parent );
std::swap( m_forceVisible, item->m_forceVisible );
std::swap( m_pos, item->m_pos );
std::swap( m_bitmapBase, item->m_bitmapBase );
m_referenceImage.SwapData( item->m_referenceImage );
}
@ -165,11 +129,7 @@ double PCB_REFERENCE_IMAGE::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
const BOX2I PCB_REFERENCE_IMAGE::GetBoundingBox() const
{
// Bitmaps are center origin, BOX2Is need top-left origin
const VECTOR2I size = m_bitmapBase->GetSize();
const VECTOR2I topLeft{ m_pos.x - size.x / 2, m_pos.y - size.y / 2 };
return BOX2I{ topLeft, size };
return m_referenceImage.GetBoundingBox();
}
@ -181,84 +141,33 @@ std::shared_ptr<SHAPE> PCB_REFERENCE_IMAGE::GetEffectiveShape( PCB_LAYER_ID aLay
}
VECTOR2I PCB_REFERENCE_IMAGE::GetPosition() const
{
return m_referenceImage.GetPosition();
}
void PCB_REFERENCE_IMAGE::SetPosition( const VECTOR2I& aPos )
{
const BOX2D newBox = BOX2D::ByCenter( aPos, m_bitmapBase->GetSize() );
if( !IsBOX2Safe( newBox ) )
return;
m_pos = aPos;
m_referenceImage.SetPosition( aPos );
}
void PCB_REFERENCE_IMAGE::Move( const VECTOR2I& aMoveVector )
{
// Defer to SetPosition to check the new position overflow
SetPosition( m_pos + aMoveVector );
}
void PCB_REFERENCE_IMAGE::SetImageScale( double aScale )
{
if( aScale < 0 )
return;
const double ratio = aScale / m_bitmapBase->GetScale();
const VECTOR2D currentOrigin = m_pos + m_transformOriginOffset;
const VECTOR2D newOffset = m_transformOriginOffset * ratio;
const VECTOR2D newCenter = currentOrigin - newOffset;
const VECTOR2D newSize = m_bitmapBase->GetSize() * ratio;
// The span of the image is limited to the size of the coordinate system
if( !IsVec2SafeXY( newSize ) )
return;
const BOX2D newBox = BOX2D::ByCenter( newCenter, newSize );
// Any overflow, just reject the call
if( !IsBOX2Safe( newBox ) )
return;
m_bitmapBase->SetScale( aScale );
SetTransformOriginOffset( KiROUND( newOffset ) );
// Don't need to recheck the box, we just did that
m_pos = KiROUND( newCenter );
}
const VECTOR2I PCB_REFERENCE_IMAGE::GetSize() const
{
return m_bitmapBase->GetSize();
SetPosition( GetPosition() + aMoveVector );
}
void PCB_REFERENCE_IMAGE::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
{
VECTOR2I newPos = m_pos;
MIRROR( newPos, aCentre, aFlipDirection );
const BOX2D newBox = BOX2D::ByCenter( newPos, m_bitmapBase->GetSize() );
if( !IsBOX2Safe( newBox ) )
return;
m_pos = newPos;
m_bitmapBase->Mirror( aFlipDirection );
m_referenceImage.Flip( aCentre, aFlipDirection );
}
void PCB_REFERENCE_IMAGE::Rotate( const VECTOR2I& aCenter, const EDA_ANGLE& aAngle )
{
EDA_ANGLE norm( aAngle.AsDegrees(), DEGREES_T );
RotatePoint( m_pos, aCenter, aAngle );
norm.Normalize();
// each call to m_bitmapBase->Rotate() rotates 90 degrees CCW
for( double ang = 45.0; ang < norm.AsDegrees(); ang += 90.0 )
m_bitmapBase->Rotate( false );
m_referenceImage.Rotate( aCenter, aAngle );
}
@ -268,31 +177,21 @@ void PCB_REFERENCE_IMAGE::Show( int nestLevel, std::ostream& os ) const
// XML output:
wxString s = GetClass();
NestedSpace( nestLevel, os ) << '<' << s.Lower().mb_str() << m_pos << "/>\n";
NestedSpace( nestLevel, os ) << '<' << s.Lower().mb_str() << m_referenceImage.GetPosition()
<< "/>\n";
}
#endif
bool PCB_REFERENCE_IMAGE::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
{
BOX2I rect = GetBoundingBox();
rect.Inflate( aAccuracy );
return rect.Contains( aPosition );
return KIGEOM::BoxHitTest( aPosition, GetBoundingBox(), aAccuracy );
}
bool PCB_REFERENCE_IMAGE::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
{
BOX2I rect = aRect;
rect.Inflate( aAccuracy );
if( aContained )
return rect.Contains( GetBoundingBox() );
return rect.Intersects( GetBoundingBox() );
return KIGEOM::BoxHitTest( aRect, GetBoundingBox(), aContained, aAccuracy );
}
@ -302,16 +201,20 @@ BITMAPS PCB_REFERENCE_IMAGE::GetMenuImage() const
}
void PCB_REFERENCE_IMAGE::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame,
void PCB_REFERENCE_IMAGE::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame,
std::vector<MSG_PANEL_ITEM>& aList )
{
aList.emplace_back( _( "Reference Image" ), wxEmptyString );
aList.emplace_back( _( "PPI" ), wxString::Format( wxT( "%d "), GetImage()->GetPPI() ) );
aList.emplace_back( _( "Scale" ), wxString::Format( wxT( "%f "), GetImageScale() ) );
aList.emplace_back( _( "PPI" ),
wxString::Format( wxT( "%d " ), m_referenceImage.GetImage().GetPPI() ) );
aList.emplace_back( _( "Scale" ),
wxString::Format( wxT( "%f " ), m_referenceImage.GetImageScale() ) );
aList.emplace_back( _( "Width" ), aFrame->MessageTextFromValue( GetSize().x ) );
aList.emplace_back( _( "Height" ), aFrame->MessageTextFromValue( GetSize().y ) );
aList.emplace_back( _( "Width" ),
aFrame->MessageTextFromValue( m_referenceImage.GetSize().x ) );
aList.emplace_back( _( "Height" ),
aFrame->MessageTextFromValue( m_referenceImage.GetSize().y ) );
aList.emplace_back( _( "Layer" ), LayerName( m_layer ) );
}
@ -339,22 +242,7 @@ bool PCB_REFERENCE_IMAGE::operator==( const PCB_REFERENCE_IMAGE& aOther ) const
if( m_layer != aOther.m_layer )
return false;
if( m_pos != aOther.m_pos )
return false;
if( m_bitmapBase->GetSize() != aOther.m_bitmapBase->GetSize() )
return false;
if( m_bitmapBase->GetPPI() != aOther.m_bitmapBase->GetPPI() )
return false;
if( m_bitmapBase->GetScale() != aOther.m_bitmapBase->GetScale() )
return false;
if( m_bitmapBase->GetImageID() != aOther.m_bitmapBase->GetImageID() )
return false;
if( m_bitmapBase->GetImageData() != aOther.m_bitmapBase->GetImageData() )
if( m_referenceImage != aOther.m_referenceImage )
return false;
return true;
@ -373,28 +261,52 @@ double PCB_REFERENCE_IMAGE::Similarity( const BOARD_ITEM& aOther ) const
if( m_layer != other.m_layer )
similarity *= 0.9;
if( m_pos != other.m_pos )
similarity *= 0.9;
if( m_bitmapBase->GetSize() != other.m_bitmapBase->GetSize() )
similarity *= 0.9;
if( m_bitmapBase->GetPPI() != other.m_bitmapBase->GetPPI() )
similarity *= 0.9;
if( m_bitmapBase->GetScale() != other.m_bitmapBase->GetScale() )
similarity *= 0.9;
if( m_bitmapBase->GetImageID() != other.m_bitmapBase->GetImageID() )
similarity *= 0.9;
if( m_bitmapBase->GetImageData() != other.m_bitmapBase->GetImageData() )
similarity *= 0.9;
similarity *= m_referenceImage.Similarity( other.m_referenceImage );
return similarity;
}
int PCB_REFERENCE_IMAGE::GetTransformOriginOffsetX() const
{
return m_referenceImage.GetTransformOriginOffset().x;
}
void PCB_REFERENCE_IMAGE::SetTransformOriginOffsetX( int aX )
{
VECTOR2I offset = m_referenceImage.GetTransformOriginOffset();
offset.x = aX;
m_referenceImage.SetTransformOriginOffset( offset );
}
int PCB_REFERENCE_IMAGE::GetTransformOriginOffsetY() const
{
return m_referenceImage.GetTransformOriginOffset().y;
}
void PCB_REFERENCE_IMAGE::SetTransformOriginOffsetY( int aY )
{
VECTOR2I offset = m_referenceImage.GetTransformOriginOffset();
offset.y = aY;
m_referenceImage.SetTransformOriginOffset( offset );
}
double PCB_REFERENCE_IMAGE::GetImageScale() const
{
return m_referenceImage.GetImageScale();
}
void PCB_REFERENCE_IMAGE::SetImageScale( double aScale )
{
m_referenceImage.SetImageScale( aScale );
}
static struct PCB_REFERENCE_IMAGE_DESC
{
PCB_REFERENCE_IMAGE_DESC()

View File

@ -27,6 +27,7 @@
#include <board_item.h>
#include <bitmap_base.h>
#include <reference_image.h>
/**
@ -44,39 +45,11 @@ public:
PCB_REFERENCE_IMAGE& operator=( const BOARD_ITEM& aItem );
const BITMAP_BASE* GetImage() const
{
wxCHECK_MSG( m_bitmapBase != nullptr, nullptr,
wxS( "Invalid PCB_REFERENCE_IMAGE init, m_bitmapBase is NULL." ) );
return m_bitmapBase;
}
/**
* Only use this if you really need to modify the underlying image
* @return the underlying reference image object.
*/
BITMAP_BASE* MutableImage() const
{
return m_bitmapBase;
}
/**
* @return the image "zoom" value.
* scale = 1.0 = original size of bitmap.
* scale < 1.0 = the bitmap is drawn smaller than its original size.
* scale > 1.0 = the bitmap is drawn bigger than its original size.
*/
double GetImageScale() const { return m_bitmapBase->GetScale(); }
/**
* Set the image "zoom" value.
*
* The image is scaled such that the position of the image's
* transform origin is unchanged.
*
* If the scale is negaive or the image would overflow the
* the coordinate system, nothing is updated.
*/
void SetImageScale( double aScale );
REFERENCE_IMAGE& GetReferenceImage() { return m_referenceImage; }
const REFERENCE_IMAGE& GetReferenceImage() const { return m_referenceImage; }
static inline bool ClassOf( const EDA_ITEM* aItem )
{
@ -85,11 +58,6 @@ public:
wxString GetClass() const override { return wxT( "PCB_REFERENCE_IMAGE" ); }
/**
* @return the actual size (in user units, not in pixels) of the image.
*/
const VECTOR2I GetSize() const;
double ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const override;
const BOX2I GetBoundingBox() const override;
@ -102,26 +70,6 @@ public:
/// @copydoc VIEW_ITEM::ViewGetLayers()
virtual void ViewGetLayers( int aLayers[], int& aCount ) const override;
/**
* Read and store an image file.
*
* Initialize the bitmap used to draw this item format.
*
* @param aFullFilename is the full filename of the image file to read.
* @return true if success reading else false.
*/
bool ReadImageFile( const wxString& aFullFilename );
/**
* Read and store an image file.
*
* Initialize the bitmap used to draw this item format.
*
* @param aBuf is the memory buffer containing the image file to read.
* @return true if success reading else false.
*/
bool ReadImageFile( wxMemoryBuffer& aBuf );
void Move( const VECTOR2I& aMoveVector ) override;
void Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection ) override;
@ -139,7 +87,7 @@ public:
/**
* Get the position of the image (this is the center of the image).
*/
VECTOR2I GetPosition() const override { return m_pos; }
VECTOR2I GetPosition() const override;
/**
* Set the position of the image.
@ -148,12 +96,6 @@ public:
*/
void SetPosition( const VECTOR2I& aPosition ) override;
/**
* Get the center of scaling, etc, relative to the image center (GetPosition()).
*/
VECTOR2I GetTransformOriginOffset() const { return m_transformOriginOffset; }
void SetTransformOriginOffset( const VECTOR2I& aCenter ) { m_transformOriginOffset = aCenter; }
bool HitTest( const VECTOR2I& aPosition, int aAccuracy = 0 ) const override;
bool HitTest( const BOX2I& aRect, bool aContained, int aAccuracy = 0 ) const override;
@ -168,18 +110,20 @@ public:
void Show( int nestLevel, std::ostream& os ) const override;
#endif
// Property manager interfaces
int GetTransformOriginOffsetX() const { return m_transformOriginOffset.x; }
void SetTransformOriginOffsetX( int aX ) { m_transformOriginOffset.x = aX; }
int GetTransformOriginOffsetY() const { return m_transformOriginOffset.y; }
void SetTransformOriginOffsetY( int aY ) { m_transformOriginOffset.y = aY; }
protected:
void swapData( BOARD_ITEM* aItem ) override;
private:
VECTOR2I m_pos; // XY coordinates of center of the bitmap
///< Center of scaling, etc, relative to the image center
VECTOR2I m_transformOriginOffset;
BITMAP_BASE* m_bitmapBase; // the BITMAP_BASE item
friend struct PCB_REFERENCE_IMAGE_DESC;
// Property manager interfaces
int GetTransformOriginOffsetX() const;
void SetTransformOriginOffsetX( int aX );
int GetTransformOriginOffsetY() const;
void SetTransformOriginOffsetY( int aY );
double GetImageScale() const;
void SetImageScale( double aScale );
REFERENCE_IMAGE m_referenceImage;
};

View File

@ -746,7 +746,7 @@ int DRAWING_TOOL::PlaceReferenceImage( const TOOL_EVENT& aEvent )
if( wxFileExists( fullFilename ) )
image = new PCB_REFERENCE_IMAGE( m_frame->GetModel(), cursorPos );
if( !image || !image->ReadImageFile( fullFilename ) )
if( !image || !image->GetReferenceImage().ReadImageFile( fullFilename ) )
{
wxMessageBox( wxString::Format(_( "Could not load image from '%s'." ), fullFilename ) );
delete image;

View File

@ -214,16 +214,18 @@ std::shared_ptr<EDIT_POINTS> PCB_POINT_EDITOR::makePoints( EDA_ITEM* aItem )
{
case PCB_REFERENCE_IMAGE_T:
{
const PCB_REFERENCE_IMAGE* refImage = static_cast<const PCB_REFERENCE_IMAGE*>( aItem );
const VECTOR2I topLeft = refImage->GetPosition() - refImage->GetSize() / 2;
const VECTOR2I botRight = refImage->GetPosition() + refImage->GetSize() / 2;
const REFERENCE_IMAGE& refImage =
static_cast<const PCB_REFERENCE_IMAGE&>( *aItem ).GetReferenceImage();
const VECTOR2I topLeft = refImage.GetPosition() - refImage.GetSize() / 2;
const VECTOR2I botRight = refImage.GetPosition() + refImage.GetSize() / 2;
points->AddPoint( topLeft );
points->AddPoint( VECTOR2I( botRight.x, topLeft.y ) );
points->AddPoint( botRight );
points->AddPoint( VECTOR2I( topLeft.x, botRight.y ) );
points->AddPoint( refImage->GetPosition() + refImage->GetTransformOriginOffset() );
points->AddPoint( refImage.GetPosition() + refImage.GetTransformOriginOffset() );
break;
}
@ -1361,7 +1363,8 @@ void PCB_POINT_EDITOR::updateItem( BOARD_COMMIT* aCommit )
{
case PCB_REFERENCE_IMAGE_T:
{
PCB_REFERENCE_IMAGE* bitmap = static_cast<PCB_REFERENCE_IMAGE*>( item );
PCB_REFERENCE_IMAGE& bitmap = static_cast<PCB_REFERENCE_IMAGE&>( *item );
REFERENCE_IMAGE& refImg = bitmap.GetReferenceImage();
const VECTOR2I topLeft = m_editPoints->Point( RECT_TOP_LEFT ).GetPosition();
const VECTOR2I topRight = m_editPoints->Point( RECT_TOP_RIGHT ).GetPosition();
const VECTOR2I botLeft = m_editPoints->Point( RECT_BOT_LEFT ).GetPosition();
@ -1373,52 +1376,53 @@ void PCB_POINT_EDITOR::updateItem( BOARD_COMMIT* aCommit )
// Moving the transform origin
// As the other points didn't move, we can get the image extent from them
const VECTOR2I newOffset = xfrmOrigin - ( topLeft + botRight ) / 2;
bitmap->SetTransformOriginOffset( newOffset );
refImg.SetTransformOriginOffset( newOffset );
}
else
{
const VECTOR2I oldOrigin = bitmap->GetPosition() + bitmap->GetTransformOriginOffset();
const VECTOR2I oldSize = bitmap->GetSize();
const VECTOR2I oldOrigin = refImg.GetPosition() + refImg.GetTransformOriginOffset();
const VECTOR2I oldSize = refImg.GetSize();
const VECTOR2I pos = refImg.GetPosition();
OPT_VECTOR2I newCorner;
OPT_VECTOR2I oldCorner;
VECTOR2I oldCorner = pos;
if( isModified( m_editPoints->Point( RECT_TOP_LEFT ) ) )
{
newCorner = topLeft;
oldCorner = ( bitmap->GetPosition() - oldSize / 2 );
oldCorner -= oldSize / 2;
}
else if( isModified( m_editPoints->Point( RECT_TOP_RIGHT ) ) )
{
newCorner = topRight;
oldCorner = ( bitmap->GetPosition() - VECTOR2I( -oldSize.x, oldSize.y ) / 2 );
oldCorner -= VECTOR2I( -oldSize.x, oldSize.y ) / 2;
}
else if( isModified( m_editPoints->Point( RECT_BOT_LEFT ) ) )
{
newCorner = botLeft;
oldCorner = ( bitmap->GetPosition() - VECTOR2I( oldSize.x, -oldSize.y ) / 2 );
oldCorner -= VECTOR2I( oldSize.x, -oldSize.y ) / 2;
}
else if( isModified( m_editPoints->Point( RECT_BOT_RIGHT ) ) )
{
newCorner = botRight;
oldCorner = ( bitmap->GetPosition() + oldSize / 2 );
oldCorner += oldSize / 2;
}
if( newCorner && oldCorner )
if( newCorner )
{
// Turn in the respective vectors from the origin
*newCorner -= xfrmOrigin;
*oldCorner -= oldOrigin;
oldCorner -= oldOrigin;
// If we tried to cross the origin, clamp it to stop it
if( sign( newCorner->x ) != sign( oldCorner->x )
|| sign( newCorner->y ) != sign( oldCorner->y ) )
if( sign( newCorner->x ) != sign( oldCorner.x )
|| sign( newCorner->y ) != sign( oldCorner.y ) )
{
*newCorner = VECTOR2I( 0, 0 );
}
const double newLength = newCorner->EuclideanNorm();
const double oldLength = oldCorner->EuclideanNorm();
const double oldLength = oldCorner.EuclideanNorm();
double ratio = oldLength > 0 ? ( newLength / oldLength ) : 1.0;
@ -1429,7 +1433,7 @@ void PCB_POINT_EDITOR::updateItem( BOARD_COMMIT* aCommit )
ratio = std::min( newWidth / oldSize.x, newHeight / oldSize.y );
// Also handles the origin offset
bitmap->SetImageScale( bitmap->GetImageScale() * ratio );
refImg.SetImageScale( refImg.GetImageScale() * ratio );
}
}
@ -2064,9 +2068,10 @@ void PCB_POINT_EDITOR::updatePoints()
{
case PCB_REFERENCE_IMAGE_T:
{
const PCB_REFERENCE_IMAGE* bitmap = static_cast<const PCB_REFERENCE_IMAGE*>( item );
const VECTOR2I topLeft = bitmap->GetPosition() - bitmap->GetSize() / 2;
const VECTOR2I botRight = bitmap->GetPosition() + bitmap->GetSize() / 2;
const REFERENCE_IMAGE& refImg =
static_cast<const PCB_REFERENCE_IMAGE&>( *item ).GetReferenceImage();
const VECTOR2I topLeft = refImg.GetPosition() - refImg.GetSize() / 2;
const VECTOR2I botRight = refImg.GetPosition() + refImg.GetSize() / 2;
m_editPoints->Point( RECT_TOP_LEFT ).SetPosition( topLeft );
m_editPoints->Point( RECT_TOP_RIGHT ).SetPosition( botRight.x, topLeft.y );
@ -2074,7 +2079,7 @@ void PCB_POINT_EDITOR::updatePoints()
m_editPoints->Point( RECT_BOT_RIGHT ).SetPosition( botRight );
m_editPoints->Point( REFIMG_ORIGIN )
.SetPosition( bitmap->GetPosition() + bitmap->GetTransformOriginOffset() );
.SetPosition( refImg.GetPosition() + refImg.GetTransformOriginOffset() );
break;
}

View File

@ -3580,8 +3580,8 @@ void PCB_SELECTION_TOOL::GuessSelectionCandidates( GENERAL_COLLECTOR& aCollector
}
else if( item->Type() == PCB_REFERENCE_IMAGE_T )
{
VECTOR2D size = static_cast<const PCB_REFERENCE_IMAGE*>( item )->GetSize();
area = size.x * size.y;
BOX2I box = item->GetBoundingBox();
area = (double) box.GetWidth() * box.GetHeight();
}
else
{

View File

@ -105,18 +105,15 @@ BOOST_FIXTURE_TEST_CASE( ReferenceImageLoading, REFERENCE_IMAGE_LOAD_TEST_FIXTUR
const auto& image =
static_cast<PCB_REFERENCE_IMAGE&>( KI_TEST::RequireBoardItemWithTypeAndId(
aBoard, PCB_REFERENCE_IMAGE_T, imageTestCase.m_imageUuid ) );
const REFERENCE_IMAGE& refImage = image.GetReferenceImage();
BOOST_CHECK_EQUAL( image.IsLocked(), imageTestCase.m_expectedLocked );
BOOST_CHECK_EQUAL( image.GetPosition(), imageTestCase.m_expectedPos * 1000000 );
BOOST_CHECK_CLOSE( image.GetImageScale(), imageTestCase.m_expectedScale, 1e-6 );
BOOST_CHECK_CLOSE( refImage.GetImageScale(), imageTestCase.m_expectedScale, 1e-6 );
const BITMAP_BASE* bitmap = image.GetImage();
const BITMAP_BASE& bitmap = refImage.GetImage();
BOOST_REQUIRE( bitmap );
BOOST_TEST_MESSAGE( "Got underlying image" );
BOOST_CHECK_EQUAL( bitmap->GetSizePixels(), imageTestCase.m_expectedPixelSize );
BOOST_CHECK_EQUAL( bitmap.GetSizePixels(), imageTestCase.m_expectedPixelSize );
}
};