/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/
#include <bf_svx/eeitem.hxx>
#ifndef _ZFORLIST_HXX //autogen
#ifndef _ZFORLIST_DECLARE_TABLE
#define _ZFORLIST_DECLARE_TABLE
#endif
#include <bf_svtools/zforlist.hxx>
#endif

#include <bf_svx/svdocirc.hxx>
#include <bf_svx/svdopath.hxx>

#include "schattr.hxx"
#ifndef _SVX_CHRTITEM_HXX //autogen
#define ITEMID_DOUBLE           0
#define ITEMID_CHARTDATADESCR   SCHATTR_DATADESCR_DESCR
#endif

#define ITEMID_FONTHEIGHT  EE_CHAR_FONTHEIGHT
#define ITEMID_FONTWIDTH   EE_CHAR_FONTWIDTH
#include <bf_svx/fwdtitem.hxx>
#include <bf_svx/fhgtitem.hxx>
#include <bf_svx/svxids.hrc>

#include "strings.hrc"
#include "glob.hrc"
#include <math.h>
#include <float.h>

#include "pairs.hxx"
#include "globfunc.hxx"
#include "arrayhelper.hxx"

#include <bf_svx/xlineit.hxx>
// header for Line

#include "chaxis.hxx"
#include "chdescr.hxx"
#include "calculat.hxx"

