karbon

vellipse.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 "vellipse.h"
22#include "vtransformcmd.h"
23#include <tdelocale.h>
24#include <KoUnit.h>
25#include <KoStore.h>
26#include <KoXmlWriter.h>
27#include <KoXmlNS.h>
28#include <vglobal.h>
29#include <vdocument.h>
30#include <tqdom.h>
31#include <core/vfill.h>
32
33VEllipse::VEllipse( VObject* parent, VState state ) : VPath( parent, state )
34{
35}
36
37VEllipse::VEllipse( VObject* parent,
38 const KoPoint& topLeft, double width, double height,
39 VEllipseType type, double startAngle, double endAngle )
40 : VPath( parent ), m_type( type ), m_startAngle( startAngle ), m_endAngle( endAngle )
41{
42 setDrawCenterNode();
43
44 m_rx = width / 2.0;
45 m_ry = height / 2.0;
46 m_center.setX( topLeft.x() + m_rx );
47 m_center.setY( topLeft.y() + m_ry );
48
49 init();
50}
51
52void
53VEllipse::init()
54{
55 // to radials
56 int nsegs;
57 if( m_startAngle < m_endAngle )
58 nsegs = int( floor( ( m_endAngle - m_startAngle ) / 90.0 ) );
59 else
60 nsegs = 4 - int( ceil( ( m_startAngle - m_endAngle ) / 90.0 ) );
61 double startAngle = m_startAngle - 90.0;
62 if( startAngle < 0 ) startAngle += 360.0;
63 startAngle = VGlobal::pi_2 * ( startAngle / 90.0 );
64 double endAngle = m_endAngle - 90.0;
65 if( endAngle < 0 ) endAngle += 360.0;
66 endAngle = VGlobal::pi_2 * ( endAngle / 90.0 );
67 // Create (half-)unity circle with topLeft at (0|0):
68 double currentAngle = -startAngle - VGlobal::pi_2;
69 KoPoint start( 0.5 * sin( -startAngle ), 0.5 * cos( -startAngle ) );
70 moveTo( KoPoint( start.x(), start.y() ) );
71 double midAngle = currentAngle + VGlobal::pi_2 / 2.0;
72 double midAmount = 0.5 / sin( VGlobal::pi_2 / 2.0 );
73 for( int i = 0;i < nsegs;i++ )
74 {
75 midAngle -= VGlobal::pi_2;
76 arcTo( KoPoint( cos( midAngle ) * midAmount, -sin( midAngle ) * midAmount ),
77 KoPoint( 0.5 * sin( currentAngle ), 0.5 * cos( currentAngle ) ), 0.5 );
78 currentAngle -= VGlobal::pi_2;
79 }
80 double rest = ( -endAngle - VGlobal::pi_2 - currentAngle ) * 90.0 / VGlobal::pi_2;
81 if( rest > 0 )
82 rest -= 360.0;
83 if( rest != 0 )
84 {
85 midAngle = currentAngle - ( -rest / 360.0 ) * VGlobal::pi;
86 midAmount = 0.5 / cos( currentAngle - midAngle );
87 KoPoint end( 0.5 * sin( -endAngle ), 0.5 * cos( -endAngle ) );
88 arcTo( KoPoint( cos( midAngle ) * midAmount, -sin( midAngle ) * midAmount ),
89 KoPoint( 0.5 * sin( -endAngle ), 0.5 * cos( -endAngle ) ), 0.5 );
90 }
91 if( m_type == cut )
92 lineTo( KoPoint( 0.0, 0.0 ) );
93 if( m_type != arc )
94 close();
95
96 // Translate and scale:
97 TQWMatrix m;
98 m.translate( m_center.x(), m_center.y() );
99 m.scale( 2.0 * m_rx, 2.0 * m_ry );
100
101 // only tranform the path data
102 VTransformCmd cmd( 0L, m );
103 cmd.VVisitor::visitVPath( *this );
104
105 m_matrix.reset();
106}
107
108TQString
109VEllipse::name() const
110{
111 TQString result = VObject::name();
112 return !result.isEmpty() ? result : i18n( "Ellipse" );
113}
114
115void
116VEllipse::save( TQDomElement& element ) const
117{
118 VDocument *doc = document();
119 if( doc && doc->saveAsPath() )
120 {
121 VPath::save( element );
122 return;
123 }
124
125 if( state() != deleted )
126 {
127 TQDomElement me = element.ownerDocument().createElement( "ELLIPSE" );
128 element.appendChild( me );
129
130 // save fill/stroke untransformed
131 VPath path( *this );
132 VTransformCmd cmd( 0L, m_matrix.invert() );
133 cmd.visit( path );
134 path.VObject::save( me );
135 //VObject::save( me );
136
137 me.setAttribute( "cx", m_center.x() );
138 me.setAttribute( "cy", m_center.y() );
139
140 me.setAttribute( "rx", m_rx );
141 me.setAttribute( "ry", m_ry );
142
143 me.setAttribute( "start-angle", m_startAngle );
144 me.setAttribute( "end-angle", m_endAngle );
145
146 if( m_type == cut )
147 me.setAttribute( "kind", "cut" );
148 else if( m_type == section )
149 me.setAttribute( "kind", "section" );
150 else if( m_type == arc )
151 me.setAttribute( "kind", "arc" );
152 else
153 me.setAttribute( "kind", "full" );
154
155 TQString transform = buildSvgTransform();
156 if( !transform.isEmpty() )
157 me.setAttribute( "transform", transform );
158 }
159}
160
161void
162VEllipse::saveOasis( KoStore *store, KoXmlWriter *docWriter, KoGenStyles &mainStyles, int &index ) const
163{
164 // do not save deleted objects
165 if( state() == deleted )
166 return;
167
168 docWriter->startElement( "draw:ellipse" );
169
170 //save all into pt
171 docWriter->addAttributePt( "svg:cx", m_center.x() );
172 docWriter->addAttributePt( "svg:cy", m_center.y() );
173 docWriter->addAttributePt( "svg:rx", m_rx );
174 docWriter->addAttributePt( "svg:ry", m_ry );
175
176 if( m_type == full )
177 docWriter->addAttribute( "draw:kind", "full" );
178 else
179 {
180 // the meaning of cut and section is mixed up in karbon, so just set them so for now
181 // be sure to do the right thing tm for karbon 2.0
182 if( m_type == section )
183 docWriter->addAttribute( "draw:kind", "cut" );
184 else if( m_type == cut )
185 docWriter->addAttribute( "draw:kind", "section" );
186 else
187 docWriter->addAttribute( "draw:kind", "arc" );
188
189 docWriter->addAttribute( "draw:start-angle", m_startAngle );
190 docWriter->addAttribute( "draw:end-angle", m_endAngle );
191 }
192
193 VObject::saveOasis( store, docWriter, mainStyles, index );
194
195 TQWMatrix tmpMat;
196 tmpMat.scale( 1, -1 );
197 tmpMat.translate( 0, -document()->height() );
198
199 TQString transform = buildOasisTransform( m_matrix*tmpMat );
200 if( !transform.isEmpty() )
201 docWriter->addAttribute( "draw:transform", transform );
202
203 docWriter->endElement();
204}
205
206bool
207VEllipse::loadOasis( const TQDomElement &element, KoOasisLoadingContext &context )
208{
209 setState( normal );
210
211 if( element.tagName() == "ellipse" )
212 {
213 if( element.hasAttributeNS( KoXmlNS::svg, "rx" ) )
214 m_rx = KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "rx", TQString() ) );
215 else
216 m_rx = 0.5 * KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "width", TQString() ) );
217
218 if( element.hasAttributeNS( KoXmlNS::svg, "ry" ) )
219 m_ry = KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "ry", TQString() ) );
220 else
221 m_ry = 0.5 * KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "height", TQString() ) );
222
223 }
224 else if( element.tagName() == "circle" )
225 {
226 if( element.hasAttributeNS( KoXmlNS::svg, "r" ) )
227 m_rx = m_ry = KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "r", TQString() ) );
228 else
229 m_rx = m_ry = 0.5 * KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "width", TQString() ) );
230 }
231
232 if( element.hasAttributeNS( KoXmlNS::svg, "cx" ) )
233 m_center.setX( KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "cx", TQString() ) ) );
234 else
235 m_center.setX( m_rx + KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "x", TQString() ) ) );
236
237 if( element.hasAttributeNS( KoXmlNS::svg, "cy" ) )
238 m_center.setY( KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "cy", TQString() ) ) );
239 else
240 m_center.setY( m_ry + KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "y", TQString() ) ) );
241
242 // the meaning of cut and section is mixed up in karbon, so just set them so for now
243 // be sure to do the right thing tm for karbon 2.0
244 TQString kind = element.attributeNS( KoXmlNS::draw, "kind", TQString() );
245 if( kind == "cut" )
246 m_type = section;
247 else if( kind == "section" )
248 m_type = cut;
249 else if( kind == "arc" )
250 m_type = arc;
251 else
252 m_type = full;
253
254 double startAngle = element.attributeNS( KoXmlNS::draw, "start-angle", TQString() ).toDouble();
255 double endAngle = element.attributeNS( KoXmlNS::draw, "end-angle", TQString() ).toDouble();
256
257 // the shape gets mirrored in y-direction, so make the angles temporary clockwise
258 // just for creating the path
259 m_startAngle = 360.0 - endAngle;
260 m_endAngle = 360.0 - startAngle;
261
262 init();
263
264 // now set the right angles
265 m_startAngle = startAngle;
266 m_endAngle = endAngle;
267
268 transformByViewbox( element, element.attributeNS( KoXmlNS::svg, "viewBox", TQString() ) );
269
270 TQString trafo = element.attributeNS( KoXmlNS::draw, "transform", TQString() );
271 if( !trafo.isEmpty() )
272 transformOasis( trafo );
273
274 return VObject::loadOasis( element, context );
275}
276
277void
278VEllipse::load( const TQDomElement& element )
279{
280 setState( normal );
281
282 TQDomNodeList list = element.childNodes();
283 for( uint i = 0; i < list.count(); ++i )
284 if( list.item( i ).isElement() )
285 VObject::load( list.item( i ).toElement() );
286
287 m_rx = KoUnit::parseValue( element.attribute( "rx" ) );
288 m_ry = KoUnit::parseValue( element.attribute( "ry" ) );
289
290 m_center.setX( KoUnit::parseValue( element.attribute( "cx" ) ) );
291 m_center.setY( KoUnit::parseValue( element.attribute( "cy" ) ) );
292
293 m_startAngle = element.attribute( "start-angle" ).toDouble();
294 m_endAngle = element.attribute( "end-angle" ).toDouble();
295
296 if( element.attribute( "kind" ) == "cut" )
297 m_type = cut;
298 else if( element.attribute( "kind" ) == "section" )
299 m_type = section;
300 else if( element.attribute( "kind" ) == "arc" )
301 m_type = arc;
302 else
303 m_type = full;
304
305 init();
306
307 TQString trafo = element.attribute( "transform" );
308 if( !trafo.isEmpty() )
309 transform( trafo );
310}
311
312VPath*
313VEllipse::clone() const
314{
315 return new VEllipse( *this );
316}
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 void saveOasis(KoStore *store, KoXmlWriter *docWriter, KoGenStyles &mainStyles, int &index) const
Save this object's state to OpenDocument.
Definition vobject.cpp:116
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
virtual bool loadOasis(const TQDomElement &element, KoOasisLoadingContext &context)
Load this object's state from OpenDocument and initialize this object accordingly.
Definition vobject.cpp:181
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.