KiCad PCB EDA Suite
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-2021 Kicad Developers, see change_log.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 <painter.h>
29 #include <view/view.h>
30 #include <trigo.h>
31 
32 using namespace KIGFX::PREVIEW;
33 
34 static const double maxTickDensity = 10.0; // min pixels between tick marks
35 static const double midTickLengthFactor = 1.5;
36 static 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  */
46 static int getShadowLayer( KIGFX::GAL* aGal )
47 {
48  if( aGal->IsCairoEngine() )
49  return LAYER_SELECT_OVERLAY;
50  else
51  return LAYER_GP_OVERLAY;
52 }
53 
54 
55 static void drawCursorStrings( KIGFX::VIEW* aView, const VECTOR2D& aCursor,
56  const VECTOR2D& aRulerVec, 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( wxT( "x" ), temp.x, aUnits ) );
71  cursorStrings.push_back( DimensionLabel( wxT( "y" ), temp.y, aUnits ) );
72 
73  cursorStrings.push_back( DimensionLabel( wxT( "r" ), aRulerVec.EuclideanNorm(), aUnits ) );
74 
75  double degs = RAD2DECIDEG( -aRulerVec.Angle() );
76  cursorStrings.push_back( DimensionLabel( wxString::FromUTF8( "θ" ), degs,
78 
79  temp = aRulerVec;
80  DrawTextNextToCursor( aView, aCursor, -temp, cursorStrings, aDrawingDropShadows );
81 }
82 
83 
84 static 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 {
101  double divisionBase;
102  int majorStep;
103  int midStep;
104 };
105 
106 
107 static 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 
150 void drawTicksAlongLine( KIGFX::VIEW* aView, const VECTOR2D& aOrigin, const VECTOR2D& aLine,
151  double aMinorTickLen, EDA_UNITS aUnits, bool aDrawingDropShadows )
152 {
153  KIGFX::GAL* gal = aView->GetGAL();
154  VECTOR2D tickLine = aLine.Rotate( -M_PI_2 );
155  double tickSpace;
156  TICK_FORMAT tickF = getTickFormatForScale( gal->GetWorldScale(), tickSpace, aUnits );
157 
158  // number of ticks in whole ruler
159  int numTicks = (int) std::ceil( aLine.EuclideanNorm() / tickSpace );
160 
161  // work out which way up the tick labels go
162  TEXT_DIMS textDims = SetConstantGlyphHeight( gal, -1 );
163  double textThickness = textDims.StrokeWidth;
164  double labelAngle = -tickLine.Angle();
165  double textOffset = 0;
166 
167  if( aDrawingDropShadows )
168  {
169  textOffset = textDims.ShadowWidth;
170  textThickness += 2 * textDims.ShadowWidth;
171  }
172 
173  double majorTickLen = aMinorTickLen * ( majorTickLengthFactor + 1 );
174  VECTOR2D labelOffset = tickLine.Resize( majorTickLen - textOffset );
175 
176  if( aView->IsMirroredX() )
177  {
178  textOffset = -textOffset;
179  labelOffset = -labelOffset;
180  }
181 
182  if( aLine.Angle() > 0 )
183  {
185  }
186  else
187  {
189  labelAngle += M_PI;
190  }
191 
192  BOX2D viewportD = aView->GetViewport();
193  BOX2I viewport( VECTOR2I( viewportD.GetPosition() ), VECTOR2I( viewportD.GetSize() ) );
194 
195  viewport.Inflate( majorTickLen * 2 ); // Doesn't have to be accurate, just big enough not
196  // to exclude anything that should be partially drawn
197 
198  for( int i = 0; i < numTicks; ++i )
199  {
200  const VECTOR2D tickPos = aOrigin + aLine.Resize( tickSpace * i );
201 
202  if( !viewport.Contains( tickPos ) )
203  continue;
204 
205  double length = aMinorTickLen;
206  bool drawLabel = false;
207 
208  if( i % tickF.majorStep == 0 )
209  {
210  drawLabel = true;
211  length *= majorTickLengthFactor;
212  }
213  else if( tickF.midStep && i % tickF.midStep == 0 )
214  {
215  drawLabel = true;
216  length *= midTickLengthFactor;
217  }
218 
219  gal->SetLineWidth( textThickness / 2 );
220  gal->DrawLine( tickPos, tickPos + tickLine.Resize( length ) );
221 
222  if( drawLabel )
223  {
224  wxString label = DimensionLabel( wxEmptyString, tickSpace * i, aUnits, false );
225  gal->SetLineWidth( textThickness );
226  gal->StrokeText( label, tickPos + labelOffset, labelAngle );
227  }
228  }
229 }
230 
231 
242 void drawBacksideTicks( KIGFX::VIEW* aView, const VECTOR2D& aOrigin, const VECTOR2D& aLine,
243  double aTickLen, int aNumDivisions, bool aDrawingDropShadows )
244 {
245  KIGFX::GAL* gal = aView->GetGAL();
246  const double backTickSpace = aLine.EuclideanNorm() / aNumDivisions;
247  const VECTOR2D backTickVec = aLine.Rotate( M_PI_2 ).Resize( aTickLen );
248  TEXT_DIMS textDims = SetConstantGlyphHeight( gal, -1 );
249 
250  BOX2D viewportD = aView->GetViewport();
251  BOX2I viewport( VECTOR2I( viewportD.GetPosition() ), VECTOR2I( viewportD.GetSize() ) );
252 
253  viewport.Inflate( aTickLen * 4 ); // Doesn't have to be accurate, just big enough not to
254  // exclude anything that should be partially drawn
255 
256  for( int i = 0; i < aNumDivisions + 1; ++i )
257  {
258  const VECTOR2D backTickPos = aOrigin + aLine.Resize( backTickSpace * i );
259 
260  if( !viewport.Contains( backTickPos ) )
261  continue;
262 
263  gal->SetLineWidth( getTickLineWidth( textDims, aDrawingDropShadows ) );
264  gal->DrawLine( backTickPos, backTickPos + backTickVec );
265  }
266 }
267 
268 
270  bool aFlipX, bool aFlipY )
271  : EDA_ITEM( NOT_USED ), // Never added to anything - just a preview
272  m_geomMgr( aGeomMgr ),
273  m_userUnits( userUnits ),
274  m_flipX( aFlipX ),
275  m_flipY( aFlipY )
276 {
277 }
278 
279 
281 {
282  BOX2I tmp;
283 
284  if( m_geomMgr.GetOrigin() == m_geomMgr.GetEnd() )
285  return tmp;
286 
287  // this is an edit-time artefact; no reason to try and be smart with the bounding box
288  // (besides, we can't tell the text extents without a view to know what the scale is)
289  tmp.SetMaximum();
290  return tmp;
291 }
292 
293 
294 void RULER_ITEM::ViewGetLayers( int aLayers[], int& aCount ) const
295 {
296  aLayers[0] = LAYER_SELECT_OVERLAY;
297  aLayers[1] = LAYER_GP_OVERLAY;
298  aCount = 2;
299 }
300 
301 
302 void RULER_ITEM::ViewDraw( int aLayer, KIGFX::VIEW* aView ) const
303 {
304  KIGFX::GAL* gal = aView->GetGAL();
305  RENDER_SETTINGS* rs = aView->GetPainter()->GetSettings();
306  bool drawingDropShadows = ( aLayer == getShadowLayer( gal ) );
307 
308  gal->PushDepth();
309  gal->SetLayerDepth( gal->GetMinDepth() );
310 
311  VECTOR2D origin = m_geomMgr.GetOrigin();
312  VECTOR2D end = m_geomMgr.GetEnd();
313 
314  gal->SetIsStroke( true );
315  gal->SetIsFill( false );
316 
317  gal->SetTextMirrored( false );
319 
320  if( drawingDropShadows )
321  gal->SetStrokeColor( GetShadowColor( gal->GetStrokeColor() ) );
322 
323  gal->ResetTextAttributes();
324  TEXT_DIMS textDims = SetConstantGlyphHeight( gal );
325 
326  // draw the main line from the origin to cursor
327  gal->SetLineWidth( getTickLineWidth( textDims, drawingDropShadows ) );
328  gal->DrawLine( origin, end );
329 
330  VECTOR2D rulerVec( end - origin );
331 
332  drawCursorStrings( aView, end, rulerVec, m_userUnits, drawingDropShadows, m_flipX, m_flipY );
333 
334  // basic tick size
335  const double minorTickLen = 5.0 / gal->GetWorldScale();
336  const double majorTickLen = minorTickLen * majorTickLengthFactor;
337 
338  drawTicksAlongLine( aView, origin, rulerVec, minorTickLen, m_userUnits, drawingDropShadows );
339 
340  drawBacksideTicks( aView, origin, rulerVec, majorTickLen, 2, drawingDropShadows );
341 
342  // draw the back of the origin "crosshair"
343  gal->DrawLine( origin, origin + rulerVec.Resize( -minorTickLen * midTickLengthFactor ) );
344  gal->PopDepth();
345 }
double GetMinDepth() const
Return the minimum depth in the currently used range (the top).
currently selected items overlay
Definition: layer_ids.h:226
const BOX2I ViewBBox() const override
Return the all the layers within the VIEW the object is painted on.
Definition: ruler_item.cpp:280
BOX2D GetViewport() const
Return the current viewport visible area rectangle.
Definition: view.cpp:512
Auxiliary items (guides, rule, etc)
Definition: layer_ids.h:229
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
TEXT_DIMS SetConstantGlyphHeight(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.
Represent a very simple geometry manager for items that have a start and end point.
the 3d code uses this value
Definition: typeinfo.h:79
#define M_PI_2
Definition: transline.cpp:40
const COLOR4D & GetLayerColor(int aLayer) const
Return the color used to draw a layer.
double RAD2DECIDEG(double rad)
Definition: trigo.h:234
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:190
int midStep
ticks between medium ticks (0 if no medium ticks)
Definition: ruler_item.cpp:103
double divisionBase
multiple from the last scale
Definition: ruler_item.cpp:101
virtual void DrawLine(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint)
Draw a line.
VECTOR2< int > VECTOR2I
Definition: vector2d.h:622
wxString DimensionLabel(const wxString &prefix, double aVal, EDA_UNITS aUnits, bool aIncludeUnits=true)
Get a formatted string showing a dimension to a sane precision with an optional prefix and unit suffi...
virtual void SetLayerDepth(double aLayerDepth)
Set the depth of the layer (position on the z-axis)
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:208
const TWO_POINT_GEOMETRY_MANAGER & m_geomMgr
Definition: ruler_item.h:86
bool IsImperialUnit(EDA_UNITS aUnit)
Definition: eda_units.cpp:26
virtual void SetLineWidth(float aLineWidth)
Set the line width.
static const double majorTickLengthFactor
Definition: ruler_item.cpp:36
static double getTickLineWidth(const TEXT_DIMS &textDims, bool aDrawingDropShadows)
Definition: ruler_item.cpp:84
static void drawCursorStrings(KIGFX::VIEW *aView, const VECTOR2D &aCursor, const VECTOR2D &aRulerVec, EDA_UNITS aUnits, bool aDrawingDropShadows, bool aFlipX, bool aFlipY)
Definition: ruler_item.cpp:55
const COLOR4D & GetStrokeColor() const
Get the stroke color.
void ResetTextAttributes()
Reset text attributes to default styling.
virtual void SetIsFill(bool aIsFillEnabled)
Enable/disable fill.
void PopDepth()
Restore previously stored drawing depth for the depth stack.
virtual void StrokeText(const wxString &aText, const VECTOR2D &aPosition, double aRotationAngle)
Draw a vector type text using preloaded Newstroke font.
bool Contains(const Vec &aPoint) const
Definition: box2.h:134
void SetMaximum()
Definition: box2.h:57
virtual bool IsCairoEngine()
Return true if the GAL engine is a Cairo based type.
static const double midTickLengthFactor
Definition: ruler_item.cpp:35
double Angle() const
Compute the angle of the vector.
Definition: vector2d.h:307
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:242
RULER_ITEM(const TWO_POINT_GEOMETRY_MANAGER &m_geomMgr, EDA_UNITS userUnits, bool aFlipX, bool aFlipY)
Return the bounding box of the item covering all its layers.
Definition: ruler_item.cpp:269
bool IsMirroredX() const
Return true if view is flipped across the X axis.
Definition: view.h:238
const Vec & GetPosition() const
Definition: box2.h:177
EDA_UNITS
Definition: eda_units.h:38
void SetTextMirrored(bool aMirrored)
Set a mirrored property of text.
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
Definition: vector2d.h:404
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
virtual void SetStrokeColor(const COLOR4D &aColor)
Set the stroke color.
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:281
VECTOR2< T > Rotate(double aAngle) const
Rotate the vector by a given angle.
Definition: vector2d.h:371
void ViewGetLayers(int aLayers[], int &aCount) const override
Definition: ruler_item.cpp:294
void PushDepth()
Store current drawing depth on the depth stack.
general purpose overlay
Definition: layer_ids.h:225
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:99
Description of a "tick format" for a scale factor - how many ticks there are between medium/major tic...
Definition: ruler_item.cpp:99
static TICK_FORMAT getTickFormatForScale(double aScale, double &aTickSpace, EDA_UNITS aUnits)
Definition: ruler_item.cpp:107
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition: vector2d.h:293
const Vec & GetSize() const
Definition: box2.h:172
void SetHorizontalJustify(const EDA_TEXT_HJUSTIFY_T aHorizontalJustify)
Set the horizontal justify for text drawing.
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:68
static const double maxTickDensity
Definition: ruler_item.cpp:34
static int getShadowLayer(KIGFX::GAL *aGal)
Definition: ruler_item.cpp:46
int majorStep
ticks between major ticks
Definition: ruler_item.cpp:102
double GetWorldScale() const
Get the world scale.
void ViewDraw(int aLayer, KIGFX::VIEW *aView) const override final
Draw the parts of the object belonging to layer aLayer.
Definition: ruler_item.cpp:302
virtual void SetIsStroke(bool aIsStrokeEnabled)
Enable/disable stroked outlines.
void DrawTextNextToCursor(KIGFX::VIEW *aView, const VECTOR2D &aCursorPos, const VECTOR2D &aTextQuadrant, const std::vector< wxString > &aStrings, bool aDrawingDropShadows)
Draw strings next to the cursor.
void drawTicksAlongLine(KIGFX::VIEW *aView, const VECTOR2D &aOrigin, const VECTOR2D &aLine, double aMinorTickLen, EDA_UNITS aUnits, bool aDrawingDropShadows)
Draw labelled ticks on a line.
Definition: ruler_item.cpp:150
Abstract interface for drawing on a 2D-surface.
COLOR4D GetShadowColor(const COLOR4D &aColor)