karbon

vspiral.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2001, 2002, 2003 The Karbon Developers
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18*/
19
20
21#include <math.h>
22
23#include <tqwmatrix.h>
24#include <tqdom.h>
25
26#include "vglobal.h"
27#include "vspiral.h"
28#include "vtransformcmd.h"
29#include <tdelocale.h>
30#include <KoUnit.h>
31#include <vdocument.h>
32
33VSpiral::VSpiral( VObject* parent, VState state )
34 : VPath( parent, state )
35{
36}
37
38VSpiral::VSpiral( VObject* parent,
39 const KoPoint& center, double radius, uint segments, double fade,
40 bool clockwise, double angle, VSpiralType type )
41 : VPath( parent ), m_center( center), m_radius( radius ), m_fade( fade ), m_segments( segments ), m_clockwise( clockwise ), m_angle( angle ), m_type( type )
42{
43 init();
44}
45
46void
47VSpiral::init()
48{
49 // It makes sense to have at least one segment:
50 if( m_segments < 1 )
51 m_segments = 1;
52
53 // Make sure the radius is positive:
54 if( m_radius < 0.0 )
55 m_radius = -m_radius;
56
57 // Fall back, when fade is out of range:
58 if( m_fade <= 0.0 || m_fade >= 1.0 )
59 m_fade = 0.5;
60
61 setFillRule( winding );
62
63 // advance by pi/2 clockwise or cclockwise?
64 double adv_ang = ( m_clockwise ? -1.0 : 1.0 ) * VGlobal::pi_2;
65 // radius of first segment is non-faded radius:
66 double r = m_radius;
67
68 KoPoint oldP( 0.0, ( m_clockwise ? -1.0 : 1.0 ) * m_radius );
69 KoPoint newP;
70 KoPoint newCenter( 0.0, 0.0 );
71 moveTo( oldP );
72
73 for ( uint i = 0; i < m_segments; ++i )
74 {
75 newP.setX( r * cos( adv_ang * ( i + 2 ) ) + newCenter.x() );
76 newP.setY( r * sin( adv_ang * ( i + 2 ) ) + newCenter.y() );
77
78 if( m_type == round )
79 arcTo( oldP + newP - newCenter, newP, r );
80 else
81 lineTo( newP );
82
83 newCenter += ( newP - newCenter ) * ( 1.0 - m_fade );
84 oldP = newP;
85 r *= m_fade;
86 }
87
88 // translate path to center:
89 TQWMatrix m;
90 m.translate( m_center.x(), m_center.y() );
91
92 // sadly it's not feasible to simply add angle while creation.
93 m.rotate(
94 ( m_angle + ( m_clockwise ? VGlobal::pi : 0.0 ) ) * // make cw-spiral start at mouse-pointer
95 VGlobal::one_pi_180 ); // one_pi_180 = 1/(pi/180) = 180/pi.
96
97 // only tranform the path data
98 VTransformCmd cmd( 0L, m );
99 cmd.VVisitor::visitVPath( *this );
100
101 m_matrix.reset();
102}
103
104TQString
105VSpiral::name() const
106{
107 TQString result = VObject::name();
108 return !result.isEmpty() ? result : i18n( "Spiral" );
109}
110
111void
112VSpiral::save( TQDomElement& element ) const
113{
114 VDocument *doc = document();
115 if( doc && doc->saveAsPath() )
116 {
117 VPath::save( element );
118 return;
119 }
120
121 if( state() != deleted )
122 {
123 TQDomElement me = element.ownerDocument().createElement( "SPIRAL" );
124 element.appendChild( me );
125
126 // save fill/stroke untransformed
127 VPath path( *this );
128 VTransformCmd cmd( 0L, m_matrix.invert() );
129 cmd.visit( path );
130 path.VObject::save( me );
131 //VObject::save( me );
132
133 me.setAttribute( "cx", m_center.x() );
134 me.setAttribute( "cy", m_center.y() );
135
136 me.setAttribute( "radius", m_radius );
137 me.setAttribute( "angle", m_angle );
138 me.setAttribute( "fade", m_fade );
139
140 me.setAttribute( "segments", m_segments );
141
142 me.setAttribute( "clockwise", m_clockwise );
143
144 me.setAttribute( "type", m_type );
145
146 TQString transform = buildSvgTransform();
147 if( !transform.isEmpty() )
148 me.setAttribute( "transform", transform );
149 }
150}
151
152void
153VSpiral::load( const TQDomElement& element )
154{
155 setState( normal );
156
157 TQDomNodeList list = element.childNodes();
158 for( uint i = 0; i < list.count(); ++i )
159 if( list.item( i ).isElement() )
160 VObject::load( list.item( i ).toElement() );
161
162 m_radius = KoUnit::parseValue( element.attribute( "radius" ) );
163 m_angle = element.attribute( "angle" ).toDouble();
164 m_fade = element.attribute( "fade" ).toDouble();
165
166 m_center.setX( KoUnit::parseValue( element.attribute( "cx" ) ) );
167 m_center.setY( KoUnit::parseValue( element.attribute( "cy" ) ) );
168
169 m_segments = element.attribute( "segments" ).toUInt(),
170
171 m_clockwise = element.attribute( "clockwise" ).toInt();
172
173 m_type = (VSpiral::VSpiralType)element.attribute( "type" ).toInt();
174
175 init();
176
177 TQString trafo = element.attribute( "transform" );
178 if( !trafo.isEmpty() )
179 transform( trafo );
180}
181
182VPath*
183VSpiral::clone() const
184{
185 return new VSpiral( *this );
186}
All non-visual, static doc info is in here.
Definition vdocument.h:53
The base class for all karbon objects.
Definition vobject.h:50
virtual TQString name() const
Returns the name of the object.
Definition vobject.cpp:225
virtual void load(const TQDomElement &element)
Load this object's state from xml and initialize this object accordingly.
Definition vobject.cpp:157
A composite path consists of one or many subpaths.
Definition vcomposite.h:48
virtual void save(TQDomElement &element) const
Save this object's state to xml.