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 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 
25 
29 #include <painter.h>
30 #include <view/view.h>
31 #include <trigo.h>
32 
33 #include <common.h>
34 
35 using namespace KIGFX::PREVIEW;
36 
37 static const double maxTickDensity = 10.0; // min pixels between tick marks
38 static const double midTickLengthFactor = 1.5;
39 static const double majorTickLengthFactor = 2.5;
40 
41 
42 /*
43  * It would be nice to know why Cairo seems to have an opposite layer order from GAL, but
44  * only when drawing RULER_ITEMs (the TWO_POINT_ASSISTANT and ARC_ASSISTANT are immune from
45  * this issue).
46  *
47  * Until then, this egregious hack...
48  */
49 static int getShadowLayer( KIGFX::GAL* aGal )
50 {
51  if( aGal->IsCairoEngine() )
52  return LAYER_SELECT_OVERLAY;
53  else
54  return LAYER_GP_OVERLAY;
55 }
56 
57 
58 static void drawCursorStrings( KIGFX::VIEW* aView, const VECTOR2D& aCursor,
59  const VECTOR2D& aRulerVec, EDA_UNITS aUnits,
60  bool aDrawingDropShadows )
61 {
62  // draw the cursor labels
63  std::vector<wxString> cursorStrings;
64 
65  cursorStrings.push_back( DimensionLabel( "x", aRulerVec.x, aUnits ) );
66  cursorStrings.push_back( DimensionLabel( "y", aRulerVec.y, aUnits ) );
67 
68  cursorStrings.push_back( DimensionLabel( "r", aRulerVec.EuclideanNorm(), aUnits ) );
69 
70  double degs = RAD2DECIDEG( -aRulerVec.Angle() );
71  cursorStrings.push_back( DimensionLabel( wxString::FromUTF8( "θ" ), degs,
73 
74  auto temp = aRulerVec;
75  DrawTextNextToCursor( aView, aCursor, -temp, cursorStrings, aDrawingDropShadows );
76 }
77 
78 
79 static double getTickLineWidth( const TEXT_DIMS& textDims, bool aDrawingDropShadows )
80 {
81  double width = textDims.StrokeWidth * 0.8;
82 
83  if( aDrawingDropShadows )
84  width += textDims.ShadowWidth;
85 
86  return width;
87 }
88 
89 
95 {
96  double divisionBase;
97  int majorStep;
98  int midStep;
99 };
100 
101 
102 static TICK_FORMAT getTickFormatForScale( double aScale, double& aTickSpace, EDA_UNITS aUnits )
103 {
104  // simple 1/2/5 scales per decade
105  static std::vector<TICK_FORMAT> tickFormats =
106  {
107  { 2, 10, 5 }, // |....:....|
108  { 2, 5, 0 }, // |....|
109  { 2.5, 2, 0 }, // |.|.|
110  };
111 
112  // could start at a set number of MM, but that's not available in common
113  aTickSpace = 1;
114 
115  // convert to a round (mod-10) number of mils
116  if( aUnits == EDA_UNITS::INCHES )
117  {
118  aTickSpace *= 2.54;
119  }
120 
121  int tickFormat = 0;
122 
123  while( true )
124  {
125  const auto pixelSpace = aTickSpace * aScale;
126 
127  if( pixelSpace >= maxTickDensity )
128  break;
129 
130  tickFormat = ( tickFormat + 1 ) % tickFormats.size();
131  aTickSpace *= tickFormats[tickFormat].divisionBase;
132  }
133 
134  return tickFormats[tickFormat];
135 }
136 
137 
147 void drawTicksAlongLine( KIGFX::GAL* aGal, const VECTOR2D& aOrigin, const VECTOR2D& aLine,
148  double aMinorTickLen, EDA_UNITS aUnits, bool aDrawingDropShadows )
149 {
150  VECTOR2D tickLine = aLine.Rotate( -M_PI_2 );
151  double tickSpace;
152  TICK_FORMAT tickF = getTickFormatForScale( aGal->GetWorldScale(), tickSpace, aUnits );
153 
154  // number of ticks in whole ruler
155  int numTicks = (int) std::ceil( aLine.EuclideanNorm() / tickSpace );
156 
157  // work out which way up the tick labels go
158  TEXT_DIMS textDims = SetConstantGlyphHeight( aGal, -1 );
159  double textThickness = textDims.StrokeWidth;
160  double labelAngle = -tickLine.Angle();
161  double textOffset = 0;
162 
163  if( aDrawingDropShadows )
164  {
165  textOffset = textDims.ShadowWidth;
166  textThickness += 2 * textDims.ShadowWidth;
167  }
168 
169  double majorTickLen = aMinorTickLen * ( majorTickLengthFactor + 1 );
170  VECTOR2D labelOffset = tickLine.Resize( majorTickLen - textOffset );
171 
172  if( aLine.Angle() > 0 )
173  {
175  }
176  else
177  {
179  labelAngle += M_PI;
180  }
181 
182  for( int i = 0; i < numTicks; ++i )
183  {
184  const auto tickPos = aOrigin + aLine.Resize( tickSpace * i );
185 
186  double length = aMinorTickLen;
187  bool drawLabel = false;
188 
189  if( i % tickF.majorStep == 0 )
190  {
191  drawLabel = true;
192  length *= majorTickLengthFactor;
193  }
194  else if( tickF.midStep && i % tickF.midStep == 0 )
195  {
196  drawLabel = true;
197  length *= midTickLengthFactor;
198  }
199 
200  aGal->SetLineWidth( textThickness / 2 );
201  aGal->DrawLine( tickPos, tickPos + tickLine.Resize( length ) );
202 
203  if( drawLabel )
204  {
205  wxString label = DimensionLabel( "", tickSpace * i, aUnits, false );
206  aGal->SetLineWidth( textThickness );
207  aGal->StrokeText( label, tickPos + labelOffset, labelAngle );
208  }
209  }
210 }
211 
212 
223 void drawBacksideTicks( KIGFX::GAL* aGal, const VECTOR2D& aOrigin, const VECTOR2D& aLine,
224  double aTickLen, int aNumDivisions, bool aDrawingDropShadows )
225 {
226  const double backTickSpace = aLine.EuclideanNorm() / aNumDivisions;
227  const VECTOR2D backTickVec = aLine.Rotate( M_PI_2 ).Resize( aTickLen );
228  TEXT_DIMS textDims = SetConstantGlyphHeight( aGal, -1 );
229 
230  for( int i = 0; i < aNumDivisions + 1; ++i )
231  {
232  const VECTOR2D backTickPos = aOrigin + aLine.Resize( backTickSpace * i );
233  aGal->SetLineWidth( getTickLineWidth( textDims, aDrawingDropShadows ) );
234  aGal->DrawLine( backTickPos, backTickPos + backTickVec );
235  }
236 }
237 
238 
240  : EDA_ITEM( NOT_USED ), // Never added to anything - just a preview
241  m_geomMgr( aGeomMgr ),
242  m_userUnits( userUnits )
243 {
244 }
245 
246 
248 {
249  BOX2I tmp;
250 
251  if( m_geomMgr.GetOrigin() == m_geomMgr.GetEnd() )
252  return tmp;
253 
254  // this is an edit-time artefact; no reason to try and be smart with the bounding box
255  // (besides, we can't tell the text extents without a view to know what the scale is)
256  tmp.SetMaximum();
257  return tmp;
258 }
259 
260 
261 void RULER_ITEM::ViewGetLayers( int aLayers[], int& aCount ) const
262 {
263  aLayers[0] = LAYER_SELECT_OVERLAY;
264  aLayers[1] = LAYER_GP_OVERLAY;
265  aCount = 2;
266 }
267 
268 
269 void RULER_ITEM::ViewDraw( int aLayer, KIGFX::VIEW* aView ) const
270 {
271  KIGFX::GAL* gal = aView->GetGAL();
272  RENDER_SETTINGS* rs = aView->GetPainter()->GetSettings();
273  bool drawingDropShadows = ( aLayer == getShadowLayer( gal ) );
274 
275  gal->PushDepth();
276  gal->SetLayerDepth( gal->GetMinDepth() );
277 
278  VECTOR2D origin = m_geomMgr.GetOrigin();
279  VECTOR2D end = m_geomMgr.GetEnd();
280 
281  gal->SetIsStroke( true );
282  gal->SetIsFill( false );
283 
284  gal->SetTextMirrored( false );
286 
287  if( drawingDropShadows )
288  gal->SetStrokeColor( GetShadowColor( gal->GetStrokeColor() ) );
289 
290  gal->ResetTextAttributes();
291  TEXT_DIMS textDims = SetConstantGlyphHeight( gal );
292 
293  // draw the main line from the origin to cursor
294  gal->SetLineWidth( getTickLineWidth( textDims, drawingDropShadows ) );
295  gal->DrawLine( origin, end );
296 
297  VECTOR2D rulerVec( end - origin );
298 
299  drawCursorStrings( aView, end, rulerVec, m_userUnits, drawingDropShadows );
300 
301  // basic tick size
302  const double minorTickLen = 5.0 / gal->GetWorldScale();
303  const double majorTickLen = minorTickLen * majorTickLengthFactor;
304 
305  drawTicksAlongLine( gal, origin, rulerVec, minorTickLen, m_userUnits, drawingDropShadows );
306 
307  drawBacksideTicks( gal, origin, rulerVec, majorTickLen, 2, drawingDropShadows );
308 
309  // draw the back of the origin "crosshair"
310  gal->DrawLine( origin, origin + rulerVec.Resize( -minorTickLen * midTickLengthFactor ) );
311  gal->PopDepth();
312 }
double GetMinDepth() const
Returns the minimum depth in the currently used range (the top).
const BOX2I ViewBBox() const override
Definition: ruler_item.cpp:247
RENDER_SETTINGS Contains all the knowledge about how graphical objects are drawn on any output surfac...
void drawBacksideTicks(KIGFX::GAL *aGal, 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:223
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.
the 3d code uses this value
Definition: typeinfo.h:80
#define M_PI_2
Definition: transline.cpp:37
const COLOR4D & GetLayerColor(int aLayer) const
Function GetLayerColor Returns the color used to draw a layer.
double RAD2DECIDEG(double rad)
Definition: trigo.h:225
GAL * GetGAL() const
Function GetGAL() Returns the GAL this view is using to draw graphical primitives.
Definition: view.h:182
int midStep
ticks between major ticks
Definition: ruler_item.cpp:98
double divisionBase
Definition: ruler_item.cpp:96
virtual void DrawLine(const VECTOR2D &aStartPoint, const VECTOR2D &aEndPoint)
Draw a line.
RULER_ITEM(const TWO_POINT_GEOMETRY_MANAGER &m_geomMgr, EDA_UNITS userUnits)
Definition: ruler_item.cpp:239
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
Function GetPainter() Returns the painter object used by the view for drawing VIEW_ITEMS.
Definition: view.h:201
const TWO_POINT_GEOMETRY_MANAGER & m_geomMgr
Definition: ruler_item.h:81
virtual void SetLineWidth(float aLineWidth)
Set the line width.
void drawTicksAlongLine(KIGFX::GAL *aGal, const VECTOR2D &aOrigin, const VECTOR2D &aLine, double aMinorTickLen, EDA_UNITS aUnits, bool aDrawingDropShadows)
Draw labelled ticks on a line.
Definition: ruler_item.cpp:147
static const double majorTickLengthFactor
Definition: ruler_item.cpp:39
COLOR4D GetShadowColor(COLOR4D aColor)
static double getTickLineWidth(const TEXT_DIMS &textDims, bool aDrawingDropShadows)
Definition: ruler_item.cpp:79
const COLOR4D & GetStrokeColor() const
Get the stroke color.
Auxiliary items (guides, rule, etc)
void ResetTextAttributes()
Reset text attributes to default styling.
virtual void SetIsFill(bool aIsFillEnabled)
Enable/disable fill.
void PopDepth()
Restores previously stored drawing depth for the depth stack.
virtual void StrokeText(const wxString &aText, const VECTOR2D &aPosition, double aRotationAngle)
Draws a vector type text using preloaded Newstroke font.
void SetMaximum()
Definition: box2.h:73
virtual bool IsCairoEngine()
Returns true if the GAL engine is a cairo based type.
static const double midTickLengthFactor
Definition: ruler_item.cpp:38
void SetTextMirrored(const bool aMirrored)
Set a mirrored property of text.
double Angle() const
Function Angle computes the angle of the vector.
Definition: vector2d.h:313
EDA_UNITS
Definition: eda_units.h:38
VECTOR2< T > Resize(T aNewLength) const
Function Resize returns a vector of the same direction, but length specified in aNewLength.
Definition: vector2d.h:392
virtual RENDER_SETTINGS * GetSettings()=0
Function GetAdapter Returns pointer to current settings that are going to be used when drawing items.
virtual void SetStrokeColor(const COLOR4D &aColor)
Set the stroke color.
VECTOR2< T > Rotate(double aAngle) const
Function Rotate rotates the vector by a given angle.
Definition: vector2d.h:377
void ViewGetLayers(int aLayers[], int &aCount) const override
Definition: ruler_item.cpp:261
void PushDepth()
Stores current drawing depth on the depth stack.
Board layer functions and definitions.
currently selected items overlay
EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boards.
Definition: eda_item.h:148
The common library.
Description of a "tick format" for a scale factor - how many ticks there are between medium/major tic...
Definition: ruler_item.cpp:94
static TICK_FORMAT getTickFormatForScale(double aScale, double &aTickSpace, EDA_UNITS aUnits)
Definition: ruler_item.cpp:102
T EuclideanNorm() const
Destructor.
Definition: vector2d.h:299
void SetHorizontalJustify(const EDA_TEXT_HJUSTIFY_T aHorizontalJustify)
Set the horizontal justify for text drawing.
VIEW.
Definition: view.h:63
static const double maxTickDensity
Definition: ruler_item.cpp:37
static int getShadowLayer(KIGFX::GAL *aGal)
Definition: ruler_item.cpp:49
int majorStep
multiple from the last scale
Definition: ruler_item.cpp:97
double GetWorldScale() const
Get the world scale.
void ViewDraw(int aLayer, KIGFX::VIEW *aView) const override final
Definition: ruler_item.cpp:269
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.
static void drawCursorStrings(KIGFX::VIEW *aView, const VECTOR2D &aCursor, const VECTOR2D &aRulerVec, EDA_UNITS aUnits, bool aDrawingDropShadows)
Definition: ruler_item.cpp:58
Class GAL is the abstract interface for drawing on a 2D-surface.