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     docWriter->startElement( "draw:ellipse" );
00165 
00166     //save all into pt
00167     docWriter->addAttributePt( "svg:cx", m_center.x() );
00168     docWriter->addAttributePt( "svg:cy", m_center.y() );
00169     docWriter->addAttributePt( "svg:rx", m_rx );
00170     docWriter->addAttributePt( "svg:ry", m_ry );
00171 
00172     if( m_type == full )
00173         docWriter->addAttribute( "draw:kind", "full" );
00174     else
00175     {
00176         if( m_type == cut )
00177             docWriter->addAttribute( "draw:kind", "cut" );
00178         else if( m_type == section )
00179             docWriter->addAttribute( "draw:kind", "section" );
00180         else
00181             docWriter->addAttribute( "draw:kind", "arc" );
00182 
00183         docWriter->addAttribute( "draw:start-angle", m_startAngle );
00184         docWriter->addAttribute( "draw:end-angle", m_endAngle );
00185     }
00186 
00187     VObject::saveOasis( store, docWriter, mainStyles, index );
00188 
00189     QWMatrix tmpMat;
00190     tmpMat.scale( 1, -1 );
00191     tmpMat.translate( 0, -document()->height() );
00192     
00193     QString transform = buildOasisTransform( m_matrix*tmpMat );
00194     if( !transform.isEmpty() )
00195         docWriter->addAttribute( "draw:transform", transform );
00196 
00197     docWriter->endElement();
00198 }
00199 
00200 bool
00201 VEllipse::loadOasis( const QDomElement &element, KoOasisLoadingContext &context )
00202 {
00203     setState( normal );
00204 
00205     if( element.tagName() == "ellipse" )
00206     {
00207         if( element.hasAttributeNS( KoXmlNS::svg, "rx" ) )
00208             m_rx = KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "rx", QString::null ) );
00209         else 
00210             m_rx = 0.5 * KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "width", QString::null ) );
00211 
00212         if( element.hasAttributeNS( KoXmlNS::svg, "ry" ) )
00213             m_ry = KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "ry", QString::null ) );
00214         else 
00215             m_ry = 0.5 * KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "height", QString::null ) );
00216 
00217     }
00218     else if( element.tagName() == "circle" )
00219     {
00220         if( element.hasAttributeNS( KoXmlNS::svg, "r" ) )
00221             m_rx = m_ry = KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "r", QString::null ) );
00222         else 
00223             m_rx = m_ry = 0.5 * KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "width", QString::null ) );
00224     }
00225 
00226     if( element.hasAttributeNS( KoXmlNS::svg, "cx" ) )
00227         m_center.setX( KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "cx", QString::null ) ) );
00228     else
00229         m_center.setX( m_rx + KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "x", QString::null ) ) );
00230 
00231     if( element.hasAttributeNS( KoXmlNS::svg, "cy" ) )
00232         m_center.setY( KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "cy", QString::null ) ) );
00233     else
00234         m_center.setY( m_ry + KoUnit::parseValue( element.attributeNS( KoXmlNS::svg, "y", QString::null ) ) );
00235 
00236     m_startAngle = element.attributeNS( KoXmlNS::draw, "start-angle", QString::null ).toDouble();
00237     m_endAngle = element.attributeNS( KoXmlNS::draw, "end-angle", QString::null ).toDouble();
00238 
00239     QString kind = element.attributeNS( KoXmlNS::draw, "kind", QString::null );
00240     if( kind == "cut" )
00241         m_type = cut;
00242     else if( kind == "section" )
00243         m_type = section;
00244     else if( kind == "arc" )
00245         m_type = arc;
00246     else
00247         m_type = full;
00248 
00249     init();
00250 
00251     transformByViewbox( element, element.attributeNS( KoXmlNS::svg, "viewBox", QString::null ) );
00252 
00253     QString trafo = element.attributeNS( KoXmlNS::draw, "transform", QString::null );
00254     if( !trafo.isEmpty() )
00255         transformOasis( trafo );
00256 
00257     return VObject::loadOasis( element, context );
00258 }
00259 
00260 void
00261 VEllipse::load( const QDomElement& element )
00262 {
00263     setState( normal );
00264 
00265     QDomNodeList list = element.childNodes();
00266     for( uint i = 0; i < list.count(); ++i )
00267         if( list.item( i ).isElement() )
00268             VObject::load( list.item( i ).toElement() );
00269 
00270     m_rx = KoUnit::parseValue( element.attribute( "rx" ) );
00271     m_ry = KoUnit::parseValue( element.attribute( "ry" ) );
00272 
00273     m_center.setX( KoUnit::parseValue( element.attribute( "cx" ) ) );
00274     m_center.setY( KoUnit::parseValue( element.attribute( "cy" ) ) );
00275 
00276     m_startAngle = element.attribute( "start-angle" ).toDouble();
00277     m_endAngle = element.attribute( "end-angle" ).toDouble();
00278 
00279     if( element.attribute( "kind" ) == "cut" )
00280         m_type = cut;
00281     else if( element.attribute( "kind" ) == "section" )
00282         m_type = section;
00283     else if( element.attribute( "kind" ) == "arc" )
00284         m_type = arc;
00285     else
00286         m_type = full;
00287 
00288     init();
00289 
00290     QString trafo = element.attribute( "transform" );
00291     if( !trafo.isEmpty() )
00292         transform( trafo );
00293 }
00294 
00295 VPath* 
00296 VEllipse::clone() const
00297 {
00298     return new VEllipse( *this );
00299 }
KDE Home | KDE Accessibility Home | Description of Access Keys