コード例 #1
0
        public override void DoWork()
        {
            DateTime startTime = DateTime.Now;

            TestExecution().LogMessageWithTimeFromTrigger("[" + Name + "] started at " + startTime + Environment.NewLine);

            if (mEnabled == null)
            {
                TestExecution().LogErrorWithTimeFromTrigger("Enabled isn't defined in " + Name);
            }
            else if (mPrerequisite != null && !mPrerequisite.ValueAsBoolean())
            {
                TestExecution().LogMessageWithTimeFromTrigger(Name + ": prerequisites not met. Skipping.");
            }
            else
            {
                if (mEnabled.ValueAsBoolean())
                {
                    mDataLogDefinition.AddLine(TestExecution());
                }
                else
                {
                    TestExecution().LogMessageWithTimeFromTrigger(Name + " data log disabled. Skipped entry.");
                }
            }

            DateTime doneTime    = DateTime.Now;
            TimeSpan computeTime = doneTime - startTime;

            TestExecution().LogMessageWithTimeFromTrigger(Name + " finished at " + doneTime + "  | took " + computeTime.TotalMilliseconds + "ms");
            mIsComplete = true;
        }
コード例 #2
0
        public override void DoWork()
        {
            TestExecution().LogMessageWithTimeFromTrigger("Function " + Name + " started");

            switch (Result.Type)
            {
            case DataType.DecimalNumber:
                double resultAsDecimal = Math.Abs(mArgument.ValueAsDecimal());
                Result.SetValue(resultAsDecimal);
                break;

            case DataType.IntegerNumber:
                long resultAsLong = Math.Abs(mArgument.ValueAsLong());
                Result.SetValue(resultAsLong);
                break;

            case DataType.Boolean:
                resultAsLong = Math.Abs((mArgument.ValueAsBoolean() ? 1 : 0));     // ??? NEEDED?
                Result.SetValue(resultAsLong);
                break;

            default:
                throw new ArgumentException("Data type " + Result.Type + " not supported by Abs function.");
            }
            Result.SetIsComplete();

            TestExecution().LogMessageWithTimeFromTrigger("Function " + Name + " completed");
        }
コード例 #3
0
        public override void DoWork()
        {
            DateTime startTime = DateTime.Now;

            TestExecution().LogMessageWithTimeFromTrigger("[" + Name + "] started at " + startTime + Environment.NewLine);

            double result_pixels = -1;
            double result        = -1;

            if (mReferencePoint1.GetValueAsDouble() < 0 || mReferencePoint2.GetValueAsDouble() < 0)
            {
                TestExecution().LogMessage("ERROR: Reference point(s) for '" + Name + "' do not have valid values. ref1=" + mReferencePoint1.GetValueAsDouble() + " ref2=" + mReferencePoint2.GetValueAsDouble());
            }
            else if (mEnsure1Before2 != null && mEnsure1Before2.ValueAsBoolean() && mReferencePoint1.GetValueAsDouble() > mReferencePoint2.GetValueAsDouble())
            {
                TestExecution().LogMessage("ERROR: Reference point(s) for '" + Name + "' are out of order (1 > 2). ref1=" + mReferencePoint1.GetValueAsDouble() + " ref2=" + mReferencePoint2.GetValueAsDouble());
            }
            else
            {
                try
                {
                    result_pixels = Math.Abs(mReferencePoint2.GetValueAsDouble() - mReferencePoint1.GetValueAsDouble());
                    if (mPixelsPerUnit.ValueAsDecimal() == 0)
                    {
                        TestExecution().LogMessage("ERROR: PixelsPerUnit for '" + Name + "' is zero (0).  Unable to use it for conversion.");
                    }
                    else
                    {
                        result = result_pixels / mPixelsPerUnit.ValueAsDecimal();
                    }
                }
                catch (Exception e)
                {
                    TestExecution().LogMessageWithTimeFromTrigger("ERROR: Failure in " + Name + "; msg=" + e.Message + " " + Environment.NewLine + e.StackTrace);
                }
                finally
                {
                }
            } // end main block ("else" after all initial setup error checks)
            mDistance.SetValue(result);
            mDistance.SetIsComplete();
            if (mDistance_pixels != null)
            {
                mDistance_pixels.SetValue(result_pixels);
                mDistance_pixels.SetIsComplete();
            }
            DateTime doneTime    = DateTime.Now;
            TimeSpan computeTime = doneTime - startTime;

            TestExecution().LogMessageWithTimeFromTrigger(Name + " computed distance of " + result);

            TestExecution().LogMessageWithTimeFromTrigger(Name + " finished at " + doneTime + "  | took " + computeTime.TotalMilliseconds + "ms");
        }
コード例 #4
0
        public override object GetValueAsObject()
        {
            switch (TNDDataType)
            {
            case TNDLink.TNDDataTypeEnum.Flag:
                return(mDataValueInstance.ValueAsBoolean());

            case TNDLink.TNDDataTypeEnum.Input:     // TODO is there any reason to write to an input???
                return(mDataValueInstance.ValueAsBoolean());

            case TNDLink.TNDDataTypeEnum.Output:
                return(mDataValueInstance.ValueAsBoolean());

            case TNDLink.TNDDataTypeEnum.Number:
                return((int)mDataValueInstance.ValueAsLong());    // TODO: test for overflow?

            case TNDLink.TNDDataTypeEnum.Counter:
                return((short)mDataValueInstance.ValueAsLong());    // TODO: test for overflow?

            default:
                throw new ArgumentException("TND Write Request doesn't support converting from " + mDataValueInstance.Type + " to " + TNDDataType);
            }
        }
