/*************************************************************************** * * * Copyright notice: * * * * This is free Pier ware. You may do whatever you want with this code. * * You may cont(r)act me by email: pierphil@xs4all.nl * * * ***************************************************************************/ #include #include #include "iupPPlotInteraction.h" const float kHitDistance = (float)10.0;//pixels float pmax (float inX1, float inX2) { if (inX1>inX2) { return inX1; } return inX2; } float pmin (float inX1, float inX2) { if (inX1 inY2) ? inY1 : inY2; if (fabs (theYRange / theYMax) < PPlot::kRangeVerySmall) { return; } StoreCurrentAxisSetup (); if (IsZoomRegion () || IsZoomX ()) { mPPlot.mXAxisSetup.SetAutoScale (false); mPPlot.mXAxisSetup.mMin = pmin (inX1, inX2); mPPlot.mXAxisSetup.mMax = pmax (inX1, inX2); } if (IsZoomRegion () || IsZoomY ()) { mPPlot.mYAxisSetup.SetAutoScale (false); mPPlot.mYAxisSetup.mMin = pmin (inY1, inY2); mPPlot.mYAxisSetup.mMax = pmax (inY1, inY2); } return; } void PZoomInteraction::StoreCurrentAxisSetup () { PAxisInfo theInfo;// store the current axis setup theInfo.mXAxisSetup = mPPlot.mXAxisSetup; theInfo.mYAxisSetup = mPPlot.mYAxisSetup; mZoomHistory.push (theInfo); } void PZoomInteraction::DoZoomIn () { float theX1 = mPPlot.mXTrafo->TransformBack (mX1); float theX2 = mPPlot.mXTrafo->TransformBack (mX2); float theY1 = mPPlot.mYTrafo->TransformBack (mY1); float theY2 = mPPlot.mYTrafo->TransformBack (mY2); DoZoomIn (theX1, theX2, theY1, theY2); }; // arguments allow us to zoom out in X direction but change the Y-axis void PZoomInteraction::DoZoomOut (float inY1, float inY2) { if (mZoomHistory.size () == 0) { return; } PAxisInfo theInfo = mZoomHistory.top (); mZoomHistory.pop (); mPPlot.mXAxisSetup = theInfo.mXAxisSetup; if (inY1 != -1) { mPPlot.mYAxisSetup.mMin = pmin (inY1, inY2); mPPlot.mYAxisSetup.mMax = pmax (inY1, inY2); } else { mPPlot.mYAxisSetup = theInfo.mYAxisSetup; } } PSelectionInteraction::PSelectionInteraction (PPlot &inPPlot): PPlotInteraction (inPPlot), mCommand (kNone), mListener (0) { inPPlot.mPostCalculatorList.push_back (this); } bool PSelectionInteraction::HandleKeyEvent (const PKeyEvent &inEvent) { mCommand = kNone; if (inEvent.IsOnlyControlKeyDown () && inEvent.IsChar () && inEvent.GetChar () == 'a') { // mCalculate = true; mCommand = kSelectAll; mKeyEvent = inEvent; } return mCommand != kNone; }; void PSelectionInteraction::UpdateSelection (int inIndex, int inSampleIndex, PlotDataBase *inXData, PlotDataBase *inYData, bool inHit, PlotDataSelection *inPlotDataSelection) { if ((*inPlotDataSelection)[inSampleIndex] != inHit) { if (SelectNotify(inIndex, inSampleIndex, inXData, inYData, inHit)) (*inPlotDataSelection)[inSampleIndex] = inHit; } } void PSelectionInteraction::SelectAll (int inIndex, PlotDataBase *inXData, PlotDataBase *inYData, PlotDataSelection *inPlotDataSelection) { for (long theI=0;theIsize ();theI++) { UpdateSelection (inIndex, theI, inXData, inYData, true, inPlotDataSelection); } } bool PSelectionInteraction::HandleMouseEvent (const PMouseEvent &inEvent) { mCommand = kNone; if (inEvent.IsMouseDown ()) { if (!(inEvent.IsOnlyControlKeyDown () || inEvent.IsOnlyShiftKeyDown ())) { return false; } // fprintf (stderr, "selection\n"); // mCalculate = true; if (inEvent.IsOnlyControlKeyDown ()) { mCommand = kPointwiseSelection; } else if (inEvent.IsOnlyShiftKeyDown ()) { mCommand = kGlobalSelection; } mMouseEvent = inEvent; return true; } return false; } bool PSelectionInteraction::Calculate (Painter &inPainter, PPlot& inPPlot) { if (mCommand == kNone) { return true; } PlotDataContainer &theContainer = inPPlot.mPlotDataContainer; long thePlotCount = theContainer.GetPlotCount (); float theDist = -1; for (long theI=0;theIHandlePSelectionInteraction (); } mCommand = kNone; return true; } void PSelectionInteraction::HandleGlobalInteraction (int inIndex, PlotDataBase *inXData, PlotDataBase *inYData, bool inHit, long inNearestPointIndex, DataDrawerBase *inDataDrawer, PlotDataSelection *inPlotDataSelection) { if (inPlotDataSelection->size ()>0) { for (int theI=0;theIsize ();theI++) { UpdateSelection (inIndex, theI, inXData, inYData, inHit, inPlotDataSelection); } } } void PSelectionInteraction::HandlePointwiseInteraction (int inIndex, PlotDataBase *inXData, PlotDataBase *inYData, bool inHit, long inNearestPointIndex, DataDrawerBase *inDataDrawer, PlotDataSelection *inPlotDataSelection) { if (!inHit) { return; } if (inPlotDataSelection->size ()>inNearestPointIndex) { bool theWasHit = (*inPlotDataSelection)[inNearestPointIndex] !=0; UpdateSelection (inIndex, inNearestPointIndex, inXData, inYData, !theWasHit, inPlotDataSelection); /* for (int theI=0;theIsize ();theI++) { bool theWasHit = (*inPlotDataSelection)[theI] !=0; bool theIsHit = false; if (theI==inNearestPointIndex) { theIsHit = !theWasHit; } (*inPlotDataSelection)[theI] = theIsHit; }*/ } } float PSelectionInteraction::CalculateDistanceToPlot (const PlotDataBase *inXData, const PlotDataBase *inYData, long &outNearestPointIndex) { // const RealData *theXData = inXData->GetRealPlotData (); // const RealData *theYData = inYData->GetRealPlotData (); outNearestPointIndex = -1; float theDist = -1; for (int theI=0;theIGetSize ();theI++) { // float theX = (*theXData)[theI]; // float theY = (*theYData)[theI]; float theX = inXData->GetValue (theI); float theY = inYData->GetValue (theI); // transform to pixels theX = mPPlot.mXTrafo->Transform (theX)-mMouseEvent.mX; theY = mPPlot.mYTrafo->Transform (theY)-mMouseEvent.mY; float theTmp = theX*theX+theY*theY; if (theTmpmUpperBound) { return false; } return true; } bool PlotDataIncrementer::Increment (const vector &inIncrementList, vector &inData, const PlotDataIncrementerBounds &inGlobalBounds, const vector &inBoundList) const { bool theDontChange = true; if (!Impl_Increment (inIncrementList, inData, inGlobalBounds, inBoundList, theDontChange)) { return false; } theDontChange = false; Impl_Increment (inIncrementList, inData, inGlobalBounds, inBoundList, theDontChange); return true; } bool PlotDataIncrementer::Impl_Increment (const vector &inIncrementList, vector &inData, const PlotDataIncrementerBounds &inGlobalBounds, const vector &inBoundList, bool inDontChange) const { if (inBoundList.size ()>0 && inBoundList.size () != inData.size ()) { return false; } if (inIncrementList.size () != inData.size ()) { return false; } for (int theI=0;theI0) { if (!inBoundList[theI].CheckBounds (theIncrementedValue)) { return false; } } if (!inDontChange) { *theValue = theIncrementedValue; } } return true; } PEditInteraction::PEditInteraction (PPlot &inPPlot): PPlotInteraction (inPPlot), mCalculate (false), mListener (0) { inPPlot.mModifyingCalculatorList.push_back (this); } bool PEditInteraction::HandleKeyEvent (const PKeyEvent &inEvent) { mCalculate = Impl_HandleKeyEvent (inEvent); mKeyEvent = inEvent; return mCalculate; }; bool PEditInteraction::Calculate (Painter &inPainter, PPlot& inPPlot) { if (!mCalculate) { return true; } Impl_Calculate (inPainter, inPPlot); if (mListener) { mListener->HandlePEditInteraction (); } mCalculate = false; return true; } PVerticalCursorInteraction::PVerticalCursorInteraction (PPlot &inPPlot): PEditInteraction (inPPlot) { } bool PVerticalCursorInteraction::Impl_HandleKeyEvent (const PKeyEvent &inEvent) { if (inEvent.IsArrowDown () || inEvent.IsArrowUp ()) { return true; } return false; }; bool PVerticalCursorInteraction::Impl_Calculate (Painter &inPainter, PPlot& inPPlot) { PlotDataContainer &theContainer = inPPlot.mPlotDataContainer; long thePlotCount = theContainer.GetPlotCount (); for (long theI=0;theI(inYData); if (!theYData) { return; } vector theIncrementList (inPlotDataSelection->GetSelectedCount ()); vector theSelectedData (inPlotDataSelection->GetSelectedCount ()); float theDelta = 1;// pixels if (mKeyEvent.IsArrowDown ()) { theDelta *= -1; } if (mKeyEvent.IsOnlyControlKeyDown ()) { theDelta *= 10; } long theIndex = 0; for (int theI=0;theIGetSize ();theI++) { if (inPlotDataSelection->IsSelected (theI)) { float *theNow = &((*theYData)[theI]); float theNowPixels = mPPlot.mYTrafo->Transform (*theNow); float theNow2 = mPPlot.mYTrafo->TransformBack (theNowPixels); theNowPixels -= theDelta; float theShiftedNow = mPPlot.mYTrafo->TransformBack (theNowPixels); float theDeltaData = theShiftedNow-*theNow; theIncrementList[theIndex] = theDeltaData; theSelectedData[theIndex] = theNow; // float theNew = theNow + theDelta; // (*theYData)[theI] = theNew; theIndex++; } } PlotDataIncrementer theIncremter; vector theDummyList; theIncremter.Increment (theIncrementList, theSelectedData, mGlobalBounds, theDummyList); } PDeleteInteraction::PDeleteInteraction (PPlot &inPPlot): PEditInteraction (inPPlot) { } bool PDeleteInteraction::Impl_HandleKeyEvent (const PKeyEvent &inEvent) { if (inEvent.IsDelete ()) { return true; } return false; }; bool PDeleteInteraction::Impl_Calculate (Painter &inPainter, PPlot& inPPlot) { PlotDataContainer &theContainer = inPPlot.mPlotDataContainer; long thePlotCount = theContainer.GetPlotCount (); if (!DeleteNotify(-1, 0, NULL, NULL)) return true; for (long theI=0;theI vectorOfInt; template bool Erase (const vectorOfInt &inEraseList, T &ioVec) { vectorOfInt theSortedList = inEraseList; sort (theSortedList.begin (), theSortedList.end ()); reverse (theSortedList.begin (), theSortedList.end ()); // M.T. this is missing in OW: unique (theSortedList.begin (), theSortedList.end ());// remove duplicates for (vectorOfInt::iterator theI=theSortedList.begin();theI!=theSortedList.end ();theI++) { int theEraseIndex = *theI; // vector ::iterator theX; // theX = ioVec[theEraseIndex]; // T *theX = &(ioVec[theEraseIndex]); ioVec.erase (ioVec.begin ()+theEraseIndex); } return true; } /* bool Erase (const vectorOfInt &inEraseList, PlotData &ioVec) { vectorOfInt theSortedList = inEraseList; sort (theSortedList.begin (), theSortedList.end ()); reverse (theSortedList.begin (), theSortedList.end ()); // unique (theSortedList.begin (), theSortedList.end ());// remove duplicates for (vectorOfInt::iterator theI=theSortedList.begin();theI!=theSortedList.end ();theI++) { int theEraseIndex = *theI; ioVec.erase (ioVec.begin ()+theEraseIndex); } return true; } bool Erase (const vectorOfInt &inEraseList, PlotDataSelection &ioVec) { vectorOfInt theSortedList = inEraseList; sort (theSortedList.begin (), theSortedList.end ()); reverse (theSortedList.begin (), theSortedList.end ()); // unique (theSortedList.begin (), theSortedList.end ());// remove duplicates for (vectorOfInt::iterator theI=theSortedList.begin();theI!=theSortedList.end ();theI++) { int theEraseIndex = *theI; ioVec.erase (ioVec.begin ()+theEraseIndex); } return true; } */ #else template bool Erase (const vector &inEraseList, vector &ioVec) { vector theSortedList = inEraseList; sort (theSortedList.begin (), theSortedList.end ()); reverse (theSortedList.begin (), theSortedList.end ()); unique (theSortedList.begin (), theSortedList.end ());// remove duplicates for (vector::iterator theI=theSortedList.begin();theI!=theSortedList.end ();theI++) { int theEraseIndex = *theI; // vector ::iterator theX; // theX = ioVec[theEraseIndex]; // T *theX = &(ioVec[theEraseIndex]); ioVec.erase (ioVec.begin ()+theEraseIndex); } return true; } #endif void PDeleteInteraction::HandleDeleteKey (PlotDataBase *inXData, PlotDataBase *inYData, PlotDataSelection *inPlotDataSelection, int inIndex) { vector theDeleteList (inPlotDataSelection->GetSelectedCount ()); long theIndex = 0; for (int theI=0;theIGetSize ();theI++) { if (inPlotDataSelection->IsSelected (theI)) { if (DeleteNotify(inIndex, theI, inXData, inYData)) { theDeleteList[theIndex] = theI; theIndex++; } } } if (inXData->IsString()) { StringPlotData *theXData = (StringPlotData*)(inXData); PlotData *theYData = (PlotData*)(inYData); Erase (theDeleteList, theXData->mRealPlotData); Erase (theDeleteList, theXData->mStringPlotData); Erase (theDeleteList, *theYData); Erase (theDeleteList, *inPlotDataSelection); } else { PlotData *theXData = (PlotData*)(inXData); PlotData *theYData = (PlotData*)(inYData); Erase (theDeleteList, *theXData); Erase (theDeleteList, *theYData); Erase (theDeleteList, *inPlotDataSelection); } } PCrosshairInteraction::PCrosshairInteraction (PPlot &inPPlot): PPlotInteraction (inPPlot), mActive (false), mX (0), mListener (0) { inPPlot.mPostDrawerList.push_back (this); } bool PCrosshairInteraction::HandleMouseEvent (const PMouseEvent &inEvent) { if (!mActive) { if (inEvent.IsMouseDown ()) { if (inEvent.IsShiftKeyDown () && inEvent.IsControlKeyDown ()) { mActive = true; mX = inEvent.mX; return true; } } } else { if (inEvent.IsMouseUp ()) { mActive = false; return true; } if (inEvent.IsMouseMove ()) { mX = inEvent.mX; return true; } } return false; } bool PCrosshairInteraction::Draw (Painter &inPainter) { if (mActive) { float theX1 = mX; float theY1 = mPPlot.mMargins.mTop; float theX2 = mX; float theY2 = inPainter.GetHeight () - mPPlot.mMargins.mBottom; inPainter.SetLineColor (0, 0, 0); inPainter.DrawLine (theX1, theY1, theX2, theY2); PlotDataContainer &theContainer = mPPlot.mPlotDataContainer; long thePlotCount = theContainer.GetPlotCount (); for (long theI=0;theITransformBack (mX); float theYTarget = mPPlot.mYTrafo->TransformBack (theY); mListener->HandleCrosshair (theI, thePlotCount, theXTarget, theYTarget); } theX1 = mPPlot.mMargins.mLeft; theX2 = inPainter.GetWidth ()-mPPlot.mMargins.mLeft; theY1 = theY2 = theY; PColor theC = theLegendData->mColor; inPainter.SetLineColor (theC.mR, theC.mG, theC.mB); inPainter.DrawLine (theX1, theY1, theX2, theY2); } } } return true; } bool PCrosshairInteraction::GetCrossPoint (const PlotDataBase *inXData, const PlotDataBase *inYData, float &outY) { if (inXData->GetSize ()==0 ){ return false; } float theXTarget = mPPlot.mXTrafo->TransformBack (mX); bool theFirstIsLess = inXData->GetValue (0) < theXTarget; for (int theI=0;theIGetSize ();theI++) { float theX = inXData->GetValue (theI); float theY = inYData->GetValue (theI); bool theCurrentIsLess = theX < theXTarget; if (theCurrentIsLess != theFirstIsLess) { outY = mPPlot.mYTrafo->Transform (theY);// transform to pixels return true; } } return false; } bool InteractionContainer::HandleMouseEvent (const PMouseEvent &inEvent) { for (int theI=0;theIIsEnabled () && theInteraction->HandleMouseEvent (inEvent)) { return true; } } return false; } bool InteractionContainer::HandleKeyEvent (const PKeyEvent &inEvent) { for (int theI=0;theIIsEnabled () && theInteraction->HandleKeyEvent (inEvent)) { return true; } } return false; } DefaultInteractionContainer::DefaultInteractionContainer (PPlot &inPPlot): mZoomInteraction (inPPlot), mSelectionInteraction (inPPlot), mVerticalCursorInteraction (inPPlot), mDeleteInteraction (inPPlot), mCrosshairInteraction (inPPlot) { AddInteraction (mZoomInteraction); AddInteraction (mSelectionInteraction); AddInteraction (mVerticalCursorInteraction); AddInteraction (mDeleteInteraction); AddInteraction (mCrosshairInteraction); /* mVerticalCursorInteraction.mGlobalBounds.mLowerBoundEnabled = true; mVerticalCursorInteraction.mGlobalBounds.mLowerBound = 0; mVerticalCursorInteraction.mGlobalBounds.mUpperBoundEnabled = true; mVerticalCursorInteraction.mGlobalBounds.mUpperBound = 10;*/ }