public FloatContour TransformContour(float[,] transform, bool disableNotificationEvents = false) { // Now that we have all the required coefficients, we'll transform // the points in the original Contour, and store them in a new one FloatContour dstContour = new FloatContour(); //***008OL if (disableNotificationEvents) { dstContour.DisableNotificationEvents(); } for (int i = 0; i < Length; i++) { float cx = this[i].X; float cy = this[i].Y; float x = transform[0, 0] * cx + transform[0, 1] * cy + transform[0, 2]; float y = transform[1, 0] * cx + transform[1, 1] * cy + transform[1, 2]; dstContour.AddPoint(x, y); } return(dstContour); }
/// <summary> /// This will do a specific mapping with p1 and desP1 as centers and will /// rotate, scale, and translate so that p1 and p2 are on top of desP1 and desP2, /// respectively. Note: The precision on this isn't great -- would probably be better /// to do the linear equation solving to find a transformation matrix similar to the /// regular MapContour method. /// </summary> /// <param name="p1"></param> /// <param name="p2"></param> /// <param name="desP1"></param> /// <param name="desP2"></param> /// <returns></returns> public FloatContour MapContour2D( PointF p1, PointF p2, PointF desP1, PointF desP2) { float currentAngle = p1.FindAngle(p2); float desiredAngle = desP1.FindAngle(desP2); float degreesToRotate = desiredAngle - currentAngle; FloatContour transformedContour = this.Rotate(p1, degreesToRotate); var p2rotated = p2.Rotate(p1, degreesToRotate); // Figure out the scaling ratio double currentDistance = MathHelper.GetDistance(p1.X, p1.Y, p2.X, p2.Y); double targetDistance = MathHelper.GetDistance(desP1.X, desP1.Y, desP2.X, desP2.Y); double scaleRatio = targetDistance / currentDistance; // So we've rotated the contour, let's translate it so that p1 is on top of desP1 // and scale them at the same time. double xDiff = desP1.X - p1.X * scaleRatio; double yDiff = desP1.Y - p1.Y * scaleRatio; foreach (var p in transformedContour.Points) { p.X = (float)((p.X + xDiff) * scaleRatio); p.Y = (float)((p.Y + yDiff) * scaleRatio); } return(transformedContour); }
public FloatContour TrimBeginningToDistanceFromPoint(double distance, PointF referencePoint, out int numPointsTrimmed, bool disableEvents = false) { FloatContour result = new FloatContour(); result.Points = new ObservableNotifiableCollection <PointF>(); if (disableEvents) { result.DisableNotificationEvents(); } bool foundBeginning = false; numPointsTrimmed = 0; foreach (var p in this.Points) { if (!foundBeginning && MathHelper.GetDistance(p.X, p.Y, referencePoint.X, referencePoint.Y) < distance) { foundBeginning = true; } if (foundBeginning) { result.Points.Add(p); } else { numPointsTrimmed += 1; } } return(result); }
public FloatContour Rotate(PointF centerPoint, float degreesToRotate) { FloatContour result = new FloatContour(); result.Points = new ObservableNotifiableCollection <PointF>(); foreach (var p in this.Points) { result.Points.Add(p.Rotate(centerPoint, degreesToRotate)); } return(result); }
//******************************************************************** // FloatContour() // public FloatContour(FloatContour contour) //***006FC new { if (contour == null) { throw new ArgumentNullException(nameof(contour)); } _points = new ObservableNotifiableCollection <PointF>(); foreach (var p in contour.Points) { _points.Add(new PointF(p.X, p.Y, p.Z)); } }
public FloatContour TransformTrimBeginningToDistanceFromPoint(float[,] transform, double distance, PointF referencePoint, out int numPointsTrimmed, bool disableEvents = false) { FloatContour result = new FloatContour(); if (disableEvents) { result.DisableNotificationEvents(); } result.Points = new ObservableNotifiableCollection <PointF>(); bool foundBeginning = false; numPointsTrimmed = 0; foreach (var p in this.Points) { float newX = transform[0, 0] * p.X + transform[0, 1] * p.Y + transform[0, 2]; float newY = transform[1, 0] * p.X + transform[1, 1] * p.Y + transform[1, 2]; if (!foundBeginning && MathHelper.GetDistance(newX, newY, referencePoint.X, referencePoint.Y) < distance) { foundBeginning = true; } if (foundBeginning) { result.Points.Add(new PointF(newX, newY)); } else { numPointsTrimmed += 1; } } return(result); }
//******************************************************************* // // Chain::Chain(FloatContour *fc) //***008OL entire function added // // Used when FloatContour is read from DB file. // // Open Question: Should updateRelativeChain() be used here? // // PRE: fc is normalized and evenly spaced // POST: Chain indices correspond to fc indices // public Chain(FloatContour fc) { if (fc == null) { throw new ArgumentNullException(nameof(fc)); } _numPoints = fc.Length; List <double> chain = new List <double>(); List <double> relativeChain = new List <double>(); // NOTE: the Chain angle at each pooint is ALWAYS the angle of // the INCOMING edge FROM the previous contour point - JHS if (_numPoints > 1) { // initial angle of chain is angle of first point relative to (0,0) //chain.push_back(rtod(atan2((*fc)[0].y, (*fc)[0].x))); //***2.1mt //***2.01 - now just duplicate the first relative angle chain.Add(MathHelper.RadiansToDegrees(Math.Atan2(fc[1].Y - fc[0].Y, fc[1].X - fc[0].X))); //***2.01 chain.Add(MathHelper.RadiansToDegrees(Math.Atan2(fc[1].Y - fc[0].Y, fc[1].X - fc[0].X))); double lastAngle = chain[1]; //***2.1mt - use this to prevent any quadrant discontinuity // initial angle in relativeChain is angle change across point[0] //***1.2 - I think initial angle is meaningless and the // initial meaningful angle is actually angle change across point[1] relativeChain.Add(0.0); //***1.2 - added this // without line above the relative chain length & indexing are off by one relativeChain.Add(chain[0] - chain[1]); for (int i = 2; i < _numPoints; i++) { double angle = MathHelper.RadiansToDegrees(Math.Atan2(fc[i].Y - fc[i - 1].Y, fc[i].X - fc[i - 1].X)); //***2.01 //***2.01 - prevent ANY discontinuity of greater than 180 degrees if (angle - lastAngle > 180.0) { chain.Add(angle - 360.0); } else if (angle - lastAngle < -180.0) { chain.Add(angle + 360.0); } else { chain.Add(angle); } lastAngle = chain[i]; //***2.01 - end //////////////////////////// begin old /////////////////////// relativeChain.Add(chain[i - 1] - chain[i]); //////////////////////// end old /////////////////////////// } } // NOTE: there is NO useful change in angle across either // the first point or the last point in fc // now copy vectors to double arrays _chain = chain.ToArray(); _relativeChain = relativeChain.ToArray(); }
public static void FitContoursToSize(double drawingWidth, double drawingHeight, FloatContour unknownContour, FloatContour dbContour, out Contour displayUnknownContour, out Contour displayDBContour, out double xOffset, out double yOffset) { if (unknownContour == null && dbContour == null) { throw new ArgumentNullException("Both contours null!"); } float xMax, yMax, xMin, yMin; if (unknownContour == null) { xMax = dbContour.MaxX(); yMax = dbContour.MaxY(); xMin = dbContour.MinX(); yMin = dbContour.MinY(); } else if (dbContour == null) { xMax = unknownContour.MaxX(); yMax = unknownContour.MaxY(); xMin = unknownContour.MinX(); yMin = unknownContour.MinY(); } else { xMax = (dbContour.MaxX() > (float)unknownContour.MaxX()) ? dbContour.MaxX() : (float)unknownContour.MaxX(); yMax = (dbContour.MaxY() > (float)unknownContour.MaxY()) ? dbContour.MaxY() : (float)unknownContour.MaxY(); xMin = (dbContour.MinX() < (float)unknownContour.MinX()) ? dbContour.MinX() : (float)unknownContour.MinX(); yMin = (dbContour.MinY() < (float)unknownContour.MinY()) ? dbContour.MinY() : (float)unknownContour.MinY(); } float xRange = xMax - xMin + 8, //***1.5 - added POINT_SIZE yRange = yMax - yMin + 8; //***1.5 - added POINT_SIZE float heightRatio = (float)(drawingWidth / yRange), widthRatio = (float)(drawingHeight / xRange); float ratio; if (heightRatio < widthRatio) { ratio = heightRatio; xOffset = (drawingWidth - ratio * xRange) / 2 - xMin * ratio; yOffset = 0 - yMin * ratio; } else { ratio = widthRatio; xOffset = 0 - xMin * ratio; yOffset = (drawingHeight - ratio * yRange) / 2 - yMin * ratio; } float ratioInverse = 1 / ratio; if (unknownContour == null) { displayUnknownContour = null; } else { displayUnknownContour = new Contour(unknownContour, ratioInverse); } if (dbContour == null) { displayDBContour = null; } else { displayDBContour = new Contour(dbContour, ratioInverse); } }
//******************************************************************** // evenlySpaceContourPoints() // public FloatContour EvenlySpaceContourPoints(int space) { if (space <= 0) { return(null); } float x, y, ccx, ccy, tx, ty, vx, vy, vsx, vsy; int i; double a, b, c, sqrt_b2_4ac, t1, t2, t, tLen; ccx = Points[0].X; ccy = Points[0].Y; i = 0; bool done = false; FloatContour newContour = new FloatContour(); while (!done) { // Contour length >= 2 vsx = Points[i].X; vsy = Points[i].Y; x = Points[i + 1].X; y = Points[i + 1].Y; vx = x - vsx; vy = y - vsy; tx = x - ccx; ty = y - ccy; tLen = Math.Sqrt(tx * tx + ty * ty); if (tLen > space) { // then evaluate intersection tx = vsx - ccx; ty = vsy - ccy; a = vx * vx + vy * vy; b = 2 * (vx * tx + vy * ty); // 2 * dot(v, t) c = tx * tx + ty * ty - space * space; sqrt_b2_4ac = Math.Sqrt(b * b - 4 * a * c); if (sqrt_b2_4ac < 0.0) // should never happen - JHS { Trace.WriteLine("Neg Rad in FloatContour::evenlySpaceContourPoints()\n"); } t1 = (-b + sqrt_b2_4ac) / (2 * a); t2 = (-b - sqrt_b2_4ac) / (2 * a); if ((t1 >= 0) && (t1 <= 1)) { t = t1; } else if ((t2 >= 0) && (t2 <= 1)) { t = t2; } else { t = 0; } // update circle ctr for next go ccx = (float)(vsx + t * vx); ccy = (float)(vsy + t * vy); newContour.AddPoint(ccx, ccy); } else { i++; } if (i >= Length - 1) { done = true; } } return(newContour); }