コード例 #5
0
        public override void DoWork()
        {
            DateTime startTime = DateTime.Now;

            TestExecution().LogMessageWithTimeFromTrigger("[" + Name + "] started at " + startTime + Environment.NewLine);

            try
            {
                if (mPrerequisite != null && !mPrerequisite.ValueAsBoolean())
                {
                    TestExecution().LogMessageWithTimeFromTrigger(Name + ": prerequisites not met. Skipping.");
                }
                else
                {
                    switch (mDestinationValue.Type)
                    {
                    case DataType.Boolean:
                        mDestinationValue.SetValue(mSourceValue.ValueAsBoolean());
                        break;

                    case DataType.DecimalNumber:
                        mDestinationValue.SetValue(mSourceValue.ValueAsDecimal());
                        break;

                    case DataType.IntegerNumber:
                        mDestinationValue.SetValue(mSourceValue.ValueAsLong());
                        break;

                    case DataType.NotDefined:
                        TestExecution().LogErrorWithTimeFromTrigger(Name + " can't copy value since the destination doesn't have its type defined.");

                        /*
                         * switch (mSourceValue.Type)
                         * {
                         *  case DataType.Boolean:
                         *      mDestinationValue.SetValue(mSourceValue.ValueAsBoolean());
                         *      break;
                         *  case DataType.DecimalNumber:
                         *      mDestinationValue.SetValue(mSourceValue.ValueAsDecimal());
                         *      break;
                         *  case DataType.IntegerNumber:
                         *      mDestinationValue.SetValue(mSourceValue.ValueAsLong());
                         *      break;
                         *  case DataType.NotDefined:
                         *      TestExecution().LogErrorWithTimeFromTrigger(Name + " can't copy value since neither the destination nor the source values have their type defined.");
                         *      mDestinationValue.SetValue(mSourceValue.ValueAsDecimal());
                         *      break;
                         *  default:
                         *      TestExecution().LogErrorWithTimeFromTrigger(Name + " can't copy value since the source is an unsupported type.");
                         *      break;
                         * }
                         */
                        break;

                    default:
                        TestExecution().LogErrorWithTimeFromTrigger(Name + " can't copy value since the destination is an unsupported type.");
                        break;
                    }
                }
            }
            catch (Exception e)
            {
                TestExecution().LogMessageWithTimeFromTrigger("ERROR: Failure in " + Name + "; msg=" + e.Message + " " + Environment.NewLine + e.StackTrace);
            }
            finally
            {
            }

            mDestinationValue.SetIsComplete();
            DateTime doneTime    = DateTime.Now;
            TimeSpan computeTime = doneTime - startTime;

            mIsComplete = true;

            TestExecution().LogMessageWithTimeFromTrigger(Name + " finished at " + doneTime + "  | took " + computeTime.TotalMilliseconds + "ms");
        }
