Files
kicad-source-mirror/include/eda_shape.h
T
Seth Hillbrand 55020c2b89 Better fix for missing end segment
Rather than skipping our endEdit() call in libedit, we need to
parameterize whether we want the shape open/closed.  Closed will remove
the last segment if it lands on the first point.  We don't want that
but we do want to remove the last point if it duplicates the second to
last (in the case of double-clicking)

Fixes https://gitlab.com/kicad/code/kicad/issues/10334
2022-01-10 13:37:47 -08:00

320 lines
10 KiB
C++

/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2018 Jean-Pierre Charras jp.charras at wanadoo.fr
* Copyright (C) 1992-2021 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
*/
#ifndef EDA_SHAPE_H
#define EDA_SHAPE_H
#include <eda_units.h>
#include <convert_to_biu.h>
#include <trigo.h>
#include <geometry/shape_poly_set.h>
#include <geometry/geometry_utils.h>
class LINE_READER;
class EDA_DRAW_FRAME;
class FOOTPRINT;
class MSG_PANEL_ITEM;
enum class SHAPE_T : int
{
SEGMENT = 0,
RECT,
ARC,
CIRCLE,
POLY,
BEZIER,
LAST ///< marker for list end
};
// WARNING: Do not change these values without updating dialogs that depend on their position values
enum class FILL_T : int
{
NO_FILL = 1,
FILLED_SHAPE, // Fill with object color
FILLED_WITH_BG_BODYCOLOR, // Fill with background body color
FILLED_WITH_COLOR // Fill with a separate color
};
class EDA_SHAPE
{
public:
EDA_SHAPE( SHAPE_T aType, int aLineWidth, FILL_T aFill, bool eeWinding );
// Do not create a copy constructor & operator=.
// The ones generated by the compiler are adequate.
~EDA_SHAPE();
void SwapShape( EDA_SHAPE* aImage );
wxString ShowShape() const;
wxString SHAPE_T_asString() const;
void SetFillMode( FILL_T aFill ) { m_fill = aFill; }
FILL_T GetFillType() const { return m_fill; }
bool IsFilled() const { return GetFillType() != FILL_T::NO_FILL; }
void SetFilled( bool aFlag )
{
m_fill = aFlag ? FILL_T::FILLED_SHAPE : FILL_T::NO_FILL;
}
void SetWidth( int aWidth ) { m_width = aWidth; }
int GetWidth() const { return m_width; }
void SetShape( SHAPE_T aShape ) { m_shape = aShape; }
SHAPE_T GetShape() const { return m_shape; }
/**
* Return the starting point of the graphic.
*/
const wxPoint& GetStart() const { return m_start; }
int GetStartY() { return m_start.y; }
int GetStartX() { return m_start.x; }
void SetStart( const wxPoint& aStart )
{
m_start = aStart;
m_endsSwapped = false;
}
void SetStartY( int y )
{
m_start.y = y;
m_endsSwapped = false;
}
void SetStartX( int x )
{
m_start.x = x;
m_endsSwapped = false;
}
/**
* Return the ending point of the graphic.
*/
const wxPoint& GetEnd() const { return m_end; }
int GetEndY() { return m_end.y; }
int GetEndX() { return m_end.x; }
void SetEnd( const wxPoint& aEnd )
{
m_end = aEnd;
m_endsSwapped = false;
}
void SetEndY( int y )
{
m_end.y = y;
m_endsSwapped = false;
}
void SetEndX( int x )
{
m_end.x = x;
m_endsSwapped = false;
}
void SetBezierC1( const wxPoint& aPt ) { m_bezierC1 = aPt; }
const wxPoint& GetBezierC1() const { return m_bezierC1; }
void SetBezierC2( const wxPoint& aPt ) { m_bezierC2 = aPt; }
const wxPoint& GetBezierC2() const { return m_bezierC2; }
wxPoint getCenter() const;
void SetCenter( const wxPoint& aCenter );
/**
* Set the end point from the angle center and start.
*
* @param aAngle is tenths of degrees.
*/
void SetArcAngleAndEnd( double aAngle, bool aCheckNegativeAngle = false );
double GetArcAngle() const;
/**
* Have the start and end points been swapped since they were set?
* @return true if they have
*/
bool EndsSwapped() const { return m_endsSwapped; }
// Some attributes are read only, since they are derived from m_Start, m_End, and m_Angle.
// No Set...() function for these attributes.
wxPoint GetArcMid() const;
std::vector<wxPoint> GetRectCorners() const;
/**
* Calc arc start and end angles such that aStartAngle < aEndAngle. Each may be between
* -360.0 and 360.0.
*/
void CalcArcAngles( double& aStartAngle, double& aEndAngle ) const;
int GetRadius() const;
/**
* Set the three controlling points for an arc.
*
* NB: these are NOT what's currently stored, so we have to do some calculations behind
* the scenes. However, they are what SHOULD be stored.
*/
void SetArcGeometry( const wxPoint& aStart, const wxPoint& aMid, const wxPoint& aEnd );
const std::vector<wxPoint>& GetBezierPoints() const { return m_bezierPoints; }
/**
* Duplicate the list of corners in a std::vector<wxPoint>
*
* It must be used only to convert the SHAPE_POLY_SET internal corner buffer
* to a list of wxPoints, and nothing else, because it duplicates the buffer,
* that is inefficient to know for instance the corner count
*/
void DupPolyPointsList( std::vector<wxPoint>& aBuffer ) const;
/**
* @return the number of corners of the polygonal shape
*/
int GetPointCount() const;
// Accessors to the polygonal shape
SHAPE_POLY_SET& GetPolyShape() { return m_poly; }
const SHAPE_POLY_SET& GetPolyShape() const { return m_poly; }
/**
* @return true if the polygonal shape is valid (has more than 2 points)
*/
bool IsPolyShapeValid() const;
void SetPolyShape( const SHAPE_POLY_SET& aShape ) { m_poly = aShape; }
void SetBezierPoints( const std::vector<wxPoint>& aPoints ) { m_bezierPoints = aPoints; }
/**
* Rebuild the m_BezierPoints vertex list that approximate the Bezier curve
* by a list of segments.
*
* Has meaning only for BEZIER shape.
*
* @param aMinSegLen is the min length of segments approximating the bezier. The shape's last
* segment can be shorter. This parameter avoids having too many very short
* segment in list. Good values are between m_width/2 and m_width.
*/
void RebuildBezierToSegmentsPointsList( int aMinSegLen );
void SetPolyPoints( const std::vector<wxPoint>& aPoints );
/**
* Make a set of SHAPE objects representing the EDA_SHAPE. Caller owns the objects.
*/
// fixme: move to shape_compound
std::vector<SHAPE*> MakeEffectiveShapes() const;
void ShapeGetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList );
/**
* Return the length of the track using the hypotenuse calculation.
*
* @return the length of the track
*/
double GetLength() const;
/**
* Convert the shape to a closed polygon.
*
* Used in filling zones calculations. Circles and arcs are approximated by segments.
*
* @param aCornerBuffer is a buffer to store the polygon.
* @param aClearanceValue is the clearance around the pad.
* @param aError is the maximum deviation from a true arc.
* @param aErrorLoc whether any approximation error shoule be placed inside or outside
* @param ignoreLineWidth is used for edge cut items where the line width is only
* for visualization
*/
void TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, int aClearanceValue,
int aError, ERROR_LOC aErrorLoc,
bool ignoreLineWidth ) const;
int Compare( const EDA_SHAPE* aOther ) const;
protected:
void setPosition( const wxPoint& aPos );
wxPoint getPosition() const;
void move( const wxPoint& aMoveVector );
void rotate( const wxPoint& aRotCentre, double aAngle );
void flip( const wxPoint& aCentre, bool aFlipLeftRight );
void scale( double aScale );
// To be implemented by concrete classes
virtual double getParentOrientation() const = 0;
virtual wxPoint getParentPosition() const = 0;
const EDA_RECT getBoundingBox() const;
void computeArcBBox( EDA_RECT& aBBox ) const;
bool hitTest( const wxPoint& aPosition, int aAccuracy = 0 ) const;
bool hitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy = 0 ) const;
const std::vector<wxPoint> buildBezierToSegmentsPointsList( int aMinSegLen ) const;
void beginEdit( const wxPoint& aStartPoint );
bool continueEdit( const wxPoint& aPosition );
void calcEdit( const wxPoint& aPosition );
/**
* Finishes editing the shape.
* @param aClosed Should polygon shapes be closed (yes for pcbnew/fpeditor, no for libedit)
*/
void endEdit( bool aClosed = true );
void setEditState( int aState ) { m_editState = aState; }
protected:
bool m_endsSwapped; // true if start/end were swapped e.g. SetArcAngleAndEnd
SHAPE_T m_shape; // Shape: line, Circle, Arc
int m_width; // thickness of lines ...
FILL_T m_fill;
wxPoint m_start; // Line start point or Circle center
wxPoint m_end; // Line end point or Circle 3 o'clock point
wxPoint m_arcCenter; // Used only for Arcs: arc end point
wxPoint m_bezierC1; // Bezier Control Point 1
wxPoint m_bezierC2; // Bezier Control Point 2
std::vector<wxPoint> m_bezierPoints;
SHAPE_POLY_SET m_poly; // Stores the S_POLYGON shape
int m_editState;
bool m_eeWinding; // Awful hack
};
#endif // EDA_SHAPE_H