KiCad PCB EDA Suite
Loading...
Searching...
No Matches
angle_item.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KICAD, a free EDA CAD application.
3 *
4 * Copyright (C) 2024 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
25#include <tool/edit_points.h>
27#include <gal/painter.h>
28#include <view/view.h>
29#include <geometry/seg.h>
31#include <font/font.h>
32#include <wx/string.h>
33#include <algorithm>
34#include <map>
35
36using namespace KIGFX::PREVIEW;
37
38ANGLE_ITEM::ANGLE_ITEM( const std::shared_ptr<EDIT_POINTS>& aPoints ) :
40 m_points( aPoints )
41{
42}
43
45{
46 std::shared_ptr<EDIT_POINTS> points = m_points.lock();
47
48 if( points )
49 return points->ViewBBox();
50
51 return BOX2I();
52}
53
55{
56 std::shared_ptr<EDIT_POINTS> points = m_points.lock();
57
58 if( !points )
59 return;
60
61 KIGFX::GAL* gal = aView->GetGAL();
62 KIGFX::RENDER_SETTINGS* settings = aView->GetPainter()->GetSettings();
63 KIGFX::COLOR4D drawColor = settings->GetLayerColor( LAYER_AUX_ITEMS );
64
65 double size = aView->ToWorld( EDIT_POINT::POINT_SIZE ) / 2.0;
66 double borderSize = aView->ToWorld( EDIT_POINT::BORDER_SIZE );
67 double radius = size * 10.0;
68
69 gal->SetStrokeColor( drawColor );
70 gal->SetFillColor( drawColor );
71 gal->SetIsFill( false );
72 gal->SetLineWidth( borderSize * 2.0 );
73 gal->SetGlyphSize( VECTOR2I( radius / 2, radius / 2 ) );
74
75 std::vector<const EDIT_POINT*> anglePoints;
76
77 for( unsigned i = 0; i < points->PointsSize(); ++i )
78 {
79 const EDIT_POINT& point = points->Point( i );
80
81 if( point.IsActive() || point.IsHover() )
82 {
83 anglePoints.push_back( &point );
84
85 EDIT_POINT* prev = points->Previous( point );
86 EDIT_POINT* next = points->Next( point );
87
88 if( prev )
89 anglePoints.push_back( prev );
90
91 if( next )
92 anglePoints.push_back( next );
93 }
94 }
95
96 std::sort( anglePoints.begin(), anglePoints.end() );
97 anglePoints.erase( std::unique( anglePoints.begin(), anglePoints.end() ), anglePoints.end() );
98
99 // First pass: collect all angles and identify congruent ones
100 struct AngleInfo
101 {
102 const EDIT_POINT* point;
103 EDA_ANGLE angle;
105 VECTOR2D v1, v2;
106 EDA_ANGLE start;
107 EDA_ANGLE sweep;
108 EDA_ANGLE mid;
109 bool isRightAngle;
110 };
111
112 std::vector<AngleInfo> angles;
113 std::map<int, int> angleCount; // Map angle (in tenths of degree) to count
114
115 for( const EDIT_POINT* pt : anglePoints )
116 {
117 EDIT_POINT* prev = points->Previous( *pt );
118 EDIT_POINT* next = points->Next( *pt );
119
120 if( !( prev && next ) )
121 continue;
122
123 SEG seg1( pt->GetPosition(), prev->GetPosition() );
124 SEG seg2( pt->GetPosition(), next->GetPosition() );
125
126 // Calculate the interior angle (0-180 degrees) instead of the smallest angle
127 VECTOR2I c = pt->GetPosition();
128 VECTOR2I v1 = prev->GetPosition() - c;
129 VECTOR2I v2 = next->GetPosition() - c;
130 EDA_ANGLE angle = seg2.Angle( seg1 );
131
132 EDA_ANGLE start = EDA_ANGLE( VECTOR2D( v1 ) );
133 EDA_ANGLE sweep = ( EDA_ANGLE( VECTOR2D( v2 ) ) - start ).Normalize180();
134 EDA_ANGLE mid = start + sweep / 2.0;
135 VECTOR2D center( c );
136
137 AngleInfo info;
138 info.point = pt;
139 info.angle = angle;
140 info.center = center;
141 info.v1 = v1;
142 info.v2 = v2;
143 info.start = start;
144 info.sweep = sweep;
145 info.mid = mid;
146 info.isRightAngle = ( angle.AsTenthsOfADegree() == 900 );
147
148 angles.push_back( info );
149 angleCount[angle.AsTenthsOfADegree()]++;
150 }
151
152 // Second pass: draw the angles with congruence markings
153 for( const AngleInfo& angleInfo : angles )
154 {
155 bool isCongruent = angleCount[angleInfo.angle.AsTenthsOfADegree()] > 1;
156
157 if( angleInfo.isRightAngle )
158 {
159 VECTOR2D u1 = VECTOR2D( angleInfo.v1 ).Resize( radius );
160 VECTOR2D u2 = VECTOR2D( angleInfo.v2 ).Resize( radius );
161 VECTOR2D p1 = angleInfo.center + u1;
162 VECTOR2D p2 = angleInfo.center + u2;
163 VECTOR2D corner = angleInfo.center + u1 + u2;
164
165 // Draw the primary right angle marker
166 gal->DrawLine( p1, corner );
167 gal->DrawLine( p2, corner );
168
169 // Draw congruence marking for right angles
170 if( isCongruent )
171 {
172 double innerRadius = radius * 0.6;
173 VECTOR2D u1_inner = VECTOR2D( angleInfo.v1 ).Resize( innerRadius );
174 VECTOR2D u2_inner = VECTOR2D( angleInfo.v2 ).Resize( innerRadius );
175 VECTOR2D p1_inner = angleInfo.center + u1_inner;
176 VECTOR2D p2_inner = angleInfo.center + u2_inner;
177 VECTOR2D corner_inner = angleInfo.center + u1_inner + u2_inner;
178
179 gal->DrawLine( p1_inner, corner_inner );
180 gal->DrawLine( p2_inner, corner_inner );
181 }
182 }
183 else
184 {
185 // Draw the primary arc
186 gal->DrawArc( angleInfo.center, radius, angleInfo.start, angleInfo.sweep );
187
188 // Draw congruence marking for non-right angles
189 if( isCongruent )
190 {
191 double innerRadius = radius * 0.7;
192 gal->DrawArc( angleInfo.center, innerRadius, angleInfo.start, angleInfo.sweep );
193 }
194 }
195
196 VECTOR2D textDir( angleInfo.mid.Cos(), angleInfo.mid.Sin() );
197 wxString label = wxString::Format( wxT( "%.1f°" ), angleInfo.angle.AsDegrees() );
198
199 // Calculate actual text dimensions to ensure proper clearance
201 VECTOR2I textSize = font->StringBoundaryLimits( label, gal->GetGlyphSize(), 0, false, false,
203
204 // Calculate offset based on text direction - use width for horizontal, height for vertical
205 double absX = std::abs( textDir.x );
206 double absY = std::abs( textDir.y );
207 double textClearance = ( absX * textSize.x + absY * textSize.y ) / 2.0;
208 double textOffset = radius + borderSize + textClearance;
209 VECTOR2I textPos = angleInfo.center + VECTOR2I( textDir * textOffset );
210 gal->BitmapText( label, textPos, ANGLE_HORIZONTAL );
211 }
212}
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
int AsTenthsOfADegree() const
Definition eda_angle.h:118
Represent a single point that can be used for modifying items.
Definition edit_points.h:48
bool IsActive() const
static const int POINT_SIZE
Single point size in pixels.
virtual VECTOR2I GetPosition() const
Return coordinates of an EDIT_POINT.
Definition edit_points.h:72
bool IsHover() const
static const int BORDER_SIZE
Border size when not hovering.
FONT is an abstract base class for both outline and stroke fonts.
Definition font.h:131
static FONT * GetFont(const wxString &aFontName=wxEmptyString, bool aBold=false, bool aItalic=false, const std::vector< wxString > *aEmbeddedFiles=nullptr, bool aForDrawingSheet=false)
Definition font.cpp:147
VECTOR2I StringBoundaryLimits(const wxString &aText, const VECTOR2I &aSize, int aThickness, bool aBold, bool aItalic, const METRICS &aFontMetrics) const
Compute the boundary limits of aText (the bounding box of all shapes).
Definition font.cpp:451
static const METRICS & Default()
Definition font.cpp:52
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:105
Abstract interface for drawing on a 2D-surface.
virtual void SetIsFill(bool aIsFillEnabled)
Enable/disable fill.
virtual void SetFillColor(const COLOR4D &aColor)
Set the fill color.
virtual void SetLineWidth(float aLineWidth)
Set the line width.
virtual void SetStrokeColor(const COLOR4D &aColor)
Set the stroke color.
const VECTOR2I & GetGlyphSize() const
virtual void DrawLine(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint)
Draw a line.
void SetGlyphSize(const VECTOR2I aSize)
virtual void DrawArc(const VECTOR2D &aCenterPoint, double aRadius, const EDA_ANGLE &aStartAngle, const EDA_ANGLE &aAngle)
Draw an arc.
virtual void BitmapText(const wxString &aText, const VECTOR2I &aPosition, const EDA_ANGLE &aAngle)
Draw a text using a bitmap font.
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
const BOX2I ViewBBox() const override
Return the bounding box of the item covering all its layers.
std::weak_ptr< EDIT_POINTS > m_points
Definition angle_item.h:53
void drawPreviewShape(KIGFX::VIEW *aView) const override
Draw the preview onto the given GAL.
ANGLE_ITEM(const std::shared_ptr< EDIT_POINTS > &aPoints)
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
const COLOR4D & GetLayerColor(int aLayer) const
Return the color used to draw a layer.
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:66
GAL * GetGAL() const
Return the GAL this view is using to draw graphical primitives.
Definition view.h:202
VECTOR2D ToWorld(const VECTOR2D &aCoord, bool aAbsolute=true) const
Converts a screen space point/vector to a point/vector in world space coordinates.
Definition view.cpp:467
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition view.h:220
Definition seg.h:42
EDA_ANGLE Angle(const SEG &aOther) const
Determine the smallest angle between two segments.
Definition seg.cpp:111
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
Definition vector2d.h:385
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
Definition eda_angle.h:407
@ LAYER_AUX_ITEMS
Auxiliary items (guides, rule, etc).
Definition layer_ids.h:283
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
CITER next(CITER it)
Definition ptree.cpp:124
VECTOR3I v1(5, 5, 5)
VECTOR2I center
int radius
VECTOR2I v2(1, 0)
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
VECTOR2< double > VECTOR2D
Definition vector2d.h:694