コード例 #6
0
        public static readonly int PIXEL_BYTE_WIDTH     = 4; // determined by PixelFormat.Format32bppArgb; http://www.bobpowell.net/lockingbits.htm
        public override void DoWork()
        {
            DateTime startTime = DateTime.Now;

            TestExecution().LogMessageWithTimeFromTrigger("[" + Name + "] started at " + startTime + Environment.NewLine);

            int startX = (int)mStartPoint_X.ValueAsLong();
            int startY = (int)mStartPoint_Y.ValueAsLong();

            int leftEdge   = -1;
            int rightEdge  = -1;
            int topEdge    = -1;
            int bottomEdge = -1;

            if (mPrerequisite != null && !mPrerequisite.ValueAsBoolean())
            {
                TestExecution().LogMessageWithTimeFromTrigger(Name + ": prerequisites not met.  Skipping.");
            }
            else if (mSourceImage.Bitmap == null)
            {
                TestExecution().LogErrorWithTimeFromTrigger("source image for '" + Name + "' does not exist.");
            }
            else if (startX < 0 || startX >= mSourceImage.Bitmap.Width ||
                     startY < 0 || startY >= mSourceImage.Bitmap.Height)
            {
                TestExecution().LogErrorWithTimeFromTrigger("Start position for '" + Name + "' isn't within the image bounds; start=" + startX + "," + startY + "; image size=" + mSourceImage.Bitmap.Width + "x" + mSourceImage.Bitmap.Height);
            }
            else
            {
                int  stepSize            = (int)mStepSize.ValueAsLong();
                bool detailedSearchAtEnd = mDetailedSearch.ValueAsBoolean();

                sourceBitmap = SourceImage.Bitmap;
                if (mImageToMark != null && mImageToMark.Bitmap != null)
                {
                    markedBitmap = mImageToMark.Bitmap;
                }

                try
                {
                    sourceBitmapData = sourceBitmap.LockBits(new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height), ImageLockMode.ReadOnly, PIXEL_FORMAT);
                    if (markedBitmap != null)
                    {
                        markedBitmapData = markedBitmap.LockBits(new Rectangle(0, 0, markedBitmap.Width, markedBitmap.Height), ImageLockMode.ReadWrite, PIXEL_FORMAT);
                    }
                    sourceStride       = sourceBitmapData.Stride;
                    sourceStrideOffset = sourceStride - (sourceBitmapData.Width * PIXEL_BYTE_WIDTH);

                    unsafe // see http://www.codeproject.com/csharp/quickgrayscale.asp?df=100&forumid=293759&select=2214623&msg=2214623
                    {
                        byte *sourcePointer;
                        byte *markedPointer;

                        sourcePointer  = (byte *)sourceBitmapData.Scan0;                        // init to first byte of image
                        sourcePointer += (startY * sourceStride) + (startX * PIXEL_BYTE_WIDTH); // adjust to current point

                        Color theColor = Color.FromArgb(sourcePointer[2], sourcePointer[1], sourcePointer[0]);
                        if (!mColorMatchDefinition.Matches(theColor))
                        {
                            TestExecution().LogErrorWithTimeFromTrigger(Name + " start position isn't within the match color; start=" + startX + "," + startY + "   color=" + theColor);
                        }
                        else
                        {
                            if (mFindBoundingRectangleDefinition.SearchRecord.GetLength(0) < sourceBitmap.Width || mFindBoundingRectangleDefinition.SearchRecord.GetLength(1) < sourceBitmap.Height)
                            {
                                mFindBoundingRectangleDefinition.SearchRecord   = new short[sourceBitmap.Width, sourceBitmap.Height];
                                mFindBoundingRectangleDefinition.LastMarkerUsed = 0;
                            }
                            if (mFindBoundingRectangleDefinition.LastMarkerUsed == int.MaxValue)
                            {
                                for (int x = 0; x < mFindBoundingRectangleDefinition.SearchRecord.GetLength(0); x++)
                                {
                                    for (int y = 0; y < mFindBoundingRectangleDefinition.SearchRecord.GetLength(1); y++)
                                    {
                                        mFindBoundingRectangleDefinition.SearchRecord[x, y] = 0;
                                    }
                                }
                                mFindBoundingRectangleDefinition.LastMarkerUsed = 0;
                            }
                            mFindBoundingRectangleDefinition.LastMarkerUsed++;

                            EdgeSearch topEdgeSearch    = new EdgeSearch(this, mColorMatchDefinition, Axis.X, startY, -1 * stepSize, 0, startX, 0, sourceBitmap.Width - 1, mFindBoundingRectangleDefinition.SearchRecord, mFindBoundingRectangleDefinition.LastMarkerUsed);
                            EdgeSearch bottomEdgeSearch = new EdgeSearch(this, mColorMatchDefinition, Axis.X, startY, +1 * stepSize, sourceBitmap.Height - 1, startX, 0, sourceBitmap.Width - 1, mFindBoundingRectangleDefinition.SearchRecord, mFindBoundingRectangleDefinition.LastMarkerUsed);
                            EdgeSearch leftEdgeSearch   = new EdgeSearch(this, mColorMatchDefinition, Axis.Y, startX, -1 * stepSize, 0, startY, 0, sourceBitmap.Height - 1, mFindBoundingRectangleDefinition.SearchRecord, mFindBoundingRectangleDefinition.LastMarkerUsed);
                            EdgeSearch rightEdgeSearch  = new EdgeSearch(this, mColorMatchDefinition, Axis.Y, startX, +1 * stepSize, sourceBitmap.Width - 1, startY, 0, sourceBitmap.Height - 1, mFindBoundingRectangleDefinition.SearchRecord, mFindBoundingRectangleDefinition.LastMarkerUsed);
                            topEdgeSearch.minSideEdge    = leftEdgeSearch;
                            topEdgeSearch.maxSideEdge    = rightEdgeSearch;
                            bottomEdgeSearch.minSideEdge = leftEdgeSearch;
                            bottomEdgeSearch.maxSideEdge = rightEdgeSearch;
                            leftEdgeSearch.minSideEdge   = topEdgeSearch;
                            leftEdgeSearch.maxSideEdge   = bottomEdgeSearch;
                            rightEdgeSearch.minSideEdge  = topEdgeSearch;
                            rightEdgeSearch.maxSideEdge  = bottomEdgeSearch;

                            while (!(topEdgeSearch.Done() && bottomEdgeSearch.Done() && leftEdgeSearch.Done() && rightEdgeSearch.Done()))
                            {
                                if (!topEdgeSearch.Done())
                                {
                                    topEdgeSearch.TestLine();
                                }
                                if (!bottomEdgeSearch.Done())
                                {
                                    bottomEdgeSearch.TestLine();
                                }
                                if (!leftEdgeSearch.Done())
                                {
                                    leftEdgeSearch.TestLine();
                                }
                                if (!rightEdgeSearch.Done())
                                {
                                    rightEdgeSearch.TestLine();
                                }
                            }

                            if (detailedSearchAtEnd)
                            {
                                //topEdgeSearch.mStep
                            }

                            leftEdge   = leftEdgeSearch.lastPosWhereObjectSeen;
                            rightEdge  = rightEdgeSearch.lastPosWhereObjectSeen;
                            topEdge    = topEdgeSearch.lastPosWhereObjectSeen;
                            bottomEdge = bottomEdgeSearch.lastPosWhereObjectSeen;

                            /* TODO: rectangle decoration? force user to use ROI?
                             * mResultantRay.SetStartX(centerX);
                             * mResultantRay.SetStartY(centerY);
                             * mResultantRay.SetEndX((int)(centerX + outerRadius * Math.Cos(overallRad)));
                             * mResultantRay.SetEndY((int)(centerY + outerRadius * Math.Sin(overallRad)));
                             * mResultantRay.SetIsComplete();
                             */
                        }
                    } // end unsafe block
                }
                catch (Exception e)
                {
                    TestExecution().LogMessageWithTimeFromTrigger("ERROR: Failure in " + Name + "; msg=" + e.Message + " " + Environment.NewLine + e.StackTrace);
                }
                finally
                {
                    sourceBitmap.UnlockBits(sourceBitmapData);
                    if (markedBitmap != null)
                    {
                        markedBitmap.UnlockBits(markedBitmapData);
                    }
                }
            } // end main block ("else" after all initial setup error checks)
            mLeftBound.SetValue(leftEdge);
            mLeftBound.SetIsComplete();
            mRightBound.SetValue(rightEdge);
            mRightBound.SetIsComplete();
            mTopBound.SetValue(topEdge);
            mTopBound.SetIsComplete();
            mBottomBound.SetValue(bottomEdge);
            mBottomBound.SetIsComplete();
            DateTime doneTime    = DateTime.Now;
            TimeSpan computeTime = doneTime - startTime;

            TestExecution().LogMessageWithTimeFromTrigger(Name + " found bounding rectangle; left=" + leftEdge + " right=" + rightEdge + " top=" + topEdge + " bottom=" + bottomEdge);

            if (mAutoSave)
            {
                try
                {
                    string filePath = ((FindRadialLineDefinition)Definition()).AutoSavePath;
                    mSourceImage.Save(filePath, Name, true);
                    if (mImageToMark != null)
                    {
                        mImageToMark.Save(filePath, Name, "_marked_" + leftEdge + "_" + rightEdge + "_" + topEdge + "_" + bottomEdge);
                    }
                    TestExecution().LogMessageWithTimeFromTrigger("Snapshot saved");
                }
                catch (ArgumentException e)
                {
                    Project().Window().logMessage("ERROR: " + e.Message);
                    TestExecution().LogErrorWithTimeFromTrigger(e.Message);
                }
                catch (Exception e)
                {
                    Project().Window().logMessage("ERROR: Unable to AutoSave snapshot from " + Name + ".  Ensure path valid and disk not full.  Low-level message=" + e.Message);
                    TestExecution().LogErrorWithTimeFromTrigger("Unable to AutoSave snapshot from " + Name + ".  Ensure path valid and disk not full.");
                }
            }
            TestExecution().LogMessageWithTimeFromTrigger(Name + " finished at " + doneTime + "  | took " + computeTime.TotalMilliseconds + "ms");
        }
