Browse Source
Replace individual LIB_* shapes with LIB_SHAPE (based on EDA_SHAPE).
Replace individual LIB_* shapes with LIB_SHAPE (based on EDA_SHAPE).
Also moves to more capable FILL_T model that can be shared.6.0.7
73 changed files with 1330 additions and 4221 deletions
-
6common/eda_item.cpp
-
125common/eda_shape.cpp
-
2common/eda_text.cpp
-
23common/plotters/DXF_plotter.cpp
-
72common/plotters/GERBER_plotter.cpp
-
26common/plotters/HPGL_plotter.cpp
-
24common/plotters/PDF_plotter.cpp
-
30common/plotters/PS_plotter.cpp
-
58common/plotters/SVG_plotter.cpp
-
4common/plotters/common_plot_functions.cpp
-
55common/plotters/plotter.cpp
-
7eeschema/CMakeLists.txt
-
20eeschema/dialogs/dialog_lib_shape_properties.cpp
-
6eeschema/dialogs/dialog_plot_schematic.cpp
-
6eeschema/dialogs/panel_eeschema_color_settings.cpp
-
544eeschema/lib_arc.cpp
-
148eeschema/lib_arc.h
-
353eeschema/lib_bezier.cpp
-
111eeschema/lib_bezier.h
-
285eeschema/lib_circle.cpp
-
111eeschema/lib_circle.h
-
3eeschema/lib_field.h
-
23eeschema/lib_item.cpp
-
36eeschema/lib_item.h
-
2eeschema/lib_pin.cpp
-
4eeschema/lib_pin.h
-
390eeschema/lib_polyline.cpp
-
125eeschema/lib_polyline.h
-
292eeschema/lib_rectangle.cpp
-
112eeschema/lib_rectangle.h
-
269eeschema/lib_shape.cpp
-
19eeschema/lib_shape.h
-
93eeschema/lib_symbol.cpp
-
2eeschema/lib_symbol.h
-
3eeschema/lib_text.h
-
2eeschema/sch_junction.cpp
-
132eeschema/sch_painter.cpp
-
12eeschema/sch_painter.h
-
112eeschema/sch_plugins/altium/sch_altium_plugin.cpp
-
135eeschema/sch_plugins/cadstar/cadstar_sch_archive_loader.cpp
-
109eeschema/sch_plugins/eagle/sch_eagle_plugin.cpp
-
52eeschema/sch_plugins/eagle/sch_eagle_plugin.h
-
79eeschema/sch_plugins/kicad/sch_sexpr_parser.cpp
-
17eeschema/sch_plugins/kicad/sch_sexpr_parser.h
-
175eeschema/sch_plugins/kicad/sch_sexpr_plugin.cpp
-
541eeschema/sch_plugins/legacy/sch_legacy_plugin.cpp
-
4eeschema/sch_sheet.cpp
-
6eeschema/sch_symbol.cpp
-
2eeschema/sch_text.cpp
-
8eeschema/tools/ee_actions.cpp
-
383eeschema/tools/ee_point_editor.cpp
-
12eeschema/tools/ee_selection_tool.cpp
-
12eeschema/tools/sch_edit_tool.cpp
-
23eeschema/tools/symbol_editor_drawing_tools.cpp
-
2eeschema/tools/symbol_editor_drawing_tools.h
-
19eeschema/tools/symbol_editor_edit_tool.cpp
-
2eeschema/tools/symbol_editor_edit_tool.h
-
6include/core/typeinfo.h
-
69include/eda_shape.h
-
37include/fill_type.h
-
14include/plotters/plotter.h
-
8include/plotters/plotter_dxf.h
-
12include/plotters/plotter_gerber.h
-
13include/plotters/plotter_hpgl.h
-
37include/plotters/plotters_pslike.h
-
1pcbnew/drc/drc_test_provider_copper_clearance.cpp
-
5pcbnew/exporters/gerber_placefile_writer.cpp
-
62pcbnew/fp_shape.cpp
-
1pcbnew/fp_shape.h
-
4pcbnew/pcb_shape.cpp
-
12pcbnew/plot_board_layers.cpp
-
19pcbnew/plot_brditems_plotter.cpp
-
23qa/eeschema/test_lib_part.cpp
@ -1,545 +1 @@ |
|||
/*
|
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr |
|||
* Copyright (C) 2004-2021 KiCad Developers, see AUTHORS.txt for contributors. |
|||
* Copyright (C) 2019 CERN |
|||
* |
|||
* 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 <sch_draw_panel.h>
|
|||
#include <plotters/plotter.h>
|
|||
#include <trigo.h>
|
|||
#include <base_units.h>
|
|||
#include <widgets/msgpanel.h>
|
|||
#include <bitmaps.h>
|
|||
#include <math/util.h> // for KiROUND
|
|||
#include <eda_draw_frame.h>
|
|||
#include <general.h>
|
|||
#include <lib_arc.h>
|
|||
#include <transform.h>
|
|||
#include <settings/color_settings.h>
|
|||
#include <status_popup.h>
|
|||
|
|||
// Helper function
|
|||
static inline wxPoint twoPointVector( const wxPoint &startPoint, const wxPoint &endPoint ) |
|||
{ |
|||
return endPoint - startPoint; |
|||
} |
|||
|
|||
|
|||
LIB_ARC::LIB_ARC( LIB_SYMBOL* aParent ) : LIB_ITEM( LIB_ARC_T, aParent ) |
|||
{ |
|||
m_Width = 0; |
|||
m_fill = FILL_TYPE::NO_FILL; |
|||
m_isFillable = true; |
|||
m_editState = 0; |
|||
} |
|||
|
|||
|
|||
int LIB_ARC::GetRadius() const |
|||
{ |
|||
return KiROUND( GetLineLength( GetCenter(), GetStart() ) ); |
|||
} |
|||
|
|||
|
|||
bool LIB_ARC::HitTest( const wxPoint& aRefPoint, int aAccuracy ) const |
|||
{ |
|||
int mindist = std::max( aAccuracy + GetPenWidth() / 2, |
|||
Mils2iu( MINIMUM_SELECTION_DISTANCE ) ); |
|||
wxPoint relativePosition = aRefPoint; |
|||
|
|||
relativePosition.y = -relativePosition.y; // reverse Y axis
|
|||
|
|||
int distance = KiROUND( GetLineLength( m_Pos, relativePosition ) ); |
|||
|
|||
if( abs( distance - GetRadius() ) > mindist ) |
|||
return false; |
|||
|
|||
// We are on the circle, ensure we are only on the arc, i.e. between
|
|||
// m_ArcStart and m_ArcEnd
|
|||
|
|||
wxPoint startEndVector = twoPointVector( m_ArcStart, m_ArcEnd ); |
|||
wxPoint startRelativePositionVector = twoPointVector( m_ArcStart, relativePosition ); |
|||
|
|||
wxPoint centerStartVector = twoPointVector( m_Pos, m_ArcStart ); |
|||
wxPoint centerEndVector = twoPointVector( m_Pos, m_ArcEnd ); |
|||
wxPoint centerRelativePositionVector = twoPointVector( m_Pos, relativePosition ); |
|||
|
|||
// Compute the cross product to check if the point is in the sector
|
|||
double crossProductStart = CrossProduct( centerStartVector, centerRelativePositionVector ); |
|||
double crossProductEnd = CrossProduct( centerEndVector, centerRelativePositionVector ); |
|||
|
|||
// The cross products need to be exchanged, depending on which side the center point
|
|||
// relative to the start point to end point vector lies
|
|||
if( CrossProduct( startEndVector, startRelativePositionVector ) < 0 ) |
|||
{ |
|||
std::swap( crossProductStart, crossProductEnd ); |
|||
} |
|||
|
|||
// When the cross products have a different sign, the point lies in sector
|
|||
// also check, if the reference is near start or end point
|
|||
return HitTestPoints( m_ArcStart, relativePosition, MINIMUM_SELECTION_DISTANCE ) || |
|||
HitTestPoints( m_ArcEnd, relativePosition, MINIMUM_SELECTION_DISTANCE ) || |
|||
( crossProductStart <= 0 && crossProductEnd >= 0 ); |
|||
} |
|||
|
|||
|
|||
bool LIB_ARC::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const |
|||
{ |
|||
if( m_flags & (STRUCT_DELETED | SKIP_STRUCT ) ) |
|||
return false; |
|||
|
|||
wxPoint center = DefaultTransform.TransformCoordinate( GetPosition() ); |
|||
int radius = GetRadius(); |
|||
int lineWidth = GetWidth(); |
|||
EDA_RECT sel = aRect ; |
|||
|
|||
if ( aAccuracy ) |
|||
sel.Inflate( aAccuracy ); |
|||
|
|||
if( aContained ) |
|||
return sel.Contains( GetBoundingBox() ); |
|||
|
|||
EDA_RECT arcRect = GetBoundingBox().Common( sel ); |
|||
|
|||
/* All following tests must pass:
|
|||
* 1. Rectangle must intersect arc BoundingBox |
|||
* 2. Rectangle must cross the outside of the arc |
|||
*/ |
|||
return arcRect.Intersects( sel ) && arcRect.IntersectsCircleEdge( center, radius, lineWidth ); |
|||
} |
|||
|
|||
|
|||
EDA_ITEM* LIB_ARC::Clone() const |
|||
{ |
|||
return new LIB_ARC( *this ); |
|||
} |
|||
|
|||
|
|||
int LIB_ARC::compare( const LIB_ITEM& aOther, LIB_ITEM::COMPARE_FLAGS aCompareFlags ) const |
|||
{ |
|||
wxASSERT( aOther.Type() == LIB_ARC_T ); |
|||
|
|||
int retv = LIB_ITEM::compare( aOther ); |
|||
|
|||
if( retv ) |
|||
return retv; |
|||
|
|||
const LIB_ARC* tmp = ( LIB_ARC* ) &aOther; |
|||
|
|||
if( m_Pos.x != tmp->m_Pos.x ) |
|||
return m_Pos.x - tmp->m_Pos.x; |
|||
|
|||
if( m_Pos.y != tmp->m_Pos.y ) |
|||
return m_Pos.y - tmp->m_Pos.y; |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
|
|||
void LIB_ARC::Offset( const wxPoint& aOffset ) |
|||
{ |
|||
m_Pos += aOffset; |
|||
m_ArcStart += aOffset; |
|||
m_ArcEnd += aOffset; |
|||
} |
|||
|
|||
|
|||
void LIB_ARC::MoveTo( const wxPoint& aPosition ) |
|||
{ |
|||
wxPoint offset = aPosition - m_Pos; |
|||
m_Pos = aPosition; |
|||
m_ArcStart += offset; |
|||
m_ArcEnd += offset; |
|||
} |
|||
|
|||
|
|||
void LIB_ARC::MirrorHorizontal( const wxPoint& aCenter ) |
|||
{ |
|||
m_Pos.x -= aCenter.x; |
|||
m_Pos.x *= -1; |
|||
m_Pos.x += aCenter.x; |
|||
m_ArcStart.x -= aCenter.x; |
|||
m_ArcStart.x *= -1; |
|||
m_ArcStart.x += aCenter.x; |
|||
m_ArcEnd.x -= aCenter.x; |
|||
m_ArcEnd.x *= -1; |
|||
m_ArcEnd.x += aCenter.x; |
|||
std::swap( m_ArcStart, m_ArcEnd ); |
|||
} |
|||
|
|||
|
|||
void LIB_ARC::MirrorVertical( const wxPoint& aCenter ) |
|||
{ |
|||
m_Pos.y -= aCenter.y; |
|||
m_Pos.y *= -1; |
|||
m_Pos.y += aCenter.y; |
|||
m_ArcStart.y -= aCenter.y; |
|||
m_ArcStart.y *= -1; |
|||
m_ArcStart.y += aCenter.y; |
|||
m_ArcEnd.y -= aCenter.y; |
|||
m_ArcEnd.y *= -1; |
|||
m_ArcEnd.y += aCenter.y; |
|||
std::swap( m_ArcStart, m_ArcEnd ); |
|||
} |
|||
|
|||
|
|||
void LIB_ARC::Rotate( const wxPoint& aCenter, bool aRotateCCW ) |
|||
{ |
|||
int rot_angle = aRotateCCW ? -900 : 900; |
|||
RotatePoint( &m_Pos, aCenter, rot_angle ); |
|||
RotatePoint( &m_ArcStart, aCenter, rot_angle ); |
|||
RotatePoint( &m_ArcEnd, aCenter, rot_angle ); |
|||
} |
|||
|
|||
|
|||
void LIB_ARC::Plot( PLOTTER* aPlotter, const wxPoint& aOffset, bool aFill, |
|||
const TRANSFORM& aTransform ) const |
|||
{ |
|||
wxASSERT( aPlotter != nullptr ); |
|||
|
|||
wxPoint center = aTransform.TransformCoordinate( GetCenter() ) + aOffset; |
|||
int startAngle; |
|||
int endAngle; |
|||
int pen_size = GetEffectivePenWidth( aPlotter->RenderSettings() ); |
|||
FILL_TYPE fill = aFill ? m_fill : FILL_TYPE::NO_FILL; |
|||
|
|||
CalcAngles( startAngle, endAngle ); |
|||
aTransform.MapAngles( &startAngle, &endAngle ); |
|||
|
|||
if( fill == FILL_TYPE::FILLED_WITH_BG_BODYCOLOR ) |
|||
{ |
|||
aPlotter->SetColor( aPlotter->RenderSettings()->GetLayerColor( LAYER_DEVICE_BACKGROUND ) ); |
|||
aPlotter->Arc( center, -endAngle, -startAngle, GetRadius(), fill, 0 ); |
|||
|
|||
if( pen_size <= 0 ) |
|||
return; |
|||
else |
|||
fill = FILL_TYPE::NO_FILL; |
|||
} |
|||
|
|||
pen_size = std::max( pen_size, aPlotter->RenderSettings()->GetMinPenWidth() ); |
|||
|
|||
aPlotter->SetColor( aPlotter->RenderSettings()->GetLayerColor( LAYER_DEVICE ) ); |
|||
aPlotter->Arc( center, -endAngle, -startAngle, GetRadius(), fill, pen_size ); |
|||
} |
|||
|
|||
|
|||
int LIB_ARC::GetPenWidth() const |
|||
{ |
|||
return m_Width; |
|||
} |
|||
|
|||
|
|||
void LIB_ARC::print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset, void* aData, |
|||
const TRANSFORM& aTransform ) |
|||
{ |
|||
bool forceNoFill = static_cast<bool>( aData ); |
|||
int penWidth = GetEffectivePenWidth( aSettings ); |
|||
|
|||
if( forceNoFill && m_fill != FILL_TYPE::NO_FILL && penWidth == 0 ) |
|||
return; |
|||
|
|||
wxDC* DC = aSettings->GetPrintDC(); |
|||
wxPoint pos1, pos2, posc; |
|||
COLOR4D color = aSettings->GetLayerColor( LAYER_DEVICE ); |
|||
|
|||
pos1 = aTransform.TransformCoordinate( m_ArcEnd ) + aOffset; |
|||
pos2 = aTransform.TransformCoordinate( m_ArcStart ) + aOffset; |
|||
posc = aTransform.TransformCoordinate( m_Pos ) + aOffset; |
|||
|
|||
int t1; |
|||
int t2; |
|||
|
|||
CalcAngles( t1, t2 ); |
|||
aTransform.MapAngles( &t1, &t2 ); |
|||
|
|||
if( forceNoFill || m_fill == FILL_TYPE::NO_FILL ) |
|||
{ |
|||
GRArc1( nullptr, DC, pos1.x, pos1.y, pos2.x, pos2.y, posc.x, posc.y, penWidth, color ); |
|||
} |
|||
else |
|||
{ |
|||
if( m_fill == FILL_TYPE::FILLED_WITH_BG_BODYCOLOR ) |
|||
color = aSettings->GetLayerColor( LAYER_DEVICE_BACKGROUND ); |
|||
|
|||
GRFilledArc( nullptr, DC, posc.x, posc.y, t1, t2, GetRadius(), penWidth, color, color ); |
|||
} |
|||
} |
|||
|
|||
|
|||
const EDA_RECT LIB_ARC::GetBoundingBox() const |
|||
{ |
|||
int radius = GetRadius(); |
|||
int minX, minY, maxX, maxY, angleStart, angleEnd; |
|||
EDA_RECT rect; |
|||
wxPoint nullPoint, startPos, endPos, centerPos; |
|||
wxPoint normStart = m_ArcStart - m_Pos; |
|||
wxPoint normEnd = m_ArcEnd - m_Pos; |
|||
|
|||
if( normStart == nullPoint || normEnd == nullPoint || radius == 0 ) |
|||
return rect; |
|||
|
|||
endPos = DefaultTransform.TransformCoordinate( m_ArcEnd ); |
|||
startPos = DefaultTransform.TransformCoordinate( m_ArcStart ); |
|||
centerPos = DefaultTransform.TransformCoordinate( m_Pos ); |
|||
|
|||
CalcAngles( angleStart, angleEnd ); |
|||
DefaultTransform.MapAngles( &angleStart, &angleEnd ); |
|||
|
|||
/* Start with the start and end point of the arc. */ |
|||
minX = std::min( startPos.x, endPos.x ); |
|||
minY = std::min( startPos.y, endPos.y ); |
|||
maxX = std::max( startPos.x, endPos.x ); |
|||
maxY = std::max( startPos.y, endPos.y ); |
|||
|
|||
/* Zero degrees is a special case. */ |
|||
if( angleStart == 0 ) |
|||
maxX = centerPos.x + radius; |
|||
|
|||
/* Arc end angle wrapped passed 360. */ |
|||
if( angleStart > angleEnd ) |
|||
angleEnd += 3600; |
|||
|
|||
if( angleStart <= 900 && angleEnd >= 900 ) /* 90 deg */ |
|||
maxY = centerPos.y + radius; |
|||
|
|||
if( angleStart <= 1800 && angleEnd >= 1800 ) /* 180 deg */ |
|||
minX = centerPos.x - radius; |
|||
|
|||
if( angleStart <= 2700 && angleEnd >= 2700 ) /* 270 deg */ |
|||
minY = centerPos.y - radius; |
|||
|
|||
if( angleStart <= 3600 && angleEnd >= 3600 ) /* 0 deg */ |
|||
maxX = centerPos.x + radius; |
|||
|
|||
rect.SetOrigin( minX, minY ); |
|||
rect.SetEnd( maxX, maxY ); |
|||
rect.Inflate( ( GetPenWidth() / 2 ) + 1 ); |
|||
|
|||
return rect; |
|||
} |
|||
|
|||
|
|||
void LIB_ARC::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) |
|||
{ |
|||
wxString msg; |
|||
EDA_RECT bBox = GetBoundingBox(); |
|||
|
|||
LIB_ITEM::GetMsgPanelInfo( aFrame, aList ); |
|||
|
|||
msg = MessageTextFromValue( aFrame->GetUserUnits(), m_Width ); |
|||
|
|||
aList.emplace_back( _( "Line Width" ), msg ); |
|||
|
|||
msg.Printf( wxT( "(%d, %d, %d, %d)" ), bBox.GetOrigin().x, |
|||
bBox.GetOrigin().y, bBox.GetEnd().x, bBox.GetEnd().y ); |
|||
|
|||
aList.emplace_back( _( "Bounding Box" ), msg ); |
|||
} |
|||
|
|||
|
|||
wxString LIB_ARC::GetSelectMenuText( EDA_UNITS aUnits ) const |
|||
{ |
|||
return wxString::Format( _( "Arc, radius %s" ), |
|||
MessageTextFromValue( aUnits, GetRadius() ) ); |
|||
} |
|||
|
|||
|
|||
BITMAPS LIB_ARC::GetMenuImage() const |
|||
{ |
|||
return BITMAPS::add_arc; |
|||
} |
|||
|
|||
|
|||
void LIB_ARC::BeginEdit( const wxPoint& aPosition ) |
|||
{ |
|||
m_ArcStart = m_ArcEnd = aPosition; |
|||
m_editState = 1; |
|||
} |
|||
|
|||
|
|||
void LIB_ARC::CalcEdit( const wxPoint& aPosition ) |
|||
{ |
|||
#define sq( x ) pow( x, 2 )
|
|||
|
|||
int radius = GetRadius(); |
|||
|
|||
// Edit state 0: drawing: place ArcStart
|
|||
// Edit state 1: drawing: place ArcEnd (center calculated for 90-degree subtended angle)
|
|||
// Edit state 2: point editing: move ArcStart (center calculated for invariant subtended angle)
|
|||
// Edit state 3: point editing: move ArcEnd (center calculated for invariant subtended angle)
|
|||
// Edit state 4: point editing: move center
|
|||
|
|||
switch( m_editState ) |
|||
{ |
|||
case 0: |
|||
m_ArcStart = aPosition; |
|||
m_ArcEnd = aPosition; |
|||
m_Pos = aPosition; |
|||
radius = 0; |
|||
return; |
|||
|
|||
case 1: |
|||
m_ArcEnd = aPosition; |
|||
radius = KiROUND( sqrt( sq( GetLineLength( m_ArcStart, m_ArcEnd ) ) / 2.0 ) ); |
|||
break; |
|||
|
|||
case 2: |
|||
case 3: |
|||
{ |
|||
wxPoint v = m_ArcStart - m_ArcEnd; |
|||
double chordBefore = sq( v.x ) + sq( v.y ); |
|||
|
|||
if( m_editState == 2 ) |
|||
m_ArcStart = aPosition; |
|||
else |
|||
m_ArcEnd = aPosition; |
|||
|
|||
v = m_ArcStart - m_ArcEnd; |
|||
double chordAfter = sq( v.x ) + sq( v.y ); |
|||
double ratio = chordAfter / chordBefore; |
|||
|
|||
if( ratio != 0 ) |
|||
{ |
|||
radius = std::max( int( sqrt( sq( radius ) * ratio ) ) + 1, |
|||
int( sqrt( chordAfter ) / 2 ) + 1 ); |
|||
} |
|||
|
|||
break; |
|||
} |
|||
|
|||
case 4: |
|||
{ |
|||
double chordA = GetLineLength( m_ArcStart, aPosition ); |
|||
double chordB = GetLineLength( m_ArcEnd, aPosition ); |
|||
radius = int( ( chordA + chordB ) / 2.0 ) + 1; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
// Calculate center based on start, end, and radius
|
|||
//
|
|||
// Let 'l' be the length of the chord and 'm' the middle point of the chord
|
|||
double l = GetLineLength( m_ArcStart, m_ArcEnd ); |
|||
wxPoint m = ( m_ArcStart + m_ArcEnd ) / 2; |
|||
|
|||
// Calculate 'd', the vector from the chord midpoint to the center
|
|||
wxPoint d; |
|||
d.x = KiROUND( sqrt( sq( radius ) - sq( l/2 ) ) * ( m_ArcStart.y - m_ArcEnd.y ) / l ); |
|||
d.y = KiROUND( sqrt( sq( radius ) - sq( l/2 ) ) * ( m_ArcEnd.x - m_ArcStart.x ) / l ); |
|||
|
|||
wxPoint c1 = m + d; |
|||
wxPoint c2 = m - d; |
|||
|
|||
// Solution gives us 2 centers; we need to pick one:
|
|||
switch( m_editState ) |
|||
{ |
|||
case 1: |
|||
{ |
|||
// Keep center clockwise from chord while drawing
|
|||
wxPoint chordVector = twoPointVector( m_ArcStart, m_ArcEnd ); |
|||
double chordAngle = ArcTangente( chordVector.y, chordVector.x ); |
|||
NORMALIZE_ANGLE_POS( chordAngle ); |
|||
|
|||
wxPoint c1Test = c1; |
|||
RotatePoint( &c1Test, m_ArcStart, -chordAngle ); |
|||
|
|||
m_Pos = c1Test.x > 0 ? c2 : c1; |
|||
} |
|||
break; |
|||
|
|||
case 2: |
|||
case 3: |
|||
// Pick the one closer to the old center
|
|||
m_Pos = ( GetLineLength( c1, m_Pos ) < GetLineLength( c2, m_Pos ) ) ? c1 : c2; |
|||
break; |
|||
|
|||
case 4: |
|||
// Pick the one closer to the mouse position
|
|||
m_Pos = ( GetLineLength( c1, aPosition ) < GetLineLength( c2, aPosition ) ) ? c1 : c2; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
|
|||
void LIB_ARC::CalcAngles( int& aStartAngle, int& aEndAngle ) const |
|||
{ |
|||
wxPoint centerStartVector = twoPointVector( GetCenter(), GetStart() ); |
|||
wxPoint centerEndVector = twoPointVector( GetCenter(), GetEnd() ); |
|||
|
|||
// Angles in Eeschema are still integers
|
|||
aStartAngle = KiROUND( ArcTangente( centerStartVector.y, centerStartVector.x ) ); |
|||
aEndAngle = KiROUND( ArcTangente( centerEndVector.y, centerEndVector.x ) ); |
|||
|
|||
NORMALIZE_ANGLE_POS( aStartAngle ); |
|||
NORMALIZE_ANGLE_POS( aEndAngle ); // angles = 0 .. 3600
|
|||
|
|||
// Restrict angle to less than 180 to avoid PBS display mirror Trace because it is
|
|||
// assumed that the arc is less than 180 deg to find orientation after rotate or mirror.
|
|||
if( ( aEndAngle - aStartAngle ) > 1800 ) |
|||
aEndAngle -= 3600; |
|||
else if( ( aEndAngle - aStartAngle ) <= -1800 ) |
|||
aEndAngle += 3600; |
|||
|
|||
while( ( aEndAngle - aStartAngle ) >= 1800 ) |
|||
{ |
|||
aEndAngle--; |
|||
aStartAngle++; |
|||
} |
|||
|
|||
while( ( aStartAngle - aEndAngle ) >= 1800 ) |
|||
{ |
|||
aEndAngle++; |
|||
aStartAngle--; |
|||
} |
|||
|
|||
NORMALIZE_ANGLE_POS( aStartAngle ); |
|||
|
|||
if( !IsMoving() ) |
|||
NORMALIZE_ANGLE_POS( aEndAngle ); |
|||
} |
|||
|
|||
|
|||
VECTOR2I LIB_ARC::CalcMidPoint() const |
|||
{ |
|||
VECTOR2D midPoint; |
|||
int radius = GetRadius(); |
|||
int t1; |
|||
int t2; |
|||
|
|||
CalcAngles( t1, t2 ); |
|||
|
|||
double startAngle = static_cast<double>( t1 ) / 10.0; |
|||
double endAngle = static_cast<double>( t2 ) / 10.0; |
|||
|
|||
if( endAngle < startAngle ) |
|||
endAngle -= 360.0; |
|||
|
|||
double midPointAngle = ( ( endAngle - startAngle ) / 2.0 ) + startAngle; |
|||
double x = cos( DEG2RAD( midPointAngle ) ) * radius; |
|||
double y = sin( DEG2RAD( midPointAngle ) ) * radius; |
|||
|
|||
midPoint.x = KiROUND( x ) + m_Pos.x; |
|||
midPoint.y = KiROUND( y ) + m_Pos.y; |
|||
|
|||
return midPoint; |
|||
} |
|||
|
@ -1,148 +0,0 @@ |
|||
/* |
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com |
|||
* Copyright (C) 2004-2021 KiCad Developers, see change_log.txt for contributors. |
|||
* Copyright (C) 2019 CERN |
|||
* |
|||
* 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 LIB_ARC_H |
|||
#define LIB_ARC_H |
|||
|
|||
#include <lib_item.h> |
|||
#include <math/vector2d.h> |
|||
|
|||
class TRANSFORM; |
|||
|
|||
|
|||
class LIB_ARC : public LIB_ITEM |
|||
{ |
|||
public: |
|||
LIB_ARC( LIB_SYMBOL* aParent ); |
|||
|
|||
// Do not create a copy constructor. The one generated by the compiler is adequate. |
|||
|
|||
~LIB_ARC() { } |
|||
|
|||
wxString GetClass() const override |
|||
{ |
|||
return wxT( "LIB_ARC" ); |
|||
} |
|||
|
|||
wxString GetTypeName() const override |
|||
{ |
|||
return _( "Arc" ); |
|||
} |
|||
|
|||
bool HitTest( const wxPoint& aPosition, int aAccuracy = 0 ) const override; |
|||
bool HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy = 0 ) const override; |
|||
|
|||
const EDA_RECT GetBoundingBox() const override; |
|||
|
|||
void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override; |
|||
|
|||
int GetPenWidth() const override; |
|||
|
|||
void BeginEdit( const wxPoint& aStartPoint ) override; |
|||
void CalcEdit( const wxPoint& aPosition ) override; |
|||
void SetEditState( int aState ) { m_editState = aState; } |
|||
|
|||
void Offset( const wxPoint& aOffset ) override; |
|||
|
|||
void MoveTo( const wxPoint& aPosition ) override; |
|||
|
|||
wxPoint GetPosition() const override { return m_Pos; } |
|||
|
|||
void MirrorHorizontal( const wxPoint& aCenter ) override; |
|||
void MirrorVertical( const wxPoint& aCenter ) override; |
|||
void Rotate( const wxPoint& aCenter, bool aRotateCCW = true ) override; |
|||
|
|||
void Plot( PLOTTER* aPlotter, const wxPoint& aOffset, bool aFill, |
|||
const TRANSFORM& aTransform ) const override; |
|||
|
|||
int GetWidth() const override { return m_Width; } |
|||
void SetWidth( int aWidth ) override { m_Width = aWidth; } |
|||
|
|||
int GetRadius() const; |
|||
|
|||
wxPoint GetStart() const { return m_ArcStart; } |
|||
void SetStart( const wxPoint& aPoint ) { m_ArcStart = aPoint; } |
|||
|
|||
wxPoint GetEnd() const { return m_ArcEnd; } |
|||
void SetEnd( const wxPoint& aPoint ) { m_ArcEnd = aPoint; } |
|||
|
|||
wxPoint GetCenter() const { return m_Pos; } |
|||
void SetCenter( const wxPoint& aPoint ) { m_Pos = aPoint; } |
|||
|
|||
|
|||
/** |
|||
* Calculate the arc mid point using the arc start and end angles and radius length. |
|||
* |
|||
* @note This is not a general purpose trigonometric arc midpoint calculation. It is |
|||
* limited to the less than 180.0 degree arcs used in symbols. |
|||
* |
|||
* @return A #VECTOR2I object containing the midpoint of the arc. |
|||
*/ |
|||
VECTOR2I CalcMidPoint() const; |
|||
|
|||
/** |
|||
* Calculate the start and end angles of an arc using the start, end, and center points. |
|||
*/ |
|||
void CalcAngles( int& aStartAngle, int& aEndAngle ) const; |
|||
|
|||
|
|||
wxString GetSelectMenuText( EDA_UNITS aUnits ) const override; |
|||
|
|||
BITMAPS GetMenuImage() const override; |
|||
|
|||
EDA_ITEM* Clone() const override; |
|||
|
|||
private: |
|||
void print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset, void* aData, |
|||
const TRANSFORM& aTransform ) override; |
|||
|
|||
/** |
|||
* @copydoc LIB_ITEM::compare() |
|||
* |
|||
* The arc specific sort order is as follows: |
|||
* - Arc horizontal (X) position. |
|||
* - Arc vertical (Y) position. |
|||
* - Arc start angle. |
|||
* - Arc end angle. |
|||
*/ |
|||
int compare( const LIB_ITEM& aOther, |
|||
LIB_ITEM::COMPARE_FLAGS aCompareFlags = LIB_ITEM::COMPARE_FLAGS::NORMAL ) const override; |
|||
|
|||
enum SELECT_T // When creating an arc: status of arc |
|||
{ |
|||
ARC_STATUS_START, |
|||
ARC_STATUS_END, |
|||
ARC_STATUS_OUTLINE, |
|||
}; |
|||
|
|||
wxPoint m_ArcStart; |
|||
wxPoint m_ArcEnd; /* Arc end position. */ |
|||
wxPoint m_Pos; /* Radius center point. */ |
|||
int m_Width; /* Line width */ |
|||
int m_editState; |
|||
}; |
|||
|
|||
|
|||
#endif // LIB_ARC_H |
@ -1,353 +0,0 @@ |
|||
/*
|
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2004-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 |
|||
*/ |
|||
|
|||
#include <sch_draw_panel.h>
|
|||
#include <plotters/plotter.h>
|
|||
#include <trigo.h>
|
|||
#include <bezier_curves.h>
|
|||
#include <base_units.h>
|
|||
#include <eda_draw_frame.h>
|
|||
#include <widgets/msgpanel.h>
|
|||
#include <eda_draw_frame.h>
|
|||
#include <general.h>
|
|||
#include <lib_bezier.h>
|
|||
#include <transform.h>
|
|||
#include <settings/color_settings.h>
|
|||
|
|||
|
|||
LIB_BEZIER::LIB_BEZIER( LIB_SYMBOL* aParent ) : |
|||
LIB_ITEM( LIB_BEZIER_T, aParent ) |
|||
{ |
|||
m_fill = FILL_TYPE::NO_FILL; |
|||
m_Width = 0; |
|||
m_isFillable = true; |
|||
} |
|||
|
|||
|
|||
EDA_ITEM* LIB_BEZIER::Clone() const |
|||
{ |
|||
return new LIB_BEZIER( *this ); |
|||
} |
|||
|
|||
|
|||
int LIB_BEZIER::compare( const LIB_ITEM& aOther, LIB_ITEM::COMPARE_FLAGS aCompareFlags ) const |
|||
{ |
|||
wxASSERT( aOther.Type() == LIB_BEZIER_T ); |
|||
|
|||
int retv = LIB_ITEM::compare( aOther ); |
|||
|
|||
if( retv ) |
|||
return retv; |
|||
|
|||
const LIB_BEZIER* tmp = ( LIB_BEZIER* ) &aOther; |
|||
|
|||
if( m_BezierPoints.size() != tmp->m_BezierPoints.size() ) |
|||
return m_BezierPoints.size() - tmp->m_BezierPoints.size(); |
|||
|
|||
for( size_t i = 0; i < m_BezierPoints.size(); i++ ) |
|||
{ |
|||
if( m_BezierPoints[i].x != tmp->m_BezierPoints[i].x ) |
|||
return m_BezierPoints[i].x - tmp->m_BezierPoints[i].x; |
|||
|
|||
if( m_BezierPoints[i].y != tmp->m_BezierPoints[i].y ) |
|||
return m_BezierPoints[i].y - tmp->m_BezierPoints[i].y; |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
|
|||
void LIB_BEZIER::Offset( const wxPoint& aOffset ) |
|||
{ |
|||
size_t i; |
|||
|
|||
for( i = 0; i < m_BezierPoints.size(); i++ ) |
|||
m_BezierPoints[i] += aOffset; |
|||
|
|||
for( i = 0; i < m_PolyPoints.size(); i++ ) |
|||
m_PolyPoints[i] += aOffset; |
|||
} |
|||
|
|||
|
|||
void LIB_BEZIER::MoveTo( const wxPoint& aPosition ) |
|||
{ |
|||
if ( !m_PolyPoints.size() ) |
|||
m_PolyPoints.emplace_back(0, 0 ); |
|||
|
|||
Offset( aPosition - m_PolyPoints[ 0 ] ); |
|||
} |
|||
|
|||
|
|||
const wxPoint LIB_BEZIER::GetOffset() const |
|||
{ |
|||
if ( !m_PolyPoints.size() ) |
|||
return wxPoint(0, 0); |
|||
|
|||
return m_PolyPoints[0]; |
|||
} |
|||
|
|||
|
|||
void LIB_BEZIER::MirrorHorizontal( const wxPoint& aCenter ) |
|||
{ |
|||
size_t i, imax = m_PolyPoints.size(); |
|||
|
|||
for( i = 0; i < imax; i++ ) |
|||
{ |
|||
m_PolyPoints[i].x -= aCenter.x; |
|||
m_PolyPoints[i].x *= -1; |
|||
m_PolyPoints[i].x += aCenter.x; |
|||
} |
|||
|
|||
imax = m_BezierPoints.size(); |
|||
|
|||
for( i = 0; i < imax; i++ ) |
|||
{ |
|||
m_BezierPoints[i].x -= aCenter.x; |
|||
m_BezierPoints[i].x *= -1; |
|||
m_BezierPoints[i].x += aCenter.x; |
|||
} |
|||
} |
|||
|
|||
|
|||
void LIB_BEZIER::MirrorVertical( const wxPoint& aCenter ) |
|||
{ |
|||
size_t i, imax = m_PolyPoints.size(); |
|||
|
|||
for( i = 0; i < imax; i++ ) |
|||
{ |
|||
m_PolyPoints[i].y -= aCenter.y; |
|||
m_PolyPoints[i].y *= -1; |
|||
m_PolyPoints[i].y += aCenter.y; |
|||
} |
|||
|
|||
imax = m_BezierPoints.size(); |
|||
|
|||
for( i = 0; i < imax; i++ ) |
|||
{ |
|||
m_BezierPoints[i].y -= aCenter.y; |
|||
m_BezierPoints[i].y *= -1; |
|||
m_BezierPoints[i].y += aCenter.y; |
|||
} |
|||
} |
|||
|
|||
|
|||
void LIB_BEZIER::Rotate( const wxPoint& aCenter, bool aRotateCCW ) |
|||
{ |
|||
int rot_angle = aRotateCCW ? -900 : 900; |
|||
|
|||
for( wxPoint& point : m_PolyPoints ) |
|||
RotatePoint( &point, aCenter, rot_angle ); |
|||
|
|||
for( wxPoint& bezierPoint : m_BezierPoints ) |
|||
RotatePoint( &bezierPoint, aCenter, rot_angle ); |
|||
} |
|||
|
|||
|
|||
void LIB_BEZIER::Plot( PLOTTER* aPlotter, const wxPoint& aOffset, bool aFill, |
|||
const TRANSFORM& aTransform ) const |
|||
{ |
|||
wxASSERT( aPlotter != nullptr ); |
|||
|
|||
static std::vector< wxPoint > cornerList; |
|||
cornerList.clear(); |
|||
|
|||
for( wxPoint pos : m_PolyPoints ) |
|||
{ |
|||
pos = aTransform.TransformCoordinate( pos ) + aOffset; |
|||
cornerList.push_back( pos ); |
|||
} |
|||
|
|||
if( aFill && m_fill == FILL_TYPE::FILLED_WITH_BG_BODYCOLOR ) |
|||
{ |
|||
aPlotter->SetColor( aPlotter->RenderSettings()->GetLayerColor( LAYER_DEVICE_BACKGROUND ) ); |
|||
aPlotter->PlotPoly( cornerList, FILL_TYPE::FILLED_WITH_BG_BODYCOLOR, 0 ); |
|||
} |
|||
|
|||
bool already_filled = m_fill == FILL_TYPE::FILLED_WITH_BG_BODYCOLOR; |
|||
int pen_size = GetEffectivePenWidth( aPlotter->RenderSettings() ); |
|||
|
|||
if( !already_filled || pen_size > 0 ) |
|||
{ |
|||
aPlotter->SetColor( aPlotter->RenderSettings()->GetLayerColor( LAYER_DEVICE ) ); |
|||
aPlotter->PlotPoly( cornerList, already_filled ? FILL_TYPE::NO_FILL : m_fill, pen_size ); |
|||
} |
|||
} |
|||
|
|||
|
|||
int LIB_BEZIER::GetPenWidth() const |
|||
{ |
|||
return m_Width; |
|||
} |
|||
|
|||
|
|||
void LIB_BEZIER::print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset, void* aData, |
|||
const TRANSFORM& aTransform ) |
|||
{ |
|||
bool forceNoFill = static_cast<bool>( aData ); |
|||
int penWidth = GetEffectivePenWidth( aSettings ); |
|||
|
|||
if( forceNoFill && m_fill != FILL_TYPE::NO_FILL && penWidth == 0 ) |
|||
return; |
|||
|
|||
std::vector<wxPoint> PolyPointsTraslated; |
|||
|
|||
wxDC* DC = aSettings->GetPrintDC(); |
|||
COLOR4D color = aSettings->GetLayerColor( LAYER_DEVICE ); |
|||
BEZIER_POLY converter( m_BezierPoints ); |
|||
converter.GetPoly( m_PolyPoints ); |
|||
|
|||
PolyPointsTraslated.clear(); |
|||
|
|||
for( wxPoint& point : m_PolyPoints ) |
|||
PolyPointsTraslated.push_back( aTransform.TransformCoordinate( point ) + aOffset ); |
|||
|
|||
if( forceNoFill || m_fill == FILL_TYPE::NO_FILL ) |
|||
{ |
|||
GRPoly( nullptr, DC, m_PolyPoints.size(), &PolyPointsTraslated[0], false, penWidth, |
|||
color, color ); |
|||
} |
|||
else |
|||
{ |
|||
if( m_fill == FILL_TYPE::FILLED_WITH_BG_BODYCOLOR ) |
|||
color = aSettings->GetLayerColor( LAYER_DEVICE_BACKGROUND ); |
|||
|
|||
GRPoly( nullptr, DC, m_PolyPoints.size(), &PolyPointsTraslated[0], true, penWidth, |
|||
color, color ); |
|||
} |
|||
} |
|||
|
|||
|
|||
bool LIB_BEZIER::HitTest( const wxPoint& aRefPos, int aAccuracy ) const |
|||
{ |
|||
int mindist = std::max( aAccuracy + GetPenWidth() / 2, |
|||
Mils2iu( MINIMUM_SELECTION_DISTANCE ) ); |
|||
wxPoint start, end; |
|||
|
|||
for( unsigned ii = 1; ii < GetCornerCount(); ii++ ) |
|||
{ |
|||
start = DefaultTransform.TransformCoordinate( m_PolyPoints[ii - 1] ); |
|||
end = DefaultTransform.TransformCoordinate( m_PolyPoints[ii] ); |
|||
|
|||
if ( TestSegmentHit( aRefPos, start, end, mindist ) ) |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
|
|||
bool LIB_BEZIER::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const |
|||
{ |
|||
if( m_flags & (STRUCT_DELETED | SKIP_STRUCT ) ) |
|||
return false; |
|||
|
|||
EDA_RECT sel = aRect; |
|||
|
|||
if ( aAccuracy ) |
|||
sel.Inflate( aAccuracy ); |
|||
|
|||
if( aContained ) |
|||
return sel.Contains( GetBoundingBox() ); |
|||
|
|||
// Fast test: if aRect is outside the polygon bounding box, rectangles cannot intersect
|
|||
if( !sel.Intersects( GetBoundingBox() ) ) |
|||
return false; |
|||
|
|||
// Account for the width of the line
|
|||
sel.Inflate( GetWidth() / 2 ); |
|||
unsigned count = m_BezierPoints.size(); |
|||
|
|||
for( unsigned ii = 1; ii < count; ii++ ) |
|||
{ |
|||
wxPoint vertex = DefaultTransform.TransformCoordinate( m_BezierPoints[ii-1] ); |
|||
wxPoint vertexNext = DefaultTransform.TransformCoordinate( m_BezierPoints[ii] ); |
|||
|
|||
// Test if the point is within aRect
|
|||
if( sel.Contains( vertex ) ) |
|||
return true; |
|||
|
|||
// Test if this edge intersects aRect
|
|||
if( sel.Intersects( vertex, vertexNext ) ) |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
|
|||
const EDA_RECT LIB_BEZIER::GetBoundingBox() const |
|||
{ |
|||
EDA_RECT rect; |
|||
int xmin, xmax, ymin, ymax; |
|||
|
|||
if( !GetCornerCount() ) |
|||
return rect; |
|||
|
|||
xmin = xmax = m_PolyPoints[0].x; |
|||
ymin = ymax = m_PolyPoints[0].y; |
|||
|
|||
for( unsigned ii = 1; ii < GetCornerCount(); ii++ ) |
|||
{ |
|||
xmin = std::min( xmin, m_PolyPoints[ii].x ); |
|||
xmax = std::max( xmax, m_PolyPoints[ii].x ); |
|||
ymin = std::min( ymin, m_PolyPoints[ii].y ); |
|||
ymax = std::max( ymax, m_PolyPoints[ii].y ); |
|||
} |
|||
|
|||
rect.SetOrigin( xmin, ymin ); |
|||
rect.SetEnd( xmax, ymax ); |
|||
rect.Inflate( ( GetPenWidth() / 2 ) + 1 ); |
|||
|
|||
rect.RevertYAxis(); |
|||
|
|||
return rect; |
|||
} |
|||
|
|||
|
|||
void LIB_BEZIER::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) |
|||
{ |
|||
wxString msg; |
|||
EDA_RECT bBox = GetBoundingBox(); |
|||
|
|||
LIB_ITEM::GetMsgPanelInfo( aFrame, aList ); |
|||
|
|||
msg = MessageTextFromValue( aFrame->GetUserUnits(), m_Width ); |
|||
|
|||
aList.emplace_back( _( "Line Width" ), msg ); |
|||
|
|||
msg.Printf( wxT( "(%d, %d, %d, %d)" ), |
|||
bBox.GetOrigin().x, |
|||
bBox.GetOrigin().y, |
|||
bBox.GetEnd().x, |
|||
bBox.GetEnd().y ); |
|||
|
|||
aList.emplace_back( _( "Bounding Box" ), msg ); |
|||
} |
|||
|
|||
wxPoint LIB_BEZIER::GetPosition() const |
|||
{ |
|||
if( !m_PolyPoints.size() ) |
|||
return wxPoint(0, 0); |
|||
|
|||
return m_PolyPoints[0]; |
|||
} |
@ -1,111 +0,0 @@ |
|||
/* |
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com |
|||
* Copyright (C) 2004-2021 KiCad Developers, see change_log.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 LIB_BEZIER_H |
|||
#define LIB_BEZIER_H |
|||
|
|||
#include <lib_item.h> |
|||
|
|||
|
|||
/** |
|||
* Define a bezier curve graphic body item. |
|||
*/ |
|||
class LIB_BEZIER : public LIB_ITEM |
|||
{ |
|||
public: |
|||
LIB_BEZIER( LIB_SYMBOL* aParent ); |
|||
|
|||
// Do not create a copy constructor. The one generated by the compiler is adequate. |
|||
|
|||
~LIB_BEZIER() { } |
|||
|
|||
wxString GetClass() const override |
|||
{ |
|||
return wxT( "LIB_BEZIER" ); |
|||
} |
|||
|
|||
wxString GetTypeName() const override |
|||
{ |
|||
return _( "Bezier" ); |
|||
} |
|||
|
|||
void Reserve( size_t aCount ) { m_BezierPoints.reserve( aCount ); } |
|||
void AddPoint( const wxPoint& aPoint ) { m_BezierPoints.push_back( aPoint ); } |
|||
|
|||
void Offset( const wxPoint& aOffset ) override; |
|||
const wxPoint GetOffset() const; |
|||
|
|||
/** |
|||
* @return the number of corners |
|||
*/ |
|||
unsigned GetCornerCount() const { return m_PolyPoints.size(); } |
|||
|
|||
const std::vector< wxPoint >& GetPoints() const { return m_BezierPoints; } |
|||
|
|||
bool HitTest( const wxPoint& aPosition, int aAccuracy = 0 ) const override; |
|||
bool HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy = 0 ) const override; |
|||
|
|||
const EDA_RECT GetBoundingBox() const override; |
|||
|
|||
void MoveTo( const wxPoint& aPosition ) override; |
|||
|
|||
wxPoint GetPosition() const override; |
|||
|
|||
void MirrorHorizontal( const wxPoint& aCenter ) override; |
|||
void MirrorVertical( const wxPoint& aCenter ) override; |
|||
void Rotate( const wxPoint& aCenter, bool aRotateCCW = true ) override; |
|||
|
|||
void Plot( PLOTTER* aPlotter, const wxPoint& aOffset, bool aFill, |
|||
const TRANSFORM& aTransform ) const override; |
|||
|
|||
int GetWidth() const override { return m_Width; } |
|||
void SetWidth( int aWidth ) override { m_Width = aWidth; } |
|||
|
|||
int GetPenWidth() const override; |
|||
|
|||
void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override; |
|||
|
|||
EDA_ITEM* Clone() const override; |
|||
|
|||
private: |
|||
/** |
|||
* @copydoc LIB_ITEM::compare() |
|||
* |
|||
* The bezier curve specific sort order for each curve segment point is as follows: |
|||
* - Bezier horizontal (X) point position. |
|||
* - Bezier vertical (Y) point position. |
|||
*/ |
|||
int compare( const LIB_ITEM& aOther, |
|||
LIB_ITEM::COMPARE_FLAGS aCompareFlags = LIB_ITEM::COMPARE_FLAGS::NORMAL ) const override; |
|||
|
|||
void print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset, |
|||
void* aData, const TRANSFORM& aTransform ) override; |
|||
|
|||
int m_Width; // Line width |
|||
std::vector<wxPoint> m_BezierPoints; // list of parameter (3|4) |
|||
std::vector<wxPoint> m_PolyPoints; // list of points (>= 2) |
|||
}; |
|||
|
|||
|
|||
#endif // LIB_BEZIER_H |
@ -1,285 +0,0 @@ |
|||
/*
|
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr |
|||
* Copyright (C) 2004-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 |
|||
*/ |
|||
|
|||
#include <eda_draw_frame.h>
|
|||
#include <sch_draw_panel.h>
|
|||
#include <plotters/plotter.h>
|
|||
#include <trigo.h>
|
|||
#include <base_units.h>
|
|||
#include <widgets/msgpanel.h>
|
|||
#include <bitmaps.h>
|
|||
#include <math/util.h> // for KiROUND
|
|||
#include <eda_draw_frame.h>
|
|||
#include <general.h>
|
|||
#include <lib_circle.h>
|
|||
#include <settings/color_settings.h>
|
|||
#include <transform.h>
|
|||
|
|||
|
|||
LIB_CIRCLE::LIB_CIRCLE( LIB_SYMBOL* aParent ) : |
|||
LIB_ITEM( LIB_CIRCLE_T, aParent ) |
|||
{ |
|||
m_Width = 0; |
|||
m_fill = FILL_TYPE::NO_FILL; |
|||
m_isFillable = true; |
|||
} |
|||
|
|||
|
|||
bool LIB_CIRCLE::HitTest( const wxPoint& aPosRef, int aAccuracy ) const |
|||
{ |
|||
int mindist = std::max( aAccuracy + GetPenWidth() / 2, |
|||
Mils2iu( MINIMUM_SELECTION_DISTANCE ) ); |
|||
int dist = KiROUND( GetLineLength( aPosRef, DefaultTransform.TransformCoordinate( m_Pos ) ) ); |
|||
|
|||
if( abs( dist - GetRadius() ) <= mindist ) |
|||
return true; |
|||
|
|||
if( m_fill == FILL_TYPE::NO_FILL ) |
|||
return false; |
|||
|
|||
return dist <= GetRadius(); |
|||
} |
|||
|
|||
|
|||
bool LIB_CIRCLE::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const |
|||
{ |
|||
if( m_flags & (STRUCT_DELETED | SKIP_STRUCT ) ) |
|||
return false; |
|||
|
|||
wxPoint center = DefaultTransform.TransformCoordinate( GetPosition() ); |
|||
int radius = GetRadius(); |
|||
int lineWidth = GetWidth(); |
|||
EDA_RECT sel = aRect ; |
|||
|
|||
if ( aAccuracy ) |
|||
sel.Inflate( aAccuracy ); |
|||
|
|||
if( aContained ) |
|||
return sel.Contains( GetBoundingBox() ); |
|||
|
|||
// If the rectangle does not intersect the bounding box, this is a much quicker test
|
|||
if( !sel.Intersects( GetBoundingBox() ) ) |
|||
return false; |
|||
else |
|||
return sel.IntersectsCircleEdge( center, radius, lineWidth ); |
|||
} |
|||
|
|||
|
|||
EDA_ITEM* LIB_CIRCLE::Clone() const |
|||
{ |
|||
return new LIB_CIRCLE( *this ); |
|||
} |
|||
|
|||
|
|||
int LIB_CIRCLE::compare( const LIB_ITEM& aOther, LIB_ITEM::COMPARE_FLAGS aCompareFlags ) const |
|||
{ |
|||
wxASSERT( aOther.Type() == LIB_CIRCLE_T ); |
|||
|
|||
int retv = LIB_ITEM::compare( aOther, aCompareFlags ); |
|||
|
|||
if( retv ) |
|||
return retv; |
|||
|
|||
const LIB_CIRCLE* tmp = ( LIB_CIRCLE* ) &aOther; |
|||
|
|||
if( m_Pos.x != tmp->m_Pos.x ) |
|||
return m_Pos.x - tmp->m_Pos.x; |
|||
|
|||
if( m_Pos.y != tmp->m_Pos.y ) |
|||
return m_Pos.y - tmp->m_Pos.y; |
|||
|
|||
if( m_EndPos.x != tmp->m_EndPos.x ) |
|||
return m_EndPos.x - tmp->m_EndPos.x; |
|||
|
|||
if( m_EndPos.y != tmp->m_EndPos.y ) |
|||
return m_EndPos.y - tmp->m_EndPos.y; |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
|
|||
void LIB_CIRCLE::Offset( const wxPoint& aOffset ) |
|||
{ |
|||
m_Pos += aOffset; |
|||
m_EndPos += aOffset; |
|||
} |
|||
|
|||
|
|||
void LIB_CIRCLE::MoveTo( const wxPoint& aPosition ) |
|||
{ |
|||
Offset( aPosition - m_Pos ); |
|||
} |
|||
|
|||
|
|||
void LIB_CIRCLE::MirrorHorizontal( const wxPoint& aCenter ) |
|||
{ |
|||
m_Pos.x -= aCenter.x; |
|||
m_Pos.x *= -1; |
|||
m_Pos.x += aCenter.x; |
|||
m_EndPos.x -= aCenter.x; |
|||
m_EndPos.x *= -1; |
|||
m_EndPos.x += aCenter.x; |
|||
} |
|||
|
|||
|
|||
void LIB_CIRCLE::MirrorVertical( const wxPoint& aCenter ) |
|||
{ |
|||
m_Pos.y -= aCenter.y; |
|||
m_Pos.y *= -1; |
|||
m_Pos.y += aCenter.y; |
|||
m_EndPos.y -= aCenter.y; |
|||
m_EndPos.y *= -1; |
|||
m_EndPos.y += aCenter.y; |
|||
} |
|||
|
|||
|
|||
void LIB_CIRCLE::Rotate( const wxPoint& aCenter, bool aRotateCCW ) |
|||
{ |
|||
int rot_angle = aRotateCCW ? -900 : 900; |
|||
|
|||
RotatePoint( &m_Pos, aCenter, rot_angle ); |
|||
RotatePoint( &m_EndPos, aCenter, rot_angle ); |
|||
} |
|||
|
|||
|
|||
void LIB_CIRCLE::Plot( PLOTTER* aPlotter, const wxPoint& aOffset, bool aFill, |
|||
const TRANSFORM& aTransform ) const |
|||
{ |
|||
wxPoint pos = aTransform.TransformCoordinate( m_Pos ) + aOffset; |
|||
|
|||
if( aFill && m_fill == FILL_TYPE::FILLED_WITH_BG_BODYCOLOR ) |
|||
{ |
|||
aPlotter->SetColor( aPlotter->RenderSettings()->GetLayerColor( LAYER_DEVICE_BACKGROUND ) ); |
|||
aPlotter->Circle( pos, GetRadius() * 2, FILL_TYPE::FILLED_WITH_BG_BODYCOLOR, 0 ); |
|||
} |
|||
|
|||
bool already_filled = m_fill == FILL_TYPE::FILLED_WITH_BG_BODYCOLOR; |
|||
int pen_size = GetEffectivePenWidth( aPlotter->RenderSettings() ); |
|||
|
|||
if( !already_filled || pen_size > 0 ) |
|||
{ |
|||
aPlotter->SetColor( aPlotter->RenderSettings()->GetLayerColor( LAYER_DEVICE ) ); |
|||
aPlotter->Circle( pos, GetRadius() * 2, already_filled ? FILL_TYPE::NO_FILL : m_fill, |
|||
pen_size ); |
|||
} |
|||
} |
|||
|
|||
|
|||
int LIB_CIRCLE::GetPenWidth() const |
|||
{ |
|||
return m_Width; |
|||
} |
|||
|
|||
|
|||
void LIB_CIRCLE::print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset, |
|||
void* aData, const TRANSFORM& aTransform ) |
|||
{ |
|||
bool forceNoFill = static_cast<bool>( aData ); |
|||
int penWidth = GetEffectivePenWidth( aSettings ); |
|||
|
|||
if( forceNoFill && m_fill != FILL_TYPE::NO_FILL && penWidth == 0 ) |
|||
return; |
|||
|
|||
wxDC* DC = aSettings->GetPrintDC(); |
|||
wxPoint pos1 = aTransform.TransformCoordinate( m_Pos ) + aOffset; |
|||
COLOR4D color = aSettings->GetLayerColor( LAYER_DEVICE ); |
|||
|
|||
if( forceNoFill || m_fill == FILL_TYPE::NO_FILL ) |
|||
{ |
|||
GRCircle( nullptr, DC, pos1.x, pos1.y, GetRadius(), penWidth, color ); |
|||
} |
|||
else |
|||
{ |
|||
if( m_fill == FILL_TYPE::FILLED_WITH_BG_BODYCOLOR ) |
|||
color = aSettings->GetLayerColor( LAYER_DEVICE_BACKGROUND ); |
|||
|
|||
GRFilledCircle( nullptr, DC, pos1.x, pos1.y, GetRadius(), 0, color, color ); |
|||
} |
|||
} |
|||
|
|||
|
|||
const EDA_RECT LIB_CIRCLE::GetBoundingBox() const |
|||
{ |
|||
EDA_RECT rect; |
|||
int radius = GetRadius(); |
|||
|
|||
rect.SetOrigin( m_Pos.x - radius, m_Pos.y - radius ); |
|||
rect.SetEnd( m_Pos.x + radius, m_Pos.y + radius ); |
|||
rect.Inflate( ( GetPenWidth() / 2 ) + 1 ); |
|||
|
|||
rect.RevertYAxis(); |
|||
|
|||
return rect; |
|||
} |
|||
|
|||
|
|||
void LIB_CIRCLE::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) |
|||
{ |
|||
EDA_RECT bBox = GetBoundingBox(); |
|||
|
|||
LIB_ITEM::GetMsgPanelInfo( aFrame, aList ); |
|||
|
|||
aList.emplace_back( _( "Line Width" ), MessageTextFromValue( aFrame->GetUserUnits(), |
|||
m_Width ) ); |
|||
|
|||
aList.emplace_back( _( "Radius" ), MessageTextFromValue( aFrame->GetUserUnits(), |
|||
GetRadius() ) ); |
|||
|
|||
aList.emplace_back( _( "Bounding Box" ), wxString::Format( wxT( "(%d, %d, %d, %d)" ), |
|||
bBox.GetOrigin().x, |
|||
bBox.GetOrigin().y, |
|||
bBox.GetEnd().x, |
|||
bBox.GetEnd().y ) ); |
|||
} |
|||
|
|||
|
|||
int LIB_CIRCLE::GetRadius() const |
|||
{ |
|||
return KiROUND( GetLineLength( m_EndPos, m_Pos ) ); |
|||
} |
|||
|
|||
|
|||
wxString LIB_CIRCLE::GetSelectMenuText( EDA_UNITS aUnits ) const |
|||
{ |
|||
return wxString::Format( _( "Circle, radius %s" ), |
|||
MessageTextFromValue( aUnits, GetRadius() ) ); |
|||
} |
|||
|
|||
|
|||
BITMAPS LIB_CIRCLE::GetMenuImage() const |
|||
{ |
|||
return BITMAPS::add_circle; |
|||
} |
|||
|
|||
|
|||
void LIB_CIRCLE::BeginEdit( const wxPoint& aPosition ) |
|||
{ |
|||
m_Pos = aPosition; |
|||
} |
|||
|
|||
|
|||
void LIB_CIRCLE::CalcEdit( const wxPoint& aPosition ) |
|||
{ |
|||
SetEnd( aPosition ); |
|||
} |
@ -1,111 +0,0 @@ |
|||
/* |
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com |
|||
* Copyright (C) 2004-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 LIB_CIRCLE_H |
|||
#define LIB_CIRCLE_H |
|||
|
|||
#include <lib_item.h> |
|||
|
|||
|
|||
class LIB_CIRCLE : public LIB_ITEM |
|||
{ |
|||
public: |
|||
LIB_CIRCLE( LIB_SYMBOL* aParent ); |
|||
|
|||
// Do not create a copy constructor. The one generated by the compiler is adequate. |
|||
|
|||
~LIB_CIRCLE() { } |
|||
|
|||
wxString GetClass() const override |
|||
{ |
|||
return wxT( "LIB_CIRCLE" ); |
|||
} |
|||
|
|||
wxString GetTypeName() const override |
|||
{ |
|||
return _( "Circle" ); |
|||
} |
|||
|
|||
bool HitTest( const wxPoint& aPosition, int aAccuracy = 0 ) const override; |
|||
bool HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy = 0 ) const override; |
|||
|
|||
int GetPenWidth() const override; |
|||
|
|||
const EDA_RECT GetBoundingBox() const override; |
|||
|
|||
void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override; |
|||
|
|||
void BeginEdit( const wxPoint& aStartPoint ) override; |
|||
void CalcEdit( const wxPoint& aPosition ) override; |
|||
|
|||
void Offset( const wxPoint& aOffset ) override; |
|||
|
|||
void MoveTo( const wxPoint& aPosition ) override; |
|||
|
|||
wxPoint GetPosition() const override { return m_Pos; } |
|||
|
|||
void SetEnd( const wxPoint& aPosition ) { m_EndPos = aPosition; } |
|||
wxPoint GetEnd() const { return m_EndPos; } |
|||
|
|||
void MirrorHorizontal( const wxPoint& aCenter ) override; |
|||
void MirrorVertical( const wxPoint& aCenter ) override; |
|||
void Rotate( const wxPoint& aCenter, bool aRotateCCW = true ) override; |
|||
|
|||
void Plot( PLOTTER* aPlotter, const wxPoint& aOffset, bool aFill, |
|||
const TRANSFORM& aTransform ) const override; |
|||
|
|||
int GetWidth() const override { return m_Width; } |
|||
void SetWidth( int aWidth ) override { m_Width = aWidth; } |
|||
|
|||
void SetRadius( int aRadius ) { m_EndPos = wxPoint( m_Pos.x + aRadius, m_Pos.y ); } |
|||
int GetRadius() const; |
|||
|
|||
wxString GetSelectMenuText( EDA_UNITS aUnits ) const override; |
|||
|
|||
BITMAPS GetMenuImage() const override; |
|||
|
|||
EDA_ITEM* Clone() const override; |
|||
|
|||
private: |
|||
/** |
|||
* @copydoc LIB_ITEM::compare() |
|||
* |
|||
* The circle specific sort order is as follows: |
|||
* - Circle horizontal (X) position. |
|||
* - Circle vertical (Y) position. |
|||
* - Circle radius. |
|||
*/ |
|||
int compare( const LIB_ITEM& aOther, |
|||
LIB_ITEM::COMPARE_FLAGS aCompareFlags = LIB_ITEM::COMPARE_FLAGS::NORMAL ) const override; |
|||
|
|||
void print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset, void* aData, |
|||
const TRANSFORM& aTransform ) override; |
|||
|
|||
wxPoint m_Pos; // Position or centre (Arc and Circle) or start point (segments). |
|||
wxPoint m_EndPos; // A point on the circumference of the circle. |
|||
int m_Width; // Line width. |
|||
}; |
|||
|
|||
|
|||
#endif // LIB_CIRCLE_H |
@ -1,390 +0,0 @@ |
|||
/*
|
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr |
|||
* Copyright (C) 2004-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 |
|||
*/ |
|||
|
|||
#include <sch_draw_panel.h>
|
|||
#include <plotters/plotter.h>
|
|||
#include <trigo.h>
|
|||
#include <base_units.h>
|
|||
#include <widgets/msgpanel.h>
|
|||
#include <bitmaps.h>
|
|||
#include <eda_draw_frame.h>
|
|||
#include <general.h>
|
|||
#include <lib_polyline.h>
|
|||
#include <settings/color_settings.h>
|
|||
#include <transform.h>
|
|||
|
|||
|
|||
LIB_POLYLINE::LIB_POLYLINE( LIB_SYMBOL* aParent ) : |
|||
LIB_ITEM( LIB_POLYLINE_T, aParent ) |
|||
{ |
|||
m_fill = FILL_TYPE::NO_FILL; |
|||
m_Width = 0; |
|||
m_isFillable = true; |
|||
} |
|||
|
|||
|
|||
EDA_ITEM* LIB_POLYLINE::Clone() const |
|||
{ |
|||
return new LIB_POLYLINE( *this ); |
|||
} |
|||
|
|||
|
|||
int LIB_POLYLINE::compare( const LIB_ITEM& aOther, LIB_ITEM::COMPARE_FLAGS aCompareFlags ) const |
|||
{ |
|||
wxASSERT( aOther.Type() == LIB_POLYLINE_T ); |
|||
|
|||
int retv = LIB_ITEM::compare( aOther ); |
|||
|
|||
if( retv ) |
|||
return retv; |
|||
|
|||
const LIB_POLYLINE* tmp = (LIB_POLYLINE*) &aOther; |
|||
|
|||
if( m_PolyPoints.size() != tmp->m_PolyPoints.size() ) |
|||
return m_PolyPoints.size() - tmp->m_PolyPoints.size(); |
|||
|
|||
for( size_t i = 0; i < m_PolyPoints.size(); i++ ) |
|||
{ |
|||
if( m_PolyPoints[i].x != tmp->m_PolyPoints[i].x ) |
|||
return m_PolyPoints[i].x - tmp->m_PolyPoints[i].x; |
|||
|
|||
if( m_PolyPoints[i].y != tmp->m_PolyPoints[i].y ) |
|||
return m_PolyPoints[i].y - tmp->m_PolyPoints[i].y; |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
|
|||
void LIB_POLYLINE::Offset( const wxPoint& aOffset ) |
|||
{ |
|||
for( wxPoint& point : m_PolyPoints ) |
|||
point += aOffset; |
|||
} |
|||
|
|||
|
|||
void LIB_POLYLINE::MoveTo( const wxPoint& aPosition ) |
|||
{ |
|||
Offset( aPosition - m_PolyPoints[ 0 ] ); |
|||
} |
|||
|
|||
|
|||
void LIB_POLYLINE::MirrorHorizontal( const wxPoint& aCenter ) |
|||
{ |
|||
for( wxPoint& point : m_PolyPoints ) |
|||
{ |
|||
point.x -= aCenter.x; |
|||
point.x *= -1; |
|||
point.x += aCenter.x; |
|||
} |
|||
} |
|||
|
|||
void LIB_POLYLINE::MirrorVertical( const wxPoint& aCenter ) |
|||
{ |
|||
for( wxPoint& point : m_PolyPoints ) |
|||
{ |
|||
point.y -= aCenter.y; |
|||
point.y *= -1; |
|||
point.y += aCenter.y; |
|||
} |
|||
} |
|||
|
|||
void LIB_POLYLINE::Rotate( const wxPoint& aCenter, bool aRotateCCW ) |
|||
{ |
|||
for( wxPoint& point : m_PolyPoints ) |
|||
RotatePoint( &point, aCenter, aRotateCCW ? -900 : 900 ); |
|||
} |
|||
|
|||
|
|||
void LIB_POLYLINE::Plot( PLOTTER* aPlotter, const wxPoint& aOffset, bool aFill, |
|||
const TRANSFORM& aTransform ) const |
|||
{ |
|||
wxASSERT( aPlotter != nullptr ); |
|||
|
|||
static std::vector< wxPoint > cornerList; |
|||
cornerList.clear(); |
|||
|
|||
for( wxPoint pos : m_PolyPoints ) |
|||
{ |
|||
pos = aTransform.TransformCoordinate( pos ) + aOffset; |
|||
cornerList.push_back( pos ); |
|||
} |
|||
|
|||
if( aFill && m_fill == FILL_TYPE::FILLED_WITH_BG_BODYCOLOR ) |
|||
{ |
|||
aPlotter->SetColor( aPlotter->RenderSettings()->GetLayerColor( LAYER_DEVICE_BACKGROUND ) ); |
|||
aPlotter->PlotPoly( cornerList, FILL_TYPE::FILLED_WITH_BG_BODYCOLOR, 0 ); |
|||
} |
|||
|
|||
bool already_filled = m_fill == FILL_TYPE::FILLED_WITH_BG_BODYCOLOR; |
|||
int pen_size = GetEffectivePenWidth( aPlotter->RenderSettings() ); |
|||
|
|||
if( !already_filled || pen_size > 0 ) |
|||
{ |
|||
aPlotter->SetColor( aPlotter->RenderSettings()->GetLayerColor( LAYER_DEVICE ) ); |
|||
aPlotter->PlotPoly( cornerList, already_filled ? FILL_TYPE::NO_FILL : m_fill, pen_size ); |
|||
} |
|||
} |
|||
|
|||
|
|||
void LIB_POLYLINE::AddPoint( const wxPoint& aPosition ) |
|||
{ |
|||
m_PolyPoints.push_back( aPosition ); |
|||
} |
|||
|
|||
|
|||
void LIB_POLYLINE::AddCorner( const wxPoint& aPosition ) |
|||
{ |
|||
int currentMinDistance = INT_MAX; |
|||
int closestLineStart = 0; |
|||
|
|||
for( unsigned i = 0; i < m_PolyPoints.size() - 1; ++i ) |
|||
{ |
|||
int distance = (int) DistanceLinePoint( m_PolyPoints[i], m_PolyPoints[i + 1], aPosition ); |
|||
|
|||
if( distance < currentMinDistance ) |
|||
{ |
|||
currentMinDistance = distance; |
|||
closestLineStart = i; |
|||
} |
|||
} |
|||
|
|||
m_PolyPoints.insert( m_PolyPoints.begin() + closestLineStart, aPosition ); |
|||
} |
|||
|
|||
|
|||
void LIB_POLYLINE::RemoveCorner( int aIdx ) |
|||
{ |
|||
m_PolyPoints.erase( m_PolyPoints.begin() + aIdx ); |
|||
} |
|||
|
|||
|
|||
int LIB_POLYLINE::GetPenWidth() const |
|||
{ |
|||
return m_Width; |
|||
} |
|||
|
|||
|
|||
void LIB_POLYLINE::print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset, void* aData, |
|||
const TRANSFORM& aTransform ) |
|||
{ |
|||
bool forceNoFill = static_cast<bool>( aData ); |
|||
int penWidth = GetEffectivePenWidth( aSettings ); |
|||
|
|||
if( forceNoFill && m_fill != FILL_TYPE::NO_FILL && penWidth == 0 ) |
|||
return; |
|||
|
|||
wxDC* DC = aSettings->GetPrintDC(); |
|||
COLOR4D color = aSettings->GetLayerColor( LAYER_DEVICE ); |
|||
wxPoint* buffer = new wxPoint[ m_PolyPoints.size() ]; |
|||
|
|||
for( unsigned ii = 0; ii < m_PolyPoints.size(); ii++ ) |
|||
buffer[ii] = aTransform.TransformCoordinate( m_PolyPoints[ii] ) + aOffset; |
|||
|
|||
if( forceNoFill || m_fill == FILL_TYPE::NO_FILL ) |
|||
{ |
|||
GRPoly( nullptr, DC, m_PolyPoints.size(), buffer, false, penWidth, color, color ); |
|||
} |
|||
else |
|||
{ |
|||
if( m_fill == FILL_TYPE::FILLED_WITH_BG_BODYCOLOR ) |
|||
color = aSettings->GetLayerColor( LAYER_DEVICE_BACKGROUND ); |
|||
|
|||
GRPoly( nullptr, DC, m_PolyPoints.size(), buffer, true, penWidth, color, color ); |
|||
} |
|||
|
|||
delete[] buffer; |
|||
} |
|||
|
|||
|
|||
bool LIB_POLYLINE::HitTest( const wxPoint& aPosition, int aAccuracy ) const |
|||
{ |
|||
int delta = std::max( aAccuracy + GetPenWidth() / 2, Mils2iu( MINIMUM_SELECTION_DISTANCE ) ); |
|||
SHAPE_LINE_CHAIN shape; |
|||
|
|||
for( wxPoint pt : m_PolyPoints ) |
|||
shape.Append( DefaultTransform.TransformCoordinate( pt ) ); |
|||
|
|||
if( m_fill != FILL_TYPE::NO_FILL && m_PolyPoints.size() > 2 ) |
|||
{ |
|||
shape.SetClosed( true ); |
|||
return shape.PointInside( aPosition, delta ); |
|||
} |
|||
else |
|||
return shape.PointOnEdge( aPosition, delta ); |
|||
} |
|||
|
|||
|
|||
bool LIB_POLYLINE::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const |
|||
{ |
|||
if( m_flags & (STRUCT_DELETED | SKIP_STRUCT ) ) |
|||
return false; |
|||
|
|||
EDA_RECT sel = aRect; |
|||
|
|||
if ( aAccuracy ) |
|||
sel.Inflate( aAccuracy ); |
|||
|
|||
if( aContained ) |
|||
return sel.Contains( GetBoundingBox() ); |
|||
|
|||
// Fast test: if rect is outside the polygon bounding box, then they cannot intersect
|
|||
if( !sel.Intersects( GetBoundingBox() ) ) |
|||
return false; |
|||
|
|||
// Account for the width of the line
|
|||
sel.Inflate( ( GetPenWidth() / 2 ) + 1 ); |
|||
|
|||
for( size_t ii = 0; ii < m_PolyPoints.size(); ii++ ) |
|||
{ |
|||
wxPoint pt = DefaultTransform.TransformCoordinate( m_PolyPoints[ ii ] ); |
|||
|
|||
// Test if the point is within aRect
|
|||
if( sel.Contains( pt ) ) |
|||
return true; |
|||
|
|||
if( ii + 1 < m_PolyPoints.size() ) |
|||
{ |
|||
wxPoint ptNext = DefaultTransform.TransformCoordinate( m_PolyPoints[ ii + 1 ] ); |
|||
|
|||
// Test if this edge intersects aRect
|
|||
if( sel.Intersects( pt, ptNext ) ) |
|||
return true; |
|||
} |
|||
else if( m_fill != FILL_TYPE::NO_FILL ) |
|||
{ |
|||
wxPoint ptNext = DefaultTransform.TransformCoordinate( m_PolyPoints[ 0 ] ); |
|||
|
|||
// Test if this edge intersects aRect
|
|||
if( sel.Intersects( pt, ptNext ) ) |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
|
|||
const EDA_RECT LIB_POLYLINE::GetBoundingBox() const |
|||
{ |
|||
EDA_RECT rect; |
|||
int xmin, xmax, ymin, ymax; |
|||
|
|||
xmin = xmax = m_PolyPoints[0].x; |
|||
ymin = ymax = m_PolyPoints[0].y; |
|||
|
|||
for( unsigned ii = 1; ii < GetCornerCount(); ii++ ) |
|||
{ |
|||
xmin = std::min( xmin, m_PolyPoints[ii].x ); |
|||
xmax = std::max( xmax, m_PolyPoints[ii].x ); |
|||
ymin = std::min( ymin, m_PolyPoints[ii].y ); |
|||
ymax = std::max( ymax, m_PolyPoints[ii].y ); |
|||
} |
|||
|
|||
rect.SetOrigin( xmin, ymin ); |
|||
rect.SetEnd( xmax, ymax ); |
|||
rect.Inflate( ( GetPenWidth() / 2 ) + 1 ); |
|||
|
|||
rect.RevertYAxis(); |
|||
|
|||
return rect; |
|||
} |
|||
|
|||
|
|||
void LIB_POLYLINE::DeleteSegment( const wxPoint aPosition ) |
|||
{ |
|||
// First segment is kept, only its end point is changed
|
|||
while( GetCornerCount() > 2 ) |
|||
{ |
|||
m_PolyPoints.pop_back(); |
|||
|
|||
if( m_PolyPoints[ GetCornerCount() - 1 ] != aPosition ) |
|||
{ |
|||
m_PolyPoints[ GetCornerCount() - 1 ] = aPosition; |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
void LIB_POLYLINE::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) |
|||
{ |
|||
EDA_RECT bBox = GetBoundingBox(); |
|||
|
|||
LIB_ITEM::GetMsgPanelInfo( aFrame, aList ); |
|||
|
|||
aList.emplace_back( _( "Line Width" ), MessageTextFromValue( aFrame->GetUserUnits(), m_Width ) ); |
|||
|
|||
aList.emplace_back( _( "Bounding Box" ), wxString::Format( wxT( "(%d, %d, %d, %d)" ), |
|||
bBox.GetOrigin().x, |
|||
bBox.GetOrigin().y, |
|||
bBox.GetEnd().x, |
|||
bBox.GetEnd().y ) ); |
|||
} |
|||
|
|||
|
|||
wxString LIB_POLYLINE::GetSelectMenuText( EDA_UNITS aUnits ) const |
|||
{ |
|||
return wxString::Format( _( "Polyline, %d points" ), int( m_PolyPoints.size() ) ); |
|||
} |
|||
|
|||
|
|||
BITMAPS LIB_POLYLINE::GetMenuImage() const |
|||
{ |
|||
return BITMAPS::add_graphical_segments; |
|||
} |
|||
|
|||
|
|||
void LIB_POLYLINE::BeginEdit( const wxPoint& aPosition ) |
|||
{ |
|||
m_PolyPoints.push_back( aPosition ); // Start point of first segment.
|
|||
m_PolyPoints.push_back( aPosition ); // End point of first segment.
|
|||
} |
|||
|
|||
|
|||
bool LIB_POLYLINE::ContinueEdit( const wxPoint& aPosition ) |
|||
{ |
|||
// do not add zero length segments
|
|||
if( m_PolyPoints[m_PolyPoints.size() - 2] != m_PolyPoints.back() ) |
|||
m_PolyPoints.push_back( aPosition ); |
|||
|
|||
return true; |
|||
} |
|||
|
|||
|
|||
void LIB_POLYLINE::EndEdit() |
|||
{ |
|||
// do not include last point twice
|
|||
if( m_PolyPoints.size() > 2 ) |
|||
{ |
|||
if( m_PolyPoints[ m_PolyPoints.size() - 2 ] == m_PolyPoints.back() ) |
|||
m_PolyPoints.pop_back(); |
|||
} |
|||
} |
|||
|
|||
|
|||
void LIB_POLYLINE::CalcEdit( const wxPoint& aPosition ) |
|||
{ |
|||
m_PolyPoints[ GetCornerCount() - 1 ] = aPosition; |
|||
} |
@ -1,125 +0,0 @@ |
|||
/* |
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com |
|||
* Copyright (C) 2004-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 _LIB_POLYLINE_H_ |
|||
#define _LIB_POLYLINE_H_ |
|||
|
|||
#include <lib_item.h> |
|||
|
|||
|
|||
class LIB_POLYLINE : public LIB_ITEM |
|||
{ |
|||
public: |
|||
LIB_POLYLINE( LIB_SYMBOL* aParent ); |
|||
|
|||
// Do not create a copy constructor. The one generated by the compiler is adequate. |
|||
|
|||
~LIB_POLYLINE() { } |
|||
|
|||
wxString GetClass() const override |
|||
{ |
|||
return wxT( "LIB_POLYLINE" ); |
|||
} |
|||
|
|||
wxString GetTypeName() const override |
|||
{ |
|||
return _( "PolyLine" ); |
|||
} |
|||
|
|||
void ClearPoints() { m_PolyPoints.clear(); } |
|||
void Reserve( size_t aPointCount ) { m_PolyPoints.reserve( aPointCount ); } |
|||
void AddPoint( const wxPoint& aPoint ); |
|||
|
|||
const std::vector< wxPoint >& GetPolyPoints() const { return m_PolyPoints; } |
|||
|
|||
/** |
|||
* Delete the segment at \a aPosition. |
|||
*/ |
|||
void DeleteSegment( const wxPoint aPosition ); |
|||
|
|||
void AddCorner( const wxPoint& aPosition ); |
|||
void RemoveCorner( int aIdx ); |
|||
|
|||
/** |
|||
* @return the number of corners |
|||
*/ |
|||
unsigned GetCornerCount() const { return m_PolyPoints.size(); } |
|||
|
|||
bool HitTest( const wxPoint& aPosition, int aAccuracy = 0 ) const override; |
|||
bool HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy = 0 ) const override; |
|||
|
|||
const EDA_RECT GetBoundingBox() const override; |
|||
|
|||
int GetPenWidth() const override; |
|||
|
|||
void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override; |
|||
|
|||
void BeginEdit( const wxPoint& aStartPoint ) override; |
|||
void CalcEdit( const wxPoint& aPosition ) override; |
|||
bool ContinueEdit( const wxPoint& aNextPoint ) override; |
|||
void EndEdit() override; |
|||
|
|||
void Offset( const wxPoint& aOffset ) override; |
|||
|
|||
void MoveTo( const wxPoint& aPosition ) override; |
|||
|
|||
wxPoint GetPosition() const override { return m_PolyPoints[0]; } |
|||
|
|||
void MirrorHorizontal( const wxPoint& aCenter ) override; |
|||
void MirrorVertical( const wxPoint& aCenter ) override; |
|||
void Rotate( const wxPoint& aCenter, bool aRotateCCW = true ) override; |
|||
|
|||
void Plot( PLOTTER* aPlotter, const wxPoint& aOffset, bool aFill, |
|||
const TRANSFORM& aTransform ) const override; |
|||
|
|||
int GetWidth() const override { return m_Width; } |
|||
void SetWidth( int aWidth ) override { m_Width = aWidth; } |
|||
|
|||
wxString GetSelectMenuText( EDA_UNITS aUnits ) const override; |
|||
|
|||
BITMAPS GetMenuImage() const override; |
|||
|
|||
EDA_ITEM* Clone() const override; |
|||
|
|||
private: |
|||
|
|||
/** |
|||
* @copydoc LIB_ITEM::compare() |
|||
* |
|||
* The sort order for specific to each polyline segment point is as follows: |
|||
* - Line segment point horizontal (X) position. |
|||
* - Line segment point vertical (Y) position. |
|||
*/ |
|||
int compare( const LIB_ITEM& aOther, |
|||
LIB_ITEM::COMPARE_FLAGS aCompareFlags = LIB_ITEM::COMPARE_FLAGS::NORMAL ) const override; |
|||
|
|||
void print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset, void* aData, |
|||
const TRANSFORM& aTransform ) override; |
|||
|
|||
int m_Width; // Line width |
|||
std::vector<wxPoint> m_PolyPoints; // list of points (>= 2) |
|||
}; |
|||
|
|||
|
|||
#endif // _LIB_POLYLINE_H_ |
@ -1,292 +0,0 @@ |
|||
/*
|
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr |
|||
* Copyright (C) 2004-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 |
|||
*/ |
|||
|
|||
|
|||
#include <eda_draw_frame.h>
|
|||
#include <sch_draw_panel.h>
|
|||
#include <plotters/plotter.h>
|
|||
#include <trigo.h>
|
|||
#include <base_units.h>
|
|||
#include <widgets/msgpanel.h>
|
|||
#include <bitmaps.h>
|
|||
#include <general.h>
|
|||
#include <lib_rectangle.h>
|
|||
#include <settings/color_settings.h>
|
|||
#include <transform.h>
|
|||
|
|||
|
|||
LIB_RECTANGLE::LIB_RECTANGLE( LIB_SYMBOL* aParent ) : LIB_ITEM( LIB_RECTANGLE_T, aParent ) |
|||
{ |
|||
m_Width = 0; |
|||
m_fill = FILL_TYPE::NO_FILL; |
|||
m_isFillable = true; |
|||
} |
|||
|
|||
|
|||
EDA_ITEM* LIB_RECTANGLE::Clone() const |
|||
{ |
|||
return new LIB_RECTANGLE( *this ); |
|||
} |
|||
|
|||
|
|||
int LIB_RECTANGLE::compare( const LIB_ITEM& aOther, LIB_ITEM::COMPARE_FLAGS aCompareFlags ) const |
|||
{ |
|||
wxASSERT( aOther.Type() == LIB_RECTANGLE_T ); |
|||
|
|||
int retv = LIB_ITEM::compare( aOther ); |
|||
|
|||
if( retv ) |
|||
return retv; |
|||
|
|||
const LIB_RECTANGLE* tmp = ( LIB_RECTANGLE* ) &aOther; |
|||
|
|||
if( m_Pos.x != tmp->m_Pos.x ) |
|||
return m_Pos.x - tmp->m_Pos.x; |
|||
|
|||
if( m_Pos.y != tmp->m_Pos.y ) |
|||
return m_Pos.y - tmp->m_Pos.y; |
|||
|
|||
if( m_End.x != tmp->m_End.x ) |
|||
return m_End.x - tmp->m_End.x; |
|||
|
|||
if( m_End.y != tmp->m_End.y ) |
|||
return m_End.y - tmp->m_End.y; |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
|
|||
void LIB_RECTANGLE::Offset( const wxPoint& aOffset ) |
|||
{ |
|||
m_Pos += aOffset; |
|||
m_End += aOffset; |
|||
} |
|||
|
|||
|
|||
void LIB_RECTANGLE::MoveTo( const wxPoint& aPosition ) |
|||
{ |
|||
wxPoint size = m_End - m_Pos; |
|||
m_Pos = aPosition; |
|||
m_End = aPosition + size; |
|||
} |
|||
|
|||
|
|||
void LIB_RECTANGLE::MirrorHorizontal( const wxPoint& aCenter ) |
|||
{ |
|||
m_Pos.x -= aCenter.x; |
|||
m_Pos.x *= -1; |
|||
m_Pos.x += aCenter.x; |
|||
m_End.x -= aCenter.x; |
|||
m_End.x *= -1; |
|||
m_End.x += aCenter.x; |
|||
} |
|||
|
|||
|
|||
void LIB_RECTANGLE::MirrorVertical( const wxPoint& aCenter ) |
|||
{ |
|||
m_Pos.y -= aCenter.y; |
|||
m_Pos.y *= -1; |
|||
m_Pos.y += aCenter.y; |
|||
m_End.y -= aCenter.y; |
|||
m_End.y *= -1; |
|||
m_End.y += aCenter.y; |
|||
} |
|||
|
|||
|
|||
void LIB_RECTANGLE::Rotate( const wxPoint& aCenter, bool aRotateCCW ) |
|||
{ |
|||
int rot_angle = aRotateCCW ? -900 : 900; |
|||
RotatePoint( &m_Pos, aCenter, rot_angle ); |
|||
RotatePoint( &m_End, aCenter, rot_angle ); |
|||
} |
|||
|
|||
|
|||
void LIB_RECTANGLE::Plot( PLOTTER* aPlotter, const wxPoint& aOffset, bool aFill, |
|||
const TRANSFORM& aTransform ) const |
|||
{ |
|||
wxASSERT( aPlotter != nullptr ); |
|||
|
|||
wxPoint pos = aTransform.TransformCoordinate( m_Pos ) + aOffset; |
|||
wxPoint end = aTransform.TransformCoordinate( m_End ) + aOffset; |
|||
|
|||
if( aFill && m_fill == FILL_TYPE::FILLED_WITH_BG_BODYCOLOR ) |
|||
{ |
|||
aPlotter->SetColor( aPlotter->RenderSettings()->GetLayerColor( LAYER_DEVICE_BACKGROUND ) ); |
|||
aPlotter->Rect( pos, end, FILL_TYPE::FILLED_WITH_BG_BODYCOLOR, 0 ); |
|||
} |
|||
|
|||
bool already_filled = m_fill == FILL_TYPE::FILLED_WITH_BG_BODYCOLOR; |
|||
int pen_size = GetEffectivePenWidth( aPlotter->RenderSettings() ); |
|||
|
|||
if( !already_filled || pen_size > 0 ) |
|||
{ |
|||
aPlotter->SetColor( aPlotter->RenderSettings()->GetLayerColor( LAYER_DEVICE ) ); |
|||
aPlotter->Rect( pos, end, already_filled ? FILL_TYPE::NO_FILL : m_fill, pen_size ); |
|||
} |
|||
} |
|||
|
|||
|
|||
int LIB_RECTANGLE::GetPenWidth() const |
|||
{ |
|||
return m_Width; |
|||
} |
|||
|
|||
|
|||
void LIB_RECTANGLE::print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset, |
|||
void* aData, const TRANSFORM& aTransform ) |
|||
{ |
|||
bool forceNoFill = static_cast<bool>( aData ); |
|||
int penWidth = GetEffectivePenWidth( aSettings ); |
|||
|
|||
if( forceNoFill && m_fill != FILL_TYPE::NO_FILL && penWidth == 0 ) |
|||
return; |
|||
|
|||
wxDC* DC = aSettings->GetPrintDC(); |
|||
COLOR4D color = aSettings->GetLayerColor( LAYER_DEVICE ); |
|||
wxPoint pt1 = aTransform.TransformCoordinate( m_Pos ) + aOffset; |
|||
wxPoint pt2 = aTransform.TransformCoordinate( m_End ) + aOffset; |
|||
|
|||
if( forceNoFill || m_fill == FILL_TYPE::NO_FILL ) |
|||
{ |
|||
GRRect( nullptr, DC, pt1.x, pt1.y, pt2.x, pt2.y, penWidth, color ); |
|||
} |
|||
else |
|||
{ |
|||
if( m_fill == FILL_TYPE::FILLED_WITH_BG_BODYCOLOR ) |
|||
color = aSettings->GetLayerColor( LAYER_DEVICE_BACKGROUND ); |
|||
|
|||
GRFilledRect( nullptr, DC, pt1.x, pt1.y, pt2.x, pt2.y, penWidth, color, color ); |
|||
} |
|||
} |
|||
|
|||
|
|||
void LIB_RECTANGLE::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) |
|||
{ |
|||
LIB_ITEM::GetMsgPanelInfo( aFrame, aList ); |
|||
|
|||
aList.emplace_back( _( "Line Width" ), MessageTextFromValue( aFrame->GetUserUnits(), m_Width ) ); |
|||
} |
|||
|
|||
|
|||
const EDA_RECT LIB_RECTANGLE::GetBoundingBox() const |
|||
{ |
|||
EDA_RECT rect; |
|||
|
|||
rect.SetOrigin( m_Pos ); |
|||
rect.SetEnd( m_End ); |
|||
rect.Inflate( ( GetPenWidth() / 2 ) + 1 ); |
|||
|
|||
rect.RevertYAxis(); |
|||
|
|||
return rect; |
|||
} |
|||
|
|||
|
|||
bool LIB_RECTANGLE::HitTest( const wxPoint& aPosition, int aAccuracy ) const |
|||
{ |
|||
int mindist = std::max( aAccuracy + GetPenWidth() / 2, |
|||
Mils2iu( MINIMUM_SELECTION_DISTANCE ) ); |
|||
wxPoint actualStart = DefaultTransform.TransformCoordinate( m_Pos ); |
|||
wxPoint actualEnd = DefaultTransform.TransformCoordinate( m_End ); |
|||
|
|||
// locate lower segment
|
|||
wxPoint start, end; |
|||
|
|||
start = actualStart; |
|||
end.x = actualEnd.x; |
|||
end.y = actualStart.y; |
|||
|
|||
if( TestSegmentHit( aPosition, start, end, mindist ) ) |
|||
return true; |
|||
|
|||
// locate right segment
|
|||
start.x = actualEnd.x; |
|||
end.y = actualEnd.y; |
|||
|
|||
if( TestSegmentHit( aPosition, start, end, mindist ) ) |
|||
return true; |
|||
|
|||
// locate upper segment
|
|||
start.y = actualEnd.y; |
|||
end.x = actualStart.x; |
|||
|
|||
if( TestSegmentHit( aPosition, start, end, mindist ) ) |
|||
return true; |
|||
|
|||
// locate left segment
|
|||
start = actualStart; |
|||
end.x = actualStart.x; |
|||
end.y = actualEnd.y; |
|||
|
|||
if( TestSegmentHit( aPosition, start, end, mindist ) ) |
|||
return true; |
|||
|
|||
if( m_fill == FILL_TYPE::NO_FILL ) |
|||
return false; |
|||
|
|||
return GetBoundingBox().Contains( aPosition ); |
|||
} |
|||
|
|||
|
|||
bool LIB_RECTANGLE::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const |
|||
{ |
|||
if( m_flags & (STRUCT_DELETED | SKIP_STRUCT ) ) |
|||
return false; |
|||
|
|||
EDA_RECT sel = aRect; |
|||
|
|||
if ( aAccuracy ) |
|||
sel.Inflate( aAccuracy ); |
|||
|
|||
if( aContained ) |
|||
return sel.Contains( GetBoundingBox() ); |
|||
|
|||
return sel.Intersects( GetBoundingBox() ); |
|||
} |
|||
|
|||
|
|||
wxString LIB_RECTANGLE::GetSelectMenuText( EDA_UNITS aUnits ) const |
|||
{ |
|||
return wxString::Format( _( "Rectangle, width %s height %s" ), |
|||
MessageTextFromValue( aUnits, std::abs( m_Pos.x - m_End.x ) ), |
|||
MessageTextFromValue( aUnits, std::abs( m_Pos.y - m_End.y ) ) ); |
|||
} |
|||
|
|||
|
|||
BITMAPS LIB_RECTANGLE::GetMenuImage() const |
|||
{ |
|||
return BITMAPS::add_rectangle; |
|||
} |
|||
|
|||
|
|||
void LIB_RECTANGLE::BeginEdit( const wxPoint& aPosition ) |
|||
{ |
|||
m_Pos = m_End = aPosition; |
|||
} |
|||
|
|||
|
|||
void LIB_RECTANGLE::CalcEdit( const wxPoint& aPosition ) |
|||
{ |
|||
m_End = aPosition; |
|||
} |
@ -1,112 +0,0 @@ |
|||
/* |
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com |
|||
* Copyright (C) 2004-2021 KiCad Developers, see AUTHOR.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 LIB_RECTANGLE_H |
|||
#define LIB_RECTANGLE_H |
|||
|
|||
#include <lib_item.h> |
|||
|
|||
|
|||
class LIB_RECTANGLE : public LIB_ITEM |
|||
{ |
|||
public: |
|||
LIB_RECTANGLE( LIB_SYMBOL* aParent ); |
|||
|
|||
// Do not create a copy constructor. The one generated by the compiler is adequate. |
|||
|
|||
~LIB_RECTANGLE() { } |
|||
|
|||
wxString GetClass() const override |
|||
{ |
|||
return wxT( "LIB_RECTANGLE" ); |
|||
} |
|||
|
|||
wxString GetTypeName() const override |
|||
{ |
|||
return _( "Rectangle" ); |
|||
} |
|||
|
|||
void SetEndPosition( const wxPoint& aPosition ) { m_End = aPosition; } |
|||
|
|||
bool HitTest( const wxPoint& aPosition, int aAccuracy = 0 ) const override; |
|||
|
|||
bool HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy = 0 ) const override; |
|||
|
|||
int GetPenWidth() const override; |
|||
|
|||
const EDA_RECT GetBoundingBox() const override; |
|||
|
|||
void GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList ) override; |
|||
|
|||
void BeginEdit( const wxPoint& aStartPoint ) override; |
|||
void CalcEdit( const wxPoint& aPosition ) override; |
|||
|
|||
void Offset( const wxPoint& aOffset ) override; |
|||
|
|||
void MoveTo( const wxPoint& aPosition ) override; |
|||
|
|||
wxPoint GetPosition() const override { return m_Pos; } |
|||
|
|||
void MirrorHorizontal( const wxPoint& aCenter ) override; |
|||
void MirrorVertical( const wxPoint& aCenter ) override; |
|||
void Rotate( const wxPoint& aCenter, bool aRotateCCW = true ) override; |
|||
|
|||
void Plot( PLOTTER* aPlotter, const wxPoint& aOffset, bool aFill, |
|||
const TRANSFORM& aTransform ) const override; |
|||
|
|||
int GetWidth() const override { return m_Width; } |
|||
void SetWidth( int aWidth ) override { m_Width = aWidth; } |
|||
|
|||
void SetEnd( const wxPoint& aEnd ) { m_End = aEnd; } |
|||
wxPoint GetEnd() const { return m_End; } |
|||
|
|||
wxString GetSelectMenuText( EDA_UNITS aUnits ) const override; |
|||
|
|||
BITMAPS GetMenuImage() const override; |
|||
|
|||
EDA_ITEM* Clone() const override; |
|||
|
|||
private: |
|||
/** |
|||
* @copydoc LIB_ITEM::compare() |
|||
* |
|||
* The rectangle specific sort order is as follows: |
|||
* - Rectangle horizontal (X) start position. |
|||
* - Rectangle vertical (Y) start position. |
|||
* - Rectangle horizontal (X) end position. |
|||
* - Rectangle vertical (Y) end position. |
|||
*/ |
|||
int compare( const LIB_ITEM& aOther, |
|||
LIB_ITEM::COMPARE_FLAGS aCompareFlags = LIB_ITEM::COMPARE_FLAGS::NORMAL ) const override; |
|||
|
|||
void print( const RENDER_SETTINGS* aSettings, const wxPoint& aOffset, |
|||
void* aData, const TRANSFORM& aTransform ) override; |
|||
|
|||
wxPoint m_End; // Rectangle end point. |
|||
wxPoint m_Pos; // Rectangle start point. |
|||
int m_Width; // Line width |
|||
}; |
|||
|
|||
|
|||
#endif // LIB_RECTANGLE_H |
@ -1,37 +0,0 @@ |
|||
/* |
|||
* This program source code file is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* 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 3 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, see <http://www.gnu.org/licenses/>. |
|||
*/ |
|||
|
|||
#ifndef FILL_TYPE_H |
|||
#define FILL_TYPE_H |
|||
|
|||
/** |
|||
* The set of fill types used in plotting or drawing enclosed areas. |
|||
* |
|||
* @warning Do not renumber this enum, the legacy schematic plugin demands on these values. |
|||
*/ |
|||
enum class FILL_TYPE : int |
|||
{ |
|||
NO_FILL = 0, |
|||
FILLED_SHAPE = 1, // Fill with object color ("Solid shape") |
|||
FILLED_WITH_BG_BODYCOLOR = 2, // Fill with background body color |
|||
// (not filled in B&W mode when plotting or printing) |
|||
FILLED_WITH_COLOR =3 // Fill with a user-defined color (currently sheets only) |
|||
}; |
|||
|
|||
#endif |
Write
Preview
Loading…
Cancel
Save
Reference in new issue