@@ -39,6 +39,9 @@ QgsComposerScaleBar::QgsComposerScaleBar( QgsComposition* composition )
3939 : QgsComposerItem( composition )
4040 , mComposerMap( 0 )
4141 , mNumUnitsPerSegment( 0 )
42+ , mSegmentSizeMode( SegmentSizeFixed )
43+ , mMinBarWidth( 50 )
44+ , mMaxBarWidth( 150 )
4245 , mFontColor( QColor( 0 , 0 , 0 ) )
4346 , mStyle( 0 )
4447 , mSegmentMillimeters( 0.0 )
@@ -114,6 +117,51 @@ void QgsComposerScaleBar::setNumUnitsPerSegment( double units )
114117 emit itemChanged ();
115118}
116119
120+ void QgsComposerScaleBar::setSegmentSizeMode ( SegmentSizeMode mode )
121+ {
122+ if ( !mStyle )
123+ {
124+ mSegmentSizeMode = mode;
125+ return ;
126+ }
127+ double width = mStyle ->calculateBoxSize ().width ();
128+ mSegmentSizeMode = mode;
129+ refreshSegmentMillimeters ();
130+ double widthAfter = mStyle ->calculateBoxSize ().width ();
131+ correctXPositionAlignment ( width, widthAfter );
132+ emit itemChanged ();
133+ }
134+
135+ void QgsComposerScaleBar::setMinBarWidth ( double minWidth )
136+ {
137+ if ( !mStyle )
138+ {
139+ mMinBarWidth = minWidth;
140+ return ;
141+ }
142+ double width = mStyle ->calculateBoxSize ().width ();
143+ mMinBarWidth = minWidth;
144+ refreshSegmentMillimeters ();
145+ double widthAfter = mStyle ->calculateBoxSize ().width ();
146+ correctXPositionAlignment ( width, widthAfter );
147+ emit itemChanged ();
148+ }
149+
150+ void QgsComposerScaleBar::setMaxBarWidth ( double maxWidth )
151+ {
152+ if ( !mStyle )
153+ {
154+ mMaxBarWidth = maxWidth;
155+ return ;
156+ }
157+ double width = mStyle ->calculateBoxSize ().width ();
158+ mMaxBarWidth = maxWidth;
159+ refreshSegmentMillimeters ();
160+ double widthAfter = mStyle ->calculateBoxSize ().width ();
161+ correctXPositionAlignment ( width, widthAfter );
162+ emit itemChanged ();
163+ }
164+
117165void QgsComposerScaleBar::setNumSegmentsLeft ( int nSegmentsLeft )
118166{
119167 if ( !mStyle )
@@ -175,18 +223,65 @@ void QgsComposerScaleBar::invalidateCurrentMap()
175223 mComposerMap = 0 ;
176224}
177225
226+ // nextNiceNumber(4573.23, d) = 5000 (d=1) -> 4600 (d=10) -> 4580 (d=100) -> 4574 (d=1000) -> etc
227+ inline double nextNiceNumber ( double a, double d = 1 )
228+ {
229+ double s = pow10 ( floor ( log10 ( a ) ) ) / d;
230+ return ceil ( a / s ) * s;
231+ }
232+
233+ // prevNiceNumber(4573.23, d) = 4000 (d=1) -> 4500 (d=10) -> 4570 (d=100) -> 4573 (d=1000) -> etc
234+ inline double prevNiceNumber ( double a, double d = 1 )
235+ {
236+ double s = pow10 ( floor ( log10 ( a ) ) ) / d;
237+ return floor ( a / s ) * s;
238+ }
239+
178240void QgsComposerScaleBar::refreshSegmentMillimeters ()
179241{
180242 if ( mComposerMap )
181243 {
182- // get extent of composer map
183- QgsRectangle composerMapRect = *( mComposerMap ->currentMapExtent () );
184-
185244 // get mm dimension of composer map
186245 QRectF composerItemRect = mComposerMap ->rect ();
187246
188- // calculate size depending on mNumUnitsPerSegment
189- mSegmentMillimeters = composerItemRect.width () / mapWidth () * mNumUnitsPerSegment ;
247+ if ( mSegmentSizeMode == SegmentSizeFixed )
248+ {
249+ // calculate size depending on mNumUnitsPerSegment
250+ mSegmentMillimeters = composerItemRect.width () / mapWidth () * mNumUnitsPerSegment ;
251+ }
252+ else /* if(mSegmentSizeMode == SegmentSizeFitWidth)*/
253+ {
254+ if ( mMaxBarWidth < mMinBarWidth )
255+ {
256+ mSegmentMillimeters = 0 ;
257+ }
258+ else
259+ {
260+ double nSegments = ( mNumSegmentsLeft != 0 ) + mNumSegments ;
261+ // unitsPerSegments which fit minBarWidth resp. maxBarWidth
262+ double minUnitsPerSeg = ( mMinBarWidth * mapWidth () ) / ( nSegments * composerItemRect.width () );
263+ double maxUnitsPerSeg = ( mMaxBarWidth * mapWidth () ) / ( nSegments * composerItemRect.width () );
264+
265+ // Start with coarsest "nice" number closest to minUnitsPerSeg resp
266+ // maxUnitsPerSeg, then proceed to finer numbers as long as neither
267+ // lowerNiceUnitsPerSeg nor upperNiceUnitsPerSeg are are in
268+ // [minUnitsPerSeg, maxUnitsPerSeg]
269+ double lowerNiceUnitsPerSeg = nextNiceNumber ( minUnitsPerSeg );
270+ double upperNiceUnitsPerSeg = prevNiceNumber ( maxUnitsPerSeg );
271+
272+ double d = 1 ;
273+ while ( lowerNiceUnitsPerSeg > maxUnitsPerSeg && upperNiceUnitsPerSeg < minUnitsPerSeg )
274+ {
275+ d *= 10 ;
276+ lowerNiceUnitsPerSeg = nextNiceNumber ( minUnitsPerSeg, d );
277+ upperNiceUnitsPerSeg = prevNiceNumber ( maxUnitsPerSeg, d );
278+ }
279+
280+ // Pick mNumUnitsPerSegment from {lowerNiceUnitsPerSeg, upperNiceUnitsPerSeg}, use the larger if possible
281+ mNumUnitsPerSegment = upperNiceUnitsPerSeg < minUnitsPerSeg ? lowerNiceUnitsPerSeg : upperNiceUnitsPerSeg;
282+ mSegmentMillimeters = composerItemRect.width () / mapWidth () * mNumUnitsPerSegment ;
283+ }
284+ }
190285 }
191286}
192287
@@ -568,6 +663,9 @@ bool QgsComposerScaleBar::writeXML( QDomElement& elem, QDomDocument & doc ) cons
568663 composerScaleBarElem.setAttribute ( " numSegments" , mNumSegments );
569664 composerScaleBarElem.setAttribute ( " numSegmentsLeft" , mNumSegmentsLeft );
570665 composerScaleBarElem.setAttribute ( " numUnitsPerSegment" , QString::number ( mNumUnitsPerSegment ) );
666+ composerScaleBarElem.setAttribute ( " segmentSizeMode" , mSegmentSizeMode );
667+ composerScaleBarElem.setAttribute ( " minBarWidth" , mMinBarWidth );
668+ composerScaleBarElem.setAttribute ( " maxBarWidth" , mMaxBarWidth );
571669 composerScaleBarElem.setAttribute ( " segmentMillimeters" , QString::number ( mSegmentMillimeters ) );
572670 composerScaleBarElem.setAttribute ( " numMapUnitsPerScaleBarUnit" , QString::number ( mNumMapUnitsPerScaleBarUnit ) );
573671 composerScaleBarElem.setAttribute ( " font" , mFont .toString () );
@@ -646,6 +744,9 @@ bool QgsComposerScaleBar::readXML( const QDomElement& itemElem, const QDomDocume
646744 mNumSegments = itemElem.attribute ( " numSegments" , " 2" ).toInt ();
647745 mNumSegmentsLeft = itemElem.attribute ( " numSegmentsLeft" , " 0" ).toInt ();
648746 mNumUnitsPerSegment = itemElem.attribute ( " numUnitsPerSegment" , " 1.0" ).toDouble ();
747+ mSegmentSizeMode = static_cast <SegmentSizeMode>( itemElem.attribute ( " segmentSizeMode" , " 0" ).toInt () );
748+ mMinBarWidth = itemElem.attribute ( " minBarWidth" , " 50" ).toInt ();
749+ mMaxBarWidth = itemElem.attribute ( " maxBarWidth" , " 150" ).toInt ();
649750 mSegmentMillimeters = itemElem.attribute ( " segmentMillimeters" , " 0.0" ).toDouble ();
650751 mNumMapUnitsPerScaleBarUnit = itemElem.attribute ( " numMapUnitsPerScaleBarUnit" , " 1.0" ).toDouble ();
651752 mPen .setWidthF ( itemElem.attribute ( " outlineWidth" , " 1.0" ).toDouble () );
0 commit comments