コード例 #7
0
        public override void DoWork()
        {
            DateTime startTime = DateTime.Now;

            TestExecution().LogMessageWithTimeFromTrigger("[" + Name + "] started at " + startTime + Environment.NewLine);

            long result = -1;

            try
            {
                if (mEnabled == null)
                {
                    TestExecution().LogErrorWithTimeFromTrigger("Enabled isn't defined in " + Name);
                }
                else if (mPrerequisite != null && !mPrerequisite.ValueAsBoolean())
                {
                    TestExecution().LogMessageWithTimeFromTrigger(Name + ": prerequisites not met. Skipping.");
                }
                else if (!mEnabled.ValueAsBoolean())
                {
                    TestExecution().LogMessageWithTimeFromTrigger(Name + " disabled. Skipped entry.");
                }
                else
                {
                    string[] messageComponents = mOperatorQueryDefinition.QueryMessage.Split(new char[] { '|' });
                    if (messageComponents.GetLength(0) != mOperatorQueryDefinition.mValuesToReference.Count + 1)
                    {
                        string msg = Name + " has a mismatch between the QueryMessage and ValuesToReference.  " + mOperatorQueryDefinition.mValuesToReference.Count + " values were provided, but " + messageComponents.GetLength(0) + " were expected.";
                        TestExecution().LogErrorWithTimeFromTrigger(msg);
                    }
                    else
                    {
                        string queryMessage = string.Empty;
                        for (int x = 0; x < mOperatorQueryDefinition.mValuesToReference.Count; x++)
                        {
                            queryMessage += messageComponents[x] + TestExecution().DataValueRegistry.GetObject(mOperatorQueryDefinition.mValuesToReference[x].Name).Value;
                        }
                        queryMessage += messageComponents[messageComponents.GetLength(0) - 1];

                        TestSequence().StopExecutionTimeoutTimer();
                        if (DialogResult.Yes == MessageBox.Show(queryMessage, "Operator Query", MessageBoxButtons.YesNo))
                        {
                            result = 1;
                        }
                        else
                        {
                            result = 0;
                        }
                    }
                }
            }
            catch (Exception e)
            {
                TestExecution().LogErrorWithTimeFromTrigger("Failure in " + Name + "; msg=" + e.Message + " " + Environment.NewLine + e.StackTrace);
            }
            finally
            {
                TestSequence().StartExecutionTimeoutTimer();
            }

            mOperatorAnswer.SetValue(result);
            mOperatorAnswer.SetIsComplete();
            DateTime doneTime    = DateTime.Now;
            TimeSpan computeTime = doneTime - startTime;

            TestExecution().LogMessageWithTimeFromTrigger(Name + " answer was " + result);

            TestExecution().LogMessageWithTimeFromTrigger(Name + " finished at " + doneTime + "  | took " + computeTime.TotalMilliseconds + "ms");
        }
コード例 #8
0
 public override bool ValueAsBoolean()
 {
     return(mDataValueHolder.ValueAsBoolean());
 }