namespace binfilter {

#define SCH_SIN(a)      (sin((double)a * F_PI / 18000.0))
#define SCH_COS(a)      (cos((double)a * F_PI / 18000.0))

/*************************************************************************
|*
|* Kreisdiagramm erzeugen
|*
\************************************************************************/
/*N*/ SdrObjGroup* ChartModel::Create2DPieChart(Rectangle aRect)
/*N*/ {
/*N*/   SchObjGroup *pGroup;
/*N*/   SdrObjList  *pList;
/*N*/
/*N*/   CreateChartGroup (pGroup, pList);
/*N*/
/*N*/   // pie charts always have row number 0 for now
/*N*/   const long          nRow = 0;
/*N*/
/*N*/   double              fTotal  = 0.0;
/*N*/   long                nColCnt = GetColCount();
/*N*/   long                nSegOfsMax = 0;
/*N*/
/*N*/   SchObjGroup*        pDescrGroup  = NULL;
/*N*/   SdrObjList          *pDescrList  = NULL;
/*N*/   DataDescription*    pDescription = NULL;
/*N*/   long                nCol;
/*N*/   Size                aDescrOfs;
/*N*/
/*N*/   //  Pie charts may not have titles of axes.
/*N*/   bShowXAxisTitle = FALSE;
/*N*/   bShowYAxisTitle = FALSE;
/*N*/   bShowZAxisTitle = FALSE;
/*N*/
/*N*/   // determine the space required by the chart. For this chart type
/*N*/   // the labelling is also taken into the calculation
/*N*/   pDescrList = 0;
/*N*/
/*N*/   for (nCol = 0; nCol < nColCnt; nCol++)
/*N*/   {
/*N*/       double fData = GetData (nCol, nRow);
/*N*/       if (fData != DBL_MIN) fTotal += fabs(fData);
/*N*/   }
/*N*/
/*N*/   for( nCol = 0; nCol < nColCnt; nCol++ )
/*N*/   {
/*N*/       nSegOfsMax = Max( PieSegOfs( nCol ), nSegOfsMax );
/*N*/   }
/*N*/
/*N*/   // shrink rectangle if labels are printed beside the pies
/*N*/   if (pDescription)
/*N*/   {
/*N*/       // shrink by size of description text plus a
/*?*/       // percentage of the rect size as text offset
/*?*/       long nShrinkX = aDescrOfs.Width() + (aRect.GetWidth() / 20);
/*?*/       long nShrinkY = aDescrOfs.Height() + (aRect.GetHeight() / 20);
/*?*/
/*?*/       aRect.Left()   += nShrinkX;
/*?*/       aRect.Right()  -= nShrinkX;
/*?*/       aRect.Top()    += nShrinkY;
/*?*/       aRect.Bottom() -= nShrinkY;
/*N*/   }
/*N*/
/*N*/   // make sure the pie rectangle is a square
/*N*/   // shrink rect
/*N*/   if (aRect.GetWidth() > aRect.GetHeight())
/*N*/   {
/*N*/       aRect.Left() += (aRect.GetWidth() - aRect.GetHeight()) / 2;
/*N*/       aRect.Right() = aRect.Left() + aRect.GetHeight();
/*N*/   }
/*N*/   else if (aRect.GetHeight() > aRect.GetWidth())
/*N*/   {
/*?*/       aRect.Top() += (aRect.GetHeight() - aRect.GetWidth()) / 2;
/*?*/       aRect.Bottom() = aRect.Top() + aRect.GetWidth();
/*N*/   }
/*N*/
/*N*/   long nEndAng = 9000;
/*N*/   long nSegOfs;
/*N*/
/*N*/   Rectangle aDefaultCircRect = aRect;
/*N*/   Rectangle aCircRect;
/*N*/
/*N*/   // shrink default circle rectangle (square) to allow exploded pie segments
/*N*/   if( nSegOfsMax )
/*N*/   {
/*?*/       double fRadius = (double)(aDefaultCircRect.GetWidth()) / 2.0;
/*?*/       long   nRadiusDiff = (long)(fRadius * (1.0 - (1.0  / (1.0 + ((double)nSegOfsMax / 100.0)))));
/*?*/       aDefaultCircRect.Left()     += nRadiusDiff;
/*?*/       aDefaultCircRect.Right()    -= nRadiusDiff;
/*?*/
/*?*/       aDefaultCircRect.Top()      += nRadiusDiff;
/*?*/       aDefaultCircRect.Bottom()   -= nRadiusDiff;
/*N*/   }
/*N*/   nPieRadius = aDefaultCircRect.GetWidth() / 2;   // member set to query radius of pie segments
/*N*/
/*N*/   // create all pie objects
/*N*/   for( nCol = 0; nCol < nColCnt; nCol++ )
/*N*/   {
/*N*/       long       nStartAng      = nEndAng;
/*N*/       SfxItemSet aDataPointAttr( GetFullDataPointAttr( nCol, nRow ));
/*N*/       long       nIndex         = nCol + nRow * nColCnt;
/*N*/       double     fData          = fabs( GetData( nCol, nRow ));
/*N*/
/*N*/       if (fData != DBL_MIN)
/*N*/       {
/*N*/           if( nCol == nColCnt - 1 )
/*N*/           {
/*N*/                 // ensure that the circle is closed even if we start at 90 degrees
/*N*/               nEndAng = 9000 + 36000;
/*N*/           }
/*N*/           else if( fTotal != 0.0 )
/*N*/           {
/*?*/               nEndAng += (long)((fData / fTotal) * 36000);
/*N*/           }
/*N*/
/*N*/           aCircRect = aDefaultCircRect;
/*N*/
/*N*/           nSegOfs = PieSegOfs(nCol);
/*N*/           if( nSegOfs )
/*N*/           {
/*?*/               double fSegShift = (double)(nPieRadius * nSegOfs) / 100.0;
/*?*/
/*?*/               Point aCircPos = aCircRect.TopLeft();
/*?*/
/*?*/               long nAngleDiff;
/*?*/
/*?*/               // determine the bisector angle
/*?*/               if (nStartAng > nEndAng)
/*?*/                   nAngleDiff = (nEndAng + 36000 - nStartAng) / 2;
/*?*/               else
/*?*/                   nAngleDiff = (nEndAng - nStartAng) / 2;
/*?*/
/*?*/               // set the text position according to the position of the pie
/*?*/               if (nStartAng < 9000)
/*?*/               {
/*?*/                   long   nAngle = nAngleDiff + nStartAng;
/*?*/
/*?*/                   aCircPos.X() += (long) (SCH_COS( nAngle ) * fSegShift);
/*?*/                   aCircPos.Y() -= (long) (SCH_SIN( nAngle ) * fSegShift);
/*?*/               }
/*?*/               else if (nStartAng < 18000)
/*?*/               {
/*?*/                   long   nAngle = nAngleDiff + (nStartAng - 9000);
/*?*/
/*?*/                   aCircPos.X() -= (long) (SCH_SIN( nAngle ) * fSegShift);
/*?*/                   aCircPos.Y() -= (long) (SCH_COS( nAngle ) * fSegShift);
/*?*/               }
/*?*/               else if (nStartAng < 27000)
/*?*/               {
/*?*/                   long   nAngle = nAngleDiff + (nStartAng - 18000);
/*?*/
/*?*/                   aCircPos.X() -= (long) (SCH_COS( nAngle ) * fSegShift);
/*?*/                   aCircPos.Y() += (long) (SCH_SIN( nAngle ) * fSegShift);
/*?*/               }
/*?*/               else
/*?*/               {
/*?*/                   long   nAngle = nAngleDiff + (nStartAng - 27000);
/*?*/
/*?*/                   aCircPos.X() += (long) (SCH_SIN( nAngle ) * fSegShift);
/*?*/                   aCircPos.Y() += (long) (SCH_COS( nAngle ) * fSegShift);
/*?*/               }
/*?*/
/*?*/               aCircRect.SetPos(aCircPos);
/*?*/           }
/*N*/
/*N*/           // pies and description are not grouped
/*N*/           if( fData > 0 )
/*N*/           {
/*N*/               SdrObject* pObj = CreatePieSegment( aDataPointAttr, aCircRect, nCol, nRow,
/*N*/                                                   nStartAng, nEndAng, GetColCount() );
/*N*/               pObj->SetMoveProtect( FALSE );      // bm allow dragging pies
/*N*/               pList->NbcInsertObject( pObj );
/*N*/           }
/*N*/
/*N*/       }
/*N*/       else if( pDescription )
/*N*/       {
/*?*/           pDescription[ nIndex ].fValue = DBL_MIN;
/*N*/       }
/*N*/   }
/*N*/
/*N*/   if(pDescrGroup)
/*?*/       pList->NbcInsertObject(pDescrGroup);
/*N*/
/*N*/   pGroup->GetSubList ()->SetRectsDirty ();
/*N*/
/*N*/   // resize of pie charts is allowed proportionally only
/*N*/   SdrObjTransformInfoRec aLclInfo;
/*N*/   aLclInfo.bResizeFreeAllowed    = FALSE;
/*N*/   aLclInfo.bResizePropAllowed    = TRUE;
/*N*/   aLclInfo.bRotateFreeAllowed    = FALSE;
/*N*/   aLclInfo.bRotate90Allowed      = FALSE;
/*N*/   aLclInfo.bMirrorFreeAllowed    = FALSE;
/*N*/   aLclInfo.bMirror45Allowed      = FALSE;
/*N*/   aLclInfo.bMirror90Allowed      = FALSE;
/*N*/   aLclInfo.bShearAllowed         = FALSE;
/*N*/   pGroup->SetObjInfo(aLclInfo);
/*N*/
/*N*/   Dirty2D (1, nColCnt, &pDescrList, FALSE, pDescription);
/*N*/
/*N*/   delete[] pDescription;
/*N*/
/*N*/   return pGroup;
/*N*/ }
/*************************************************************************
|*
|* Donutdiagramm erzeugen
|*
\************************************************************************/
/*N*/ SdrObjGroup* ChartModel::Create2DDonutChart(Rectangle aRect)
/*N*/ {
/*N*/   SchObjGroup *pGroup;
/*N*/   SdrObjList  *pList;
/*N*/
/*N*/   CreateChartGroup (pGroup, pList);
/*N*/
/*N*/   long              nCol;
/*N*/   long              nRow;
/*N*/
/*N*/   long              nColCnt       = GetColCount() ;
/*N*/   long              nRowCnt       = GetRowCount() ;
/*N*/
/*N*/ 	double	          *pTotal       = ArrayHelper<double>::create_long_size(nColCnt);
/*N*/ 	SdrObjList        **pRowLists   = ArrayHelper<SdrObjList*>::create_long_size(nRowCnt);
/*N*/ 	SdrObjList        **pDescrLists = ArrayHelper<SdrObjList*>::create_long_size(nRowCnt);
/*N*/   DataDescription*  pDescription = NULL;
/*N*/   Size              aDescrOfs;
/*N*/
/*N*/   //  Donut charts may not have titles of axes.
/*N*/   bShowXAxisTitle = FALSE;
/*N*/   bShowYAxisTitle = FALSE;
/*N*/   bShowZAxisTitle = FALSE;
/*N*/
/*N*/ 	SchObjGroup**    pDescrGroups = ArrayHelper<SchObjGroup*>::create_long_size(nRowCnt);
        if( !pTotal || !pRowLists || !pDescrLists || !pDescrGroups )
        {
            delete[] pTotal;
            delete[] pRowLists;
            delete[] pDescrLists;
            delete[] pDescrGroups;
            return pGroup;
        }
/*N*/   for(nRow=0;nRow<nRowCnt;nRow++)
/*N*/       pDescrGroups[nRow]=NULL;
/*N*/
/*N*/   //Summiere ueber alle Elemente der gleichen Spalte (nicht Reihe!),
/*N*/   for (nCol = 0; nCol < nColCnt; nCol++)
/*N*/   {
/*N*/      pTotal [nCol]     = 0.0;
/*N*/      for (nRow = 0; nRow < nRowCnt; nRow++)
/*N*/       {
/*N*/           double fData = GetData (nCol, nRow);
/*N*/           if (fData != DBL_MIN) pTotal [nCol] += fabs(fData);
/*N*/      }
/*N*/   }

    // FG: 22.3.97 Als erstes wird der Platzbedarf der Beschriftung berechnet.
    //     Bei diesem Chart-Typ ist die Beschriftung mit in die Berechnung der
    //     Chartgroesse einbezogen worden.
/*N*/   for (nRow = 0; nRow < nRowCnt; nRow++)
/*N*/   {
/*N*/       SchObjGroup *pRowGroup = (SchObjGroup*) CreateSimpleGroup (CHOBJID_DIAGRAM_ROWGROUP, TRUE, TRUE);
/*N*/
/*N*/       pRowGroup->InsertUserData(new SchDataRow((short)nRow));
/*N*/       pList->NbcInsertObject(pRowGroup);
/*N*/       pRowLists[nRow]   = pRowGroup->GetSubList();
/*N*/       pDescrLists[nRow] = 0;
/*N*/   }//End for nRow

    // Das Rechteck wird dann etwas kleiner, da Text ausgegeben wird
/*N*/   if (pDescription)
/*N*/   {
/*?*/       aRect.Left()   += aDescrOfs.Width();
/*?*/       aRect.Top()    += aDescrOfs.Height();
/*?*/       aRect.Right()  -= aDescrOfs.Width();
/*?*/       aRect.Bottom() -= aDescrOfs.Height();
/*?*/
/*?*/       // prozentual verkleinern wir es noch etwas, um einen Offset zum Text zu bekommen
/*?*/       long nWidth  = (aRect.GetWidth () * 1) / 20;
/*?*/       long nHeight = (aRect.GetHeight () * 1) / 20;
/*?*/
/*?*/       aRect.Left ()   += nWidth;
/*?*/       aRect.Right ()  -= nWidth;
/*?*/       aRect.Top ()    += nHeight;
/*?*/       aRect.Bottom () -= nHeight;
/*N*/   }

/*N*/   SdrPage* pPage=GetPage(0);
/*N*/   Size aPageSize = pPage->GetSize();
/*N*/   if (GetDiagramHasBeenMovedOrResized() && (aInitialSize != aPageSize))
/*N*/   {                                           //  in dem Fall hat ein Resize stattgefunden
/*?*/       if (aInitialSize.Width() > aPageSize.Width())
/*?*/       {
/*?*/           if (aRect.GetWidth() > aRect.GetHeight())
/*?*/           {
/*?*/               aRect.Left() += (aRect.GetWidth() - aRect.GetHeight()) / 2;
/*?*/               aRect.Right() = aRect.Left() + aRect.GetHeight();
/*?*/           }
/*?*/           else if (aRect.GetHeight() > aRect.GetWidth())
/*?*/           {
/*?*/               aRect.Top() += (aRect.GetHeight() - aRect.GetWidth()) / 2;
/*?*/               aRect.Bottom() = aRect.Top() + aRect.GetWidth();
/*?*/           }
/*?*/       }
/*?*/       else
/*?*/       {
/*?*/           if (aInitialSize.Height() > aPageSize.Height())
/*?*/           {
/*?*/               if (aRect.GetWidth() > aRect.GetHeight())
/*?*/               {
/*?*/                   aRect.Left() += (aRect.GetWidth() - aRect.GetHeight()) / 2;
/*?*/                   aRect.Right() = aRect.Left() + aRect.GetHeight();
/*?*/               }
/*?*/               else if (aRect.GetHeight() > aRect.GetWidth())
/*?*/               {
/*?*/                   aRect.Top() += (aRect.GetHeight() - aRect.GetWidth()) / 2;
/*?*/                   aRect.Bottom() = aRect.Top() + aRect.GetWidth();
/*?*/               }
/*?*/           }
/*?*/           else
/*?*/           {
/*?*/               if (aRect.GetWidth() > aRect.GetHeight())
/*?*/               {
/*?*/                   aRect.Top() += (aRect.GetHeight() - aRect.GetWidth()) / 2;
/*?*/                   aRect.Bottom() = aRect.Top() + aRect.GetWidth();
/*?*/               }
/*?*/               else if (aRect.GetHeight() > aRect.GetWidth())
/*?*/               {
/*?*/                   aRect.Left() += (aRect.GetWidth() - aRect.GetHeight()) / 2;
/*?*/                   aRect.Right() = aRect.Left() + aRect.GetHeight();
/*?*/               }
/*?*/           }
/*?*/       }
/*N*/   }
/*N*/   else  // *************  nicht gemoved oder resized *****************************
/*N*/   {
/*N*/       // FG: Hier wird dafuer gesorgt, dass die Chart-Groesse immer ein Rechteck ist.
/*N*/       if (aRect.GetWidth() > aRect.GetHeight())
/*N*/       {
/*N*/           aRect.Left() += (aRect.GetWidth() - aRect.GetHeight()) / 2;
/*N*/           aRect.Right() = aRect.Left() + aRect.GetHeight();
/*N*/       }
/*N*/       else if (aRect.GetHeight() > aRect.GetWidth())
/*N*/       {
/*?*/           aRect.Top() += (aRect.GetHeight() - aRect.GetWidth()) / 2;
/*?*/           aRect.Bottom() = aRect.Top() + aRect.GetWidth();
/*N*/       }
/*N*/   }
/*N*/
/*N*/   ULONG nSegWidth = (aRect.Right() - aRect.Left()) / (2 * (nColCnt + 1));
/*N*/
/*N*/   for (nCol = 0; nCol < nColCnt; nCol++) //alle Ringe des Donuts
/*N*/   {
/*N*/       long nStartAng, nEndAng      = 9000; //90 Grad
/*N*/
/*N*/       double fTotal = pTotal[nCol];
/*N*/
/*N*/       for (nRow = 0; nRow < nRowCnt; nRow++) //Alle Datenreihen
/*N*/       {
/*N*/           nStartAng      = nEndAng;
/*N*/           SfxItemSet aDataPointAttr(GetFullDataPointAttr(nCol, nRow));
/*N*/           long      nIndex          = nCol + nRow * nColCnt;//            long       nIndex         = nRow + nRowCnt * nCol ;
/*N*/
/*N*/
/*N*/           double fData = fabs(GetData(nCol, nRow));
/*N*/
/*N*/           if (fData != DBL_MIN)
/*N*/           {
/*N*/               //letzte Datenreihe ?? (eigentlich Unsinn, nur wegen evtl. Rundungsfehler  notwendig?
/*N*/               if (nRow == nRowCnt - 1)
/*N*/               {
/*N*/                   nEndAng = 9000;
/*N*/               }
/*N*/               else if (fTotal != 0.0)
/*N*/               {
/*N*/                   nEndAng += (long)((fData / fTotal) * 36000);
/*N*/               }
/*N*/
/*N*/               Rectangle aCircRect = aRect;
/*N*/
/*N*/               if( fData > 0.0 )
/*N*/                   // Die Segmente einer Reihe werden nicht gruppiert!
/*N*/                   // Diese Ausnahme besteht, da sonst eine Reihe Segmente anderer Reihen
/*N*/                   // verdeckt (Gruppenobjekte koennen nicht ineinnander greifen (Problem
/*N*/                   // des Drawinglayer), vorher: pRowLists[nRow]-> ...
/*N*/                   pList->NbcInsertObject( CreateDonutSegment( aDataPointAttr,
/*N*/                                                            aCircRect, nSegWidth,
/*N*/                                                            nCol, nRow,
/*N*/                                                            nStartAng, nEndAng, nRowCnt));
/*N*/
/*N*/           }
/*N*/           else if (pDescription)
/*N*/           {
/*N*/               pDescription [nIndex].fValue = DBL_MIN;
/*N*/           }
/*N*/
/*N*/       }//Alle Datenreihen
/*N*/
/*N*/       //Jetzt wird die Flaeche verkleinert, um den naechst-inneren Pie zu zeichnen,
/*N*/       //Ein Donut ist nichts anderes als ein Tuerme-von-Hanoi artiger Pie-Stapel
/*N*/       aRect.Left()   += nSegWidth;
/*N*/       aRect.Top()    += nSegWidth;
/*N*/       aRect.Right()  -= nSegWidth;
/*N*/       aRect.Bottom() -= nSegWidth;
/*N*/   }//Alle Ringe
/*N*/
/*N*/   const XFillStyleItem &rFillStyleItem = (const XFillStyleItem &) pDiagramAreaAttr->Get (XATTR_FILLSTYLE);
/*N*/   SfxItemSet           aAreaAttr (*pDiagramAreaAttr);
/*N*/
/*N*/   if (rFillStyleItem.GetValue () == XFILL_NONE)
/*N*/   {
/*N*/       aAreaAttr.Put(XFillStyleItem(XFILL_SOLID));
/*N*/       aAreaAttr.Put(XFillColorItem(String(), RGBColor(COL_WHITE)));
/*N*/   }
/*N*/
/*N*/   aAreaAttr.Put(XLineStyleItem(XLINE_SOLID));
/*N*/   aAreaAttr.Put(XLineWidthItem(0));
/*N*/   aAreaAttr.Put(XLineColorItem(String(), RGBColor(COL_BLACK)));
/*N*/
/*N*/   SdrCircObj* pCirc = new SdrCircObj(OBJ_CIRC, aRect);
/*N*/   pList->NbcInsertObject(SetObjectAttr( pCirc, CHOBJID_DIAGRAM_AREA, TRUE, TRUE, &aAreaAttr));
/*N*/
/*N*/   //Descriptions zuletzt, da sie sonst verdeckt sind!
/*N*/   for(nRow=0;nRow<nRowCnt;nRow++)
/*N*/   {
/*N*/       if(pDescrGroups[nRow])
/*N*/       {
/*?*/            pList->NbcInsertObject(pDescrGroups[nRow]);
/*N*/       }
/*N*/   }
/*N*/
/*N*/   pGroup->GetSubList()->SetRectsDirty();
/*N*/
/*N*/   // Ein Kreisdiagramm soll man nur proportional Resizen koennen (vorerst)
/*N*/   SdrObjTransformInfoRec aLclInfo;
/*N*/   aLclInfo.bResizeFreeAllowed    = FALSE;
/*N*/   aLclInfo.bResizePropAllowed    = TRUE;
/*N*/   aLclInfo.bRotateFreeAllowed    = FALSE;
/*N*/   aLclInfo.bRotate90Allowed      = FALSE;
/*N*/   aLclInfo.bMirrorFreeAllowed    = FALSE;
/*N*/   aLclInfo.bMirror45Allowed      = FALSE;
/*N*/   aLclInfo.bMirror90Allowed      = FALSE;
/*N*/   aLclInfo.bShearAllowed         = FALSE;
/*N*/   pGroup->SetObjInfo(aLclInfo);
/*N*/
/*N*/   Dirty2D (nRowCnt, nColCnt, pDescrLists, TRUE, pDescription);
/*N*/
/*N*/   delete[] pTotal;
/*N*/   delete[] pDescription;
/*N*/   delete[] pDescrLists;
/*N*/   delete[] pRowLists;
/*N*/   delete[] pDescrGroups;
/*N*/
/*N*/
/*N*/   return pGroup;
/*N*/ }
/*************************************************************************
|*
|* XY-Diagramm erzeugen
|*
\************************************************************************/
/*N*/ SdrObjGroup* ChartModel::Create2DXYChart(Rectangle aRect)
/*N*/ {
/*N*/   long    nColCnt = GetColCount();
/*N*/     long    nRowCnt = GetRowCount();
/*N*/
/*N*/   long    nCol, nRow;
/*N*/
/*N*/   // ask for sorting
/*N*/
/*N*/   BOOL    bRepaint   = FALSE;

/*N*/   SchObjGroup *pGroup;
/*N*/   SdrObjList  *pList;
/*N*/   SdrObject   *pObj;
/*N*/     SdrPathObj  *pLineObject = NULL;
/*N*/
/*N*/   CreateChartGroup (pGroup, pList);
/*N*/
/*N*/   SdrPage* pPage = GetPage(0);
/*N*/
/*N*/   Create2DBackplane(aRect, *pList, TRUE,CHSTACK_NONE);
/*N*/
/*N*/ 	SdrObjList      ** pRowLists   = ArrayHelper<SdrObjList*>::create_long_size(nRowCnt);
/*N*/ 	SdrObjList      ** pStatLists  = ArrayHelper<SdrObjList*>::create_long_size(nRowCnt);
        if( !pRowLists || !pStatLists )
        {
            delete[] pRowLists;
            delete[] pStatLists;
            return pGroup;
        }
/*N*/   Size            aLegendSize (((SvxFontWidthItem &) pLegendAttr->Get (EE_CHAR_FONTWIDTH)).GetWidth (),
/*N*/                                ((SvxFontHeightItem &) pLegendAttr->Get (EE_CHAR_FONTHEIGHT)).GetHeight ());
/*N*/
/*N*/
/*N*/   ChartDataDescription aDescr(nColCnt,nRowCnt,pList,this,bShowDataDescr);

    //#54884# Was soll das hier? //Create2DXYChart
/*N*/     OutputDevice * pRefDev = GetRefDevice();
/*N*/   if(pRefDev)
/*N*/       aLegendSize = pRefDev->PixelToLogic (pRefDev->LogicToPixel (aLegendSize));
/*N*/   else
/*N*/       OSL_FAIL("ChartModel: no RefDevice");
/*N*/
/*N*/   long nLegendHeight = aLegendSize.Height () * 9 / 10;
/*N*/
/*N*/   pRowLists [0]  =
/*N*/   pStatLists [0] = 0;
/*N*/
/*N*/   XPolygon aPolygon ((unsigned short)nColCnt);
/*N*/
/*N*/   SfxItemSet aLineAttr(*pItemPool, XATTR_LINE_FIRST, XATTR_LINE_LAST, 0);
/*N*/
/*N*/   ChartAxis* pAxis=pChartYAxis;
/*N*/   BOOL    bLogarithmY   = pAxis->IsLogarithm();
/*N*/   BOOL    bLogarithmX   = pChartXAxis->IsLogarithm();
/*N*/
/*N*/   // for some reason the ChartRect is one pixel too small
/*N*/   Rectangle aClipRect( aRect );
/*N*/   aClipRect.Right() += 1;
/*N*/   aClipRect.Top() -= 1;
/*N*/
/*N*/   //  Iterate in reverse order over the data series so that the first one is displayed
/*N*/   //  in the front and the last one in the back.
/*N*/   for( nRow = nRowCnt-1; nRow >= 1; nRow-- )
/*N*/   {
/*N*/       SchObjGroup* pRowGroup = (SchObjGroup*) CreateSimpleGroup (CHOBJID_DIAGRAM_ROWGROUP, TRUE, TRUE);
/*N*/
/*N*/       pRowGroup->InsertUserData(new SchDataRow((short)nRow));
/*N*/       pList->NbcInsertObject(pRowGroup);
/*N*/       pRowLists[nRow] = pRowGroup->GetSubList();
/*N*/
/*N*/       SchObjGroup* pStatGroup = (SchObjGroup*) CreateSimpleGroup (CHOBJID_DIAGRAM_STATISTICS_GROUP, TRUE, TRUE);
/*N*/
/*N*/       pStatGroup->InsertUserData(new SchDataRow((short)nRow));
/*N*/       pList->NbcInsertObject(pStatGroup);
/*N*/       pStatLists [nRow] = pStatGroup->GetSubList ();
/*N*/
/*N*/       const SfxItemSet& rDataRowAttr = GetDataRowAttr(nRow);
/*N*/
/*N*/       pAxis=GetAxisByUID(((const SfxInt32Item&)rDataRowAttr.Get(SCHATTR_AXIS)).GetValue());
/*N*/       bLogarithmY = pAxis->IsLogarithm();
/*N*/
/*N*/       long nPoints = 0;
/*N*/         pLineObject  = NULL;
/*N*/
/*N*/
/*N*/         for (nCol = 0; nCol < nColCnt; nCol++)
/*N*/       {
/*N*/           SfxItemSet aDataPointAttr(rDataRowAttr);//#63904#
/*N*/           MergeDataPointAttr(aDataPointAttr,nCol,nRow);
/*N*/
/*N*/           Point  aPoint;
/*N*/           double fDataY    = GetData(nCol, nRow, FALSE);
/*N*/           double fDataX    = GetData(nCol, 0, FALSE);
/*N*/
/*N*/             if (((fDataX != DBL_MIN) && (!bLogarithmX || (bLogarithmX && (fDataX > 0.0)))) &&
/*N*/               ((fDataY != DBL_MIN) && (!bLogarithmY || (bLogarithmY && (fDataY > 0.0)))))
/*N*/           {
/*N*/               long nXPos = pChartXAxis->GetPos(fDataX);
/*N*/               long nYPos = pAxis->GetPos(fDataY);
/*N*/
/*N*/                 // expect nPoints to be 0 on first entry of the for loop
/*N*/                 // insert the empty polygon now, so that symbols are painted over the line
/*N*/                 if( nPoints == 0 &&
/*N*/                     IsLine( nRow ))
/*N*/                 {
/*N*/                     XPolyPolygon aSeriesPoly;
/*N*/                     pLineObject = new SdrPathObj( OBJ_PLIN, aSeriesPoly );
/*N*/                     pRowLists[ nRow ]->NbcInsertObject( pLineObject);
/*N*/                 }
/*N*/               aPolygon [(USHORT) nPoints].X () = nXPos;
/*N*/               aPolygon [(USHORT) nPoints].Y () = nYPos;
/*N*/               nPoints ++;
/*N*/
/*N*/               aPoint.X () = nXPos;
/*N*/               aPoint.Y () = nYPos;
/*N*/
/*N*/               // draw symbols only if they are contained in the diagrams boundrect
/*N*/               if( aClipRect.IsInside( aPoint ) )
/*N*/               {
/*N*/                   if(HasSymbols(nRow))
/*N*/                   {
/*N*/                       pObj = CreateSymbol (aPoint, nRow, nCol, aDataPointAttr, nLegendHeight);
/*N*/                       if(pObj)
/*N*/                       {
/*N*/                           pObj->InsertUserData(new SchObjectId(CHOBJID_DIAGRAM_DATA));
/*N*/                           pRowLists[nRow]->NbcInsertObject(pObj);
/*N*/                       }
/*N*/                   }
/*N*/
/*N*/                   if(aDescr.Enabled())
/*N*/                   {
/*N*/                       Point aPos(aPolygon[(USHORT)nPoints-1]);
/*N*/                       aPos.Y () -= 150;
/*N*/                   }
/*N*/               }
/*N*/
/*N*/           }
/*N*/       }
/*N*/
/*N*/       if(nPoints && IsLine(nRow))
/*N*/       {
/*N*/             aPolygon.SetPointCount( nPoints );
/*N*/
/*N*/             // clear old items from last loop pass
/*N*/             aLineAttr.ClearItem();
/*N*/           aLineAttr.Put(rDataRowAttr);
/*N*/
/*N*/           if( nPoints > 1 )
/*N*/           {
/*N*/               XPolyPolygon aSeriesPoly;
/*N*/
                    // line (or stripped spline)
/*N*/               {
/*N*/                   SchCalculationHelper::IntersectPolygonWithRectangle( aPolygon, aClipRect, aSeriesPoly );
/*N*/
/*N*/                     if( pLineObject )
/*N*/                         pLineObject->NbcSetPathPoly( aSeriesPoly );
/*N*/                     else
/*N*/                     {
/*?*/                         pLineObject = new SdrPathObj( OBJ_PLIN, aSeriesPoly );
/*?*/                         pRowLists[ nRow ]->NbcInsertObject( pLineObject);
/*N*/                     }
/*N*/               }
/*N*/
/*N*/               pLineObject->InsertUserData( new SchObjectId( CHOBJID_DIAGRAM_ROWSLINE ));
/*N*/               pLineObject->InsertUserData( new SchDataRow( (short)nRow ));
/*N*/
/*N*/               pLineObject->SetItemSet( aLineAttr);
/*N*/
/*N*/           }
/*N*/       }
/*N*/   }

/*N*/   aDescr.Build(TRUE);
/*N*/
/*N*/   if( bRepaint )
/*?*/       pPage->SendRepaintBroadcast();
/*N*/
/*N*/   delete[] pRowLists;
/*N*/   delete[] pStatLists;
/*N*/   return pGroup;
/*N*/ }


/*************************************************************************
|*
|* Netzdiagramm erzeugen
|*
\************************************************************************/

/*N*/ SdrObjGroup* ChartModel::Create2DNetChart(Rectangle aRect)
/*N*/ {
/*N*/   //vorlaeufiger Hack, bis logarithmus-Ueberpruefung eingebaut (autokorrektur):
/*N*/   pChartXAxis->GetItemSet()->Put(SfxBoolItem(SCHATTR_AXIS_LOGARITHM,FALSE));
/*N*/   pChartYAxis->GetItemSet()->Put(SfxBoolItem(SCHATTR_AXIS_LOGARITHM,FALSE));
/*N*/
/*N*/   //ToDo: vorlaeufig
/*N*/   SfxItemSet* pYAxisAttr=&GetAttr(CHOBJID_DIAGRAM_Y_AXIS);
/*N*/
/*N*/   SchObjGroup *pGroup;
/*N*/   SdrObjList  *pList;
/*N*/   SdrObject   *pObj;
/*N*/
/*N*/   CreateChartGroup (pGroup, pList);
/*N*/
/*N*/   long    nColCnt = GetColCount();
/*N*/   long    nRowCnt = GetRowCount();
/*N*/   long    nCol, nRow;
/*N*/
/*N*/   BOOL    bPercent   = IsPercent();
/*N*/   BOOL    bStacked   = IsStacked();
/*N*/
/*N*/   // bPercent => bStacked ... ersetzt: (bPercent || bStacked)  durch bStacked
/*N*/   USHORT  eStackMode =  bStacked ? CHSTACK_MINMAX : CHSTACK_NONE;
/*N*/
/*N*/   Size            aYDescrSize;
/*N*/ 	SdrObjList      ** pRowLists   = ArrayHelper<SdrObjList*>::create_long_size(nRowCnt);
/*N*/ 	SdrObjList      ** pDescrLists  = ArrayHelper<SdrObjList*>::create_long_size(nRowCnt);
        if( !pRowLists || !pDescrLists )
        {
            delete[] pRowLists;
            delete[] pDescrLists;
            return pGroup;
        }
/*N*/   DataDescription* pDescription   = NULL;
/*N*/   SdrObjList      *pYAxisList     = pChartYAxis->IsVisible()
/*N*/                                         ? CreateGroup (*pList, CHOBJID_DIAGRAM_Y_AXIS, 0)
/*N*/                                         : NULL;
/*N*/   SdrObjList      *pXGridMainList = bShowXGridMain
/*N*/                                         ? CreateGroup (*pList, CHOBJID_DIAGRAM_X_GRID_MAIN_GROUP, 0)
/*N*/                                         : 0;
/*N*/   SdrObjList      *pXGridHelpList = bShowXGridHelp
/*N*/                                         ? CreateGroup (*pList, CHOBJID_DIAGRAM_X_GRID_HELP_GROUP, 0)
/*N*/                                         : 0;
/*N*/
/*N*/   XPolygon aDataLine (nColCnt + 1);
/*N*/   SfxItemSet aLineAttr(*pItemPool, XATTR_LINE_FIRST, XATTR_LINE_LAST, 0);
/*N*/   SfxItemSet aTextAttr(*pItemPool, nTextWhichPairs);
/*N*/   aTextAttr.Put(*pYAxisAttr);
/*N*/
/*N*/   if (aRect.GetWidth() > aRect.GetHeight())
/*N*/   {
/*N*/       aRect.Left() += (aRect.GetWidth() - aRect.GetHeight()) / 2;
/*N*/       aRect.Right() = aRect.Left() + aRect.GetHeight();
/*N*/   }
/*N*/   else if (aRect.GetHeight() > aRect.GetWidth())
/*N*/   {
/*?*/       aRect.Top() += (aRect.GetHeight() - aRect.GetWidth()) / 2;
/*?*/       aRect.Bottom() = aRect.Top() + aRect.GetWidth();
/*N*/   }

/*N*/   if (pChartYAxis->HasDescription())
/*N*/   {
/*N*/       aYDescrSize = Size (((SvxFontWidthItem &) pYAxisTitleAttr->Get (EE_CHAR_FONTWIDTH)).GetWidth (),
/*N*/                           ((SvxFontHeightItem &) pYAxisTitleAttr->Get (EE_CHAR_FONTHEIGHT)).GetHeight ());
/*N*/
/*N*/       aRect.Bottom () -= (aYDescrSize.Height () * 12) / 5;
/*N*/       aRect.Top ()    += (aYDescrSize.Height () * 12) / 5;
/*N*/   }

/*N*/   long   nLength    = aRect.GetHeight () / 2;
/*N*/   long   nOffsetX   = aRect.Left () + aRect.GetWidth () / 2;
/*N*/   long   nOffsetY   = aRect.Top () + aRect.GetHeight () / 2;
/*N*/   double fAngleStep = F_PI * 2 / nColCnt;
/*N*/   long   aOldPos    = 0;


/*N*/   BOOL bSwitchColRow=IsDataSwitched();
/*N*/   pChartYAxis->Initialise(aRect,bSwitchColRow,eStackMode,bPercent,TRUE);
/*N*/   pChartYAxis->CalcValueSteps();
/*N*/
/*N*/   Size aMaxValueSizeY = pChartYAxis->CalcMaxTextSize(CHTXTORIENT_STANDARD);
/*N*/   //nur zu test zwecken
/*N*/
/*N*/   XPolygon aLine (2);
/*N*/   double fSteps = pChartYAxis->GetMax();
/*N*/ 	double* fOldData = ArrayHelper<double>::create_long_size(nColCnt);
/*N*/   double fAngle = F_PI / 2;
/*N*/
/*N*/   Size aLegendSize (((SvxFontWidthItem &) pLegendAttr->Get (EE_CHAR_FONTWIDTH)).GetWidth (),
/*N*/                     ((SvxFontHeightItem &) pLegendAttr->Get (EE_CHAR_FONTHEIGHT)).GetHeight ());
/*N*/
/*N*/   //#54884# Was soll das hier? Create2DNetChart
/*N*/     OutputDevice * pRefDev = GetRefDevice();
/*N*/   if(pRefDev)
/*N*/       aLegendSize = pRefDev->PixelToLogic (pRefDev->LogicToPixel (aLegendSize));
/*N*/   else
/*?*/       OSL_FAIL("ChartModel: no RefDevice");
/*N*/
/*N*/   long nLegendHeight = aLegendSize.Height () * 9 / 10;
/*N*/
/*N*/   if (pChartYAxis->HasDescription())
/*N*/       while (fSteps >= pChartYAxis->GetMin())
/*N*/       {
/*N*/           double fLength = nLength * pChartYAxis->CalcFact(fSteps);
/*N*/
/*N*/           for (nCol = 0; nCol < nColCnt; nCol++)
/*N*/           {
/*N*/               double fCos = cos (fAngle);
/*N*/               double fSin = sin (fAngle);
/*N*/
/*N*/               aLine [1].X () = (long) (nOffsetX + fLength * fCos + nMarkLen * fSin);
/*N*/               aLine [1].Y () = (long) (nOffsetY - fLength * fSin + nMarkLen * fCos);
/*N*/               aLine [0].X () = (long) (nOffsetX + fLength * fCos - nMarkLen * fSin);
/*N*/               aLine [0].Y () = (long) (nOffsetY - fLength * fSin - nMarkLen * fCos);
/*N*/
/*N*/               pYAxisList->NbcInsertObject(SetObjectAttr (new SdrPathObj(OBJ_PLIN, aLine), CHOBJID_LINE,
/*N*/                                                          TRUE, TRUE, pAxisAttr));
/*N*/
/*N*/               if (fSteps == pChartYAxis->GetMax())
/*N*/               {
/*N*/                   Point aTextPos ((long) (nOffsetX + nLength * fCos),
/*N*/                                   (long) (nOffsetY - nLength * fSin));
/*N*/                   ChartAdjust eAdjust;
/*N*/
/*N*/                   if (fAngle > 0 && fAngle < F_PI / 4)
/*N*/                   {
/*?*/                       eAdjust = CHADJUST_CENTER_LEFT;
/*?*/                       aTextPos.X () = (long) (nOffsetX + nLength * fCos + (aYDescrSize.Height () * 6) / 5);
/*N*/                   }
/*N*/                   else if (fAngle >= F_PI / 4 && fAngle <= 3 * F_PI / 4)
/*N*/                        {
/*N*/                            eAdjust = CHADJUST_BOTTOM_CENTER;
/*N*/                            aTextPos.Y () = (long) (nOffsetY - nLength * fSin - (aYDescrSize.Height () * 6) / 5);
/*N*/                        }
/*N*/                        else if (fAngle > 3 * F_PI / 4 && fAngle <= 5 * F_PI / 4)
/*N*/                             {
/*N*/                                 eAdjust = CHADJUST_CENTER_RIGHT;
/*N*/                                 aTextPos.X () = (long) (nOffsetX + nLength * fCos - (aYDescrSize.Height () * 6) / 5);
/*N*/                             }
/*N*/                             else if (fAngle > 5 * F_PI / 4 && fAngle <= 7 * F_PI / 4)
/*N*/                                  {
/*N*/                                      eAdjust = CHADJUST_TOP_CENTER;
/*N*/                                      aTextPos.Y () = (long) (nOffsetY - nLength * fSin + (aYDescrSize.Height () * 6) / 5);
/*N*/                                  }
/*N*/                                  else
/*N*/                                  {
/*N*/                                      eAdjust = CHADJUST_CENTER_LEFT;
/*N*/                                      aTextPos.X () = (long) (nOffsetX + nLength * fCos + (aYDescrSize.Height () * 6) / 5);
/*N*/                                  }
/*N*/
/*N*/                   pYAxisList->NbcInsertObject(CreateTextObj(CHOBJID_TEXT, aTextPos,
/*N*/                                                             ColText(nCol),
/*N*/                                                             aTextAttr,
/*N*/                                                             FALSE, eAdjust));
/*N*/               }
/*N*/
/*N*/               fAngle += fAngleStep;
/*N*/           }
/*N*/
/*N*/           if (pChartYAxis->HasDescription())
/*N*/           {
/*N*/               Color* pDummy = NULL;
/*N*/               String aNumStr;
/*N*/               Point aPos;
/*N*/
/*N*/               pNumFormatter->GetOutputString((bPercent)?fSteps/100.0:fSteps,
/*N*/                   GetNumFmt(CHOBJID_DIAGRAM_Y_AXIS,bPercent),aNumStr,&pDummy);
/*N*/
/*N*/               aPos.X() = (long) (nOffsetX + nMarkLen);
/*N*/               aPos.Y() = (long) (nOffsetY - fLength);
/*N*/
/*N*/                   if (aPos.Y () - aMaxValueSizeY.Height () > aOldPos)
/*N*/                   {
/*N*/                       pYAxisList->NbcInsertObject(CreateTextObj(CHOBJID_TEXT, aPos, aNumStr,
/*N*/                                                                 aTextAttr, FALSE, CHADJUST_CENTER_LEFT));
/*N*/                       aOldPos = aPos.Y ();
/*N*/                   }
/*N*/           }
/*N*/
/*N*/           if (pXGridMainList)
/*N*/           {
/*N*/               Rectangle aCircRect ((long) (nOffsetX - fLength),
/*N*/                                    (long) (nOffsetY - fLength),
/*N*/                                    (long) (nOffsetX + fLength),
/*N*/                                    (long) (nOffsetY + fLength));
/*N*/
/*N*/               SfxItemSet aCircAttr (*pItemPool,
/*N*/                                     XATTR_LINE_FIRST, XATTR_LINE_LAST,
/*N*/                                     XATTR_FILL_FIRST, XATTR_FILL_LAST,
/*N*/                                     0);
/*N*/
/*N*/               aCircAttr.Put (XLineColorItem (String (),
/*N*/                              ((XLineColorItem &) pXGridMainAttr->Get (XATTR_LINECOLOR)).GetValue ()));
/*N*/               aCircAttr.Put (XFillColorItem (String (),
/*N*/                              ((XFillColorItem &) pXGridMainAttr->Get (XATTR_FILLCOLOR)).GetValue ()));
/*N*/               aCircAttr.Put (XLineStyleItem (((XLineStyleItem &) pXGridMainAttr->Get (XATTR_LINESTYLE)).
/*N*/                                              GetValue ()));
/*N*/               aCircAttr.Put (XLineWidthItem (((XLineWidthItem &) pXGridMainAttr->Get (XATTR_LINEWIDTH)).
/*N*/                                              GetValue ()));
/*N*/               aCircAttr.Put (XFillStyleItem(XFILL_NONE));
/*N*/               SdrCircObj* pCirc = new SdrCircObj( OBJ_CIRC, aCircRect );
/*N*/               pCirc->SetModel( this );
/*N*/               pXGridMainList->NbcInsertObject(SetObjectAttr( pCirc,
/*N*/                                                              CHOBJID_DIAGRAM_NET, TRUE, TRUE,
/*N*/                                                              &aCircAttr));
/*N*/           }
/*N*/
/*N*/           DecValue(fSteps, pChartYAxis->GetStep(), FALSE);
/*N*/
/*N*/           if (pChartYAxis->GetStep() == 0.0) break;
/*N*/       }
/*N*/
/*N*/   fSteps = pChartYAxis->GetMax();
/*N*/
/*N*/   if (pXGridHelpList)
/*?*/       while (fSteps >= pChartYAxis->GetMin())
/*?*/       {
/*?*/           double fLength = nLength * pChartYAxis->CalcFact(fSteps);
/*?*/
/*?*/           Rectangle aCircRect ((long) (nOffsetX - fLength),
/*?*/                                (long) (nOffsetY - fLength),
/*?*/                                (long) (nOffsetX + fLength),
/*?*/                                (long) (nOffsetY + fLength));
/*?*/
/*?*/           SfxItemSet aCircAttr (*pItemPool,
/*?*/                                 XATTR_LINE_FIRST, XATTR_LINE_LAST,
/*?*/                                 XATTR_FILL_FIRST, XATTR_FILL_LAST,
/*?*/                                 0);
/*?*/
/*?*/           aCircAttr.Put (XLineColorItem (String (),
/*?*/                          ((XLineColorItem &) pXGridHelpAttr->Get (XATTR_LINECOLOR)).GetValue ()));
/*?*/           aCircAttr.Put (XFillColorItem (String (),
/*?*/                          ((XFillColorItem &) pXGridHelpAttr->Get (XATTR_FILLCOLOR)).GetValue ()));
/*?*/           aCircAttr.Put (XLineStyleItem (((XLineStyleItem &) pXGridHelpAttr->Get (XATTR_LINESTYLE)).
/*?*/                                          GetValue ()));
/*?*/           aCircAttr.Put (XLineWidthItem (((XLineWidthItem &) pXGridHelpAttr->Get (XATTR_LINEWIDTH)).
/*?*/                                          GetValue ()));
/*?*/           aCircAttr.Put (XFillStyleItem(XFILL_NONE));
/*?*/
/*?*/           SdrCircObj* pCirc = new SdrCircObj( OBJ_CIRC, aCircRect );
/*?*/           pCirc->SetModel( this );
/*?*/           pXGridHelpList->NbcInsertObject(SetObjectAttr( pCirc,
/*?*/                                                          CHOBJID_DIAGRAM_X_GRID_HELP, TRUE, TRUE,
/*?*/                                                          &aCircAttr));
/*?*/
/*?*/           DecValue(fSteps, pChartYAxis->GetStep(), FALSE);
/*?*/
/*?*/           if (pChartYAxis->GetStep() == 0.0) break;
/*?*/       }
/*N*/
/*N*/   fSteps = pChartYAxis->GetMin();
/*N*/
/*N*/   for (nRow = 0; nRow < nRowCnt; nRow++)
/*N*/   {
/*N*/       const SfxItemSet& rDataRowAttr = GetDataRowAttr(nRow);
/*N*/       Point aFirstPoint;
/*N*/       fAngle = F_PI / 2;
/*N*/       long nPoints = 0;
/*N*/
/*N*/       SchObjGroup* pRowGroup = (SchObjGroup*) CreateSimpleGroup (CHOBJID_DIAGRAM_ROWGROUP, TRUE, TRUE);
/*N*/
/*N*/       pRowGroup->InsertUserData(new SchDataRow((short)nRow));
/*N*/       pList->NbcInsertObject(pRowGroup);
/*N*/       pRowLists[nRow] = pRowGroup->GetSubList();
/*N*/       pDescrLists[nRow] = 0;
/*N*/
/*N*/       for (nCol = 0; nCol < nColCnt; nCol++)
/*N*/       {
/*N*/           SfxItemSet aDataPointAttr(rDataRowAttr);//#63904#
/*N*/           MergeDataPointAttr(aDataPointAttr,nCol,nRow);
/*N*/
/*N*/           long nIndex = nCol + nRow * nColCnt;
/*N*/           double fData = GetData(nCol, nRow, bPercent);
/*N*/
/*N*/           if (pYAxisList)
/*N*/           {
/*N*/               if (!nRow)
/*N*/               {
/*N*/                   aLine [0].X () = (long) (nOffsetX + nLength * cos (fAngle));
/*N*/                   aLine [0].Y () = (long) (nOffsetY - nLength * sin (fAngle));
/*N*/                   aLine [1].X () = nOffsetX;
/*N*/                   aLine [1].Y () = nOffsetY;
/*N*/
/*N*/                   pYAxisList->NbcInsertObject(SetObjectAttr (new SdrPathObj(OBJ_PLIN, aLine),
/*N*/                                                              CHOBJID_LINE, TRUE, TRUE, pYAxisAttr));
/*N*/               }
/*N*/           }
/*N*/
/*N*/           SvxChartDataDescr eDescr = ((const SvxChartDataDescrItem&)aDataPointAttr.
/*N*/                                           Get(SCHATTR_DATADESCR_DESCR)).GetValue();
/*N*/
/*N*/           if( (eDescr != CHDESCR_NONE) && bShowDataDescr)
/*N*/           {
/*?*/               pDescription [nIndex].eDescr = eDescr;
/*?*/               pDescription [nIndex].bSymbol = ((const SfxBoolItem&)aDataPointAttr.
/*?*/                                               Get(SCHATTR_DATADESCR_SHOW_SYM)).GetValue();
/*?*/
/*?*/               if (!pDescrLists[nRow])
/*?*/               {
/*?*/                   SchObjGroup* pDescrGroup = (SchObjGroup*) CreateSimpleGroup (CHOBJID_DIAGRAM_DESCRGROUP, TRUE, TRUE);
/*?*/
/*?*/                   pDescrGroup->InsertUserData(new SchDataRow((short)nRow));
/*?*/                   pList->NbcInsertObject(pDescrGroup);
/*?*/                   pDescrLists[nRow] = pDescrGroup->GetSubList();
/*?*/               }
/*N*/           }
/*N*/
/*N*/ 			if (bStacked && !nRow && fOldData)
                    fOldData[nCol] = pChartYAxis->GetOrigin();
/*N*/
/*N*/           if (fData != DBL_MIN)
/*N*/           {
/*N*/ 				if (bStacked && nRow && fOldData)
                        fData += fOldData[nCol];
/*N*/
/*N*/               double fLength = nLength * pChartYAxis->CalcFact(fData);
/*N*/
/*N*/               aDataLine [(USHORT) nPoints].X () = (long) (nOffsetX + fLength * cos (fAngle));
/*N*/               aDataLine [(USHORT) nPoints].Y () = (long) (nOffsetY - fLength * sin (fAngle));
/*N*/
/*N*/               if (!nCol)
/*N*/               {
/*N*/                   aFirstPoint.X () = aDataLine [(USHORT) nPoints].X();
/*N*/                   aFirstPoint.Y () = aDataLine [(USHORT) nPoints].Y();
/*N*/               }
/*N*/
/*N*/               nPoints ++;
/*N*/
/*N*/               if(HasSymbols(nRow))
/*N*/               {
/*N*/                   SdrObject *pNewObj = CreateSymbol (aDataLine[nPoints - 1], nRow, nCol,
/*N*/                                                      (SfxItemSet &) rDataRowAttr, nLegendHeight);
/*N*/                   if(pNewObj)
/*N*/                   {
/*N*/                       pNewObj->InsertUserData(new SchObjectId(CHOBJID_DIAGRAM_DATA));
/*N*/                       pRowLists[nRow]->NbcInsertObject(pNewObj);
/*N*/                   }
/*N*/               }
/*N*/
                    if( fOldData )
/*N*/ 				    fOldData [nCol] = fData;
/*N*/           }
/*N*/           else
/*N*/           {
/*N*/               if (nPoints)
/*N*/               {
/*?*/                   for (long nFill = nPoints;nFill < nColCnt;nFill ++)
/*?*/                       aDataLine [(USHORT) nFill] = aDataLine [(USHORT) nPoints - 1];
/*?*/
/*?*/                   aLineAttr.Put(rDataRowAttr);
/*?*/
/*?*/                   pObj = new SdrPathObj(OBJ_PLIN, aDataLine);
/*?*/                   pObj->InsertUserData(new SchObjectId (CHOBJID_DIAGRAM_ROWSLINE));
/*?*/                   pObj->InsertUserData(new SchDataRow((short)nRow));
/*?*/                   pRowLists[nRow]->NbcInsertObject(pObj,0); //#54870# Linie nach hinten
/*?*/
/*?*/                   pObj->SetItemSet(aLineAttr);
/*?*/
/*?*/                   nPoints = 0;
/*N*/               }
/*N*/
/*N*/               if (pDescription)
/*N*/               {
/*?*/                   pDescription [nIndex].fValue = DBL_MIN;
/*N*/               }
/*N*/           }
/*N*/
/*N*/           fAngle += fAngleStep;
/*N*/           if (fAngle > 2 * F_PI) fAngle -= 2 * F_PI;
/*N*/       }
/*N*/
/*N*/       if (nPoints)
/*N*/       {
/*N*/           for (long nFill = nPoints;nFill < nColCnt;nFill ++)
/*?*/               aDataLine [(USHORT) nFill] = aDataLine [(USHORT) nPoints - 1];
/*N*/
/*N*/           if (aFirstPoint.X () && aFirstPoint.Y ())
/*N*/           {
/*N*/               aDataLine [(unsigned short)nColCnt].X () = aFirstPoint.X ();
/*N*/               aDataLine [(unsigned short)nColCnt].Y () = aFirstPoint.Y ();
/*N*/           }
/*N*/           else
/*N*/           {
/*?*/               aDataLine [(unsigned short)nColCnt].X () = aDataLine [nColCnt - 1].X ();
/*?*/               aDataLine [(unsigned short)nColCnt].Y () = aDataLine [nColCnt - 1].Y ();
/*N*/           }
/*N*/
/*N*/           aLineAttr.Put(rDataRowAttr);
/*N*/
/*N*/           pObj = new SdrPathObj(OBJ_PLIN, aDataLine);
/*N*/           pObj->InsertUserData(new SchObjectId (CHOBJID_DIAGRAM_ROWSLINE));
/*N*/           pObj->InsertUserData(new SchDataRow((short)nRow));
/*N*/           pRowLists[nRow]->NbcInsertObject(pObj,0);//#54870# hinter die Symbole mit der Linie
/*N*/
/*N*/           pObj->SetItemSet(aLineAttr);
/*N*/
/*N*/       }
/*N*/
/*N*/       IncValue(fSteps, pChartYAxis->GetStep(), FALSE);
/*N*/
/*N*/       if (pChartYAxis->GetStep() == 0.0) break;
/*N*/   }
/*N*/
/*N*/   Dirty2D (nRowCnt, nColCnt, pDescrLists, TRUE/*FALSE*/, pDescription);
/*N*/
/*N*/   delete[] pDescription;
/*N*/   delete[] pDescrLists;
/*N*/   delete[] pRowLists;
/*N*/   delete[] fOldData;
/*N*/   return pGroup;
/*N*/ }

/*************************************************************************
|*
|* Frisiere die % auf 100%
|*
\************************************************************************/

/*N*/ void ChartModel::Dirty2D (long            nRowCnt,
/*N*/                         long            nColCnt,
/*N*/                         SdrObjList      **pDescrLists,
/*N*/                         BOOL            bRowDescr,
/*N*/                         DataDescription *pDescription)
/*N*/ {
/*N*/     if (!pDescription)
/*N*/       return;

/*?*/   long nStart = IsXYChart() ? 1 : 0;
/*?*/
/*?*/   if (bRowDescr)
/*?*/   {
/*?*/       for (long nCols = 0;nCols < nColCnt;nCols ++)
/*?*/       {
/*?*/           double fTotal = 0.0;
/*?*/           double fMax   = 0.0;
                long   nRows  = 0;
/*?*/
/*?*/             //    Calculate the total of all segements with percentage value
/*?*/           for (nRows = nStart;nRows < nRowCnt;nRows ++)
/*?*/               if (pDescrLists [nRows])
/*?*/               {
/*?*/                   long   nIndex= nCols + nRows * nColCnt;
/*?*/                   if ((pDescription [nIndex].eDescr == CHDESCR_PERCENT) ||
/*?*/                       (pDescription [nIndex].eDescr == CHDESCR_TEXTANDPERCENT))
/*?*/                   {
/*?*/                       double fTemp = pDescription [nIndex].fValue;
/*?*/
/*?*/                       if (fTemp != DBL_MIN)
/*?*/                       {
/*?*/                           fTotal += fTemp;
/*?*/                           if (fMax < fTemp)
/*?*/                               fMax   = fTemp;
/*?*/                       }
/*?*/                   }
/*?*/               }
/*?*/
/*?*/           for (nRows = nStart;nRows < nRowCnt;nRows ++)
/*?*/               if (pDescrLists[nRows])
/*?*/               {
/*?*/                   long nIndex = nCols + nRows * nColCnt;//                    long nIndex = nRows + nCols * nRowCnt;
/*?*/
/*?*/                   if (pDescription [nIndex].fValue != DBL_MIN)
/*?*/                       if( pDescription[nIndex].pLabelObj )
/*?*/                           pDescrLists[nRows]->NbcInsertObject( pDescription[nIndex].pLabelObj );
/*?*/               }
/*?*/       }
/*?*/   }
/*?*/   else
/*?*/   {
/*?*/       for (long nRows = nStart;nRows < nRowCnt; nRows ++)
/*?*/       {
/*?*/           if ( ! pDescrLists[nRows])
/*?*/               continue;
/*?*/
/*?*/           double fTotal = 0.0;
/*?*/           double fMax   = 0.0;
                long   nCols = 0;
/*?*/
/*?*/             //    Calculate the total of all segements with a percentage value
/*?*/           for (nCols = 0;nCols < nColCnt;nCols ++)
/*?*/           {
/*?*/               long   nIndex = nCols + nRows * nColCnt;
/*?*/               if ((pDescription [nIndex].eDescr == CHDESCR_PERCENT) ||
/*?*/                   (pDescription [nIndex].eDescr == CHDESCR_TEXTANDPERCENT))
/*?*/               {
/*?*/                   double fTemp = pDescription [nIndex].fValue;
/*?*/
/*?*/                   if (fTemp != DBL_MIN)
/*?*/                   {
/*?*/                       fTotal += fTemp;
/*?*/                       if (fMax < fTemp)
/*?*/                           fMax   = fTemp;
/*?*/                   }
/*?*/               }
/*?*/           }
/*?*/
/*?*/           for (nCols = 0;nCols < nColCnt;nCols ++)
/*?*/           {
/*?*/               long nIndex = nCols + nRows * nColCnt;
/*?*/
/*?*/               if (pDescription[ nIndex ].fValue != DBL_MIN)
/*?*/                   if( pDescription[ nIndex ].pLabelObj )
/*?*/                       pDescrLists[nRows]->NbcInsertObject( pDescription[ nIndex ].pLabelObj );
/*?*/           }
/*?*/       }
/*?*/   }
/*N*/ }

/*************************************************************************
|*
|* Erstelle Kreissegment
|*
\************************************************************************/
/*N*/ SdrObject *ChartModel::CreatePieSegment(SfxItemSet &rAttr,
/*N*/                            Rectangle  &rRect,
/*N*/                            long       nCol,
/*N*/                            long       nRow,
/*N*/                            long       nStartAngle,
/*N*/                            long       nEndAngle,
/*N*/                            long       nCnt)
/*N*/ {
/*N*/   SdrObject  *pObj;
/*N*/
/*N*/   // BM: Attention: Small angles are treated as equal, if they are equal
/*N*/   //     after divided by 10. That is because that is also done in the
/*N*/   //     drawing layer. Giving angles which differ by 1 causes the creation
/*N*/   //     of a full circle.
/*N*/
/*N*/   if( nCnt == 1 )  // only one datarow => whole circle
/*N*/   {
/*?*/       pObj = new SdrCircObj( OBJ_CIRC, rRect );
/*?*/       pObj->SetModel( this );
/*?*/       SetObjectAttr( pObj, CHOBJID_DIAGRAM_DATA, TRUE, TRUE, &rAttr);
/*N*/   }
/*N*/   else if( (nStartAngle/10) - (nEndAngle/10) )        // create pie segment
/*N*/   {
/*N*/       pObj = new SdrCircObj( OBJ_SECT, rRect, nStartAngle, nEndAngle );
/*N*/       pObj->SetModel( this );
/*N*/       SetObjectAttr( pObj, CHOBJID_DIAGRAM_DATA, TRUE, TRUE, &rAttr );
/*N*/   }
/*N*/   else // the segment is treated as line
/*N*/   {
/*?*/       pObj = new SdrCircObj( OBJ_SECT, rRect, nStartAngle, nStartAngle );
/*?*/       pObj->SetModel( this );
/*?*/       SetObjectAttr( pObj, CHOBJID_DIAGRAM_DATA, TRUE, TRUE, &rAttr );
/*N*/   }
/*N*/   pObj->InsertUserData(new SchDataPoint((short)nCol, (short)nRow));
/*N*/   return pObj;
/*N*/ }

/*************************************************************
|*
|* create donut segment - same as circle segment for now
|*
\*************************************************************/
/*N*/ SdrObject* ChartModel::CreateDonutSegment( SfxItemSet& aAttr,
/*N*/                                          Rectangle&  aRect, ULONG /*nWidth*/,
/*N*/                                          long nCol,         long nRow,
/*N*/                                          long nStartAngle,  long nEndAngle,
/*N*/                                          long nCount)
/*N*/ {
/*N*/   SdrObject* pObj;
/*N*/   if( nStartAngle > nEndAngle )
/*N*/       nStartAngle += 36000;
/*N*/
/*N*/   if( nCount==1 || nStartAngle==nEndAngle )   // we have to paint complete ring
/*N*/   {
/*?*/       pObj = new SdrCircObj( OBJ_CIRC, aRect );
/*?*/       pObj->SetModel( this );
/*?*/       SetObjectAttr( pObj, CHOBJID_DIAGRAM_DATA, TRUE, TRUE, &aAttr );
/*N*/   }
/*N*/   else
/*N*/   {
/*N*/       pObj = new SdrCircObj( OBJ_SECT, aRect, nStartAngle, nEndAngle );
/*N*/       pObj->SetModel( this );
/*N*/       SetObjectAttr( pObj, CHOBJID_DIAGRAM_DATA, TRUE, TRUE, &aAttr );
/*N*/   }
/*N*/   pObj->InsertUserData( new SchDataPoint( (short)nCol, (short)nRow ));
/*N*/   return pObj;
/*N*/ }

/*************************************************************************
|*
|* Objektgruppe erzeugen
|*
\************************************************************************/
/*N*/ SdrRectObj *ChartModel::CreateRect (Rectangle  &rRect,long nCol,long nRow,SfxItemSet &rAttr)
/*N*/ {
/*N*/   SdrRectObj* pRectObj = new SdrRectObj( rRect );
/*N*/   pRectObj->SetModel( this );
/*N*/   SetObjectAttr( pRectObj, CHOBJID_DIAGRAM_DATA, TRUE, TRUE, &rAttr );
/*N*/   pRectObj->InsertUserData(new SchDataPoint((short) nCol, (short) nRow));
/*N*/   return pRectObj;
/*N*/ }
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
