using System; using HalconDotNet; using HDisplay.ViewROI; using System.Collections; namespace HDisplay.ViewROI { public delegate void FuncROIDelegate(); /// /// This class creates and manages ROI objects. It responds /// to mouse device inputs using the methods mouseDownAction and /// mouseMoveAction. You don't have to know this class in detail when you /// build your own C# project. But you must consider a few things if /// you want to use interactive ROIs in your application: There is a /// quite close connection between the ROIController and the HWndCtrl /// class, which means that you must 'register' the ROIController /// with the HWndCtrl, so the HWndCtrl knows it has to forward user input /// (like mouse events) to the ROIController class. /// The visualization and manipulation of the ROI objects is done /// by the ROIController. /// This class provides special support for the matching /// applications by calculating a model region from the list of ROIs. For /// this, ROIs are added and subtracted according to their sign. /// public class ROIController { /// /// Constant for setting the ROI mode: positive ROI sign. /// public const int MODE_ROI_POS = 21; /// /// Constant for setting the ROI mode: negative ROI sign. /// public const int MODE_ROI_NEG = 22; /// /// Constant for setting the ROI mode: no model region is computed as /// the sum of all ROI objects. /// public const int MODE_ROI_NONE = 23; /// Constant describing an update of the region of interest public const int EVENT_UPDATE_ROI = 50; public const int EVENT_CHANGED_ROI_SIGN = 51; /// Constant describing an update of the region of interest public const int EVENT_MOVING_ROI = 52; public const int EVENT_DELETED_ACTROI = 53; public const int EVENT_DELETED_ALL_ROIS = 54; public const int EVENT_ACTIVATED_ROI = 55; public const int EVENT_CREATED_ROI = 56; public const int EVENT_REPAINT_ROI = 57; private ROI roiMode; private int stateROI; private double currX, currY; /// Index of the active ROI object public int activeROIidx; public int deletedIdx; /// List containing all created ROI objects so far public ArrayList ROIList; /// /// Region obtained by summing up all negative /// and positive ROI objects from the ROIList /// public HRegion ModelROI; private string activeCol = "green"; private string activeHdlCol = "red"; private string inactiveCol = "yellow"; /// /// Reference to the HWndCtrl, the ROI Controller is registered to /// public HWndCtrl viewController; /// /// Delegate that notifies about changes made in the model region /// public IconicDelegate NotifyRCObserver; /// Constructor public ROIController() { stateROI = MODE_ROI_NONE; ROIList = new ArrayList(); activeROIidx = -1; ModelROI = new HRegion(); NotifyRCObserver = new IconicDelegate(dummyI); deletedIdx = -1; currX = currY = -1; } /// Registers the HWndCtrl to this ROIController instance public void setViewController(HWndCtrl view) { viewController = view; } /// Gets the ModelROI object public HRegion getModelRegion() { return ModelROI; } /// Gets the List of ROIs created so far public ArrayList getROIList() { return ROIList; } /// Get the active ROI public ROI getActiveROI() { if (activeROIidx != -1) return ((ROI)ROIList[activeROIidx]); return null; } public int getActiveROIIdx() { return activeROIidx; } public void setActiveROIIdx(int active) { activeROIidx = active; } public int getDelROIIdx() { return deletedIdx; } /// /// To create a new ROI object the application class initializes a /// 'seed' ROI instance and passes it to the ROIController. /// The ROIController now responds by manipulating this new ROI /// instance. /// /// /// 'Seed' ROI object forwarded by the application forms class. /// public void setROIShape(ROI r) { roiMode = r; roiMode.setOperatorFlag(stateROI); } /// /// Sets the sign of a ROI object to the value 'mode' (MODE_ROI_NONE, /// MODE_ROI_POS,MODE_ROI_NEG) /// public void setROISign(int mode) { stateROI = mode; if ((activeROIidx != -1)) { ((ROI)ROIList[activeROIidx]).setOperatorFlag(stateROI); NotifyRCObserver(ROIController.EVENT_REPAINT_ROI); NotifyRCObserver(ROIController.EVENT_CHANGED_ROI_SIGN); } } /// /// Removes the ROI object that is marked as active. /// If no ROI object is active, then nothing happens. /// public void removeActive() { if (activeROIidx != -1) { ROIList.RemoveAt(activeROIidx); deletedIdx = activeROIidx; activeROIidx = -1; //viewController.repaint(); NotifyRCObserver(EVENT_REPAINT_ROI); NotifyRCObserver(EVENT_DELETED_ACTROI); } } /// /// Calculates the ModelROI region for all objects contained /// in ROIList, by adding and subtracting the positive and /// negative ROI objects. /// public bool defineModelROI() { HRegion tmpAdd, tmpDiff, tmp; double row, col; double rowDiff, colDiff; if (stateROI == MODE_ROI_NONE) return true; tmp = new HRegion(); tmpAdd = new HRegion(); tmpDiff = new HRegion(); tmpAdd.GenEmptyRegion(); tmpDiff.GenEmptyRegion(); for (int i=0; i < ROIList.Count; i++) { switch (((ROI)ROIList[i]).getOperatorFlag()) { case ROI.POSITIVE_FLAG: tmp = ((ROI)ROIList[i]).getRegion(); tmpAdd = tmp.Union2(tmpAdd); break; case ROI.NEGATIVE_FLAG: tmp = ((ROI)ROIList[i]).getRegion(); tmpDiff = tmp.Union2(tmpDiff); break; default: break; }//end of switch }//end of for ModelROI = null; if (tmpAdd.AreaCenter(out row, out col) > 0) { if (tmpDiff.AreaCenter(out rowDiff, out colDiff) > 0) tmp = tmpAdd.Difference(tmpDiff); else tmp = tmpAdd; if (tmp.AreaCenter(out row, out col) > 0) ModelROI = tmp; } //in case the set of positiv and negative ROIs dissolve if (ModelROI == null || ROIList.Count == 0) return false; return true; } /// /// Clears all variables managing ROI objects /// public void reset() { ROIList.Clear(); activeROIidx = -1; ModelROI = null; roiMode = null; NotifyRCObserver(EVENT_DELETED_ALL_ROIS); } /// /// Deletes this ROI instance if a 'seed' ROI object has been passed /// to the ROIController by the application class. /// /// public void resetROI() { activeROIidx = -1; roiMode = null; } /// Defines the colors for the ROI objects /// Color for the active ROI object /// Color for the inactive ROI objects /// /// Color for the active handle of the active ROI object /// public void setDrawColor(string aColor, string aHdlColor, string inaColor) { if (aColor != "") activeCol = aColor; if (aHdlColor != "") activeHdlCol = aHdlColor; if (inaColor != "") inactiveCol = inaColor; } /// /// Paints all objects from the ROIList into the HALCON window /// /// HALCON window public void paintData(HalconDotNet.HWindow window) { window.SetDraw("margin"); window.SetLineWidth(1); if (ROIList.Count > 0) { window.SetDraw("fill"); window.SetLineStyle(new HTuple()); window.SetColor("blue"); defineModelROI(); if (ModelROI != null) window.DispRegion(ModelROI); } if (ROIList.Count > 0) { window.SetColor(inactiveCol); window.SetDraw("margin"); for (int i=0; i < ROIList.Count; i++) { window.SetLineStyle(((ROI)ROIList[i]).flagLineStyle); ((ROI)ROIList[i]).draw(window); } if (activeROIidx != -1) { window.SetColor(activeCol); window.SetLineStyle(((ROI)ROIList[activeROIidx]).flagLineStyle); ((ROI)ROIList[activeROIidx]).draw(window); window.SetColor(activeHdlCol); ((ROI)ROIList[activeROIidx]).displayActive(window); } } } /// /// Paints specified region from the ROIList into the HALCON window /// /// HALCON window public void paintSpecifiedROI(HalconDotNet.HWindow window, int RegionID) { window.SetDraw("margin"); window.SetLineWidth(1); if ((ROIList.Count > 0) && (ROIList.Count > RegionID)) { window.SetColor(inactiveCol); window.SetDraw("margin"); window.SetLineStyle(((ROI)ROIList[RegionID]).flagLineStyle); ((ROI)ROIList[RegionID]).draw(window); if ((activeROIidx != -1) && (activeROIidx == RegionID)) { window.SetColor(activeCol); window.SetLineStyle(((ROI)ROIList[activeROIidx]).flagLineStyle); ((ROI)ROIList[activeROIidx]).draw(window); window.SetColor(activeHdlCol); ((ROI)ROIList[activeROIidx]).displayActive(window); } } } public HRegion getSpecifiedRegion(int RegionID) { HRegion reg; if ((RegionID > -1) && (ROIList.Count > RegionID)) { reg = ((ROI)ROIList[RegionID]).getRegion(); return reg; } else return null; } /// /// Reaction of ROI objects to the 'mouse button down' event: changing /// the shape of the ROI and adding it to the ROIList if it is a 'seed' /// ROI. /// /// x coordinate of mouse event /// y coordinate of mouse event /// public int mouseDownAction(double imgX, double imgY) { int idxROI= -1; double max = 10000, dist = 0; double epsilon = 35.0; //maximal shortest distance to one of //the handles if (roiMode != null) //either a new ROI object is created { roiMode.createROI(imgX, imgY); roiMode.PropertyChanged += RoiMode_PropertyChanged; ROIList.Add(roiMode); roiMode = null; activeROIidx = ROIList.Count - 1; viewController.repaint(); NotifyRCObserver(ROIController.EVENT_CREATED_ROI); } else if (ROIList.Count > 0) // ... or an existing one is manipulated { // identify activated ROI activeROIidx = -1; for (int i =0; i < ROIList.Count; i++) { dist = ((ROI)ROIList[i]).distToClosestHandle(imgX, imgY); if ((dist < max) && (dist < epsilon)) { max = dist; idxROI = i; } }//end of for // if (idxROI >= 0) { activeROIidx = idxROI; NotifyRCObserver(ROIController.EVENT_ACTIVATED_ROI); } //viewController.repaint(); NotifyRCObserver(ROIController.EVENT_REPAINT_ROI); } return activeROIidx; } private void RoiMode_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { viewController.repaint(); NotifyRCObserver(ROIController.EVENT_ACTIVATED_ROI); NotifyRCObserver(ROIController.EVENT_REPAINT_ROI); } /// /// Reaction of ROI objects to the 'mouse button move' event: moving /// the active ROI. /// /// x coordinate of mouse event /// y coordinate of mouse event public void mouseMoveAction(double newX, double newY) { if ((newX == currX) && (newY == currY)) return; if (activeROIidx < ROIList.Count) { ((ROI)ROIList[activeROIidx]).moveByHandle(newX, newY); viewController.repaint(); currX = newX; currY = newY; NotifyRCObserver(ROIController.EVENT_MOVING_ROI); } } /***********************************************************/ public void dummyI(int v) { } }//end of class }//end of namespace