Skip to content

Commit 05dee08

Browse files
committedAug 9, 2012
Change vertical alignment
Use x-height for vertical offset rather than font-height/2
1 parent 487879d commit 05dee08

File tree

1 file changed

+297
-298
lines changed

1 file changed

+297
-298
lines changed
 

‎src/core/qgsdiagram.cpp

+297-298
Original file line numberDiff line numberDiff line change
@@ -1,298 +1,297 @@
1-
/***************************************************************************
2-
qgsdiagram.cpp
3-
---------------------
4-
begin : March 2011
5-
copyright : (C) 2011 by Marco Hugentobler
6-
email : marco dot hugentobler at sourcepole dot ch
7-
***************************************************************************
8-
* *
9-
* This program is free software; you can redistribute it and/or modify *
10-
* it under the terms of the GNU General Public License as published by *
11-
* the Free Software Foundation; either version 2 of the License, or *
12-
* (at your option) any later version. *
13-
* *
14-
***************************************************************************/
15-
#include "qgsdiagram.h"
16-
#include "qgsdiagramrendererv2.h"
17-
#include "qgsrendercontext.h"
18-
19-
#include <QPainter>
20-
21-
void QgsDiagram::setPenWidth( QPen& pen, const QgsDiagramSettings& s, const QgsRenderContext& c )
22-
{
23-
if ( s.sizeType == QgsDiagramSettings::MM )
24-
{
25-
pen.setWidthF( s.penWidth * c.scaleFactor() );
26-
}
27-
else
28-
{
29-
pen.setWidthF( s.penWidth / c.mapToPixel().mapUnitsPerPixel() );
30-
}
31-
}
32-
33-
QSizeF QgsDiagram::sizePainterUnits( const QSizeF& size, const QgsDiagramSettings& s, const QgsRenderContext& c )
34-
{
35-
Q_UNUSED( size );
36-
if ( s.sizeType == QgsDiagramSettings::MM )
37-
{
38-
return QSizeF( s.size.width() * c.scaleFactor(), s.size.height() * c.scaleFactor() );
39-
}
40-
else
41-
{
42-
return QSizeF( s.size.width() / c.mapToPixel().mapUnitsPerPixel(), s.size.height() / c.mapToPixel().mapUnitsPerPixel() );
43-
}
44-
}
45-
46-
QFont QgsDiagram::scaledFont( const QgsDiagramSettings& s, const QgsRenderContext& c )
47-
{
48-
QFont f = s.font;
49-
if ( s.sizeType == QgsDiagramSettings::MM )
50-
{
51-
f.setPixelSize( s.font.pointSizeF() * 0.376 * c.scaleFactor() );
52-
}
53-
else
54-
{
55-
f.setPixelSize( s.font.pointSizeF() / c.mapToPixel().mapUnitsPerPixel() );
56-
}
57-
58-
return f;
59-
}
60-
61-
QgsTextDiagram::QgsTextDiagram(): mOrientation( Vertical ), mShape( Circle )
62-
{
63-
mPen.setWidthF( 2.0 );
64-
mPen.setColor( QColor( 0, 0, 0 ) );
65-
mPen.setCapStyle( Qt::FlatCap );
66-
mBrush.setStyle( Qt::SolidPattern );
67-
}
68-
69-
QgsTextDiagram::~QgsTextDiagram()
70-
{
71-
}
72-
73-
void QgsTextDiagram::renderDiagram( const QgsAttributeMap& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position )
74-
{
75-
QPainter* p = c.painter();
76-
if ( !p )
77-
{
78-
return;
79-
}
80-
81-
double scaleDenominator = c.rendererScale();
82-
if (( s.minScaleDenominator != -1 && scaleDenominator < s.minScaleDenominator )
83-
|| ( s.maxScaleDenominator != -1 && scaleDenominator > s.maxScaleDenominator ) )
84-
{
85-
return;
86-
}
87-
88-
//convert from mm / map units to painter units
89-
QSizeF spu = sizePainterUnits( s.size, s, c );
90-
double w = spu.width();
91-
double h = spu.height();
92-
93-
double baseX = position.x();
94-
double baseY = position.y() - h;
95-
96-
QList<QPointF> textPositions; //midpoints for text placement
97-
int nCategories = s.categoryIndices.size();
98-
for ( int i = 0; i < nCategories; ++i )
99-
{
100-
if ( mOrientation == Horizontal )
101-
{
102-
textPositions.push_back( QPointF( baseX + ( w / nCategories ) * i + w / nCategories / 2.0 , baseY + h / 2.0 ) );
103-
}
104-
else //vertical
105-
{
106-
textPositions.push_back( QPointF( baseX + w / 2.0, baseY + h / nCategories * i + w / nCategories / 2.0 ) );
107-
}
108-
}
109-
110-
mPen.setColor( s.penColor );
111-
setPenWidth( mPen, s, c );
112-
p->setPen( mPen );
113-
mBrush.setColor( s.backgroundColor );
114-
p->setBrush( mBrush );
115-
116-
//draw shapes and separator lines first
117-
if ( mShape == Circle )
118-
{
119-
p->drawEllipse( baseX, baseY, w, h );
120-
121-
//draw separator lines
122-
QList<QPointF> intersect; //intersections between shape and separation lines
123-
QPointF center( baseX + w / 2.0, baseY + h / 2.0 );
124-
double r1 = w / 2.0; double r2 = h / 2.0;
125-
126-
for ( int i = 1; i < nCategories; ++i )
127-
{
128-
if ( mOrientation == Horizontal )
129-
{
130-
lineEllipseIntersection( QPointF( baseX + w / nCategories * i, baseY ), QPointF( baseX + w / nCategories * i, baseY + h ), center, r1, r2, intersect );
131-
}
132-
else //vertical
133-
{
134-
lineEllipseIntersection( QPointF( baseX, baseY + h / nCategories * i ), QPointF( baseX + w, baseY + h / nCategories * i ), center, r1, r2, intersect );
135-
}
136-
if ( intersect.size() > 1 )
137-
{
138-
p->drawLine( intersect.at( 0 ), intersect.at( 1 ) );
139-
}
140-
}
141-
}
142-
else if ( mShape == Rectangle )
143-
{
144-
p->drawRect( QRectF( baseX, baseY, w, h ) );
145-
for ( int i = 1; i < nCategories; ++i )
146-
{
147-
if ( mOrientation == Horizontal )
148-
{
149-
p->drawLine( QPointF( baseX + w / nCategories * i , baseY ), QPointF( baseX + w / nCategories * i, baseY + h ) );
150-
}
151-
else
152-
{
153-
p->drawLine( QPointF( baseX, baseY + h / nCategories * i ) , QPointF( baseX + w, baseY + h / nCategories * i ) );
154-
}
155-
}
156-
}
157-
else //triangle
158-
{
159-
QPolygonF triangle;
160-
triangle << QPointF( baseX, baseY + h ) << QPointF( baseX + w, baseY + h ) << QPointF( baseX + w / 2.0, baseY );
161-
p->drawPolygon( triangle );
162-
163-
QLineF triangleEdgeLeft( baseX + w / 2.0, baseY, baseX, baseY + h );
164-
QLineF triangleEdgeRight( baseX + w, baseY + h, baseX + w / 2.0, baseY );
165-
QPointF intersectionPoint1, intersectionPoint2;
166-
167-
for ( int i = 1; i < nCategories; ++i )
168-
{
169-
if ( mOrientation == Horizontal )
170-
{
171-
QLineF verticalLine( baseX + w / nCategories * i, baseY + h, baseX + w / nCategories * i, baseY );
172-
if ( baseX + w / nCategories * i < baseX + w / 2.0 )
173-
{
174-
verticalLine.intersect( triangleEdgeLeft, &intersectionPoint1 );
175-
}
176-
else
177-
{
178-
verticalLine.intersect( triangleEdgeRight, &intersectionPoint1 );
179-
}
180-
p->drawLine( QPointF( baseX + w / nCategories * i, baseY + h ), intersectionPoint1 );
181-
}
182-
else //vertical
183-
{
184-
QLineF horizontalLine( baseX, baseY + h / nCategories * i, baseX + w, baseY + h / nCategories * i );
185-
horizontalLine.intersect( triangleEdgeLeft, &intersectionPoint1 );
186-
horizontalLine.intersect( triangleEdgeRight, &intersectionPoint2 );
187-
p->drawLine( intersectionPoint1, intersectionPoint2 );
188-
}
189-
}
190-
}
191-
192-
//draw text
193-
QFont sFont = scaledFont( s, c );
194-
QFontMetricsF fontMetrics( sFont );
195-
p->setFont( sFont );
196-
197-
for ( int i = 0; i < textPositions.size(); ++i )
198-
{
199-
QString val = att[ s.categoryIndices.at( i )].toString();
200-
//find out dimensions
201-
double textHeight = fontMetrics.height();
202-
double textWidth = fontMetrics.width( val );
203-
mPen.setColor( s.categoryColors.at( i ) );
204-
p->setPen( mPen );
205-
QPointF position = textPositions.at( i );
206-
p->drawText( QPointF( position.x() - textWidth / 2.0, position.y() + textHeight / 2.0 ), val );
207-
}
208-
}
209-
210-
void QgsTextDiagram::lineEllipseIntersection( const QPointF& lineStart, const QPointF& lineEnd, const QPointF& ellipseMid, double r1, double r2, QList<QPointF>& result ) const
211-
{
212-
result.clear();
213-
214-
double rrx = r1 * r1;
215-
double rry = r2 * r2;
216-
double x21 = lineEnd.x() - lineStart.x();
217-
double y21 = lineEnd.y() - lineStart.y();
218-
double x10 = lineStart.x() - ellipseMid.x();
219-
double y10 = lineStart.y() - ellipseMid.y();
220-
double a = x21 * x21 / rrx + y21 * y21 / rry;
221-
double b = x21 * x10 / rrx + y21 * y10 / rry;
222-
double c = x10 * x10 / rrx + y10 * y10 / rry;
223-
double d = b * b - a * ( c - 1 );
224-
if ( d > 0 )
225-
{
226-
double e = sqrt( d );
227-
double u1 = ( -b - e ) / a;
228-
double u2 = ( -b + e ) / a;
229-
//work with a tolerance of 0.00001 because of limited numerical precision
230-
if ( -0.00001 <= u1 && u1 < 1.00001 )
231-
{
232-
result.push_back( QPointF( lineStart.x() + x21 * u1, lineStart.y() + y21 * u1 ) );
233-
}
234-
if ( -0.00001 <= u2 && u2 <= 1.00001 )
235-
{
236-
result.push_back( QPointF( lineStart.x() + x21 * u2, lineStart.y() + y21 * u2 ) );
237-
}
238-
}
239-
}
240-
241-
QgsPieDiagram::QgsPieDiagram()
242-
{
243-
mCategoryBrush.setStyle( Qt::SolidPattern );
244-
mPen.setStyle( Qt::SolidLine );
245-
}
246-
247-
QgsPieDiagram::~QgsPieDiagram()
248-
{
249-
}
250-
251-
void QgsPieDiagram::renderDiagram( const QgsAttributeMap& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position )
252-
{
253-
QPainter* p = c.painter();
254-
if ( !p )
255-
{
256-
return;
257-
}
258-
259-
//get sum of values
260-
QList<double> values;
261-
double currentVal = 0;
262-
double valSum = 0;
263-
264-
QList<int>::const_iterator catIt = s.categoryIndices.constBegin();
265-
for ( ; catIt != s.categoryIndices.constEnd(); ++catIt )
266-
{
267-
currentVal = att[*catIt].toDouble();
268-
values.push_back( currentVal );
269-
valSum += currentVal;
270-
}
271-
272-
//draw the slices
273-
double totalAngle = 0;
274-
double currentAngle;
275-
276-
//convert from mm / map units to painter units
277-
QSizeF spu = sizePainterUnits( s.size, s, c );
278-
double w = spu.width();
279-
double h = spu.height();
280-
281-
double baseX = position.x();
282-
double baseY = position.y() - h;
283-
284-
mPen.setColor( s.penColor );
285-
setPenWidth( mPen, s, c );
286-
p->setPen( mPen );
287-
288-
QList<double>::const_iterator valIt = values.constBegin();
289-
QList< QColor >::const_iterator colIt = s.categoryColors.constBegin();
290-
for ( ; valIt != values.constEnd(); ++valIt, ++colIt )
291-
{
292-
currentAngle = *valIt / valSum * 360 * 16;
293-
mCategoryBrush.setColor( *colIt );
294-
p->setBrush( mCategoryBrush );
295-
p->drawPie( baseX, baseY, w, h, totalAngle, currentAngle );
296-
totalAngle += currentAngle;
297-
}
298-
}
1+
/***************************************************************************
2+
qgsdiagram.cpp
3+
---------------------
4+
begin : March 2011
5+
copyright : (C) 2011 by Marco Hugentobler
6+
email : marco dot hugentobler at sourcepole dot ch
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
#include "qgsdiagram.h"
16+
#include "qgsdiagramrendererv2.h"
17+
#include "qgsrendercontext.h"
18+
19+
#include <QPainter>
20+
21+
void QgsDiagram::setPenWidth( QPen& pen, const QgsDiagramSettings& s, const QgsRenderContext& c )
22+
{
23+
if ( s.sizeType == QgsDiagramSettings::MM )
24+
{
25+
pen.setWidthF( s.penWidth * c.scaleFactor() );
26+
}
27+
else
28+
{
29+
pen.setWidthF( s.penWidth / c.mapToPixel().mapUnitsPerPixel() );
30+
}
31+
}
32+
33+
QSizeF QgsDiagram::sizePainterUnits( const QSizeF& size, const QgsDiagramSettings& s, const QgsRenderContext& c )
34+
{
35+
Q_UNUSED( size );
36+
if ( s.sizeType == QgsDiagramSettings::MM )
37+
{
38+
return QSizeF( s.size.width() * c.scaleFactor(), s.size.height() * c.scaleFactor() );
39+
}
40+
else
41+
{
42+
return QSizeF( s.size.width() / c.mapToPixel().mapUnitsPerPixel(), s.size.height() / c.mapToPixel().mapUnitsPerPixel() );
43+
}
44+
}
45+
46+
QFont QgsDiagram::scaledFont( const QgsDiagramSettings& s, const QgsRenderContext& c )
47+
{
48+
QFont f = s.font;
49+
if ( s.sizeType == QgsDiagramSettings::MM )
50+
{
51+
f.setPixelSize( s.font.pointSizeF() * 0.376 * c.scaleFactor() );
52+
}
53+
else
54+
{
55+
f.setPixelSize( s.font.pointSizeF() / c.mapToPixel().mapUnitsPerPixel() );
56+
}
57+
58+
return f;
59+
}
60+
61+
QgsTextDiagram::QgsTextDiagram(): mOrientation( Vertical ), mShape( Circle )
62+
{
63+
mPen.setWidthF( 2.0 );
64+
mPen.setColor( QColor( 0, 0, 0 ) );
65+
mPen.setCapStyle( Qt::FlatCap );
66+
mBrush.setStyle( Qt::SolidPattern );
67+
}
68+
69+
QgsTextDiagram::~QgsTextDiagram()
70+
{
71+
}
72+
73+
void QgsTextDiagram::renderDiagram( const QgsAttributeMap& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position )
74+
{
75+
QPainter* p = c.painter();
76+
if ( !p )
77+
{
78+
return;
79+
}
80+
81+
double scaleDenominator = c.rendererScale();
82+
if (( s.minScaleDenominator != -1 && scaleDenominator < s.minScaleDenominator )
83+
|| ( s.maxScaleDenominator != -1 && scaleDenominator > s.maxScaleDenominator ) )
84+
{
85+
return;
86+
}
87+
88+
//convert from mm / map units to painter units
89+
QSizeF spu = sizePainterUnits( s.size, s, c );
90+
double w = spu.width();
91+
double h = spu.height();
92+
93+
double baseX = position.x();
94+
double baseY = position.y() - h;
95+
96+
QList<QPointF> textPositions; //midpoints for text placement
97+
int nCategories = s.categoryIndices.size();
98+
for ( int i = 0; i < nCategories; ++i )
99+
{
100+
if ( mOrientation == Horizontal )
101+
{
102+
textPositions.push_back( QPointF( baseX + ( w / nCategories ) * i + w / nCategories / 2.0 , baseY + h / 2.0 ) );
103+
}
104+
else //vertical
105+
{
106+
textPositions.push_back( QPointF( baseX + w / 2.0, baseY + h / nCategories * i + w / nCategories / 2.0 ) );
107+
}
108+
}
109+
110+
mPen.setColor( s.penColor );
111+
setPenWidth( mPen, s, c );
112+
p->setPen( mPen );
113+
mBrush.setColor( s.backgroundColor );
114+
p->setBrush( mBrush );
115+
116+
//draw shapes and separator lines first
117+
if ( mShape == Circle )
118+
{
119+
p->drawEllipse( baseX, baseY, w, h );
120+
121+
//draw separator lines
122+
QList<QPointF> intersect; //intersections between shape and separation lines
123+
QPointF center( baseX + w / 2.0, baseY + h / 2.0 );
124+
double r1 = w / 2.0; double r2 = h / 2.0;
125+
126+
for ( int i = 1; i < nCategories; ++i )
127+
{
128+
if ( mOrientation == Horizontal )
129+
{
130+
lineEllipseIntersection( QPointF( baseX + w / nCategories * i, baseY ), QPointF( baseX + w / nCategories * i, baseY + h ), center, r1, r2, intersect );
131+
}
132+
else //vertical
133+
{
134+
lineEllipseIntersection( QPointF( baseX, baseY + h / nCategories * i ), QPointF( baseX + w, baseY + h / nCategories * i ), center, r1, r2, intersect );
135+
}
136+
if ( intersect.size() > 1 )
137+
{
138+
p->drawLine( intersect.at( 0 ), intersect.at( 1 ) );
139+
}
140+
}
141+
}
142+
else if ( mShape == Rectangle )
143+
{
144+
p->drawRect( QRectF( baseX, baseY, w, h ) );
145+
for ( int i = 1; i < nCategories; ++i )
146+
{
147+
if ( mOrientation == Horizontal )
148+
{
149+
p->drawLine( QPointF( baseX + w / nCategories * i , baseY ), QPointF( baseX + w / nCategories * i, baseY + h ) );
150+
}
151+
else
152+
{
153+
p->drawLine( QPointF( baseX, baseY + h / nCategories * i ) , QPointF( baseX + w, baseY + h / nCategories * i ) );
154+
}
155+
}
156+
}
157+
else //triangle
158+
{
159+
QPolygonF triangle;
160+
triangle << QPointF( baseX, baseY + h ) << QPointF( baseX + w, baseY + h ) << QPointF( baseX + w / 2.0, baseY );
161+
p->drawPolygon( triangle );
162+
163+
QLineF triangleEdgeLeft( baseX + w / 2.0, baseY, baseX, baseY + h );
164+
QLineF triangleEdgeRight( baseX + w, baseY + h, baseX + w / 2.0, baseY );
165+
QPointF intersectionPoint1, intersectionPoint2;
166+
167+
for ( int i = 1; i < nCategories; ++i )
168+
{
169+
if ( mOrientation == Horizontal )
170+
{
171+
QLineF verticalLine( baseX + w / nCategories * i, baseY + h, baseX + w / nCategories * i, baseY );
172+
if ( baseX + w / nCategories * i < baseX + w / 2.0 )
173+
{
174+
verticalLine.intersect( triangleEdgeLeft, &intersectionPoint1 );
175+
}
176+
else
177+
{
178+
verticalLine.intersect( triangleEdgeRight, &intersectionPoint1 );
179+
}
180+
p->drawLine( QPointF( baseX + w / nCategories * i, baseY + h ), intersectionPoint1 );
181+
}
182+
else //vertical
183+
{
184+
QLineF horizontalLine( baseX, baseY + h / nCategories * i, baseX + w, baseY + h / nCategories * i );
185+
horizontalLine.intersect( triangleEdgeLeft, &intersectionPoint1 );
186+
horizontalLine.intersect( triangleEdgeRight, &intersectionPoint2 );
187+
p->drawLine( intersectionPoint1, intersectionPoint2 );
188+
}
189+
}
190+
}
191+
192+
//draw text
193+
QFont sFont = scaledFont( s, c );
194+
QFontMetricsF fontMetrics( sFont );
195+
p->setFont( sFont );
196+
197+
for ( int i = 0; i < textPositions.size(); ++i )
198+
{
199+
QString val = att[ s.categoryIndices.at( i )].toString();
200+
//find out dimensions
201+
double textWidth = fontMetrics.width( val );
202+
mPen.setColor( s.categoryColors.at( i ) );
203+
p->setPen( mPen );
204+
QPointF position = textPositions.at( i );
205+
p->drawText( QPointF( position.x() - textWidth / 2.0, position.y() + fontMetrics.xHeight() ), val );
206+
}
207+
}
208+
209+
void QgsTextDiagram::lineEllipseIntersection( const QPointF& lineStart, const QPointF& lineEnd, const QPointF& ellipseMid, double r1, double r2, QList<QPointF>& result ) const
210+
{
211+
result.clear();
212+
213+
double rrx = r1 * r1;
214+
double rry = r2 * r2;
215+
double x21 = lineEnd.x() - lineStart.x();
216+
double y21 = lineEnd.y() - lineStart.y();
217+
double x10 = lineStart.x() - ellipseMid.x();
218+
double y10 = lineStart.y() - ellipseMid.y();
219+
double a = x21 * x21 / rrx + y21 * y21 / rry;
220+
double b = x21 * x10 / rrx + y21 * y10 / rry;
221+
double c = x10 * x10 / rrx + y10 * y10 / rry;
222+
double d = b * b - a * ( c - 1 );
223+
if ( d > 0 )
224+
{
225+
double e = sqrt( d );
226+
double u1 = ( -b - e ) / a;
227+
double u2 = ( -b + e ) / a;
228+
//work with a tolerance of 0.00001 because of limited numerical precision
229+
if ( -0.00001 <= u1 && u1 < 1.00001 )
230+
{
231+
result.push_back( QPointF( lineStart.x() + x21 * u1, lineStart.y() + y21 * u1 ) );
232+
}
233+
if ( -0.00001 <= u2 && u2 <= 1.00001 )
234+
{
235+
result.push_back( QPointF( lineStart.x() + x21 * u2, lineStart.y() + y21 * u2 ) );
236+
}
237+
}
238+
}
239+
240+
QgsPieDiagram::QgsPieDiagram()
241+
{
242+
mCategoryBrush.setStyle( Qt::SolidPattern );
243+
mPen.setStyle( Qt::SolidLine );
244+
}
245+
246+
QgsPieDiagram::~QgsPieDiagram()
247+
{
248+
}
249+
250+
void QgsPieDiagram::renderDiagram( const QgsAttributeMap& att, QgsRenderContext& c, const QgsDiagramSettings& s, const QPointF& position )
251+
{
252+
QPainter* p = c.painter();
253+
if ( !p )
254+
{
255+
return;
256+
}
257+
258+
//get sum of values
259+
QList<double> values;
260+
double currentVal = 0;
261+
double valSum = 0;
262+
263+
QList<int>::const_iterator catIt = s.categoryIndices.constBegin();
264+
for ( ; catIt != s.categoryIndices.constEnd(); ++catIt )
265+
{
266+
currentVal = att[*catIt].toDouble();
267+
values.push_back( currentVal );
268+
valSum += currentVal;
269+
}
270+
271+
//draw the slices
272+
double totalAngle = 0;
273+
double currentAngle;
274+
275+
//convert from mm / map units to painter units
276+
QSizeF spu = sizePainterUnits( s.size, s, c );
277+
double w = spu.width();
278+
double h = spu.height();
279+
280+
double baseX = position.x();
281+
double baseY = position.y() - h;
282+
283+
mPen.setColor( s.penColor );
284+
setPenWidth( mPen, s, c );
285+
p->setPen( mPen );
286+
287+
QList<double>::const_iterator valIt = values.constBegin();
288+
QList< QColor >::const_iterator colIt = s.categoryColors.constBegin();
289+
for ( ; valIt != values.constEnd(); ++valIt, ++colIt )
290+
{
291+
currentAngle = *valIt / valSum * 360 * 16;
292+
mCategoryBrush.setColor( *colIt );
293+
p->setBrush( mCategoryBrush );
294+
p->drawPie( baseX, baseY, w, h, totalAngle, currentAngle );
295+
totalAngle += currentAngle;
296+
}
297+
}

0 commit comments

Comments
 (0)
Please sign in to comment.