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 (C) 2017-2023 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 void drawCursorStrings( KIGFX::VIEW* aView, const VECTOR2D& aCursor,
56 const VECTOR2D& aRulerVec, const EDA_IU_SCALE& aIuScale, EDA_UNITS aUnits,
57 bool aDrawingDropShadows, bool aFlipX, bool aFlipY )
58{
59 // draw the cursor labels
60 std::vector<wxString> cursorStrings;
61
62 VECTOR2D temp = aRulerVec;
63
64 if( aFlipX )
65 temp.x = -temp.x;
66
67 if( aFlipY )
68 temp.y = -temp.y;
69
70 cursorStrings.push_back( DimensionLabel( "x", temp.x, aIuScale, aUnits ) );
71 cursorStrings.push_back( DimensionLabel( "y", temp.y, aIuScale, aUnits ) );
72
73 cursorStrings.push_back( DimensionLabel( "r", aRulerVec.EuclideanNorm(), aIuScale, aUnits ) );
74
75 EDA_ANGLE angle = -EDA_ANGLE( aRulerVec );
76 cursorStrings.push_back( DimensionLabel( wxString::FromUTF8( "θ" ), angle.AsDegrees(), aIuScale,
78
79 temp = aRulerVec;
80 DrawTextNextToCursor( aView, aCursor, -temp, cursorStrings, aDrawingDropShadows );
81}
82
83
84static double getTickLineWidth( const TEXT_DIMS& textDims, bool aDrawingDropShadows )
85{
86 double width = textDims.StrokeWidth * 0.8;
87
88 if( aDrawingDropShadows )
89 width += textDims.ShadowWidth;
90
91 return width;
92}
93
94
100{
104};
105
106
107static TICK_FORMAT getTickFormatForScale( double aScale, double& aTickSpace, EDA_UNITS aUnits )
108{
109 // simple 1/2/5 scales per decade
110 static std::vector<TICK_FORMAT> tickFormats =
111 {
112 { 2, 10, 5 }, // |....:....|
113 { 2, 5, 0 }, // |....|
114 { 2.5, 2, 0 }, // |.|.|
115 };
116
117 // could start at a set number of MM, but that's not available in common
118 aTickSpace = 1;
119
120 // Convert to a round (mod-10) number of mils for imperial units
121 if( EDA_UNIT_UTILS::IsImperialUnit( aUnits ) )
122 aTickSpace *= 2.54;
123
124 int tickFormat = 0;
125
126 while( true )
127 {
128 const auto pixelSpace = aTickSpace * aScale;
129
130 if( pixelSpace >= maxTickDensity )
131 break;
132
133 tickFormat = ( tickFormat + 1 ) % tickFormats.size();
134 aTickSpace *= tickFormats[tickFormat].divisionBase;
135 }
136
137 return tickFormats[tickFormat];
138}
139
140
150void drawTicksAlongLine( KIGFX::VIEW* aView, const VECTOR2D& aOrigin, const VECTOR2D& aLine,
151 double aMinorTickLen, const EDA_IU_SCALE& aIuScale, EDA_UNITS aUnits, bool aDrawingDropShadows )
152{
153 KIGFX::GAL* gal = aView->GetGAL();
155 double tickSpace;
156 TICK_FORMAT tickFormat = getTickFormatForScale( gal->GetWorldScale(), tickSpace, aUnits );
157 double majorTickLen = aMinorTickLen * ( majorTickLengthFactor + 1 );
158 VECTOR2D tickLine = aLine;
159
160 RotatePoint( tickLine, ANGLE_90 );
161
162 // number of ticks in whole ruler
163 int numTicks = (int) std::ceil( aLine.EuclideanNorm() / tickSpace );
164
165 // work out which way up the tick labels go
166 TEXT_DIMS labelDims = GetConstantGlyphHeight( gal, -1 );
167 EDA_ANGLE labelAngle = - EDA_ANGLE( tickLine );
168 VECTOR2I labelOffset = tickLine.Resize( majorTickLen );
169
170 // text is left (or right) aligned, so shadow text need a small offset to be draw
171 // around the basic text
172 int shadowXoffset = 0;
173
174 if( aDrawingDropShadows )
175 {
176 labelDims.StrokeWidth += 2 * labelDims.ShadowWidth;
177 shadowXoffset = labelDims.ShadowWidth;
178 // Due to the fact a shadow text is drawn left or right aligned,
179 // it needs an offset = shadowXoffset to be drawn at the same place as normal text
180 // But for some reason we need to slightly modify this offset
181 // for a better look for KiCad font (better alignment of shadow shape)
182 const float adjust = 1.2f; // Value chosen after tests
183 shadowXoffset *= adjust;
184 }
185
186 if( aView->IsMirroredX() )
187 {
188 labelOffset = -labelOffset;
189 shadowXoffset = -shadowXoffset;
190 }
191
192 TEXT_ATTRIBUTES labelAttrs;
193 labelAttrs.m_Size = labelDims.GlyphSize;
194 labelAttrs.m_StrokeWidth = labelDims.StrokeWidth;
195 labelAttrs.m_Mirrored = aView->IsMirroredX(); // Prevent text mirrored when view is mirrored
196
197 if( EDA_ANGLE( aLine ) > ANGLE_0 )
198 {
199 labelAttrs.m_Halign = GR_TEXT_H_ALIGN_LEFT;
200 labelAttrs.m_Angle = labelAngle;
201
202 // Adjust the text position of the shadow shape:
203 labelOffset.x -= shadowXoffset * labelAttrs.m_Angle.Cos();;
204 labelOffset.y += shadowXoffset * labelAttrs.m_Angle.Sin();;
205 }
206 else
207 {
208 labelAttrs.m_Halign = GR_TEXT_H_ALIGN_RIGHT;
209 labelAttrs.m_Angle = labelAngle + ANGLE_180;
210
211 // Adjust the text position of the shadow shape:
212 labelOffset.x += shadowXoffset * labelAttrs.m_Angle.Cos();;
213 labelOffset.y -= shadowXoffset * labelAttrs.m_Angle.Sin();;
214 }
215
216 BOX2D viewportD = aView->GetViewport();
217 BOX2I viewport( VECTOR2I( viewportD.GetPosition() ), VECTOR2I( viewportD.GetSize() ) );
218
219 viewport.Inflate( majorTickLen * 2 ); // Doesn't have to be accurate, just big enough not
220 // to exclude anything that should be partially drawn
221
222 int isign = aView->IsMirroredX() ? -1 : 1;
223
224 for( int i = 0; i < numTicks; ++i )
225 {
226 const VECTOR2D tickPos = aOrigin + aLine.Resize( tickSpace * i );
227
228 if( !viewport.Contains( tickPos ) )
229 continue;
230
231 double length = aMinorTickLen;
232 bool drawLabel = false;
233
234 if( i % tickFormat.majorStep == 0 )
235 {
236 drawLabel = true;
237 length *= majorTickLengthFactor;
238 }
239 else if( tickFormat.midStep && i % tickFormat.midStep == 0 )
240 {
241 drawLabel = true;
242 length *= midTickLengthFactor;
243 }
244
245 gal->SetLineWidth( labelAttrs.m_StrokeWidth / 2 );
246 gal->DrawLine( tickPos, tickPos + tickLine.Resize( length*isign ) );
247
248 if( drawLabel )
249 {
250 wxString label = DimensionLabel( "", tickSpace * i, aIuScale, aUnits, false );
251 font->Draw( gal, label, tickPos + labelOffset, labelAttrs, KIFONT::METRICS::Default() );
252 }
253 }
254}
255
256
267void drawBacksideTicks( KIGFX::VIEW* aView, const VECTOR2D& aOrigin, const VECTOR2D& aLine,
268 double aTickLen, int aNumDivisions, bool aDrawingDropShadows )
269{
270 KIGFX::GAL* gal = aView->GetGAL();
271 TEXT_DIMS textDims = GetConstantGlyphHeight( gal, -1 );
272 const double backTickSpace = aLine.EuclideanNorm() / aNumDivisions;
273 VECTOR2D backTickVec = aLine;
274 int isign = aView->IsMirroredX() ? -1 : 1;
275
276 RotatePoint( backTickVec, -ANGLE_90 );
277 backTickVec = backTickVec.Resize( aTickLen * isign );
278
279 BOX2D viewportD = aView->GetViewport();
280 BOX2I viewport( VECTOR2I( viewportD.GetPosition() ), VECTOR2I( viewportD.GetSize() ) );
281
282 viewport.Inflate( aTickLen * 4 ); // Doesn't have to be accurate, just big enough not to
283 // exclude anything that should be partially drawn
284
285 for( int i = 0; i < aNumDivisions + 1; ++i )
286 {
287 const VECTOR2D backTickPos = aOrigin + aLine.Resize( backTickSpace * i );
288
289 if( !viewport.Contains( backTickPos ) )
290 continue;
291
292 gal->SetLineWidth( getTickLineWidth( textDims, aDrawingDropShadows ) );
293 gal->DrawLine( backTickPos, backTickPos + backTickVec );
294 }
295}
296
297
298RULER_ITEM::RULER_ITEM( const TWO_POINT_GEOMETRY_MANAGER& aGeomMgr, const EDA_IU_SCALE& aIuScale, EDA_UNITS userUnits,
299 bool aFlipX, bool aFlipY )
300 : EDA_ITEM( NOT_USED ), // Never added to anything - just a preview
301 m_geomMgr( aGeomMgr ),
302 m_userUnits( userUnits ),
303 m_iuScale( aIuScale ),
304 m_flipX( aFlipX ),
305 m_flipY( aFlipY )
306{
307}
308
309
311{
312 BOX2I tmp;
313
315 return tmp;
316
317 // this is an edit-time artefact; no reason to try and be smart with the bounding box
318 // (besides, we can't tell the text extents without a view to know what the scale is)
319 tmp.SetMaximum();
320 return tmp;
321}
322
323
324void RULER_ITEM::ViewGetLayers( int aLayers[], int& aCount ) const
325{
326 aLayers[0] = LAYER_SELECT_OVERLAY;
327 aLayers[1] = LAYER_GP_OVERLAY;
328 aCount = 2;
329}
330
331
332void RULER_ITEM::ViewDraw( int aLayer, KIGFX::VIEW* aView ) const
333{
334 KIGFX::GAL* gal = aView->GetGAL();
335 RENDER_SETTINGS* rs = aView->GetPainter()->GetSettings();
336 bool drawingDropShadows = ( aLayer == getShadowLayer( gal ) );
337
338 gal->PushDepth();
339 gal->SetLayerDepth( gal->GetMinDepth() );
340
341 VECTOR2D origin = m_geomMgr.GetOrigin();
342 VECTOR2D end = m_geomMgr.GetEnd();
343
344 gal->SetIsStroke( true );
345 gal->SetIsFill( false );
346
347 gal->SetTextMirrored( false );
349
350 if( drawingDropShadows )
352
353 gal->ResetTextAttributes();
354 TEXT_DIMS textDims = GetConstantGlyphHeight( gal );
355
356 // draw the main line from the origin to cursor
357 gal->SetLineWidth( getTickLineWidth( textDims, drawingDropShadows ) );
358 gal->DrawLine( origin, end );
359
360 VECTOR2D rulerVec( end - origin );
361
362 drawCursorStrings( aView, end, rulerVec, m_iuScale, m_userUnits, drawingDropShadows, m_flipX,
363 m_flipY );
364
365 // basic tick size
366 const double minorTickLen = 5.0 / gal->GetWorldScale();
367 const double majorTickLen = minorTickLen * majorTickLengthFactor;
368
369 drawTicksAlongLine( aView, origin, rulerVec, minorTickLen, m_iuScale, m_userUnits, drawingDropShadows );
370
371 drawBacksideTicks( aView, origin, rulerVec, majorTickLen, 2, drawingDropShadows );
372
373 // draw the back of the origin "crosshair"
374 gal->DrawLine( origin, origin + rulerVec.Resize( -minorTickLen * midTickLengthFactor ) );
375 gal->PopDepth();
376}
const Vec & GetPosition() const
Definition: box2.h:185
void SetMaximum()
Definition: box2.h:64
bool Contains(const Vec &aPoint) const
Definition: box2.h:142
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:507
const Vec & GetSize() const
Definition: box2.h:180
double Sin() const
Definition: eda_angle.h:212
double AsDegrees() const
Definition: eda_angle.h:155
double Cos() const
Definition: eda_angle.h:227
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:88
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)
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:257
static const METRICS & Default()
Definition: font.cpp:52
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 PushDepth()
Store current drawing depth on the depth stack.
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
void PopDepth()
Restore previously stored drawing depth for the depth stack.
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.
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:298
const TWO_POINT_GEOMETRY_MANAGER & m_geomMgr
Definition: ruler_item.h:86
void ViewGetLayers(int aLayers[], int &aCount) const override
Definition: ruler_item.cpp:324
void ViewDraw(int aLayer, KIGFX::VIEW *aView) const override final
Draw the parts of the object belonging to layer aLayer.
Definition: ruler_item.cpp:332
const BOX2I ViewBBox() const override
Return the all the layers within the VIEW the object is painted on.
Definition: ruler_item.cpp:310
const EDA_IU_SCALE & m_iuScale
Definition: ruler_item.h:88
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:68
BOX2D GetViewport() const
Return the current viewport visible area rectangle.
Definition: view.cpp:512
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:197
bool IsMirroredX() const
Return true if view is flipped across the X axis.
Definition: view.h:245
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:215
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:265
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
Definition: vector2d.h:350
static constexpr EDA_ANGLE ANGLE_0
Definition: eda_angle.h:435
static constexpr EDA_ANGLE ANGLE_90
Definition: eda_angle.h:437
static constexpr EDA_ANGLE ANGLE_180
Definition: eda_angle.h:439
EDA_UNITS
Definition: eda_units.h:46
@ LAYER_GP_OVERLAY
general purpose overlay
Definition: layer_ids.h:222
@ LAYER_AUX_ITEMS
Auxiliary items (guides, rule, etc)
Definition: layer_ids.h:226
@ LAYER_SELECT_OVERLAY
currently selected items overlay
Definition: layer_ids.h:223
KICOMMON_API bool IsImperialUnit(EDA_UNITS aUnit)
Definition: eda_units.cpp:47
COLOR4D GetShadowColor(const COLOR4D &aColor)
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...
void DrawTextNextToCursor(KIGFX::VIEW *aView, const VECTOR2D &aCursorPos, const VECTOR2D &aTextQuadrant, const std::vector< wxString > &aStrings, bool aDrawingDropShadows)
Draw strings next to the cursor.
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:84
static const double maxTickDensity
Definition: ruler_item.cpp:34
static TICK_FORMAT getTickFormatForScale(double aScale, double &aTickSpace, EDA_UNITS aUnits)
Definition: ruler_item.cpp:107
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:267
void drawTicksAlongLine(KIGFX::VIEW *aView, const VECTOR2D &aOrigin, const VECTOR2D &aLine, double aMinorTickLen, const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, bool aDrawingDropShadows)
Draw labelled ticks on a line.
Definition: ruler_item.cpp:150
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
static void drawCursorStrings(KIGFX::VIEW *aView, const VECTOR2D &aCursor, const VECTOR2D &aRulerVec, const EDA_IU_SCALE &aIuScale, EDA_UNITS aUnits, bool aDrawingDropShadows, bool aFlipX, bool aFlipY)
Definition: ruler_item.cpp:55
Description of a "tick format" for a scale factor - how many ticks there are between medium/major tic...
Definition: ruler_item.cpp:100
int majorStep
ticks between major ticks
Definition: ruler_item.cpp:102
double divisionBase
multiple from the last scale
Definition: ruler_item.cpp:101
int midStep
ticks between medium ticks (0 if no medium ticks)
Definition: ruler_item.cpp:103
@ 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:228
@ NOT_USED
the 3d code uses this value
Definition: typeinfo.h:79
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588