22 #include "wx/wxprec.h"
29 #include "wx/dcbuffer.h"
30 #include "wx/gdicmn.h"
31 #include "ObjCryst/ObjCryst/General.h"
32 #include "ObjCryst/wxCryst/wxMultiGraph.h"
33 #include "ObjCryst/wxCryst/wxCryst.h"
39 static const char* swxColourNameList[]={
67 "DARK SLATE GREY DARK TURQUOISE",
81 "MEDIUM FOREST GREEN",
86 "MEDIUM SPRING GREEN",
114 static const long ID_UPDATEUI= WXCRYST_ID();
115 static const long ID_MENU_AUTOSCALE= WXCRYST_ID();
117 BEGIN_EVENT_TABLE(WXMultiGraph, wxWindow)
118 EVT_PAINT( WXMultiGraph::OnPaint)
119 EVT_MOUSE_EVENTS( WXMultiGraph::OnMouse)
120 EVT_CHAR( WXMultiGraph::OnKeyDown)
121 EVT_MOUSEWHEEL( WXMultiGraph::OnMouseWheel)
122 EVT_UPDATE_UI(ID_UPDATEUI, WXMultiGraph::OnUpdateUI)
123 EVT_SIZE( WXMultiGraph::OnSize)
127 WXMultiGraph::WXMultiGraph(wxFrame *frame):
128 wxWindow(frame,-1,wxPoint(-1,-1),wxSize(-1,-1)),
129 mMinX(0.0),mMaxX(1.0),mMinY(0.0),mMaxY(1.0),
130 mLeft(40),mRight(10),mTop(10),mBottom(25),
131 mIsDragging(false),mpParentFrame(frame)
133 #ifdef VFN_CRYST_MUTEX
134 cout <<
"new CrystMutex("<<&mMutexData<<
")for WXMultiGraph:"<<
this<<endl;
136 mpPopUpMenu=
new wxMenu(_T(
"Graph"));
137 mpPopUpMenu->Append(ID_MENU_AUTOSCALE, _T(
"&AutoScale"));
141 WXMultiGraph::~WXMultiGraph()
143 VFN_DEBUG_MESSAGE(
"WXMultiGraph::~WXMultiGraph():",4)
145 #ifdef VFN_CRYST_MUTEX
146 cout <<
"Deleting CrystMutex("<<&mMutexData<<
")for WXMultiGraph:"<<
this<<endl;
150 unsigned long WXMultiGraph::AddGraph(
const string &name)
152 wxMutexLocker mlock(mMutexData);
154 for(
id=mvData.size();
id>=0;
id--)
155 if(mvData.end()==mvData.find(
id))
break;
156 mvData[id].name=name;
158 mvData[id].xmax=-1.0;
160 mvData[id].ymax=-1.0;
164 void WXMultiGraph::SetGraphData
165 (
const unsigned long id,
const std::valarray<float> &vx,
166 const std::valarray<float> &vy)
170 if(mvData[
id].xmin>mvData[
id].xmax)rescale=
true;
171 mvData[id].vx.resize(vx.size());
172 mvData[id].vy.resize(vx.size());
177 mvData[id].xmin=mvData[id].vx.min();
178 mvData[id].xmax=mvData[id].vx.max();
179 mvData[id].ymin=mvData[id].vy.min();
180 mvData[id].ymax=mvData[id].vy.max();
181 VFN_DEBUG_MESSAGE(
"WXMultiGraph::SetGraphData():"<<mvData[
id].vx.size()<<
":"
182 << mvData[id].xmin<<
","<< mvData[id].xmax<<
","
183 << mvData[id].ymin<<
","<< mvData[id].ymax<<
",",3)
188 else mMutexData.Unlock();
192 void WXMultiGraph::DeleteGraph(
const unsigned long id)
197 void WXMultiGraph::OnPaint(wxPaintEvent &event)
199 wxMutexLocker mlock(mMutexData);
200 if(mvData.size()<1)
return;
201 VFN_DEBUG_ENTRY(
"WXMultiGraph::OnPaint()",4)
202 wxBufferedPaintDC dc(this);
204 mpParentFrame->PrepareDC(dc);
206 dc.DestroyClippingRegion();
207 dc.SetBackground(wxBrush(_T("white"), wxSOLID));
212 dc.SetFont(*wxNORMAL_FONT);
214 dc.SetFont(*wxSMALL_FONT);
217 wxCoord width,height;
218 this->GetSize(&width, &height);
221 VFN_DEBUG_MESSAGE(
"WXMultiGraph::OnPaint():Axis",3)
223 dc.SetPen(*wxBLACK_PEN);
224 dc.SetTextForeground(*wxBLACK);
229 float yStep,xStep,dx,dy;
234 yStep=pow((
float)10,(
float)floor(log10(dy/nbTick)));
235 yStep *= floor((dy/yStep+0.1)/nbTick);
237 xStep=pow((
float)10,(
float)floor(log10(dx/nbTick)));
238 xStep *= floor((dx/xStep+0.1)/nbTick);
241 for(
float y=yStep*ceil(mMinY/yStep);y<mMaxY;y+=yStep)
243 fontInfo.Printf(_T(
"%g"),y);
244 dc.GetTextExtent(fontInfo, &tmpW, &tmpH);
245 if((tmpW+3)>mLeft) mLeft=tmpW+3;
248 fontInfo.Printf(_T(
"%g"),xStep);
249 dc.GetTextExtent(fontInfo, &tmpW, &tmpH);
253 dc.DrawLine(mLeft,height-mBottom,mLeft,mTop);
254 VFN_DEBUG_MESSAGE(
"WXMultiGraph::OnPaint():AxisStep="<<yStep<<
","<<mMinY<<
","<<mMaxY,3)
255 nbTick=
int(dy/yStep);
256 for(
int i=0;i<nbTick;i++)
258 float y=yStep*ceil(mMinY/yStep)+i*yStep;
261 this->Data2Screen(xs,ys);
262 VFN_DEBUG_MESSAGE(
"WXMultiGraph::OnPaint():Axis:"<<xs<<
","<<ys,3)
263 dc.DrawLine(wxCoord(xs-3),wxCoord(ys),wxCoord(xs+3),wxCoord(ys));
264 fontInfo.Printf(_T("%g"),y);
265 dc.GetTextExtent(fontInfo, &tmpW, &tmpH);
266 dc.DrawText(fontInfo,wxCoord(xs-tmpW-3),wxCoord(ys-tmpH/2));
269 dc.DrawLine(mLeft,height-mBottom,width-mRight,height-mBottom);
270 nbTick=
int(dx/xStep);
271 for(
int i=0;i<nbTick;i++)
273 float x=xStep*ceil(mMinX/xStep)+i*xStep;
276 this->Data2Screen(xs,ys);
277 dc.DrawLine(wxCoord(xs),wxCoord(ys-3),wxCoord(xs),wxCoord(ys+3));
278 fontInfo.Printf(_T(
"%g"),x);
279 dc.GetTextExtent(fontInfo, &tmpW, &tmpH);
280 dc.DrawText(fontInfo,wxCoord(xs-tmpW/2),wxCoord(ys+tmpH/2));
283 dc.GetTextExtent(mYLabel, &tmpW, &tmpH);
284 dc.DrawText(mYLabel,wxCoord(0),wxCoord(0));
285 xs=xStep*ceil(mMinX/xStep)+(nbTick-1.5)*xStep;
287 this->Data2Screen(xs,ys);
288 dc.GetTextExtent(mXLabel, &tmpW, &tmpH);
289 dc.DrawText(mXLabel,wxCoord(xs-tmpW/2),wxCoord(ys+tmpH/2+3));
292 map<unsigned long, GraphData >::const_iterator pos;
293 long ix=-1,ixdrawn=-1;
294 for(pos=mvData.begin();pos!=mvData.end();++pos)
297 VFN_DEBUG_MESSAGE(
"WXMultiGraph::OnPaint():Data#"<<ix,3)
298 if((pos->second.vx.size()<1)||(pos->second.vx.size()!=pos->second.vy.size())) continue;
300 dc.SetPen(wxPen(wxTheColourDatabase->Find(wxString::FromAscii(swxColourNameList[ix])),1,wxSOLID));
302 x2=pos->second.vx[0];
303 y2=pos->second.vy[0];
304 this->Data2Screen(x2,y2);
305 for(
unsigned long i=0;i<pos->second.vx.size();i++)
309 x2=pos->second.vx[i];
310 y2=pos->second.vy[i];
311 this->Data2Screen(x2,y2);
312 if( ((x1>=mLeft)&&(x1<=(width-mRight))&&(y1>=mBottom)&&(y1<=(height-mTop)))
313 ||((x2>=mLeft)&&(x2<=(width-mRight))&&(y2>=mBottom)&&(y2<=(height-mTop))))
314 dc.DrawLine(wxCoord(x1),wxCoord(y1),wxCoord(x2),wxCoord(y2));
317 dc.SetTextForeground(wxPen(wxTheColourDatabase->Find(wxString::FromAscii(swxColourNameList[ix])),1,wxSOLID).GetColour());
319 fontInfo.Printf(wxString::FromAscii(pos->second.name.c_str()));
320 dc.GetTextExtent(fontInfo, &tmpW, &tmpH);
321 dc.DrawText(fontInfo,wxCoord(width-tmpW-2),wxCoord(tmpH*(ixdrawn)+2));
324 VFN_DEBUG_EXIT(
"WXMultiGraph::OnPaint()",4)
327 void WXMultiGraph::OnMouse(wxMouseEvent &event)
331 if(event.Leaving())
return;
332 wxCoord width,height;
333 this->GetSize(&width, &height);
337 mpParentFrame->PrepareDC(dc);
339 wxPoint pos=
event.GetPosition();
340 float x= float(dc.DeviceToLogicalX(pos.x));
341 float y= float(dc.DeviceToLogicalY(pos.y));
343 if((x>width)||(y>height))
347 this->Screen2Data(x,y);
349 str.Printf(_T(
"x=%f ,y=%f"),x,y);
350 mpParentFrame->SetStatusText(str);
352 if(event.RightIsDown())
354 this->PopupMenu(mpPopUpMenu, event.GetX(),
event.GetY() );
357 if (event.Dragging() &&
event.LeftIsDown() && (!mIsDragging))
364 if(event.LeftUp() && mIsDragging)
388 if(mMaxX<=mMinX) mMaxX=mMinX+1e-6;
389 if(mMaxY<=mMinY) mMaxY=mMinY+1e-6;
391 this->UpdateDisplay();
394 if(
false==event.Dragging()) mIsDragging=
false;
396 if(event.LeftDClick())
399 this->UpdateDisplay();
404 void WXMultiGraph::OnMouseWheel(wxMouseEvent &event)
406 if(event.GetWheelRotation()>=
event.GetWheelDelta())
408 const REAL range=mMaxX-mMinX;
412 if(event.GetWheelRotation()<=(-
event.GetWheelDelta()))
414 const REAL range=mMaxX-mMinX;
418 this->UpdateDisplay();
421 void WXMultiGraph::AutoScale(
const long id,
const bool xmin,
const bool xmax,
422 const bool ymin,
const bool ymax)
424 wxMutexLocker mlock(mMutexData);
425 if(mvData.size()==0)
return;
426 std::map<unsigned long, GraphData>::const_iterator pos;
427 if(
id<0)pos=mvData.end();
428 else pos=mvData.find((
unsigned long)
id);
429 if(pos==mvData.end())
432 if(xmax) mMaxX=pos->second.xmax;
433 if(xmin) mMinX=pos->second.xmin;
434 if(ymax) mMaxY=pos->second.ymax;
435 if(ymin) mMinY=pos->second.ymin;
437 for(;pos!=mvData.end();++pos)
439 if(xmax)
if(mMaxX<pos->second.xmax) mMaxX=pos->second.xmax;
440 if(xmin)
if(mMinX>pos->second.xmin) mMinX=pos->second.xmin;
441 if(ymax)
if(mMaxY<pos->second.ymax) mMaxY=pos->second.ymax;
442 if(ymin)
if(mMinY>pos->second.ymin) mMinY=pos->second.ymin;
447 if(xmax) mMaxX=pos->second.xmax;
448 if(xmin) mMinX=pos->second.xmin;
449 if(ymax) mMaxY=pos->second.ymax;
450 if(ymin) mMinY=pos->second.ymin;
452 if(mMaxX<=mMinX) mMaxX=mMinX+1e-6;
453 if(mMaxY<=mMinY) mMaxY=mMinY+1e-6;
457 void WXMultiGraph::OnKeyDown(wxKeyEvent& event)
459 switch(event.GetKeyCode())
463 const REAL range=mMaxX-mMinX;
470 const REAL range=mMaxX-mMinX;
477 const REAL range=mMaxY-mMinY;
484 const REAL range=mMaxY-mMinY;
491 const REAL range=mMaxX-mMinX;
492 const REAL center=(mMaxX+mMinX)/2;
493 mMinX=center-range/3.0;
494 mMaxX=center+range/3.0;
499 const REAL range=mMaxX-mMinX;
500 const REAL center=(mMaxX+mMinX)/2;
501 mMinX=center-range*2.0/3.0;
502 mMaxX=center+range*2.0/3.0;
507 const REAL range=mMaxY-mMinY;
508 mMaxY=mMinY+range*2.0/3.0;
513 const REAL range=mMaxY-mMinY;
514 mMaxY=mMinY+range*4.0/3.0;
519 VFN_DEBUG_MESSAGE(
"WXMultiGraph::OnKeyDown(): no command for key #"<<event.GetKeyCode(),5);
522 this->UpdateDisplay();
526 void WXMultiGraph::OnUpdateUI(wxUpdateUIEvent &event)
528 VFN_DEBUG_MESSAGE(
"WXMultiGraph::OnUpdateUI()",4)
529 this->Refresh(false);
533 void WXMultiGraph::OnSize(wxSizeEvent &event)
535 this->Refresh(
false);
537 void WXMultiGraph::SetXLabel(
const wxString &xlabel)
542 void WXMultiGraph::SetYLabel(
const wxString &ylabel)
547 void WXMultiGraph::UpdateDisplay()
549 VFN_DEBUG_ENTRY(
"WXMultiGraph::UpdateDisplay()",4)
550 if(wxThread::IsMain()) this->Refresh(false);
553 wxUpdateUIEvent event(ID_UPDATEUI);
554 wxPostEvent(
this,event);
556 VFN_DEBUG_EXIT(
"WXMultiGraph::UpdateDisplay()",4)
560 void WXMultiGraph::Screen2Data(
float &x,
float &y)
562 wxCoord width,height;
563 this->GetSize(&width, &height);
565 float range=float(width-(mLeft+mRight));
566 if(range<=0) range=1.0;
568 x=mMinX+x*(mMaxX-mMinX);
570 range=float(height-(mTop+mBottom));
571 if(range<=0) range=1.0;
572 y=(height-mBottom-y)/range;
573 y=mMinY+y*(mMaxY-mMinY);
576 void WXMultiGraph::Data2Screen(
float &x,
float &y)
578 VFN_DEBUG_ENTRY(
"WXMultiGraph::Data2Screen()"<<x<<
","<<y,2)
579 wxCoord width,height;
580 this->GetSize(&width, &height);
582 float range=float(width-(mLeft+mRight));
583 x=(x-mMinX)/(mMaxX-mMinX);
586 range=float(height-(mTop+mBottom));
587 y=(y-mMinY)/(mMaxY-mMinY);
588 y=height-mBottom-y*range;
589 VFN_DEBUG_EXIT(
"WXMultiGraph::Data2Screen()->"<<x<<
","<<y,2)
The namespace which includes all objects (crystallographic and algorithmic) in ObjCryst++.