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.
 
 
 
 
 

438 lines
15 KiB

/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2020 Thomas Pointhuber <thomas.pointhuber@gmx.at>
* Copyright (C) 2020 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
*/
/**
* @file pcb_barcode.h
* @brief BARCODE class definition.
*/
#ifndef BARCODE_H_
#define BARCODE_H_
#include <board_item.h>
#include <geometry/shape_poly_set.h>
#include <pcb_text.h>
class LINE_READER;
class MSG_PANEL_ITEM;
enum class BARCODE_T : int
{
CODE_39 = 0,
CODE_128 = 1,
DATA_MATRIX = 2,
QR_CODE = 3,
MICRO_QR_CODE = 4
};
enum class BARCODE_ECC_T : int
{
L = 1, // Low
M = 2, // Medium
Q = 3, // Quartile
H = 4 // High
};
// Provide wxAny conversion helpers for property system
DECLARE_ENUM_TO_WXANY( BARCODE_T );
DECLARE_ENUM_TO_WXANY( BARCODE_ECC_T );
class PCB_BARCODE : public BOARD_ITEM
{
public:
/**
* Construct a PCB_BARCODE.
*
* @param aParent Parent board item (usually the BOARD object).
*/
PCB_BARCODE( BOARD_ITEM* aParent );
// Do not create a copy constructor & operator=.
// The ones generated by the compiler are adequate.
/**
* Destructor.
*/
~PCB_BARCODE();
/**
* Type-check helper.
*
* @return true if the given EDA_ITEM is a PCB_BARCODE.
*/
static inline bool ClassOf( const EDA_ITEM* aItem ) { return aItem && PCB_BARCODE_T == aItem->Type(); }
/**
* Get the position (center) of the barcode in internal units.
*
* @return center position of the barcode.
*/
VECTOR2I GetPosition() const override;
void SetPosition( const VECTOR2I& aPos ) override;
/**
* Set the displayed text size used by the internal PCB_TEXT object.
*
* @param aTextSize text size vector (width, height) in internal units.
*/
void SetTextSize( const VECTOR2I& aTextSize );
/**
* Change the height of the human-readable text displayed below the barcode.
*
* @param aHeight text height in internal units.
*/
void SetTextHeight( int aHeight );
int GetTextHeight() const;
void SetBarcodeTextHeight( int aHeight ); // Includes re-compute
/**
* Set the drawing layer for the barcode and its text.
*
* @param aLayer target PCB layer id.
*/
void SetLayer( PCB_LAYER_ID aLayer ) override;
/**
* Get the barcode width (in internal units).
*/
int GetWidth() const { return m_width; }
void SetWidth( int aWidth ) { m_width = aWidth; }
/**
* Get the barcode height (in internal units).
*/
int GetHeight() const { return m_height; }
void SetHeight( int aHeight ) { m_height = aHeight; }
/**
* Get the barcode margin (in internal units).
*/
const VECTOR2I& GetMargin() const { return m_margin; }
void SetMargin( const VECTOR2I& aMargin ) { m_margin = aMargin; }
/**
* Access the underlying polygonal representation generated for the barcode.
*
* @return reference to internal SHAPE_POLY_SET holding outlines for the barcode.
*/
const SHAPE_POLY_SET& GetPolyShape() const { return m_poly; }
/**
* Access the cached polygon for the barcode symbol only (no text, no margins/knockout).
*/
const SHAPE_POLY_SET& GetSymbolPoly() const { return m_symbolPoly; }
/**
* Access the cached polygon for the human-readable text only (already scaled/placed).
*/
const SHAPE_POLY_SET& GetTextPoly() const { return m_textPoly; }
/**
* Convert the barcode (text + symbol shapes) to polygonal geometry suitable for filling/collision tests.
*
* The function appends geometry to @p aBuffer for the specified @p aLayer. When @p aClearance is non-zero
* the internal polygon is inflated by that amount before being merged.
*
* @param aBuffer output buffer to receive polygon outlines.
* @param aLayer layer to convert (only geometry on this layer is added).
* @param aClearance clearance/inflation to apply around shapes (in internal units).
* @param aMaxError maximum error when approximating arcs.
* @param aErrorLoc whether approximation error should be placed outside or inside the polygon.
* @param ignoreLineWidth unused.
*/
void TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer, int aClearance,
int aMaxError, ERROR_LOC aErrorLoc = ERROR_INSIDE,
bool ignoreLineWidth = false ) const override;
// @copydoc BOARD_ITEM::GetEffectiveShape
virtual std::shared_ptr<SHAPE> GetEffectiveShape( PCB_LAYER_ID aLayer = UNDEFINED_LAYER,
FLASHING aFlash = FLASHING::DEFAULT ) const override;
/*
* Add two rectangular polygons separately bounding the barcode's symbol and the barcode's text.
*/
void GetBoundingHull( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer, int aClearance,
int aMaxError, ERROR_LOC aErrorLoc = ERROR_INSIDE );
/**
* Generate the internal polygon representation for the current barcode text, kind and error correction.
*
* This uses the Zint backend to encode the text and populate @c m_poly. After calling this the
* barcode bounding box and polygon are available and scaled to the current width/height.
*/
void ComputeBarcode();
/**
* Generate the internal polygon representation for the human-readable text.
*
* This uses the internal PCB_TEXT object to generate the text polygon and position it
* below the barcode symbol. The resulting polygon is stored in @c m_textPoly.
*/
void ComputeTextPoly();
/**
* Assemble the barcode polygon and text polygons into a single polygonal representation.
* Optionally apply a knockout and margins.
*/
void AssembleBarcode( bool aRebuildBarcode = false, bool aRebuildText = false );
/**
* Set the barcode content text to encode.
*
* @param aText UTF-8 string content for the barcode.
*/
void SetText( const wxString& aText );
wxString GetText() const;
wxString GetShownText() const;
/**
* Access the internal `PCB_TEXT` object used for showing the human-readable text.
*/
PCB_TEXT& Text() { return m_text; }
const PCB_TEXT& Text() const { return m_text; }
/**
* Function Move
* @param offset : moving vector
*/
/**
* Translate the barcode and its text by the given offset.
*
* @param offset translation vector in internal units.
*/
void Move( const VECTOR2I& offset ) override;
/**
* Rotate the barcode around a given centre by the given angle.
* The underlying polygon and text are rotated; the width/height are updated from the new bounding box.
*
* @param aRotCentre rotation centre in internal units.
* @param aAngle rotation angle.
*/
void Rotate( const VECTOR2I& aRotCentre, const EDA_ANGLE& aAngle ) override;
/**
* Flip the barcode horizontally or vertically around a centre point.
* The layer may be adjusted when flipping.
*
* @param aCentre flip origin in internal units.
* @param aFlipLeftRight flip direction enum.
*/
void Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipLeftRight ) override;
/**
* Get the top-left corner of the barcode bounding rectangle.
*
* @return top-left point in internal units.
*/
VECTOR2I GetTopLeft() const;
/**
* Get the bottom-right corner of the barcode bounding rectangle.
*
* @return bottom-right point in internal units.
*/
VECTOR2I GetBotRight() const;
/**
* Get the centre of the barcode (alias for GetPosition).
*/
VECTOR2I GetCenter() const override { return GetPosition(); }
/**
* Set the bounding rectangle of the barcode. This will scale the internal polygon outlines
* to fit the given rectangle and update width/height accordingly. This refers to
* the size of the barcode symbol excluding margins and text.
*
* @param aTopLeft top-left coordinate in internal units.
* @param aBotRight bottom-right coordinate in internal units.
*/
void SetRect( const VECTOR2I& aTopLeft, const VECTOR2I& aBotRight );
/**
* Populate message panel information entries (e.g. for selection/property panel).
*
* @param aFrame parent draw frame used for context.
* @param aList vector to append MSG_PANEL_ITEM entries to.
*/
void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override;
/**
* Hit-test a point against the barcode (text and symbol area).
*
* @param aPosition point to test in internal units.
* @param aAccuracy tolerance (in internal units) for the hit test.
* @return true if the point hits the barcode or its text.
*/
bool HitTest( const VECTOR2I& aPosition, int aAccuracy ) const override;
/**
* Hit-test a rectangle against the barcode bounding area.
*
* @param aRect rectangle to test.
* @param aContained if true, test whether barcode is fully contained in aRect; otherwise test intersection.
* @param aAccuracy optional tolerance to inflate the barcode bounding box before testing.
*/
bool HitTest( const BOX2I& aRect, bool aContained, int aAccuracy = 0 ) const override;
/**
* Return the class name for display/debugging purposes.
*/
wxString GetClass() const override { return wxT( "BARCODE" ); }
// Virtual function
/**
* Get the axis-aligned bounding box of the barcode including text.
*
* @return bounding BOX2I in internal units.
*/
const BOX2I GetBoundingBox() const override;
/**
* Produce a short human-readable description of the item for UI lists.
*
* @param aUnitsProvider unit conversion helper (may be null).
* @param aFull if true produce a more verbose description.
* @return localized description string.
*/
wxString GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const override;
/**
* Icon to show in context menus/toolbars for this item type.
*/
BITMAPS GetMenuImage() const override;
/**
* Create a copy of this item. The returned pointer is owned by the caller.
*
* @return newly allocated EDA_ITEM pointer that is a copy of this object.
*/
EDA_ITEM* Clone() const override;
void swapData( BOARD_ITEM* aImage ) override;
/**
* Get the bbox used for drawing/view culling, may include additional view-only extents.
*/
virtual const BOX2I ViewBBox() const override;
/**
* Compute a simple similarity score between this barcode and another board item.
*
* @param aItem other item to compare.
* @return similarity value between 0.0 and 1.0.
*/
double Similarity( const BOARD_ITEM& aItem ) const override;
/**
* Equality comparison operator for board-level deduplication.
*
* @param aItem other item to compare against.
* @return true if the other item is a PCB_BARCODE and has identical key properties.
*/
bool operator==( const BOARD_ITEM& aItem ) const override;
/**
* Returns the type of the barcode (QR, CODE_39, etc.).
*/
BARCODE_T GetKind() const { return m_kind; }
void SetKind( BARCODE_T aKind );
void SetBarcodeKind( BARCODE_T aKind ); // Includes re-compute
/**
* Set the error correction level used for QR codes.
*
* @param aErrorCorrection error correction enum value.
*/
void SetErrorCorrection( BARCODE_ECC_T aErrorCorrection );
BARCODE_ECC_T GetErrorCorrection() const { return m_errorCorrection; }
void SetBarcodeErrorCorrection( BARCODE_ECC_T aErrorCorrection ); // Includes re-compute
void SetBarcodeText( const wxString& aText ) { SetText( aText ); AssembleBarcode( true, true ); }
void SetShowText( bool aShow ) { m_text.SetVisible( aShow ); AssembleBarcode( false, true ); }
bool GetShowText() const { return m_text.IsVisible(); }
void SetBarcodeWidth( int aWidth ) { m_width = aWidth; AssembleBarcode( false, true ); }
void SetBarcodeHeight( int aHeight ) { m_height = aHeight; AssembleBarcode( false, true ); }
double GetOrientation() const { return m_angle.AsDegrees(); }
void SetOrientation( double aDegrees )
{
EDA_ANGLE newAngle( aDegrees, DEGREES_T );
EDA_ANGLE oldAngle = m_angle;
if( newAngle != oldAngle )
{
Rotate( GetPosition(), newAngle - oldAngle );
}
}
int GetMarginX() const { return m_margin.x; }
int GetMarginY() const { return m_margin.y; }
void SetMarginX( int aX )
{
aX = std::max( pcbIUScale.mmToIU( 1 ), aX );
m_margin.x = aX;
AssembleBarcode();
}
void SetMarginY( int aY )
{
aY = std::max( pcbIUScale.mmToIU( 1 ), aY );
m_margin.y = aY;
AssembleBarcode();
}
bool IsKnockout() const override { return BOARD_ITEM::IsKnockout(); }
void SetIsKnockout( bool aEnable ) override
{
BOARD_ITEM::SetIsKnockout( aEnable );
AssembleBarcode();
}
private:
int m_width; ///< Barcode width
int m_height; ///< Barcode height
int m_poly_width; ///< Current width of full polygon (barcode + extras)
int m_poly_height;///< Current height of full polygon (barcode + extras)
VECTOR2I m_pos; ///< Position of the barcode
VECTOR2I m_margin; ///< Margin around the barcode (only valid for knockout)
PCB_TEXT m_text;
bool m_textHeightIsCustom = false;
BARCODE_T m_kind;
EDA_ANGLE m_angle;
BARCODE_ECC_T m_errorCorrection; ///< Error correction level for QR codes
SHAPE_POLY_SET m_poly; ///< Full geometry (barcode + optional text or knockout)
SHAPE_POLY_SET m_symbolPoly; ///< Barcode symbol only (cached, centered at origin)
SHAPE_POLY_SET m_textPoly; ///< Human-readable text only (cached, centered/positioned)
};
#endif // DIMENSION_H_