コード例 #9
0
        public static readonly int PIXEL_BYTE_WIDTH     = 4; // determined by PixelFormat.Format32bppArgb; http://www.bobpowell.net/lockingbits.htm
        public override void DoWork()
        {
            DateTime startTime = DateTime.Now;

            TestExecution().LogMessageWithTimeFromTrigger("[" + Name + "] started at " + startTime + Environment.NewLine);

            int leftEdge   = -1;
            int rightEdge  = -1;
            int topEdge    = -1;
            int bottomEdge = -1;

            int    minObjectHeight            = -1;
            int    maxObjectHeight            = -1;
            int    minObjectWidth             = -1;
            int    maxObjectWidth             = -1;
            double allowedObjectSizeVariation = 0;

            if (mAllowedSizeVariation != null)
            {
                allowedObjectSizeVariation = mAllowedSizeVariation.ValueAsDecimal() / 100.0;
            }

            if (mExpectedObjectHeight != null)
            {
                minObjectHeight = (int)(mExpectedObjectHeight.ValueAsDecimal() * (1 - allowedObjectSizeVariation));
                maxObjectHeight = (int)(mExpectedObjectHeight.ValueAsDecimal() * (1 + allowedObjectSizeVariation));
            }
            if (mExpectedObjectWidth != null)
            {
                minObjectWidth = (int)(mExpectedObjectWidth.ValueAsDecimal() * (1 - allowedObjectSizeVariation));
                maxObjectWidth = (int)(mExpectedObjectWidth.ValueAsDecimal() * (1 + allowedObjectSizeVariation));
            }

            if (mMinObjectHeight != null)
            {
                minObjectHeight = (int)mMinObjectHeight.ValueAsLong();
            }
            if (mMinObjectWidth != null)
            {
                minObjectWidth = (int)mMinObjectWidth.ValueAsLong();
            }
            if (mMaxObjectHeight != null)
            {
                maxObjectHeight = (int)mMaxObjectHeight.ValueAsLong();
            }
            if (mMaxObjectWidth != null)
            {
                maxObjectWidth = (int)mMaxObjectWidth.ValueAsLong();
            }

            if (minObjectHeight < 0)
            {
                TestExecution().LogErrorWithTimeFromTrigger("A minimum height for the object hasn't been defined within '" + Name + "'.");
            }
            else if (maxObjectHeight < 0)
            {
                TestExecution().LogErrorWithTimeFromTrigger("A maximum height for the object hasn't been defined within '" + Name + "'.");
            }
            else if (minObjectWidth < 0)
            {
                TestExecution().LogErrorWithTimeFromTrigger("A minimum width for the object hasn't been defined within '" + Name + "'.");
            }
            else if (maxObjectWidth < 0)
            {
                TestExecution().LogErrorWithTimeFromTrigger("A maximum width for the object hasn't been defined within '" + Name + "'.");
            }
            else if (mPrerequisite != null && !mPrerequisite.ValueAsBoolean())
            {
                TestExecution().LogMessageWithTimeFromTrigger(Name + ": prerequisites not met.  Skipping.");
            }
            else if (mSourceImage.Bitmap == null)
            {
                TestExecution().LogErrorWithTimeFromTrigger("Source image for '" + Name + "' does not exist.");
            }
            else
            {
                int searchXStep = Math.Max(1, (int)(minObjectWidth * 0.3));
                int searchYStep = Math.Max(1, (int)(minObjectHeight * 0.3));
                int startX      = (int)mROI.Left + searchXStep;
                int startY      = (int)mROI.Top + searchYStep;

                if (startX < 0 || startX >= mSourceImage.Bitmap.Width || startY < 0 || startY >= mSourceImage.Bitmap.Height)
                {
                    TestExecution().LogErrorWithTimeFromTrigger("Start position for '" + Name + "' isn't within the image bounds; start=" + startX + "," + startY + "; image size=" + mSourceImage.Bitmap.Width + "x" + mSourceImage.Bitmap.Height);
                }
                else
                {
                    int  stepSize            = (int)mStepSize.ValueAsLong();
                    bool detailedSearchAtEnd = mDetailedSearch.ValueAsBoolean();

                    sourceBitmap = SourceImage.Bitmap;
                    if (mImageMarkingEnabled.ValueAsBoolean() && mImageToMark != null && mImageToMark.Bitmap != null)
                    {
                        markedBitmap = mImageToMark.Bitmap;
                    }

                    // TODO: replace LockBits implementation with array pointer

                    try
                    {
                        sourceBitmapData = sourceBitmap.LockBits(new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height), ImageLockMode.ReadOnly, PIXEL_FORMAT);
                        if (markedBitmap != null)
                        {
                            markedBitmapData = markedBitmap.LockBits(new Rectangle(0, 0, markedBitmap.Width, markedBitmap.Height), ImageLockMode.ReadWrite, PIXEL_FORMAT);
                        }
                        sourceStride       = sourceBitmapData.Stride;
                        sourceStrideOffset = sourceStride - (sourceBitmapData.Width * PIXEL_BYTE_WIDTH);

                        unsafe // see http://www.codeproject.com/csharp/quickgrayscale.asp?df=100&forumid=293759&select=2214623&msg=2214623
                        {
                            byte *sourcePointer;
                            byte *markedPointer;

                            if (mFindBlobOfSizeAndColorDefinition.SearchRecord.GetLength(0) < sourceBitmap.Width || mFindBlobOfSizeAndColorDefinition.SearchRecord.GetLength(1) < sourceBitmap.Height)
                            {
                                mFindBlobOfSizeAndColorDefinition.SearchRecord   = new short[sourceBitmap.Width, sourceBitmap.Height];
                                mFindBlobOfSizeAndColorDefinition.LastMarkerUsed = 0;
                            }
                            if (mFindBlobOfSizeAndColorDefinition.LastMarkerUsed == short.MaxValue)
                            {
                                short initialValue = short.MinValue + 1; // we don't use short.MinValue since that is a special case (see ClearSearchRecordArea(); before switching from int to short, we were initializing to 0 here and -1 in ClearSearchRecordArea())
                                for (int x = 0; x < mFindBlobOfSizeAndColorDefinition.SearchRecord.GetLength(0); x++)
                                {
                                    for (int y = 0; y < mFindBlobOfSizeAndColorDefinition.SearchRecord.GetLength(1); y++)
                                    {
                                        mFindBlobOfSizeAndColorDefinition.SearchRecord[x, y] = initialValue;
                                    }
                                }
                                mFindBlobOfSizeAndColorDefinition.LastMarkerUsed = 0;
                            }
                            mFindBlobOfSizeAndColorDefinition.LastMarkerUsed++;

                            for (int x = startX; x < ROI.Right && leftEdge < 0; x += searchXStep)
                            {
                                for (int y = startY; y < ROI.Bottom && leftEdge < 0; y += searchYStep)
                                {
                                    if (markedBitmap != null)
                                    {
                                        markedPointer    = (byte *)markedBitmapData.Scan0;              // init to first byte of image
                                        markedPointer   += (y * sourceStride) + (x * PIXEL_BYTE_WIDTH); // adjust to current point
                                        markedPointer[3] = Color.Lime.A;
                                        markedPointer[2] = Color.Lime.R;
                                        markedPointer[1] = Color.Lime.G;
                                        markedPointer[0] = Color.Lime.B;
                                    }

                                    bool failed = false;
                                    sourcePointer  = (byte *)sourceBitmapData.Scan0;              // init to first byte of image
                                    sourcePointer += (y * sourceStride) + (x * PIXEL_BYTE_WIDTH); // adjust to current point

                                    Color theColor = Color.FromArgb(sourcePointer[2], sourcePointer[1], sourcePointer[0]);
                                    if (mColorMatchDefinition.Matches(theColor))
                                    {
                                        TestExecution().LogMessageWithTimeFromTrigger(Name + ": found match at " + x + "," + y + "; beginning search of area");

                                        EdgeSearch topEdgeSearch    = new EdgeSearch(this, mColorMatchDefinition, Axis.X, y, -1 * stepSize, mROI.Top, x, mROI.Left, mROI.Right, mFindBlobOfSizeAndColorDefinition.SearchRecord, mFindBlobOfSizeAndColorDefinition.LastMarkerUsed);
                                        EdgeSearch bottomEdgeSearch = new EdgeSearch(this, mColorMatchDefinition, Axis.X, y, +1 * stepSize, mROI.Bottom, x, mROI.Left, mROI.Right, mFindBlobOfSizeAndColorDefinition.SearchRecord, mFindBlobOfSizeAndColorDefinition.LastMarkerUsed);
                                        EdgeSearch leftEdgeSearch   = new EdgeSearch(this, mColorMatchDefinition, Axis.Y, x, -1 * stepSize, mROI.Left, y, mROI.Top, mROI.Bottom, mFindBlobOfSizeAndColorDefinition.SearchRecord, mFindBlobOfSizeAndColorDefinition.LastMarkerUsed);
                                        EdgeSearch rightEdgeSearch  = new EdgeSearch(this, mColorMatchDefinition, Axis.Y, x, +1 * stepSize, mROI.Right, y, mROI.Top, mROI.Bottom, mFindBlobOfSizeAndColorDefinition.SearchRecord, mFindBlobOfSizeAndColorDefinition.LastMarkerUsed);
                                        topEdgeSearch.minSideEdge     = leftEdgeSearch;
                                        topEdgeSearch.maxSideEdge     = rightEdgeSearch;
                                        topEdgeSearch.opposingEdge    = bottomEdgeSearch;
                                        bottomEdgeSearch.minSideEdge  = leftEdgeSearch;
                                        bottomEdgeSearch.maxSideEdge  = rightEdgeSearch;
                                        bottomEdgeSearch.opposingEdge = topEdgeSearch;
                                        leftEdgeSearch.minSideEdge    = topEdgeSearch;
                                        leftEdgeSearch.maxSideEdge    = bottomEdgeSearch;
                                        leftEdgeSearch.opposingEdge   = rightEdgeSearch;
                                        rightEdgeSearch.minSideEdge   = topEdgeSearch;
                                        rightEdgeSearch.maxSideEdge   = bottomEdgeSearch;
                                        rightEdgeSearch.opposingEdge  = leftEdgeSearch;
                                        topEdgeSearch.maxSize         = maxObjectHeight;
                                        bottomEdgeSearch.maxSize      = maxObjectHeight;
                                        leftEdgeSearch.maxSize        = maxObjectWidth;
                                        rightEdgeSearch.maxSize       = maxObjectWidth;

                                        do
                                        {
                                            if (!topEdgeSearch.Done())
                                            {
                                                topEdgeSearch.TestLine();
                                            }
                                            if (!bottomEdgeSearch.Done())
                                            {
                                                bottomEdgeSearch.TestLine();
                                            }
                                            if (!leftEdgeSearch.Done())
                                            {
                                                leftEdgeSearch.TestLine();
                                            }
                                            if (!rightEdgeSearch.Done())
                                            {
                                                rightEdgeSearch.TestLine();
                                            }
                                            if (bottomEdgeSearch.lastPosWhereObjectSeen - topEdgeSearch.lastPosWhereObjectSeen > maxObjectHeight)
                                            {
                                                TestExecution().LogMessageWithTimeFromTrigger(Name + ": aborting area search because y-axis size exceeded; top=" + topEdgeSearch.lastPosWhereObjectSeen + " bottom=" + bottomEdgeSearch.lastPosWhereObjectSeen + " left=" + leftEdgeSearch.lastPosWhereObjectSeen + " right=" + rightEdgeSearch.lastPosWhereObjectSeen);
                                                failed = true;
                                                break;
                                            }
                                            if (rightEdgeSearch.lastPosWhereObjectSeen - leftEdgeSearch.lastPosWhereObjectSeen > maxObjectWidth)
                                            {
                                                TestExecution().LogMessageWithTimeFromTrigger(Name + ": aborting area search because x-axis size exceeded; top=" + topEdgeSearch.lastPosWhereObjectSeen + " bottom=" + bottomEdgeSearch.lastPosWhereObjectSeen + " left=" + leftEdgeSearch.lastPosWhereObjectSeen + " right=" + rightEdgeSearch.lastPosWhereObjectSeen);
                                                failed = true;
                                                break;
                                            }
                                            if (rightEdgeSearch.lastPosWhereObjectSeen == mROI.Right)
                                            {
                                                TestExecution().LogMessageWithTimeFromTrigger(Name + ": aborting area search because ran into right edge of ROI; top=" + topEdgeSearch.lastPosWhereObjectSeen + " bottom=" + bottomEdgeSearch.lastPosWhereObjectSeen + " left=" + leftEdgeSearch.lastPosWhereObjectSeen + " right=" + rightEdgeSearch.lastPosWhereObjectSeen);
                                                failed = true;
                                                break;
                                            }
                                            if (leftEdgeSearch.lastPosWhereObjectSeen == mROI.Left)
                                            {
                                                TestExecution().LogMessageWithTimeFromTrigger(Name + ": aborting area search because ran into left edge of ROI; top=" + topEdgeSearch.lastPosWhereObjectSeen + " bottom=" + bottomEdgeSearch.lastPosWhereObjectSeen + " left=" + leftEdgeSearch.lastPosWhereObjectSeen + " right=" + rightEdgeSearch.lastPosWhereObjectSeen);
                                                failed = true;
                                                break;
                                            }
                                            if (topEdgeSearch.lastPosWhereObjectSeen == mROI.Top)
                                            {
                                                TestExecution().LogMessageWithTimeFromTrigger(Name + ": aborting area search because ran into top edge of ROI; top=" + topEdgeSearch.lastPosWhereObjectSeen + " bottom=" + bottomEdgeSearch.lastPosWhereObjectSeen + " left=" + leftEdgeSearch.lastPosWhereObjectSeen + " right=" + rightEdgeSearch.lastPosWhereObjectSeen);
                                                failed = true;
                                                break;
                                            }
                                            if (bottomEdgeSearch.lastPosWhereObjectSeen == mROI.Bottom)
                                            {
                                                TestExecution().LogMessageWithTimeFromTrigger(Name + ": aborting area search because ran into bottom edge of ROI; top=" + topEdgeSearch.lastPosWhereObjectSeen + " bottom=" + bottomEdgeSearch.lastPosWhereObjectSeen + " left=" + leftEdgeSearch.lastPosWhereObjectSeen + " right=" + rightEdgeSearch.lastPosWhereObjectSeen);
                                                failed = true;
                                                break;
                                            }
                                        } while (!(topEdgeSearch.Done() && bottomEdgeSearch.Done() && leftEdgeSearch.Done() && rightEdgeSearch.Done()));

                                        if (detailedSearchAtEnd)
                                        {
                                            //topEdgeSearch.mStep
                                            //TODO: finish
                                            //TODO: recheck if object too big
                                        }

                                        if (leftEdgeSearch.abort || rightEdgeSearch.abort || topEdgeSearch.abort || bottomEdgeSearch.abort)
                                        {
                                            TestExecution().LogMessageWithTimeFromTrigger(Name + ": aborting area search because an edge search aborted (probably ran into an already searched pixel); top=" + topEdgeSearch.lastPosWhereObjectSeen + " bottom=" + bottomEdgeSearch.lastPosWhereObjectSeen + " left=" + leftEdgeSearch.lastPosWhereObjectSeen + " right=" + rightEdgeSearch.lastPosWhereObjectSeen);
                                            failed = true;
                                        }
                                        if (bottomEdgeSearch.lastPosWhereObjectSeen - topEdgeSearch.lastPosWhereObjectSeen < minObjectHeight)
                                        {
                                            TestExecution().LogMessageWithTimeFromTrigger(Name + ": excluding object since size too small on y-axis; top=" + topEdgeSearch.lastPosWhereObjectSeen + " bottom=" + bottomEdgeSearch.lastPosWhereObjectSeen + " left=" + leftEdgeSearch.lastPosWhereObjectSeen + " right=" + rightEdgeSearch.lastPosWhereObjectSeen);
                                            failed = true;

                                            // if the object/blob was too small, then if we re-check one of the pixels during a future search we don't want to abort on the assumption the object must be too big
                                            // ...this issue came up in Head Rest's Weld Orrient 9/18/08...in certain cases we would first find a small blob to the left of the weld, but would abort because it was too small...it's edges would be close to, but below the search color boundary.  Then we would find the main chunk of the light, which would wrap partially around the small blob (to the right and below)....during it's not-so-smart-but-fast search it would retest a pixel of the small blob and immediately abort...mistakenly assuming it bumped into a previous "too large" blob.
                                            // ...it could bump into a previous "too small" blob because of the way to search within the entire bounding rectangle...as a simplified method of catching "U" or "Z" shaped blobs (ie ones that double back)
                                            ClearSearchRecordArea(leftEdgeSearch.lastPosWhereObjectSeen, rightEdgeSearch.lastPosWhereObjectSeen, topEdgeSearch.lastPosWhereObjectSeen, bottomEdgeSearch.lastPosWhereObjectSeen);
                                        }
                                        else if (rightEdgeSearch.lastPosWhereObjectSeen - leftEdgeSearch.lastPosWhereObjectSeen < minObjectWidth)
                                        {
                                            TestExecution().LogMessageWithTimeFromTrigger(Name + ": excluding object since size too small on x-axis; top=" + topEdgeSearch.lastPosWhereObjectSeen + " bottom=" + bottomEdgeSearch.lastPosWhereObjectSeen + " left=" + leftEdgeSearch.lastPosWhereObjectSeen + " right=" + rightEdgeSearch.lastPosWhereObjectSeen);
                                            failed = true;

                                            // if the object/blob was too small, then if we re-check one of the pixels during a future search we don't want to abort on the assumption the object must be too big
                                            // ...this issue came up in Head Rest's Weld Orrient 9/18/08...in certain cases we would first find a small blob to the left of the weld, but would abort because it was too small...it's edges would be close to, but below the search color boundary.  Then we would find the main chunk of the light, which would wrap partially around the small blob (to the right and below)....during it's not-so-smart-but-fast search it would retest a pixel of the small blob and immediately abort...mistakenly assuming it bumped into a previous "too large" blob.
                                            // ...it could bump into a previous "too small" blob because of the way to search within the entire bounding rectangle...as a simplified method of catching "U" or "Z" shaped blobs (ie ones that double back)
                                            ClearSearchRecordArea(leftEdgeSearch.lastPosWhereObjectSeen, rightEdgeSearch.lastPosWhereObjectSeen, topEdgeSearch.lastPosWhereObjectSeen, bottomEdgeSearch.lastPosWhereObjectSeen);
                                        }
                                        if (!failed)
                                        {
                                            TestExecution().LogMessageWithTimeFromTrigger(Name + ": selected object bounded by: top=" + topEdgeSearch.lastPosWhereObjectSeen + " bottom=" + bottomEdgeSearch.lastPosWhereObjectSeen + " left=" + leftEdgeSearch.lastPosWhereObjectSeen + " right=" + rightEdgeSearch.lastPosWhereObjectSeen);
                                            leftEdge   = leftEdgeSearch.lastPosWhereObjectSeen;
                                            rightEdge  = rightEdgeSearch.lastPosWhereObjectSeen;
                                            topEdge    = topEdgeSearch.lastPosWhereObjectSeen;
                                            bottomEdge = bottomEdgeSearch.lastPosWhereObjectSeen;
                                        }
                                    }
                                }
                            }
                        } // end unsafe block
                    }
                    catch (Exception e)
                    {
                        TestExecution().LogMessageWithTimeFromTrigger("ERROR: Failure in " + Name + "; msg=" + e.Message + " " + Environment.NewLine + e.StackTrace);
                    }
                    finally
                    {
                        sourceBitmap.UnlockBits(sourceBitmapData);
                        if (markedBitmap != null)
                        {
                            markedBitmap.UnlockBits(markedBitmapData);
                        }
                    }
                }
            } // end main block ("else" after all initial setup error checks)
            mLeftBound.SetValue(leftEdge);
            mLeftBound.SetIsComplete();
            mRightBound.SetValue(rightEdge);
            mRightBound.SetIsComplete();
            mTopBound.SetValue(topEdge);
            mTopBound.SetIsComplete();
            mBottomBound.SetValue(bottomEdge);
            mBottomBound.SetIsComplete();
            DateTime doneTime    = DateTime.Now;
            TimeSpan computeTime = doneTime - startTime;

            if (leftEdge < 0)
            {
                TestExecution().LogMessageWithTimeFromTrigger(Name + " FAILED TO FIND BLOB");
            }

            if (mAutoSave)
            {
                try
                {
                    string filePath = ((FindRadialLineDefinition)Definition()).AutoSavePath;
                    mSourceImage.Save(filePath, Name, true);
                    if (mImageToMark != null)
                    {
                        mImageToMark.Save(filePath, Name, "_marked_" + leftEdge + "_" + rightEdge + "_" + topEdge + "_" + bottomEdge);
                    }
                    TestExecution().LogMessageWithTimeFromTrigger("Snapshot saved");
                }
                catch (ArgumentException e)
                {
                    Project().Window().logMessage("ERROR: " + e.Message);
                    TestExecution().LogErrorWithTimeFromTrigger(e.Message);
                }
                catch (Exception e)
                {
                    Project().Window().logMessage("ERROR: Unable to AutoSave snapshot from " + Name + ".  Ensure path valid and disk not full.  Low-level message=" + e.Message);
                    TestExecution().LogErrorWithTimeFromTrigger("Unable to AutoSave snapshot from " + Name + ".  Ensure path valid and disk not full.");
                }
            }
            TestExecution().LogMessageWithTimeFromTrigger(Name + " finished at " + doneTime + "  | took " + computeTime.TotalMilliseconds + "ms");
        }