karbon

vellipse.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 2001, 2002, 2003 The Karbon Developers
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
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     // to radials
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     // Create (half-)unity circle with topLeft at (0|0):
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     // Translate and scale:
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     // only tranform the path data
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         // save fill/stroke untransformed
00131         VPath path( *this );
00132         VTransformCmd cmd( 0L, m_matrix.invert() );
00133         cmd.visit( path );
00134         path.VObject::save( me );
00135         //VObject::save( me );
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     // do not save deleted objects
00165     if( state() == deleted )
00166         return;
00167 
00168     docWriter->startElement( "draw:ellipse" );
00169 
00170     //save all into pt
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         if( m_type == cut )
00181             docWriter->addAttribute( "draw:kind", "cut" );
00182         else if( m_type == section )
00183             docWriter->addAttribute( "draw:kind", "section" );
00184         else
00185             docWriter->addAttribute( "draw:kind", "arc" );
00186 
00187         docWriter->addAttribute( "draw:start-angle", m_startAngle );
00188         docWriter->addAttribute( "draw:end-angle", m_endAngle );
00189     }
00190 
00191     VObject::saveOasis( store, docWriter, mainStyles, index );
00192 
00193     QWMatrix tmpMat;
00194     tmpMat.scale( 1, -1 );
00195     tmpMat.translate( 0, -document()->height() );
00196     
00197     QString transform = buildOasisTransform( m_matrix*tmpMat );
00198     if( !transform.isEmpty() )
00199         docWriter->addAttribute( "draw:transform", transform );
00200 
00201     docWriter->endElement();
00202 }
00203 
00204 bool
00205 VEllipse::loadOasis( const QDomElement &element, KoOasisLoadingContext &context )
00206 {
00207     setState( normal );
00208 
00209     if( element.tagName() == "ellipse" )
00210     {
00211         if( element.hasAttributeNS( KoXmlNS::svg, "rx" ) )
00212             m_rx = KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "rx", QString::null ) );
00213         else 
00214             m_rx = 0.5 * KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "width", QString::null ) );
00215 
00216         if( element.hasAttributeNS( KoXmlNS::svg, "ry" ) )
00217             m_ry = KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "ry", QString::null ) );
00218         else 
00219             m_ry = 0.5 * KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "height", QString::null ) );
00220 
00221     }
00222     else if( element.tagName() == "circle" )
00223     {
00224         if( element.hasAttributeNS( KoXmlNS::svg, "r" ) )
00225             m_rx = m_ry = KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "r", QString::null ) );
00226         else 
00227             m_rx = m_ry = 0.5 * KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "width", QString::null ) );
00228     }
00229 
00230     if( element.hasAttributeNS( KoXmlNS::svg, "cx" ) )
00231         m_center.setX( KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "cx", QString::null ) ) );
00232     else
00233         m_center.setX( m_rx + KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "x", QString::null ) ) );
00234 
00235     if( element.hasAttributeNS( KoXmlNS::svg, "cy" ) )
00236         m_center.setY( KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "cy", QString::null ) ) );
00237     else
00238         m_center.setY( m_ry + KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "y", QString::null ) ) );
00239 
00240     m_startAngle = element.attributeNS( KoXmlNS::draw, "start-angle", QString::null ).toDouble();
00241     m_endAngle = element.attributeNS( KoXmlNS::draw, "end-angle", QString::null ).toDouble();
00242 
00243     QString kind = element.attributeNS( KoXmlNS::draw, "kind", QString::null );
00244     if( kind == "cut" )
00245         m_type = cut;
00246     else if( kind == "section" )
00247         m_type = section;
00248     else if( kind == "arc" )
00249         m_type = arc;
00250     else
00251         m_type = full;
00252 
00253     init();
00254 
00255     transformByViewbox( element, element.attributeNS( KoXmlNS::svg, "viewBox", QString::null ) );
00256 
00257     QString trafo = element.attributeNS( KoXmlNS::draw, "transform", QString::null );
00258     if( !trafo.isEmpty() )
00259         transformOasis( trafo );
00260 
00261     return VObject::loadOasis( element, context );
00262 }
00263 
00264 void
00265 VEllipse::load( const QDomElement& element )
00266 {
00267     setState( normal );
00268 
00269     QDomNodeList list = element.childNodes();
00270     for( uint i = 0; i < list.count(); ++i )
00271         if( list.item( i ).isElement() )
00272             VObject::load( list.item( i ).toElement() );
00273 
00274     m_rx = KoUnit::parseValue( element.attribute( "rx" ) );
00275     m_ry = KoUnit::parseValue( element.attribute( "ry" ) );
00276 
00277     m_center.setX( KoUnit::parseValue( element.attribute( "cx" ) ) );
00278     m_center.setY( KoUnit::parseValue( element.attribute( "cy" ) ) );
00279 
00280     m_startAngle = element.attribute( "start-angle" ).toDouble();
00281     m_endAngle = element.attribute( "end-angle" ).toDouble();
00282 
00283     if( element.attribute( "kind" ) == "cut" )
00284         m_type = cut;
00285     else if( element.attribute( "kind" ) == "section" )
00286         m_type = section;
00287     else if( element.attribute( "kind" ) == "arc" )
00288         m_type = arc;
00289     else
00290         m_type = full;
00291 
00292     init();
00293 
00294     QString trafo = element.attribute( "transform" );
00295     if( !trafo.isEmpty() )
00296         transform( trafo );
00297 }
00298 
00299 VPath* 
00300 VEllipse::clone() const
00301 {
00302     return new VEllipse( *this );
00303 }
KDE Home | KDE Accessibility Home | Description of Access Keys