00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "vellipse.h"
00022 #include "vtransformcmd.h"
00023 #include <klocale.h>
00024 #include <KoUnit.h>
00025 #include <KoStore.h>
00026 #include <KoXmlWriter.h>
00027 #include <KoXmlNS.h>
00028 #include <vglobal.h>
00029 #include <vdocument.h>
00030 #include <qdom.h>
00031 #include <core/vfill.h>
00032
00033 VEllipse::VEllipse( VObject* parent, VState state ) : VPath( parent, state )
00034 {
00035 }
00036
00037 VEllipse::VEllipse( VObject* parent,
00038 const KoPoint& topLeft, double width, double height,
00039 VEllipseType type, double startAngle, double endAngle )
00040 : VPath( parent ), m_type( type ), m_startAngle( startAngle ), m_endAngle( endAngle )
00041 {
00042 setDrawCenterNode();
00043
00044 m_rx = width / 2.0;
00045 m_ry = height / 2.0;
00046 m_center.setX( topLeft.x() + m_rx );
00047 m_center.setY( topLeft.y() + m_ry );
00048
00049 init();
00050 }
00051
00052 void
00053 VEllipse::init()
00054 {
00055
00056 int nsegs;
00057 if( m_startAngle < m_endAngle )
00058 nsegs = int( floor( ( m_endAngle - m_startAngle ) / 90.0 ) );
00059 else
00060 nsegs = 4 - int( ceil( ( m_startAngle - m_endAngle ) / 90.0 ) );
00061 double startAngle = m_startAngle - 90.0;
00062 if( startAngle < 0 ) startAngle += 360.0;
00063 startAngle = VGlobal::pi_2 * ( startAngle / 90.0 );
00064 double endAngle = m_endAngle - 90.0;
00065 if( endAngle < 0 ) endAngle += 360.0;
00066 endAngle = VGlobal::pi_2 * ( endAngle / 90.0 );
00067
00068 double currentAngle = -startAngle - VGlobal::pi_2;
00069 KoPoint start( 0.5 * sin( -startAngle ), 0.5 * cos( -startAngle ) );
00070 moveTo( KoPoint( start.x(), start.y() ) );
00071 double midAngle = currentAngle + VGlobal::pi_2 / 2.0;
00072 double midAmount = 0.5 / sin( VGlobal::pi_2 / 2.0 );
00073 for( int i = 0;i < nsegs;i++ )
00074 {
00075 midAngle -= VGlobal::pi_2;
00076 arcTo( KoPoint( cos( midAngle ) * midAmount, -sin( midAngle ) * midAmount ),
00077 KoPoint( 0.5 * sin( currentAngle ), 0.5 * cos( currentAngle ) ), 0.5 );
00078 currentAngle -= VGlobal::pi_2;
00079 }
00080 double rest = ( -endAngle - VGlobal::pi_2 - currentAngle ) * 90.0 / VGlobal::pi_2;
00081 if( rest > 0 )
00082 rest -= 360.0;
00083 if( rest != 0 )
00084 {
00085 midAngle = currentAngle - ( -rest / 360.0 ) * VGlobal::pi;
00086 midAmount = 0.5 / cos( currentAngle - midAngle );
00087 KoPoint end( 0.5 * sin( -endAngle ), 0.5 * cos( -endAngle ) );
00088 arcTo( KoPoint( cos( midAngle ) * midAmount, -sin( midAngle ) * midAmount ),
00089 KoPoint( 0.5 * sin( -endAngle ), 0.5 * cos( -endAngle ) ), 0.5 );
00090 }
00091 if( m_type == cut )
00092 lineTo( KoPoint( 0.0, 0.0 ) );
00093 if( m_type != arc )
00094 close();
00095
00096
00097 QWMatrix m;
00098 m.translate( m_center.x(), m_center.y() );
00099 m.scale( 2.0 * m_rx, 2.0 * m_ry );
00100
00101
00102 VTransformCmd cmd( 0L, m );
00103 cmd.VVisitor::visitVPath( *this );
00104
00105 m_matrix.reset();
00106 }
00107
00108 QString
00109 VEllipse::name() const
00110 {
00111 QString result = VObject::name();
00112 return !result.isEmpty() ? result : i18n( "Ellipse" );
00113 }
00114
00115 void
00116 VEllipse::save( QDomElement& element ) const
00117 {
00118 VDocument *doc = document();
00119 if( doc && doc->saveAsPath() )
00120 {
00121 VPath::save( element );
00122 return;
00123 }
00124
00125 if( state() != deleted )
00126 {
00127 QDomElement me = element.ownerDocument().createElement( "ELLIPSE" );
00128 element.appendChild( me );
00129
00130
00131 VPath path( *this );
00132 VTransformCmd cmd( 0L, m_matrix.invert() );
00133 cmd.visit( path );
00134 path.VObject::save( me );
00135
00136
00137 me.setAttribute( "cx", m_center.x() );
00138 me.setAttribute( "cy", m_center.y() );
00139
00140 me.setAttribute( "rx", m_rx );
00141 me.setAttribute( "ry", m_ry );
00142
00143 me.setAttribute( "start-angle", m_startAngle );
00144 me.setAttribute( "end-angle", m_endAngle );
00145
00146 if( m_type == cut )
00147 me.setAttribute( "kind", "cut" );
00148 else if( m_type == section )
00149 me.setAttribute( "kind", "section" );
00150 else if( m_type == arc )
00151 me.setAttribute( "kind", "arc" );
00152 else
00153 me.setAttribute( "kind", "full" );
00154
00155 QString transform = buildSvgTransform();
00156 if( !transform.isEmpty() )
00157 me.setAttribute( "transform", transform );
00158 }
00159 }
00160
00161 void
00162 VEllipse::saveOasis( KoStore *store, KoXmlWriter *docWriter, KoGenStyles &mainStyles, int &index ) const
00163 {
00164
00165 if( state() == deleted )
00166 return;
00167
00168 docWriter->startElement( "draw:ellipse" );
00169
00170
00171 docWriter->addAttributePt( "svg:cx", m_center.x() );
00172 docWriter->addAttributePt( "svg:cy", m_center.y() );
00173 docWriter->addAttributePt( "svg:rx", m_rx );
00174 docWriter->addAttributePt( "svg:ry", m_ry );
00175
00176 if( m_type == full )
00177 docWriter->addAttribute( "draw:kind", "full" );
00178 else
00179 {
00180
00181
00182 if( m_type == section )
00183 docWriter->addAttribute( "draw:kind", "cut" );
00184 else if( m_type == cut )
00185 docWriter->addAttribute( "draw:kind", "section" );
00186 else
00187 docWriter->addAttribute( "draw:kind", "arc" );
00188
00189 docWriter->addAttribute( "draw:start-angle", m_startAngle );
00190 docWriter->addAttribute( "draw:end-angle", m_endAngle );
00191 }
00192
00193 VObject::saveOasis( store, docWriter, mainStyles, index );
00194
00195 QWMatrix tmpMat;
00196 tmpMat.scale( 1, -1 );
00197 tmpMat.translate( 0, -document()->height() );
00198
00199 QString transform = buildOasisTransform( m_matrix*tmpMat );
00200 if( !transform.isEmpty() )
00201 docWriter->addAttribute( "draw:transform", transform );
00202
00203 docWriter->endElement();
00204 }
00205
00206 bool
00207 VEllipse::loadOasis( const QDomElement &element, KoOasisLoadingContext &context )
00208 {
00209 setState( normal );
00210
00211 if( element.tagName() == "ellipse" )
00212 {
00213 if( element.hasAttributeNS( KoXmlNS::svg, "rx" ) )
00214 m_rx = KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "rx", QString::null ) );
00215 else
00216 m_rx = 0.5 * KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "width", QString::null ) );
00217
00218 if( element.hasAttributeNS( KoXmlNS::svg, "ry" ) )
00219 m_ry = KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "ry", QString::null ) );
00220 else
00221 m_ry = 0.5 * KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "height", QString::null ) );
00222
00223 }
00224 else if( element.tagName() == "circle" )
00225 {
00226 if( element.hasAttributeNS( KoXmlNS::svg, "r" ) )
00227 m_rx = m_ry = KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "r", QString::null ) );
00228 else
00229 m_rx = m_ry = 0.5 * KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "width", QString::null ) );
00230 }
00231
00232 if( element.hasAttributeNS( KoXmlNS::svg, "cx" ) )
00233 m_center.setX( KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "cx", QString::null ) ) );
00234 else
00235 m_center.setX( m_rx + KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "x", QString::null ) ) );
00236
00237 if( element.hasAttributeNS( KoXmlNS::svg, "cy" ) )
00238 m_center.setY( KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "cy", QString::null ) ) );
00239 else
00240 m_center.setY( m_ry + KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "y", QString::null ) ) );
00241
00242
00243
00244 QString kind = element.attributeNS( KoXmlNS::draw, "kind", QString::null );
00245 if( kind == "cut" )
00246 m_type = section;
00247 else if( kind == "section" )
00248 m_type = cut;
00249 else if( kind == "arc" )
00250 m_type = arc;
00251 else
00252 m_type = full;
00253
00254 double startAngle = element.attributeNS( KoXmlNS::draw, "start-angle", QString::null ).toDouble();
00255 double endAngle = element.attributeNS( KoXmlNS::draw, "end-angle", QString::null ).toDouble();
00256
00257
00258
00259 m_startAngle = 360.0 - endAngle;
00260 m_endAngle = 360.0 - startAngle;
00261
00262 init();
00263
00264
00265 m_startAngle = startAngle;
00266 m_endAngle = endAngle;
00267
00268 transformByViewbox( element, element.attributeNS( KoXmlNS::svg, "viewBox", QString::null ) );
00269
00270 QString trafo = element.attributeNS( KoXmlNS::draw, "transform", QString::null );
00271 if( !trafo.isEmpty() )
00272 transformOasis( trafo );
00273
00274 return VObject::loadOasis( element, context );
00275 }
00276
00277 void
00278 VEllipse::load( const QDomElement& element )
00279 {
00280 setState( normal );
00281
00282 QDomNodeList list = element.childNodes();
00283 for( uint i = 0; i < list.count(); ++i )
00284 if( list.item( i ).isElement() )
00285 VObject::load( list.item( i ).toElement() );
00286
00287 m_rx = KoUnit::parseValue( element.attribute( "rx" ) );
00288 m_ry = KoUnit::parseValue( element.attribute( "ry" ) );
00289
00290 m_center.setX( KoUnit::parseValue( element.attribute( "cx" ) ) );
00291 m_center.setY( KoUnit::parseValue( element.attribute( "cy" ) ) );
00292
00293 m_startAngle = element.attribute( "start-angle" ).toDouble();
00294 m_endAngle = element.attribute( "end-angle" ).toDouble();
00295
00296 if( element.attribute( "kind" ) == "cut" )
00297 m_type = cut;
00298 else if( element.attribute( "kind" ) == "section" )
00299 m_type = section;
00300 else if( element.attribute( "kind" ) == "arc" )
00301 m_type = arc;
00302 else
00303 m_type = full;
00304
00305 init();
00306
00307 QString trafo = element.attribute( "transform" );
00308 if( !trafo.isEmpty() )
00309 transform( trafo );
00310 }
00311
00312 VPath*
00313 VEllipse::clone() const
00314 {
00315 return new VEllipse( *this );
00316 }