// PGLRegion.cpp: implementation of the CPGLRegion class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include <stdlib.h>
#include "PGL/pgl.h"
#include "PGL/PGLRegion.h"
#include "PGL/PGLRegionPropPage.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
IMPLEMENT_SERIAL(CPGLRegion,CPGLObject,1);
void CPGLRegion::Serialize(CArchive &archive)
{
// call base class function first
// base class is CPGLObject in this case
CObject::Serialize( archive );
if (archive.IsLoading())
{
}
else
{
}
}
#ifdef _DEBUG
void CPGLRegion::Dump( CDumpContext& dc ) const
{
// call base class function first
CObject::Dump( dc );
// now do the stuff for our specific class
// now dumping..
dc << _T("--- CPGLRegion ---\n")<< endl;
dc << m_view<<"\n";
}
void CPGLRegion::AssertValid() const
{
// call inherited AssertValid first
CObject::AssertValid();
// check members...
m_view.AssertValid();
// check members...
m_axe.AssertValid();
m_mObjects.AssertValid();
if (sm_mClipboard!=NULL)
ASSERT_VALID(sm_mClipboard);
}
#endif
CPGLRegion::CPGLRegion()
{
m_background=CPGLColor(1.0f,1.0f,1.0f,1.0f);
m_axe.SetView(&m_view);
m_pNormBBox[0]=m_pNormBBox[1]=0;
m_pNormBBox[2]=m_pNormBBox[3]=1;
LoadBitmap(IDB_PGL_REGION_BITMAP);
}
CPGLRegion::CPGLRegion(const CPGLRegion& g)
: CPGLObject(g)
{
m_view=g.m_view;
m_background=g.m_background;
m_axe=g.m_axe;
m_mObjects=g.m_mObjects;
for (int i=0;i<4;i++)
{
m_pNormBBox[i] = g.m_pNormBBox[i];
}
PostUpdateGraph();
}
CPGLRegion& CPGLRegion::operator =(const CPGLRegion& g)
{
if (&g!=this)
{
CPGLObject::operator =(g);
m_view=g.m_view;
m_background=g.m_background;
m_axe=g.m_axe;
for (int i=0;i<4;i++)
{
m_pNormBBox[i] = g.m_pNormBBox[i];
}
m_mObjects=g.m_mObjects;
PostUpdateGraph();
}
return *this;
}
CPGLRegion::~CPGLRegion()
{
// cleaning objects
m_mObjects.DeleteAll();
PGL_TRACE("PGL-Region: Objects deleted\n");
ASSERT(m_mObjects.IsEmpty());
}
/// adds pObject to the graph (memory must be allowed by user)
void CPGLRegion::AddObject(CPGLObject* pObject)
{
ASSERT_VALID(pObject);
ASSERT(! pObject->IsKindOf( RUNTIME_CLASS(CPGLRegion) ) );
// adding pointer
m_mObjects.AddHead(pObject);
// updating graph
PostUpdateGraph();
}
CPGLRegion* CPGLRegion::AddRegion()
{
CPGLRegion* pNewRegion = new CPGLRegion();
// adding pointer
m_mChilds.AddHead(pNewRegion);
// updating graph
PostUpdateGraph();
return pNewRegion;
}
/// removes the selected object from the graph
void CPGLRegion::DeleteSelection()
{
// deleting objects
m_mObjects.DeleteSelection();
POSITION pos=m_mChilds.GetHeadPosition();
while (pos!=NULL)
{
((CPGLRegion*)m_mChilds.GetNext(pos))->DeleteSelection();
}
// updating graph
PostUpdateGraph();
};
void CPGLRegion::SelectAll()
{
POSITION pos;
pos=m_mObjects.GetHeadPosition();
while(pos!=NULL)
{
m_mObjects.GetNext(pos)->Select();
}
pos=m_mChilds.GetHeadPosition();
while(pos!=NULL)
{
m_mChilds.GetNext(pos)->Select();
}
}
void CPGLRegion::UnhideAll()
{
POSITION pos;
pos=m_mObjects.GetHeadPosition();
while(pos!=NULL)
{
m_mObjects.GetNext(pos)->Show();
}
pos=m_mChilds.GetHeadPosition();
while(pos!=NULL)
{
m_mChilds.GetNext(pos)->Show();
}
}
void CPGLRegion::UnselectAll()
{
POSITION pos;
// unselect axe
m_axe.Deselect();
// unselect objects
pos=m_mObjects.GetHeadPosition();
while(pos!=NULL)
{
m_mObjects.GetNext(pos)->Deselect();
}
// unselect objects
pos=m_mChilds.GetHeadPosition();
while(pos!=NULL)
{
m_mChilds.GetNext(pos)->Deselect();
}
}
// finding an object by it's ID
CPGLObject* CPGLRegion::FindObject(UINT ID)
{
POSITION pos;
CPGLObject* pObject;
CPGLObject* pRegion;
// testing if it is itself
if (CheckID(ID))
return this;
// test m_axe
pObject=m_axe.FindObject(ID);
if (pObject)
return pObject;
// test objects
pos=m_mObjects.GetHeadPosition();
while (pos!=NULL)
{
pObject=m_mObjects.GetNext(pos);
if (pObject->CheckID(ID))
return pObject;
}
// test objects
pos=m_mChilds.GetHeadPosition();
while (pos!=NULL)
{
pRegion=m_mChilds.GetNext(pos);
pObject = ((CPGLRegion*)pRegion)->FindObject(ID);
if (pObject)
return pObject;
}
// not found
return NULL;
}
double* CPGLRegion::GetExtent()
{
POSITION pos;
CPGLObject* pObject;
double* locExtent;
bool first=true;
// no object case
if (m_mObjects.IsEmpty())
{
m_extent[0]=0;
m_extent[1]=1;
m_extent[2]=0;
m_extent[3]=1;
return m_extent;
}
// first, non text objects.
pos=m_mObjects.GetHeadPosition();
while (pos!=NULL)
{
pObject=m_mObjects.GetNext(pos);
ASSERT_VALID(pObject);
if (!pObject->IsVisible())
continue;
// skip text for the moment
if (pObject->GetRuntimeClass()==RUNTIME_CLASS(CPGLText)
|| pObject->GetRuntimeClass()==RUNTIME_CLASS(CPGLLineVer)
|| pObject->GetRuntimeClass()==RUNTIME_CLASS(CPGLLineHor))
continue;
// test for type...
locExtent=pObject->GetExtent(&m_view);
// testing...
if (first)
{
m_extent[0]=locExtent[0];
m_extent[1]=locExtent[1];
m_extent[2]=locExtent[2];
m_extent[3]=locExtent[3];
first=false;
}
else
{
m_extent[0]=__min(m_extent[0],locExtent[0]); //left
m_extent[1]=__max(m_extent[1],locExtent[1]); //right
m_extent[2]=__min(m_extent[2],locExtent[2]); //bottom
m_extent[3]=__max(m_extent[3],locExtent[3]); //up
}
}
return m_extent;
}
void CPGLRegion::Delete()
{
PGL_TRACE("PGL-Region: Starting cleaning\n");
// deleting axe
m_axe.Delete();
PGL_TRACE("PGL-Graph: Axe deleted\n");
// deleting objects
DeleteAllObjects();
PGL_TRACE("PGL-Region: Fonts unassigned\n");
// cleaning clipboard
if (sm_mClipboard!=NULL)
{
sm_mClipboard->DeleteAll();
delete sm_mClipboard;
sm_mClipboard=NULL;
}
// Post updating
PostUpdateGraph();
PGL_TRACE("PGL-Region: Cleaning success, processing childs\n");
}
void CPGLRegion::UpdateGraph()
{
double pExt[4];
// retreive info
m_axe.GetLimits(0,pExt);
m_axe.GetLimits(1,pExt+2);
// updating extent to put axis
m_axe.GrowExtent(pExt);
// updating view
m_view.ZoomAll(pExt[0],pExt[1],pExt[2],pExt[3]);
// update labels
m_axe.UpdateLabels();
m_bNeedUpdate=FALSE;
// computing child viewports
CPGLRegion* pRegion;
POSITION pos=m_mChilds.GetHeadPosition();
while (pos!=NULL)
{
pRegion=(CPGLRegion*)m_mChilds.GetNext(pos);
ASSERT_VALID(pRegion);
pRegion->UpdateGraph();
}
};
void CPGLRegion::SetViewport(int tx, int ty, int width, int height)
{
CPGLRegion* pRegion;
// computing own viewport
m_view.SetViewport(
tx + (int) floor(width * m_pNormBBox[0]),
ty + (int) floor(height * m_pNormBBox[1]),
(int) floor(width * (m_pNormBBox[2]-m_pNormBBox[0])),
(int) floor(height * (m_pNormBBox[3]-m_pNormBBox[1])));
// computing child viewports
POSITION pos=m_mChilds.GetHeadPosition();
while (pos!=NULL)
{
pRegion=(CPGLRegion*)m_mChilds.GetNext(pos);
ASSERT_VALID(pRegion);
pRegion->SetViewport(m_view.GetTx(), m_view.GetTy(), m_view.GetWidth(), m_view.GetHeight());
}
};
void CPGLRegion::ZoomAll(BOOL recurse)
{
// ASSERT_VALID(m_pDC);
// getting extent
double* pExt=GetExtent();
// updating extent to put axis
double pExtNew[4];
for (int i=0;i<4;i++)
pExtNew[i]=pExt[i];
// updating axis
m_axe.SetLimits(0,pExtNew[0],pExtNew[1]);
m_axe.SetLimits(1,pExtNew[2],pExtNew[3]);
// retreive info
m_axe.GetLimits(0,pExtNew);
m_axe.GetLimits(1,pExtNew+2);
// grow window
m_axe.GrowExtent(pExtNew);
// updating view
m_view.ZoomAll(pExtNew[0],pExtNew[1],pExtNew[2],pExtNew[3]);
if (recurse)
{
POSITION pos=m_mChilds.GetHeadPosition();
while (pos!=NULL)
{
((CPGLRegion*)m_mChilds.GetNext(pos))->ZoomAll(TRUE);
}
}
}
void CPGLRegion::ZoomRegion(double* pExt)
{
// updating axis
m_axe.SetLimits(0,pExt[0],pExt[1]);
m_axe.SetLimits(1,pExt[2],pExt[3]);
// retreive info
m_axe.GetLimits(0,pExt);
m_axe.GetLimits(1,pExt+2);
// updating extent to put axis
m_axe.GrowExtent(pExt);
// updating view
m_view.ZoomAll(pExt[0],pExt[1],pExt[2],pExt[3]);
}
void CPGLRegion::ZoomBox(int xStart, int yStart, int xEnd, int yEnd)
{
// putting start and end in order
int temp;
if (xStart>xEnd)
{
temp=xStart;
xStart=xEnd;
xEnd=temp;
}
// y is going down
if (yStart<yEnd)
{
temp=yStart;
yStart=yEnd;
yEnd=temp;
}
// checking that box has at least 1 of size
if (xStart==xEnd)
xEnd++;
if (yStart==yEnd)
yEnd++;
// step 1 setting axis
// sending dimension of box to axe and computing box
m_axe.SetLimits(0,
m_view.PixelToWorldCoord(0,xStart), //left
m_view.PixelToWorldCoord(0,xEnd)); //right
m_axe.SetLimits(1,
m_view.PixelToWorldCoord(1,yStart), //bottom
m_view.PixelToWorldCoord(1,yEnd)); //top
// retreivinf info
double pExt[4];
m_axe.GetLimits(0,pExt);
m_axe.GetLimits(1,pExt+2);
// Step 2 grow extent
m_axe.GrowExtent(pExt);
// Step 3, updating view
m_view.ZoomAll(pExt[0],pExt[1],pExt[2],pExt[3]);
}
void CPGLRegion::ZoomIn()
{
// step 1 zoom in of view
m_view.ZoomIn();
// step 2 set axis
m_axe.SetLimits(0,
m_view.GetLeft(), //left
m_view.GetRight()); //right
m_axe.SetLimits(1,
m_view.GetBottom(), //bottom
m_view.GetTop()); //top
// retreivinf info
double pExt[4];
m_axe.GetLimits(0,pExt);
m_axe.GetLimits(1,pExt+2);
// Step 2 grow extent
m_axe.GrowExtent(pExt);
// Step 3, updating view
m_view.ZoomAll(pExt[0],pExt[1],pExt[2],pExt[3]);
}
void CPGLRegion::ZoomOut()
{
// step 1 zoom in of view
m_view.ZoomOut();
// step 2 set axis
m_axe.SetLimits(0,
m_view.GetLeft(), //left
m_view.GetRight()); //right
m_axe.SetLimits(1,
m_view.GetBottom(), //bottom
m_view.GetTop()); //top
// retreivinf info
double pExt[4];
m_axe.GetLimits(0,pExt);
m_axe.GetLimits(1,pExt+2);
// Step 2 grow extent
m_axe.GrowExtent(pExt);
// Step 3, updating view
m_view.ZoomAll(pExt[0],pExt[1],pExt[2],pExt[3]);
}
void CPGLRegion::Pan(int x, int y)
{
// step 1 pan view
m_view.Pan(x,y);
m_axe.Pan(m_view.PixelToWorld(0,x),m_view.PixelToWorld(1,y));
}
void CPGLRegion::DeleteAllObjects()
{
// Remove objects
m_mObjects.DeleteAll();
// remove region
CPGLRegion* pRegion;
POSITION pos=m_mChilds.GetHeadPosition();
while (pos!=NULL)
{
pRegion = (CPGLRegion*)m_mChilds.GetNext(pos);
pRegion->Delete();
}
m_mChilds.DeleteAll();
}
const float* CPGLRegion::GetNormBBox() const
{
return m_pNormBBox;
}
void CPGLRegion::SetNormBBox(float BBox[])
{
// make lower left corner and upper right are ordered
m_pNormBBox[0] = __max(0, __min(BBox[0], BBox[2]));
m_pNormBBox[2] = __min(1, __max(BBox[0], BBox[2]));
m_pNormBBox[1] = __max(0, __min(BBox[1], BBox[3]));
m_pNormBBox[3] = __min(1, __max(BBox[1], BBox[3]));
ASSERT(m_pNormBBox[0] != 1);
ASSERT(m_pNormBBox[1] != 1);
ASSERT(m_pNormBBox[2] != 0);
ASSERT(m_pNormBBox[3] != 0);
ASSERT(m_pNormBBox[0] != m_pNormBBox[2]);
ASSERT(m_pNormBBox[1] != m_pNormBBox[3]);
}
void CPGLRegion::SetNormBBox(float llx, float lly, float urx, float ury)
{
// make lower left corner and upper right are ordered
m_pNormBBox[0] = __max(0, __min(llx, urx));
m_pNormBBox[2] = __min(1, __max(llx, urx));
m_pNormBBox[1] = __max(0, __min(lly, ury));
m_pNormBBox[3] = __min(1, __max(lly, ury));
ASSERT(m_pNormBBox[0] != 1);
ASSERT(m_pNormBBox[1] != 1);
ASSERT(m_pNormBBox[2] != 0);
ASSERT(m_pNormBBox[3] != 0);
ASSERT(m_pNormBBox[0] != m_pNormBBox[2]);
ASSERT(m_pNormBBox[1] != m_pNormBBox[3]);
}
void CPGLRegion::AddPropertyPage(CPropertySheet* pPropSheet)
{
ASSERT_VALID(pPropSheet);
// call own functions
CPGLRegionPropPage* propPage=new CPGLRegionPropPage(this);
pPropSheet->AddPage(propPage);
// first call base class function
CPGLObject::AddPropertyPage(pPropSheet);
}
HTREEITEM CPGLRegion::AddPropTree(CTreeCtrl* pTree, HTREEITEM hParent)
{
ASSERT_VALID(pTree);
CString str;
CImageList* pImgList=pTree->GetImageList(TVSIL_NORMAL);
ASSERT_VALID(pImgList);
ASSERT(hParent);
COLORREF crMask=0;
// adding bitmap
pImgList->Add(CBitmap::FromHandle(GetBitmap()),crMask);
// adding to tree
POSITION pos;
CPGLObject* pObject;
CPGLRegion* pRegion;
HTREEITEM pRegionItem;
HTREEITEM pObjItem;
HTREEITEM pRgnItem;
// inserting object root
pRegionItem=pTree->InsertItem(TVIF_TEXT | TVIF_IMAGE | TVIF_PARAM /* nMask*/,
GetName() /* lpszItem*/,
pImgList->GetImageCount()-1 /* nImage */,
0 /* nSelectedImage */,
0 /* nState */,
0 /* nStateMask */,
GetID() /* lParam */,
hParent /* hParent */,
TVI_LAST /* hInsertAfter */);
ASSERT(pRegionItem!=NULL);
// insert axis
// adding to tree
HTREEITEM pAxeItem=m_axe.AddPropTree(pTree,pRegionItem);
ASSERT(pAxeItem!=NULL);
// check if selected...
// if ((long)m_axe.GetID()==m_lSelID)
// pTree->SelectItem(pAxeItem);
// filling up insert structure with objects
pos=m_mObjects.GetHeadPosition();
while (pos!=NULL)
{
pObject=m_mObjects.GetNext(pos);
ASSERT_VALID(pObject);
pObjItem=pObject->AddPropTree(pTree,pRegionItem);
ASSERT(pObjItem!=NULL);
// check if selected...
// if ((long)pObject->GetID()==m_lSelID)
// pTree->SelectItem(pObjItem);
}
// filling up insert structure with subplots
pos=m_mChilds.GetHeadPosition();
while (pos!=NULL)
{
pRegion=(CPGLRegion*)m_mChilds.GetNext(pos);
ASSERT_VALID(pRegion);
pRgnItem=pRegion->AddPropTree(pTree,pRegionItem);
ASSERT(pRgnItem!=NULL);
// check if selected...
// if ((long)pRegion->GetID()==m_lSelID)
// pTree->SelectItem(pRgnItem);
}
return pRegionItem;
}
void CPGLRegion::Divide(int nrows, int ncols)
{
float llx, lly, urx, ury;
CString str;
if ((nrows == 0) || (ncols == 0))
return;
// deleting all objects
DeleteAllObjects();
// hiding axis
m_axe.Hide();
// adding new regions...
CPGLRegion* pRegion;
int i,j;
for (i=0;i<nrows;i++)
{
lly = (float)((double) i / (double) (nrows));
ury = (float)((double) (i+1) / (double) (nrows));
for (j=ncols-1;j>=0;j--)
{
llx = (float)((double) j / (double) (ncols));
urx = (float)((double) (j+1) / (double) (ncols));
pRegion = AddRegion();
pRegion->SetNormBBox(llx, lly, urx, ury);
str.Format("Subplot (%i,%i)",i+1,j+1);
pRegion->SetName(str);
}
}
}
CPGLRegion* CPGLRegion::GetChild(int i)
{
POSITION pos = m_mChilds.FindIndex(i);
if (pos)
return (CPGLRegion*)m_mChilds.GetAt(pos);
else
return NULL;
}
void CPGLRegion::PlotGfx(gfxinterface::CGfxInterface& gfx)
{
CPGLObject::PlotGfx(gfx);
CString str;
POSITION pos;
// updating graph
UpdateGraph();
str.Format("--- CPGLRegion %s ---", GetName());
gfx.AddComment(str);
gfx.PushState();
// setting bounding box
m_view.PlotGfx(gfx);
// drawing background...
gfx.PushState();
gfx.SetFillColor(m_background.GetRed(), m_background.GetGreen(), m_background.GetBlue(), m_background.GetAlpha());
gfx.SetColor(m_background.GetRed(), m_background.GetGreen(), m_background.GetBlue(), m_background.GetAlpha());
gfx.DrawRect( m_view.GetLeft(), m_view.GetBottom(), m_view.GetRight(), m_view.GetTop() , TRUE);
gfx.PopState();
// setting clipping path
m_axe.ClipGfx(gfx);
// now plotting the objects
pos=m_mObjects.GetHeadPosition();
while (pos!=NULL)
{
m_mObjects.GetNext(pos)->PlotGfx(gfx);
}
// remove clipping path
m_axe.UnClipGfx(gfx);
// plotting the axe
m_axe.PlotGfx(gfx);
gfx.PopState();
// Drawing childs
pos=m_mChilds.GetHeadPosition();
while (pos!=NULL)
{
m_mChilds.GetNext(pos)->PlotGfx(gfx);
}
};