KiCad PCB EDA Suite
Loading...
Searching...
No Matches
ruler_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 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
27#include <layer_ids.h>
28#include <gal/painter.h>
29#include <view/view.h>
30#include <trigo.h>
31
32using namespace KIGFX::PREVIEW;
33
34static const double maxTickDensity = 10.0; // min pixels between tick marks
35static const double midTickLengthFactor = 1.5;
36static const double majorTickLengthFactor = 2.5;
37
38
39/*
40 * It would be nice to know why Cairo seems to have an opposite layer order from GAL, but
41 * only when drawing RULER_ITEMs (the TWO_POINT_ASSISTANT and ARC_ASSISTANT are immune from
42 * this issue).
43 *
44 * Until then, this egregious hack...
45 */
46static int getShadowLayer( KIGFX::GAL* aGal )
47{
48 if( aGal->IsCairoEngine() )
50 else
51 return LAYER_GP_OVERLAY;
52}
53
54
55static double getTickLineWidth( const TEXT_DIMS& textDims, bool aDrawingDropShadows )
56{
57 double width = textDims.StrokeWidth * 0.8;
58
59 if( aDrawingDropShadows )
60 width += textDims.ShadowWidth;
61
62 return width;
63}
64
65
71{
72 double divisionBase;
74 int midStep;
75};
76
77
78static TICK_FORMAT getTickFormatForScale( double aScale, double& aTickSpace, EDA_UNITS aUnits )
79{
80 // simple 1/2/5 scales per decade
81 static std::vector<TICK_FORMAT> tickFormats =
82 {
83 { 2, 10, 5 }, // |....:....|
84 { 2, 5, 0 }, // |....|
85 { 2.5, 2, 0 }, // |.|.|
86 };
87
88 // could start at a set number of MM, but that's not available in common
89 aTickSpace = 1;
90
91 // Convert to a round (mod-10) number of mils for imperial units
92 if( EDA_UNIT_UTILS::IsImperialUnit( aUnits ) )
93 aTickSpace *= 2.54;
94
95 int tickFormat = 0;
96
97 while( true )
98 {
99 const auto pixelSpace = aTickSpace * aScale;
100
101 if( pixelSpace >= maxTickDensity )
102 break;
103
104 tickFormat = ( tickFormat + 1 ) % tickFormats.size();
105 aTickSpace *= tickFormats[tickFormat].divisionBase;
106 }
107
108 return tickFormats[tickFormat];
109}
110
111
121void drawTicksAlongLine( KIGFX::VIEW* aView, const VECTOR2D& aOrigin, const VECTOR2D& aLine,
122 double aMinorTickLen, const EDA_IU_SCALE& aIuScale, EDA_UNITS aUnits,
123 bool aDrawingDropShadows )
124{
125 KIGFX::GAL* gal = aView->GetGAL();
127 double tickSpace;
128 TICK_FORMAT tickFormat = getTickFormatForScale( gal->GetWorldScale(), tickSpace, aUnits );
129 double majorTickLen = aMinorTickLen * ( majorTickLengthFactor + 1 );
130 VECTOR2D tickLine = aLine;
131
132 RotatePoint( tickLine, ANGLE_90 );
133
134 // number of ticks in whole ruler
135 int numTicks = (int) std::ceil( aLine.EuclideanNorm() / tickSpace );
136
137 // work out which way up the tick labels go
138 TEXT_DIMS labelDims = GetConstantGlyphHeight( gal, -1 );
139 EDA_ANGLE labelAngle = - EDA_ANGLE( tickLine );
140 VECTOR2I labelOffset = tickLine.Resize( majorTickLen );
141
142 // text is left (or right) aligned, so shadow text need a small offset to be draw
143 // around the basic text
144 int shadowXoffset = 0;
145
146 if( aDrawingDropShadows )
147 {
148 labelDims.StrokeWidth += 2 * labelDims.ShadowWidth;
149 shadowXoffset = labelDims.ShadowWidth;
150
151 // Due to the fact a shadow text is drawn left or right aligned,
152 // it needs an offset = shadowXoffset to be drawn at the same place as normal text
153 // But for some reason we need to slightly modify this offset
154 // for a better look for KiCad font (better alignment of shadow shape)
155 const float adjust = 1.2f; // Value chosen after tests
156 shadowXoffset *= adjust;
157 }
158
159 if( aView->IsMirroredX() )
160 {
161 labelOffset = -labelOffset;
162 shadowXoffset = -shadowXoffset;
163 }
164
165 TEXT_ATTRIBUTES labelAttrs;
166 labelAttrs.m_Size = labelDims.GlyphSize;
167 labelAttrs.m_StrokeWidth = labelDims.StrokeWidth;
168 labelAttrs.m_Mirrored = aView->IsMirroredX(); // Prevent text mirrored when view is mirrored
169
170 if( EDA_ANGLE( aLine ) > ANGLE_0 )
171 {
172 labelAttrs.m_Halign = GR_TEXT_H_ALIGN_LEFT;
173 labelAttrs.m_Angle = labelAngle;
174
175 // Adjust the text position of the shadow shape:
176 labelOffset.x -= shadowXoffset * labelAttrs.m_Angle.Cos();;
177 labelOffset.y += shadowXoffset * labelAttrs.m_Angle.Sin();;
178 }
179 else
180 {
181 labelAttrs.m_Halign = GR_TEXT_H_ALIGN_RIGHT;
182 labelAttrs.m_Angle = labelAngle + ANGLE_180;
183
184 // Adjust the text position of the shadow shape:
185 labelOffset.x += shadowXoffset * labelAttrs.m_Angle.Cos();;
186 labelOffset.y -= shadowXoffset * labelAttrs.m_Angle.Sin();;
187 }
188
189 BOX2D viewportD = aView->GetViewport();
190 BOX2I viewport( VECTOR2I( viewportD.GetPosition() ), VECTOR2I( viewportD.GetSize() ) );
191
192 viewport.Inflate( majorTickLen * 2 ); // Doesn't have to be accurate, just big enough not
193 // to exclude anything that should be partially drawn
194
195 int isign = aView->IsMirroredX() ? -1 : 1;
196
197 for( int i = 0; i < numTicks; ++i )
198 {
199 const VECTOR2D tickPos = aOrigin + aLine.Resize( tickSpace * i );
200
201 if( !viewport.Contains( tickPos ) )
202 continue;
203
204 double length = aMinorTickLen;
205 bool drawLabel = false;
206
207 if( i % tickFormat.majorStep == 0 )
208 {
209 drawLabel = true;
210 length *= majorTickLengthFactor;
211 }
212 else if( tickFormat.midStep && i % tickFormat.midStep == 0 )
213 {
214 drawLabel = true;
215 length *= midTickLengthFactor;
216 }
217
218 gal->SetLineWidth( labelAttrs.m_StrokeWidth / 2 );
219 gal->DrawLine( tickPos, tickPos + tickLine.Resize( length*isign ) );
220
221 if( drawLabel )
222 {
223 wxString label = DimensionLabel( "", tickSpace * i, aIuScale, aUnits, false );
224 font->Draw( gal, label, tickPos + labelOffset, labelAttrs, KIFONT::METRICS::Default() );
225 }
226 }
227}
228
229
240void drawBacksideTicks( KIGFX::VIEW* aView, const VECTOR2D& aOrigin, const VECTOR2D& aLine,
241 double aTickLen, int aNumDivisions, bool aDrawingDropShadows )
242{
243 KIGFX::GAL* gal = aView->GetGAL();
244 TEXT_DIMS textDims = GetConstantGlyphHeight( gal, -1 );
245 const double backTickSpace = aLine.EuclideanNorm() / aNumDivisions;
246 VECTOR2D backTickVec = aLine;
247 int isign = aView->IsMirroredX() ? -1 : 1;
248
249 RotatePoint( backTickVec, -ANGLE_90 );
250 backTickVec = backTickVec.Resize( aTickLen * isign );
251
252 BOX2D viewportD = aView->GetViewport();
253 BOX2I viewport( VECTOR2I( viewportD.GetPosition() ), VECTOR2I( viewportD.GetSize() ) );
254
255 viewport.Inflate( aTickLen * 4 ); // Doesn't have to be accurate, just big enough not to
256 // exclude anything that should be partially drawn
257
258 for( int i = 0; i < aNumDivisions + 1; ++i )
259 {
260 const VECTOR2D backTickPos = aOrigin + aLine.Resize( backTickSpace * i );
261
262 if( !viewport.Contains( backTickPos ) )
263 continue;
264
265 gal->SetLineWidth( getTickLineWidth( textDims, aDrawingDropShadows ) );
266 gal->DrawLine( backTickPos, backTickPos + backTickVec );
267 }
268}
269
270
272 EDA_UNITS userUnits, bool aFlipX, bool aFlipY )
273 : EDA_ITEM( NOT_USED ), // Never added to anything - just a preview
274 m_geomMgr( aGeomMgr ),
275 m_userUnits( userUnits ),
276 m_iuScale( aIuScale ),
277 m_flipX( aFlipX ),
278 m_flipY( aFlipY )
279{
280}
281
282
284{
285 BOX2I tmp;
286
288 return tmp;
289
290 // this is an edit-time artefact; no reason to try and be smart with the bounding box
291 // (besides, we can't tell the text extents without a view to know what the scale is)
292 tmp.SetMaximum();
293 return tmp;
294}
295
296
297std::vector<int> RULER_ITEM::ViewGetLayers() const
298{
299 std::vector<int> layers{ LAYER_SELECT_OVERLAY, LAYER_GP_OVERLAY };
300 return layers;
301}
302
303
304void RULER_ITEM::ViewDraw( int aLayer, KIGFX::VIEW* aView ) const
305{
306 KIGFX::GAL* gal = aView->GetGAL();
307 RENDER_SETTINGS* rs = aView->GetPainter()->GetSettings();
308 bool drawingDropShadows = ( aLayer == getShadowLayer( gal ) );
309
311 gal->SetLayerDepth( gal->GetMinDepth() );
312
313 VECTOR2D origin = m_geomMgr.GetOrigin();
314 VECTOR2D end = m_geomMgr.GetEnd();
315
316 gal->SetIsStroke( true );
317 gal->SetIsFill( false );
318 gal->SetTextMirrored( false );
319
320 if( m_color )
321 gal->SetStrokeColor( *m_color );
322 else
324
325 if( drawingDropShadows )
327
328 gal->ResetTextAttributes();
329 TEXT_DIMS textDims = GetConstantGlyphHeight( gal );
330
331 // draw the main line from the origin to cursor
332 gal->SetLineWidth( getTickLineWidth( textDims, drawingDropShadows ) );
333 gal->DrawLine( origin, end );
334
335 VECTOR2D rulerVec( end - origin );
336
337 wxArrayString cursorStrings = GetDimensionStrings();
338 DrawTextNextToCursor( aView, end, -rulerVec, cursorStrings, drawingDropShadows );
339
340 // basic tick size
341 const double minorTickLen = 5.0 / gal->GetWorldScale();
342 const double majorTickLen = minorTickLen * majorTickLengthFactor;
343
344 if( m_showTicks )
345 {
346 drawTicksAlongLine( aView, origin, rulerVec, minorTickLen, m_iuScale, m_userUnits,
347 drawingDropShadows );
348
349 drawBacksideTicks( aView, origin, rulerVec, majorTickLen, 2, drawingDropShadows );
350 }
351
353 {
354 const EDA_ANGLE arrowAngle{ 30.0 };
355 VECTOR2D arrowHead = rulerVec;
356 RotatePoint( arrowHead, arrowAngle );
357 arrowHead = arrowHead.Resize( majorTickLen );
358
359 gal->DrawLine( end, end - arrowHead );
360
361 arrowHead = rulerVec;
362 RotatePoint( arrowHead, -arrowAngle );
363 arrowHead = arrowHead.Resize( majorTickLen );
364
365 gal->DrawLine( end, end - arrowHead );
366 }
367 else
368 {
369 // draw the back of the origin "crosshair"
370 gal->DrawLine( origin, origin + rulerVec.Resize( -minorTickLen * midTickLengthFactor ) );
371 }
372}
373
374
376{
377 const VECTOR2D rulerVec = m_geomMgr.GetEnd() - m_geomMgr.GetOrigin();
378 VECTOR2D temp = rulerVec;
379
380 if( m_flipX )
381 temp.x = -temp.x;
382
383 if( m_flipY )
384 temp.y = -temp.y;
385
386 wxArrayString cursorStrings;
387
388 cursorStrings.push_back( DimensionLabel( "x", temp.x, m_iuScale, m_userUnits ) );
389 cursorStrings.push_back( DimensionLabel( "y", temp.y, m_iuScale, m_userUnits ) );
390
391 cursorStrings.push_back(
392 DimensionLabel( "r", rulerVec.EuclideanNorm(), m_iuScale, m_userUnits ) );
393
394 EDA_ANGLE angle = -EDA_ANGLE( rulerVec );
395 cursorStrings.push_back( DimensionLabel( wxString::FromUTF8( "θ" ), angle.AsDegrees(),
396 m_iuScale, EDA_UNITS::DEGREES ) );
397 return cursorStrings;
398}
constexpr const Vec & GetPosition() const
Definition: box2.h:211
constexpr void SetMaximum()
Definition: box2.h:80
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:558
constexpr bool Contains(const Vec &aPoint) const
Definition: box2.h:168
constexpr const SizeVec & GetSize() const
Definition: box2.h:206
double Sin() const
Definition: eda_angle.h:170
double AsDegrees() const
Definition: eda_angle.h:113
double Cos() const
Definition: eda_angle.h:189
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:89
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:146
void Draw(KIGFX::GAL *aGal, const wxString &aText, const VECTOR2I &aPosition, const VECTOR2I &aCursor, const TEXT_ATTRIBUTES &aAttributes, const METRICS &aFontMetrics) const
Draw a string.
Definition: font.cpp:249
static const METRICS & Default()
Definition: font.cpp:52
Attribute save/restore for GAL attributes.
Abstract interface for drawing on a 2D-surface.
virtual void SetLayerDepth(double aLayerDepth)
Set the depth of the layer (position on the z-axis)
virtual void SetIsFill(bool aIsFillEnabled)
Enable/disable fill.
const COLOR4D & GetStrokeColor() const
Get the stroke color.
void ResetTextAttributes()
Reset text attributes to default styling.
virtual void SetLineWidth(float aLineWidth)
Set the line width.
void SetTextMirrored(const bool aMirrored)
virtual void SetStrokeColor(const COLOR4D &aColor)
Set the stroke color.
virtual void SetIsStroke(bool aIsStrokeEnabled)
Enable/disable stroked outlines.
virtual bool IsCairoEngine()
Return true if the GAL engine is a Cairo based type.
virtual void DrawLine(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint)
Draw a line.
double GetMinDepth() const
double GetWorldScale() const
Get the world scale.
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
std::vector< int > ViewGetLayers() const override
Definition: ruler_item.cpp:297
RULER_ITEM(const TWO_POINT_GEOMETRY_MANAGER &m_geomMgr, const EDA_IU_SCALE &aIuScale, EDA_UNITS userUnits, bool aFlipX, bool aFlipY)
Return the bounding box of the item covering all its layers.
Definition: ruler_item.cpp:271
const TWO_POINT_GEOMETRY_MANAGER & m_geomMgr
Definition: ruler_item.h:100
wxArrayString GetDimensionStrings() const
Get the strings for the dimensions of the ruler.
Definition: ruler_item.cpp:375
std::optional< COLOR4D > m_color
Definition: ruler_item.h:105
void ViewDraw(int aLayer, KIGFX::VIEW *aView) const override final
Draw the parts of the object belonging to layer aLayer.
Definition: ruler_item.cpp:304
const BOX2I ViewBBox() const override
Return the all the layers within the VIEW the object is painted on.
Definition: ruler_item.cpp:283
const EDA_IU_SCALE & m_iuScale
Definition: ruler_item.h:102
Represent a very simple geometry manager for items that have a start and end point.
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:67
BOX2D GetViewport() const
Return the current viewport visible area rectangle.
Definition: view.cpp:520
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:198
bool IsMirroredX() const
Return true if view is flipped across the X axis.
Definition: view.h:246
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:216
GR_TEXT_H_ALIGN_T m_Halign
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition: vector2d.h:283
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_0
Definition: eda_angle.h:401
static constexpr EDA_ANGLE ANGLE_90
Definition: eda_angle.h:403
static constexpr EDA_ANGLE ANGLE_180
Definition: eda_angle.h:405
EDA_UNITS
Definition: eda_units.h:46
@ LAYER_GP_OVERLAY
General purpose overlay.
Definition: layer_ids.h:241
@ LAYER_AUX_ITEMS
Auxiliary items (guides, rule, etc).
Definition: layer_ids.h:245
@ LAYER_SELECT_OVERLAY
Selected items overlay.
Definition: layer_ids.h:242
KICOMMON_API bool IsImperialUnit(EDA_UNITS aUnit)
Definition: eda_units.cpp:47
COLOR4D GetShadowColor(const COLOR4D &aColor)
void DrawTextNextToCursor(KIGFX::VIEW *aView, const VECTOR2D &aCursorPos, const VECTOR2D &aTextQuadrant, const wxArrayString &aStrings, bool aDrawingDropShadows)
Draw strings next to the cursor.
wxString DimensionLabel(const wxString &prefix, double aVal, const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, bool aIncludeUnits=true)
Get a formatted string showing a dimension to a sane precision with an optional prefix and unit suffi...
TEXT_DIMS GetConstantGlyphHeight(KIGFX::GAL *aGal, int aRelativeSize=0)
Set the GAL glyph height to a constant scaled value, so that it always looks the same on screen.
static double getTickLineWidth(const TEXT_DIMS &textDims, bool aDrawingDropShadows)
Definition: ruler_item.cpp:55
static const double maxTickDensity
Definition: ruler_item.cpp:34
static TICK_FORMAT getTickFormatForScale(double aScale, double &aTickSpace, EDA_UNITS aUnits)
Definition: ruler_item.cpp:78
void drawBacksideTicks(KIGFX::VIEW *aView, const VECTOR2D &aOrigin, const VECTOR2D &aLine, double aTickLen, int aNumDivisions, bool aDrawingDropShadows)
Draw simple ticks on the back of a line such that the line is divided into n parts.
Definition: ruler_item.cpp:240
void drawTicksAlongLine(KIGFX::VIEW *aView, const VECTOR2D &aOrigin, const VECTOR2D &aLine, double aMinorTickLen, const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, bool aDrawingDropShadows)
Draw labeled ticks on a line.
Definition: ruler_item.cpp:121
static const double majorTickLengthFactor
Definition: ruler_item.cpp:36
static int getShadowLayer(KIGFX::GAL *aGal)
Definition: ruler_item.cpp:46
static const double midTickLengthFactor
Definition: ruler_item.cpp:35
Description of a "tick format" for a scale factor - how many ticks there are between medium/major tic...
Definition: ruler_item.cpp:71
int majorStep
ticks between major ticks
Definition: ruler_item.cpp:73
double divisionBase
multiple from the last scale
Definition: ruler_item.cpp:72
int midStep
ticks between medium ticks (0 if no medium ticks)
Definition: ruler_item.cpp:74
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition: trigo.cpp:229
@ NOT_USED
the 3d code uses this value
Definition: typeinfo.h:79
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:695