28#include "vtransformcmd.h"
33VStar::VStar(
VObject* parent, VState state )
34 :
VPath( parent, state )
39 const KoPoint& center,
double outerRadius,
double innerRadius,
40 uint edges,
double angle, uint innerAngle,
double roundness, VStarType type )
41 :
VPath( parent ), m_center( center), m_outerRadius( outerRadius ), m_innerRadius( innerRadius), m_edges( edges ), m_angle( angle ), m_innerAngle( innerAngle ), m_roundness( roundness ), m_type( type )
49 double angle = m_angle;
56 if( m_outerRadius < 0.0 )
57 m_outerRadius = -m_outerRadius;
59 if( m_innerRadius < 0.0 )
60 m_innerRadius = -m_innerRadius;
63 if( m_type == spoke || m_type == wheel && m_roundness == 0.0 )
69 m_outerRadius * cos( angle + VGlobal::pi_2 ),
70 m_outerRadius * sin( angle + VGlobal::pi_2 ) );
73 double inAngle = VGlobal::twopi / 360 * m_innerAngle;
77 int j = ( m_edges % 2 == 0 ) ? ( m_edges - 2 ) / 2 : ( m_edges - 1 ) / 2;
80 bool discontinueous = ( m_edges % 4 == 2 );
82 double outerRoundness = ( VGlobal::twopi * m_outerRadius * m_roundness ) / m_edges;
83 double nextOuterAngle;
85 for ( uint i = 1; i < m_edges + 1; ++i )
87 double nextInnerAngle = angle + inAngle + VGlobal::pi_2 + VGlobal::twopi / m_edges * ( jumpto + 0.5 );
88 p.setX( m_innerRadius * cos( nextInnerAngle ) );
89 p.setY( m_innerRadius * sin( nextInnerAngle ) );
90 if( m_roundness == 0.0 )
94 nextOuterAngle = angle + VGlobal::pi_2 + VGlobal::twopi / m_edges * jumpto;
95 p2.setX( m_outerRadius * cos( nextOuterAngle ) -
96 cos( angle + VGlobal::twopi / m_edges * jumpto ) * outerRoundness );
97 p2.setY( m_outerRadius * sin( nextOuterAngle ) -
98 sin( angle + VGlobal::twopi / m_edges * jumpto ) * outerRoundness );
103 jumpto = ( i * j ) % m_edges;
104 nextInnerAngle = angle + inAngle + VGlobal::pi_2 + VGlobal::twopi / m_edges * ( jumpto - 0.5 );
105 p.setX( m_innerRadius * cos( nextInnerAngle ) );
106 p.setY( m_innerRadius * sin( nextInnerAngle ) );
109 nextOuterAngle = angle + VGlobal::pi_2 + VGlobal::twopi / m_edges * jumpto;
110 p.setX( m_outerRadius * cos( nextOuterAngle ) );
111 p.setY( m_outerRadius * sin( nextOuterAngle ) );
113 if( m_roundness == 0.0 )
117 p2.setX( m_innerRadius * cos( nextInnerAngle ) );
118 p2.setY( m_innerRadius * sin( nextInnerAngle ) );
120 p3.setX( m_outerRadius * cos( nextOuterAngle ) +
121 cos( angle + VGlobal::twopi / m_edges * jumpto ) * outerRoundness );
122 p3.setY( m_outerRadius * sin( nextOuterAngle ) +
123 sin( angle + VGlobal::twopi / m_edges * jumpto ) * outerRoundness );
125 curveTo( p2, p3, p );
127 if( discontinueous && i == ( m_edges / 2 ) )
129 angle += VGlobal::pi;
130 nextOuterAngle = angle + VGlobal::pi_2 + VGlobal::twopi / m_edges * jumpto;
131 p.setX( m_outerRadius * cos( nextOuterAngle ) );
132 p.setY( m_outerRadius * sin( nextOuterAngle ) );
139 if( m_type == wheel || m_type == spoke )
142 double innerRoundness = ( VGlobal::twopi * m_innerRadius * m_roundness ) / m_edges;
143 double outerRoundness = ( VGlobal::twopi * m_outerRadius * m_roundness ) / m_edges;
145 for ( uint i = 0; i < m_edges; ++i )
147 double nextOuterAngle = angle + VGlobal::pi_2 + VGlobal::twopi / m_edges * ( i + 1.0 );
148 double nextInnerAngle = angle + inAngle + VGlobal::pi_2 + VGlobal::twopi / m_edges * ( i + 0.5 );
149 if( m_type != polygon )
151 p.setX( m_innerRadius * cos( nextInnerAngle ) );
152 p.setY( m_innerRadius * sin( nextInnerAngle ) );
154 if( m_roundness == 0.0 )
158 p2.setX( m_outerRadius *
159 cos( angle + VGlobal::pi_2 + VGlobal::twopi / m_edges * ( i ) ) -
160 cos( angle + VGlobal::twopi / m_edges * ( i ) ) * outerRoundness );
161 p2.setY( m_outerRadius *
162 sin( angle + VGlobal::pi_2 + VGlobal::twopi / m_edges * ( i ) ) -
163 sin( angle + VGlobal::twopi / m_edges * ( i ) ) * outerRoundness );
165 p3.setX( m_innerRadius * cos( nextInnerAngle ) +
166 cos( angle + inAngle + VGlobal::twopi / m_edges * ( i + 0.5 ) ) * innerRoundness );
167 p3.setY( m_innerRadius * sin( nextInnerAngle ) +
168 sin( angle + inAngle + VGlobal::twopi / m_edges * ( i + 0.5 ) ) * innerRoundness );
177 curveTo( p2, p3, p );
181 p.setX( m_outerRadius * cos( nextOuterAngle ) );
182 p.setY( m_outerRadius * sin( nextOuterAngle ) );
184 if( m_roundness == 0.0 )
188 p2.setX( m_innerRadius * cos( nextInnerAngle ) -
189 cos( angle + inAngle + VGlobal::twopi / m_edges * ( i + 0.5 ) ) * innerRoundness );
190 p2.setY( m_innerRadius * sin( nextInnerAngle ) -
191 sin( angle + inAngle + VGlobal::twopi / m_edges * ( i + 0.5 ) ) * innerRoundness );
193 p3.setX( m_outerRadius * cos( nextOuterAngle ) +
194 cos( angle + VGlobal::twopi / m_edges * ( i + 1.0 ) ) * outerRoundness );
195 p3.setY( m_outerRadius * sin( nextOuterAngle ) +
196 sin( angle + VGlobal::twopi / m_edges * ( i + 1.0 ) ) * outerRoundness );
205 curveTo( p2, p3, p );
209 if( m_type == wheel || m_type == framed_star )
212 for (
int i = m_edges - 1; i >= 0; --i )
214 double nextOuterAngle = angle + VGlobal::pi_2 + VGlobal::twopi / m_edges * ( i + 1.0 );
215 p.setX( m_outerRadius * cos( nextOuterAngle ) );
216 p.setY( m_outerRadius * sin( nextOuterAngle ) );
224 m.translate( m_center.x(), m_center.y() );
227 VTransformCmd cmd( 0L, m );
228 cmd.VVisitor::visitVPath( *
this );
230 setFillRule( evenOdd );
236VStar::getOptimalInnerRadius( uint edges,
double outerRadius, uint )
238 int j = (edges % 2 == 0 ) ? ( edges - 2 ) / 2 : ( edges - 1 ) / 2;
241 KoPoint p1( outerRadius * cos( VGlobal::pi_2 ), outerRadius * sin( VGlobal::pi_2 ) );
242 int jumpto = ( j ) % edges;
243 double nextOuterAngle = VGlobal::pi_2 + VGlobal::twopi / edges * jumpto;
244 KoPoint p2( outerRadius * cos( nextOuterAngle ), outerRadius * sin( nextOuterAngle ) );
246 nextOuterAngle = VGlobal::pi_2 + VGlobal::twopi / edges;
247 KoPoint p3( outerRadius * cos( nextOuterAngle ),
248 outerRadius * sin( nextOuterAngle ) );
249 jumpto = ( edges - j + 1 ) % edges;
250 nextOuterAngle = VGlobal::pi_2 + VGlobal::twopi / edges * jumpto;
251 KoPoint p4( outerRadius * cos( nextOuterAngle ), outerRadius * sin( nextOuterAngle ) );
254 double b1 = ( p2.y() - p1.y() ) / ( p2.x() - p1.x() );
255 double b2 = ( p4.y() - p3.y() ) / ( p4.x() - p3.x() );
256 double a1 = p1.y() - b1 * p1.x();
257 double a2 = p3.y() - b2 * p3.x();
258 double x = -( a1 - a2 ) / ( b1 - b2 );
259 double y = a1 + b1 * x;
261 return sqrt( x * x + y * y );
268 return !result.isEmpty() ? result : i18n(
"Star" );
275 if( doc && doc->saveAsPath() )
283 TQDomElement me = element.ownerDocument().createElement(
"STAR" );
284 element.appendChild( me );
288 VTransformCmd cmd( 0L, m_matrix.invert() );
290 path.VObject::save( me );
293 me.setAttribute(
"cx", m_center.x() );
294 me.setAttribute(
"cy", m_center.y() );
296 me.setAttribute(
"outerradius", m_outerRadius );
297 me.setAttribute(
"innerradius", m_innerRadius );
298 me.setAttribute(
"edges", m_edges );
300 me.setAttribute(
"angle", m_angle );
301 me.setAttribute(
"innerangle", m_innerAngle );
303 me.setAttribute(
"roundness", m_roundness );
305 me.setAttribute(
"type", m_type );
307 TQString transform = buildSvgTransform();
308 if( !transform.isEmpty() )
309 me.setAttribute(
"transform", transform );
318 TQDomNodeList list = element.childNodes();
319 for( uint i = 0; i < list.count(); ++i )
320 if( list.item( i ).isElement() )
323 m_center.setX( KoUnit::parseValue( element.attribute(
"cx" ) ) );
324 m_center.setY( KoUnit::parseValue( element.attribute(
"cy" ) ) );
326 m_outerRadius = KoUnit::parseValue( element.attribute(
"outerradius" ) );
327 m_innerRadius = KoUnit::parseValue( element.attribute(
"innerradius" ) );
328 m_edges = element.attribute(
"edges" ).toUInt();
330 m_innerAngle = element.attribute(
"innerangle" ).toUInt();
331 m_angle = element.attribute(
"angle" ).toDouble();
333 m_roundness = element.attribute(
"roundness" ).toDouble();
335 m_type =(VStar::VStarType) element.attribute(
"type" ).toInt();
339 TQString trafo = element.attribute(
"transform" );
340 if( !trafo.isEmpty() )
347 return new VStar( *
this );
All non-visual, static doc info is in here.
The base class for all karbon objects.
virtual void setState(const VState state)
Sets the state to a specified new state.
@ deleted
deleted, nearly dead
@ normal
visible, not active
virtual TQString name() const
Returns the name of the object.
virtual void load(const TQDomElement &element)
Load this object's state from xml and initialize this object accordingly.
VDocument * document() const
Return document the object belongs to.
VState state() const
Get the state the object is in.
A composite path consists of one or many subpaths.
void close()
Closes the current subpath.
virtual void save(TQDomElement &element) const
Save this object's state to xml.
virtual VPath * clone() const
Create an exact copy of this object.
virtual void save(TQDomElement &element) const
Save this object's state to xml.
virtual TQString name() const
Returns the name of the object.
virtual void load(const TQDomElement &element)
Load this object's state from xml and initialize this object accordingly.
virtual bool visit(VObject &object)
General visit method.