using System;
using HalconDotNet;
namespace HalconTools
{
///
/// This model data class holds general information about a measure
/// object. To define more specialized measure data objects the
/// classes MeasurementEdge and MeasurementPair are derived from this
/// class to be able to distinguish the measure
/// types and results for simple edges and for edge pairs. The base
/// class contains the methods to create measure handles and to create
/// the display results of a measure action. The derived classes
/// implement the specialized methods to perform a measure operation
/// and generate the measure results.
///
public class Measurement
{
/// HALCON measure object (handle).
protected HMeasure mHandle;
///
/// Flag to distinguish between a linear and circular measure object.
///
protected int mROIType;
///
/// Model coordinates obtained from the ROI instance.
/// This coordinates are the base to calculate the measuring field.
///
protected HTuple mROICoord;
/// Reference to the ROI.
protected ROI mRoi;
///
/// Auxiliary information about the
/// measuring field calculated using the ROI coordinates.
///
protected HTuple mMeasROI;
/// Iconic object to display measure edge results.
protected HXLDCont mEdgeXLD;
/// Iconic object to display mMeasROI.
protected HRegion mMeasureRegion;
///
/// Reference to controller class to obtain information about
/// the context of the measurement, e.g. image, parameter setups etc.
///
protected MeasureAssistant mMeasAssist;
///
/// Creates and initializes a measure object based on information the ROI object
/// about the ROI.
///
/// ROI instance
/// Reference to controller class
public Measurement(ROI roi, MeasureAssistant mAssist)
{
mRoi = roi;
mMeasAssist = mAssist;
mROICoord = mRoi.getModelData();
mEdgeXLD = new HXLDCont();
mMeasureRegion = new HRegion();
if (mRoi is ROICircularArc)
mROIType = ROI.ROI_TYPE_CIRCLEARC;
else
mROIType = ROI.ROI_TYPE_LINE;
}
///
/// Triggers an update of the measure object for all
/// changes concerning the shape of the ROI or the measurement
/// parameters.
///
public void UpdateROI()
{
mROICoord = mRoi.getModelData();
UpdateMeasure();
}
///
/// Creates a measure object based on the model data
/// defined by the ROI instance and the parameters
/// describing the measure context.
///
protected void UpdateMeasure()
{
double extent, sPhi, radius;
if (mHandle != null)
mHandle.Dispose();
mMeasAssist.exceptionText = "";
try
{
switch (mROIType)
{
case ROI.ROI_TYPE_CIRCLEARC:
radius = mROICoord[2].D;
sPhi = mROICoord[3].D;
extent = mROICoord[4].D;
mMeasROI = GenSurCircle(mROICoord, mMeasAssist.mRoiWidth);
mHandle = new HMeasure(mROICoord[0].D, mROICoord[1].D, radius,
sPhi, extent,
mMeasAssist.mRoiWidth,
mMeasAssist.mWidth, mMeasAssist.mHeight,
mMeasAssist.mInterpolation);
break;
case ROI.ROI_TYPE_LINE:
mMeasROI = GenSurRect2(mROICoord, mMeasAssist.mRoiWidth);
mHandle = new HMeasure(mMeasROI[0].D, mMeasROI[1].D,
mMeasROI[2].D, mMeasROI[3].D, mMeasROI[4].D,
mMeasAssist.mWidth, mMeasAssist.mHeight,
mMeasAssist.mInterpolation);
break;
//case ROI.ROI_TYPE_LINE:
// mMeasROI = GenSurRect2(mROICoord,mMeasAssist.mRoiHeight, mMeasAssist.mRoiWidth);
// mHandle = new HMeasure(mMeasROI[0].D, mMeasROI[1].D,
// mMeasROI[2].D, mMeasROI[3].D, mMeasROI[4].D,
// mMeasAssist.mWidth, mMeasAssist.mHeight,
// mMeasAssist.mInterpolation);
break;
}
}
catch (HOperatorException e)
{
mEdgeXLD.Dispose();
mMeasureRegion.Dispose();
mMeasAssist.exceptionText = e.Message;
ClearResultData();
return;
}
UpdateResults();
UpdateMeasureRegion();
}
///
/// Defines the measuring field of a linear ROI.
///
///
/// Model data for a linear interactive ROI
///
/// Half width of (rectangular) measure ROI
/// Model data describing a linear measuring field
private HTuple GenSurRect2(HTuple line, double width)
{
double row1 = line[0];
double col1 = line[1];
double row2 = line[2];
double col2 = line[3];
double phi = HMisc.AngleLx(row1, col1, row2, col2);
double length1 = (HMisc.DistancePp(row1, col1, row2, col2)) / 2.0;
double length2 = width;
double rowM = (row1 + row2) / 2;
double colM = (col1 + col2) / 2;
return new HTuple(new double[] { rowM, colM, phi, length1, length2 });
}
private HTuple GenSurRect2(HTuple line,double height, double width)
{
double row1 = line[0];
double col1 = line[1];
double row2 = line[2];
double col2 = line[3];
double phi = HMisc.AngleLx(row1, col1, row2, col2);
double length1 = height / 2.0;
double length2 = width;
double rowM = (row1 + row2) / 2;
double colM = (col1 + col2) / 2;
return new HTuple(new double[] { rowM, colM, phi, length1, length2 });
}
///
/// Defines the measuring field of a circular ROI.
///
///
/// Model data for a circular ROI
///
/// Radius (half width) of the circular (ring-shaped) ROI
/// Model data describing circular measuring field
private HTuple GenSurCircle(HTuple circle, double width)
{
double row1 = circle[0];
double col1 = circle[1];
double radius = circle[2];
double startPhi = circle[3];
double extent = circle[4];
if (radius <= width)
return new HTuple(new double[] { row1, col1, startPhi, extent, (radius + width), 0.0 });
else
return new HTuple(new double[] { row1, col1, startPhi, extent, (radius + width), (radius - width) });
}
/// Releases resources used for this measure object.
public void ClearMeasurement()
{
if (mHandle != null)
{
mHandle.Dispose();
mEdgeXLD.Dispose();
mMeasureRegion.Dispose();
}
}
///
/// Creates the iconic object for displaying a measured
/// edge in a linear ROI.
///
/// Contour depicting the measured edge
public static HXLDCont DetermineEdgeLine(double row, double col, double phi, double width)
{
double row1, row2, col1, col2;
row1 = row - width * Math.Sin(phi + 0.5 * Math.PI);
col1 = col + width * Math.Cos(phi + 0.5 * Math.PI);
row2 = row - width * Math.Sin(phi + 1.5 * Math.PI);
col2 = col + width * Math.Cos(phi + 1.5 * Math.PI);
return DetermineLine(row1, col1, row2, col2);
}
///
/// Creates the iconic object for displaying a measured
/// edge from the coordinates of the end points.
///
/// Contour depicting the measured edge
public static HXLDCont DetermineLine(double row1, double col1, double row2, double col2)
{
HXLDCont edge = new HXLDCont();
HTuple rows, cols;
rows = new HTuple(new double[] { row1, row2 });
cols = new HTuple(new double[] { col1, col2 });
edge.GenContourPolygonXld(rows, cols);
return edge;
}
///
/// Creates the iconic object for displaying a measured
/// edge in a circular ROI.
///
/// Edge contour depicting a measured edge
public static HXLDCont DetermineEdgeCircularArc(double row, double col, double center_row, double center_col, double radius, double width)
{
double row1, row2, col1, col2;
row1 = row + (center_row - row) / radius * width;
col1 = col + (center_col - col) / radius * width;
row2 = row - (center_row - row) / radius * width;
col2 = col - (center_col - col) / radius * width;
return DetermineLine(row1, col1, row2, col2);
}
///
/// Creates the iconic object for displaying
/// the arc between edges of a pair.
///
/// Edge contour depicting the arc between edges of a pair
public static HXLDCont DeterminePairCircularArc(double row1, double col1, double row2, double col2, double cRow, double cCol, double radius, double width, bool positive)
{
HXLDCont arc = new HXLDCont();
double startPhi, endPhi;
startPhi = Math.Atan2(cRow - row1, col1 - cCol);
endPhi = Math.Atan2(cRow - row2, col2 - cCol);
arc.GenEllipseContourXld(cRow, cCol, 0.0, radius, radius, startPhi, endPhi, (positive ? "positive" : "negative"), 1.5);
return arc;
}
///
/// Creates an iconic object depicting the
/// measuring field.
///
public void UpdateMeasureRegion()
{
mMeasureRegion.Dispose();
mMeasureRegion.GenEmptyObj();
if (mROIType == ROI.ROI_TYPE_CIRCLEARC)
{
double sPhi, extent, innerRad, outerRad;
HTuple innerR, outerR, innerC, outerC;
HXLDCont outCont, innerCont, contour;
outCont = new HXLDCont();
innerCont = new HXLDCont();
sPhi = mMeasROI[2].D;
extent = mMeasROI[3].D;
outerRad = mMeasROI[4].D;
innerRad = mMeasROI[5].D;
innerCont.GenCircleContourXld(mMeasROI[0].D, mMeasROI[1].D, innerRad, sPhi, (sPhi + extent), (extent > 0) ? "positive" : "negative", 1.0);
outCont.GenCircleContourXld(mMeasROI[0].D, mMeasROI[1].D, outerRad, (sPhi + extent), sPhi, (extent > 0) ? "negative" : "positive", 1.0);
innerCont.GetContourXld(out innerR, out innerC);
outCont.GetContourXld(out outerR, out outerC);
innerR = innerR.TupleConcat(outerR);
innerC = innerC.TupleConcat(outerC);
contour = new HXLDCont(innerR, innerC);
contour = contour.CloseContoursXld();
mMeasureRegion = contour.GenRegionContourXld("margin");
contour.Dispose();
innerCont.Dispose();
outCont.Dispose();
}
else
{
mMeasureRegion.GenRectangle2(mMeasROI[0].D, mMeasROI[1].D,
mMeasROI[2].D, mMeasROI[3].D,
mMeasROI[4].D);
}
}
///
/// If calibration data is available and valid, then rectify
/// measure result coordinates, otherwise leave them the same
///
public void Rectify(HTuple row, HTuple col, out HTuple rowRect, out HTuple colRect)
{
double unitScale=0.0;
if (mMeasAssist.mIsCalibValid)
{
switch (mMeasAssist.mUnit)
{
case "µm":
unitScale = 0.000001;
break;
case "mm":
unitScale = 0.001;
break;
case "cm":
unitScale = 0.01;
break;
case "m":
unitScale = 1.0;
break;
default:
break;
}
HOperatorSet.ImagePointsToWorldPlane(mMeasAssist.mCamParameter,
mMeasAssist.mCamPose,
row, col, new HTuple(unitScale),
out colRect, out rowRect);
}
else
{
rowRect = row;
colRect = col;
}
}
///
/// If calibration data is available and valid, then transform the
/// distance between measure result edges into world coordinates,
/// else leave them the same.
///
public HTuple Distance(HTuple row1, HTuple col1, HTuple row2, HTuple col2, int shift)
{
HTuple rows, cols, rowRect, colRect;
HTuple distance = new HTuple();
HXLDCont contour;
if (shift == 0)
{
if (mROIType == ROI.ROI_TYPE_CIRCLEARC)
{
double cRow, cCol, radius, extent, phi1, phi2, phi, res, length, tmp;
cRow = mROICoord[0].D;
cCol = mROICoord[1].D;
radius = mROICoord[2].D;
extent = mROICoord[4].D;
HOperatorSet.TupleGenConst(new HTuple(row1.Length), 0.0, out distance);
for (int i=0; i < distance.Length; i++)
{
phi1 = HMisc.AngleLx(cRow, cCol, row1[i].D, col1[i].D);
phi2 = HMisc.AngleLx(cRow, cCol, row2[i].D, col2[i].D);
if (extent < 0)
{
tmp = phi1;
phi1 = phi2;
phi2 = tmp;
}
phi = phi2 - phi1;
if (phi < 0)
phi += 2 * Math.PI;
res = 0.05 * 24.0 / (radius * phi);
contour = new HXLDCont();
contour.GenEllipseContourXld(cRow, cCol, 0, radius, radius, phi1, phi2, "positive", res);
contour.GetContourXld(out rows, out cols);
Rectify(rows, cols, out rowRect, out colRect);
contour.Dispose();
contour.GenContourPolygonXld(rowRect, colRect);
length = contour.LengthXld();
distance[i].D = length;
contour.Dispose();
}
}
else if (mROIType == ROI.ROI_TYPE_LINE)
{
HTuple rRect1, cRect1, rRect2, cRect2;
Rectify(row1, col1, out rRect1, out cRect1);
Rectify(row2, col2, out rRect2, out cRect2);
distance = HMisc.DistancePp(rRect1, cRect1, rRect2, cRect2);
}
return distance;
}
else
{
HTuple rClip1, cClip1, rShift2, cShift2;
rClip1 = row1.TupleSelectRange(new HTuple(0), new HTuple(row1.Length - shift - 1));
cClip1 = col1.TupleSelectRange(new HTuple(0), new HTuple(col1.Length - shift - 1));
rShift2 = row2.TupleSelectRange(new HTuple(shift), new HTuple(row2.Length - 1));
cShift2 = col2.TupleSelectRange(new HTuple(shift), new HTuple(col2.Length - 1));
return this.Distance(rClip1, cClip1, rShift2, cShift2, 0);
}
}
///
/// Returns the iconic object describing the measuring field
/// of the measure object.
///
public HRegion getMeasureRegion()
{
return mMeasureRegion;
}
///
/// Returns the iconic object depicting the measured edges.
///
public HXLDCont getMeasureResults()
{
return mEdgeXLD;
}
///
/// Returns the gray-value profile obtained by the measure projection
/// operation.
///
/// Gray-value profile
public double[] getGrayValueProj()
{
HTuple grayVal;
if (mHandle == null || (int)mHandle.Handle < 0)
return null;
grayVal = mHandle.MeasureProjection(mMeasAssist.mImage);
return grayVal.ToDArr();
}
/********************************************************/
/********************************************************/
///
/// Virtual method to be implemented by the derived classes.
///
public virtual void UpdateResults() { }
///
/// Virtual method to be implemented by the derived classes.
///
public virtual void UpdateXLD() { }
///
/// Virtual method to be implemented by the derived classes.
///
public virtual void ClearResultData() { }
///
/// Virtual method to be implemented by the derived classes.
///
public virtual MeasureResult getMeasureResultData()
{
return null;
}
}//end of class
}//end of namespace