public GeneralizedDistanceTransform2D( Range rangeX, Range rangeY, Size gridSize) { if (rangeX.Outside || rangeY.Outside) throw new ArgumentException("Outside ranges are not allowed."); this.RangeX = rangeX; this.RangeY = rangeY; this.GridSize = gridSize; this.values = new double[this.GridSize.Width, this.GridSize.Height]; this.bestIndices = new Tuple<int, int>[this.GridSize.Width, this.GridSize.Height]; this.timeStamps = new int[this.GridSize.Width, this.GridSize.Height]; this.transformsForFixedGridX = new GeneralizedDistanceTransform1D[this.GridSize.Width]; for (int x = 0; x < this.GridSize.Width; ++x) this.transformsForFixedGridX[x] = new GeneralizedDistanceTransform1D(rangeY, this.GridSize.Height); this.transformsForFixedGridY = new GeneralizedDistanceTransform1D[this.GridSize.Height]; this.usedTransformsForFixedGridY = new GeneralizedDistanceTransform1D[this.GridSize.Height]; for (int y = 0; y < this.GridSize.Height; ++y) transformsForFixedGridY[y] = new GeneralizedDistanceTransform1D(rangeX, this.GridSize.Width); this.infiniteTransformX = new GeneralizedDistanceTransform1D(rangeX, this.GridSize.Width); this.infiniteTransformX.Compute(1, x => 1e+20); }
public void TestRange5() { Range range1 = new Range(1, 2, true); Range range2 = new Range(1.1, 1.3, true); Assert.IsTrue(range1.IntersectsWith(range2)); Assert.IsTrue(range2.IntersectsWith(range1)); Assert.IsTrue(Double.IsPositiveInfinity(range1.Length)); Assert.IsTrue(Double.IsPositiveInfinity(range2.Length)); }
public void TestRange4() { const double eps = 1e-10; Range range1 = new Range(1, 2, true); Range range2 = new Range(1.1, 1.3, false); Assert.IsFalse(range1.IntersectsWith(range2)); Assert.IsFalse(range2.IntersectsWith(range1)); Assert.IsTrue(Double.IsPositiveInfinity(range1.Length)); Assert.AreEqual(range2.Length, 0.2, eps); }
public void TestRange6() { const double eps = 1e-10; Range range1 = new Range(1, 1); Range range2 = new Range(1, 2); Assert.IsTrue(range1.IntersectsWith(range2)); Assert.IsTrue(range2.IntersectsWith(range1)); Assert.AreEqual(range1.Length, 0, eps); Assert.AreEqual(range2.Length, 1, eps); }
public void TestRange2() { const double eps = 1e-10; Range range1 = new Range(1, 2); Range range2 = new Range(2.1, 2.5); Assert.IsFalse(range1.IntersectsWith(range2)); Assert.IsFalse(range2.IntersectsWith(range1)); Assert.AreEqual(range1.Length, 1, eps); Assert.AreEqual(range2.Length, 0.4, eps); }
public LengthAngleSpaceSeparator( Vector segmentStart, Vector segmentEnd, Vector point, double allowedLength, double allowedAngle, bool swapDirection) { if (allowedAngle < -Math.PI || allowedAngle > Math.PI) throw new ArgumentOutOfRangeException("allowedAngle", "Allowed angle should be in [-pi, pi] range."); if (allowedLength < 0) throw new ArgumentOutOfRangeException("allowedLength", "Allowed length should be positive."); if ((segmentStart - segmentEnd).LengthSquared < 1e-6) throw new ArgumentException("Given segment must have non-zero length!"); double distanceToSegmentSqr, alpha; point.DistanceToSegmentSquared(segmentStart, segmentEnd, out distanceToSegmentSqr, out alpha); Vector zeroAngleVec = segmentStart + (segmentEnd - segmentStart) * alpha - point; this.distanceSqr = zeroAngleVec.LengthSquared; if (this.distanceSqr < 1e-6) { this.singularMode = true; double angle = Vector.AngleBetween(Vector.UnitX, segmentEnd - segmentStart); double minAngle, maxAngle; if (angle < 0) { minAngle = angle; maxAngle = angle + Math.PI; } else { maxAngle = angle; minAngle = angle - Math.PI; } singularModeAngleRange = new Range(minAngle, maxAngle); if (!singularModeAngleRange.Contains(allowedAngle)) singularModeAngleRange = singularModeAngleRange.Invert(); } else { this.singularMode = false; this.angleOffset = -Vector.AngleBetween(Vector.UnitX, zeroAngleVec); double offsetedAllowedAngle = this.OffsetAngle(allowedAngle); if (offsetedAllowedAngle < -Math.PI * 0.5 || offsetedAllowedAngle > Math.PI * 0.5) throw new ArgumentOutOfRangeException("allowedAngle", "After translation to the coordinate system of the given segment, allowed angle must be in [-pi/2, pi/2] range."); this.sign = Math.Sign(this.SeparationValue(allowedLength, offsetedAllowedAngle)); } this.swapDirection = swapDirection; }
public bool IntersectsWith(Range other) { // Regular ranges if (!this.Outside && !other.Outside) { return this.Left >= other.Left && this.Left <= other.Right || other.Left >= this.Left && other.Left <= this.Right; } // Two inverted ranges always intersect if (this.Outside && other.Outside) return true; // Regular range intersects with inverted if it's not inside if (this.Outside) return other.Left <= this.Left || other.Right >= this.Right; return this.Left <= other.Left || this.Right >= other.Right; }
public GeneralizedDistanceTransform1D(Range range, int gridSize) { if (range.Outside) throw new ArgumentException("Outside ranges are not allowed.", "range"); this.Range = range; this.GridSize = gridSize; // Our grid covers all the evenly distributed points from min to max in a way that each point is the center of its cell this.GridStepSize = range.Length / (this.GridSize - 1); // Allocate all the necessary things this.envelope = new int[this.GridSize]; this.parabolaRange = new double[this.GridSize + 1]; this.functionValues = new double[this.GridSize]; this.values = new double[this.GridSize]; this.bestIndices = new int[this.GridSize]; this.timeStamps = new int[this.GridSize]; }
public void TestRange8() { Range range1 = new Range(1, 2); Range range2 = new Range(1, 2); Assert.IsTrue(range1.IntersectsWith(range2)); Assert.IsTrue(range2.IntersectsWith(range1)); }
public void AddFinitePenaltyRangeY(Range rangeY) { this.IsComputed = false; foreach (GeneralizedDistanceTransform1D transform in transformsForFixedGridX) transform.AddFinitePenaltyRange(rangeY); }
public void TestEdgeConstraintSplitsNonIntersection() { EdgeConstraints constraints = new EdgeConstraints(3, 5); List<EdgeConstraints> split = constraints.Split(); Assert.IsTrue(split.Count == 2); Range range1 = new Range(split[0].MinWidth, split[0].MaxWidth, false); Range range2 = new Range(split[1].MinWidth, split[1].MaxWidth, false); Assert.IsFalse(range1.IntersectsWith(range2)); }
public void AddInterestRangeX(Range rangeX) { this.IsComputed = false; foreach (GeneralizedDistanceTransform1D transform in transformsForFixedGridY) transform.AddInterestRange(rangeX); }
private static double CalculateSingleEdgeLowerBound( ShapeModel model, ShapeConstraints shapeConstraints, IList<ILengthAngleConstraints> lengthAngleConstraints) { // TODO: support models with multiple edges but without pairwise constraints Debug.Assert(model.Structure.Edges.Count == 1); Debug.Assert(lengthAngleConstraints.Count == 1); double result; // Calculate best possible edge width penalty EdgeConstraints edgeConstraints = shapeConstraints.EdgeConstraints[0]; ShapeEdgeParams edgeParams = model.GetEdgeParams(0); Range lengthBoundary = lengthAngleConstraints[0].LengthBoundary; Range scaledLengthRange = new Range(lengthBoundary.Left * edgeParams.WidthToEdgeLengthRatio, lengthBoundary.Right * edgeParams.WidthToEdgeLengthRatio); Range widthRange = new Range(edgeConstraints.MinWidth, edgeConstraints.MaxWidth); if (scaledLengthRange.IntersectsWith(widthRange)) result = 0; else { result = model.CalculateEdgeWidthEnergyTerm(0, widthRange.Right, lengthBoundary.Left); result = Math.Min(result, model.CalculateEdgeWidthEnergyTerm(0, widthRange.Left, lengthBoundary.Right)); } return result; }
private static void TestEdgeLimitsCommonImpl( VertexConstraints constraint1, VertexConstraints constraint2, out Range lengthRange, out Range angleRange) { BoxSetLengthAngleConstraints lengthAngleConstraints = BoxSetLengthAngleConstraints.FromVertexConstraints(constraint1, constraint2, 3, 0); GeneralizedDistanceTransform2D transform = new GeneralizedDistanceTransform2D( new Range(0, 35), new Range(-Math.PI * 2, Math.PI * 2), new Size(2000, 2000)); AllowedLengthAngleChecker allowedLengthAngleChecker = new AllowedLengthAngleChecker(constraint1, constraint2, transform, 1, 0); lengthRange = lengthAngleConstraints.LengthBoundary; angleRange = lengthAngleConstraints.AngleBoundary; const int insideCheckCount = 1000; for (int i = 0; i < insideCheckCount; ++i) { Vector edgePoint1 = constraint1.MinCoord + new Vector( Random.Double() * (constraint1.MaxCoord.X - constraint1.MinCoord.X), Random.Double() * (constraint1.MaxCoord.Y - constraint1.MinCoord.Y)); Vector edgePoint2 = constraint2.MinCoord + new Vector( Random.Double() * (constraint2.MaxCoord.X - constraint2.MinCoord.X), Random.Double() * (constraint2.MaxCoord.Y - constraint2.MinCoord.Y)); Vector vec = edgePoint2 - edgePoint1; double length = vec.Length; double angle = Vector.AngleBetween(Vector.UnitX, vec); const double tolerance = 1e-10; Assert.IsTrue(lengthAngleConstraints.InRange(length, tolerance, angle, tolerance)); Assert.IsTrue(lengthAngleConstraints.OverallRange.InRange(length, tolerance, angle, tolerance)); Assert.IsTrue(allowedLengthAngleChecker.IsAllowed(length, angle)); } const int outsideCheckCount = 1000; for (int i = 0; i < outsideCheckCount; ++i) { Vector edgePoint1 = constraint1.MinCoord + new Vector( (Random.Double() * 2 - 0.5) * (constraint1.MaxCoord.X - constraint1.MinCoord.X), (Random.Double() * 2 - 0.5) * (constraint1.MaxCoord.Y - constraint1.MinCoord.Y)); Vector edgePoint2 = constraint2.MinCoord + new Vector( (Random.Double() * 2 - 0.5) * (constraint2.MaxCoord.X - constraint2.MinCoord.X), (Random.Double() * 2 - 0.5) * (constraint2.MaxCoord.Y - constraint2.MinCoord.Y)); Vector vec = edgePoint2 - edgePoint1; double length = vec.Length; double angle = Vector.AngleBetween(Vector.UnitX, vec); // We've generated too long edge if (length > transform.RangeX.Right) continue; bool definitelyOutside = !lengthAngleConstraints.OverallRange.InRange(length, 1e-6, angle, 1e-6); Assert.IsTrue(!definitelyOutside || !allowedLengthAngleChecker.IsAllowed(length, angle)); Assert.IsTrue(!definitelyOutside || !lengthAngleConstraints.InRange(length, 1e-6, angle, 1e-6)); } }
private void AddRange(Range range, IList<Range> rangeCollection) { if (range.Outside) throw new ArgumentException("Outside ranges are not supported.", "range"); if (!this.Range.Contains(range.Left) || !this.Range.Contains(range.Right)) throw new ArgumentException("Given range is outside range of this distance tranform.", "range"); rangeCollection.Add(range); this.IsComputed = false; }
public void AddFinitePenaltyRange(Range range) { AddRange(range, this.finitePenaltyRanges); }
public void TestVertexConstraintSplitsNonIntersection() { VertexConstraints constraints = new VertexConstraints(new Vector(0, 0), new Vector(1, 1)); List<VertexConstraints> split = constraints.Split(); Assert.IsTrue(split.Count == 4); for (int i = 0; i < split.Count; ++i) { for (int j = i + 1; j < split.Count; ++j) { Range xRange1 = new Range(split[i].MinCoord.X, split[i].MaxCoord.X, false); Range yRange1 = new Range(split[i].MinCoord.Y, split[i].MaxCoord.Y, false); Range xRange2 = new Range(split[j].MinCoord.X, split[j].MaxCoord.X, false); Range yRange2 = new Range(split[j].MinCoord.Y, split[j].MaxCoord.Y, false); Assert.IsFalse(xRange1.IntersectsWith(xRange2) && yRange1.IntersectsWith(yRange2)); } } }
public static BoxLengthAngleConstraints FromVertexConstraints(VertexConstraints constraints1, VertexConstraints constraints2) { Range angleRange; Range xRange1 = new Range(constraints1.MinCoord.X, constraints1.MaxCoord.X); Range yRange1 = new Range(constraints1.MinCoord.Y, constraints1.MaxCoord.Y); Range xRange2 = new Range(constraints2.MinCoord.X, constraints2.MaxCoord.X); Range yRange2 = new Range(constraints2.MinCoord.Y, constraints2.MaxCoord.Y); bool xIntersection = xRange1.IntersectsWith(xRange2); bool yIntersection = yRange1.IntersectsWith(yRange2); double minLength = Double.PositiveInfinity, maxLength = 0; if (xIntersection && yIntersection) { // Special case: intersecting rectangles angleRange = new Range(-Math.PI, Math.PI); minLength = 0; } else { // Angle changes from PI to -PI when second constraint is to the left of the first one bool angleSignChanges = constraints1.MinCoord.X > constraints2.MaxCoord.X && yIntersection; double minAngle = angleSignChanges ? -Math.PI : Math.PI; double maxAngle = angleSignChanges ? Math.PI : -Math.PI; foreach (Vector point1 in constraints1.Corners) { foreach (Vector point2 in constraints2.Corners) { double angle = Vector.AngleBetween(new Vector(1, 0), point2 - point1); if (angleSignChanges) { if (angle < 0) minAngle = Math.Max(minAngle, angle); else maxAngle = Math.Min(maxAngle, angle); } else { minAngle = Math.Min(minAngle, angle); maxAngle = Math.Max(maxAngle, angle); } } } angleRange = new Range(minAngle, maxAngle, angleSignChanges); // One constraint is on top or on bottom of another if (xIntersection) { // 1 on top of 2 if (constraints1.MinCoord.Y > constraints2.MaxCoord.Y) minLength = Math.Min(minLength, constraints1.MinCoord.Y - constraints2.MaxCoord.Y); // 2 on top of 1 else minLength = Math.Min(minLength, constraints2.MinCoord.Y - constraints1.MaxCoord.Y); } else if (yIntersection) { // 1 to the left of 2 if (constraints1.MaxCoord.X < constraints2.MinCoord.X) minLength = Math.Min(minLength, constraints2.MinCoord.X - constraints1.MaxCoord.X); // 2 to the left of 1 else minLength = Math.Min(minLength, constraints1.MinCoord.X - constraints2.MaxCoord.X); } } foreach (Vector point1 in constraints1.Corners) { foreach (Vector point2 in constraints2.Corners) { double length = (point1 - point2).Length; minLength = Math.Min(minLength, length); maxLength = Math.Max(maxLength, length); } } Range lengthRange = new Range(minLength, maxLength); return new BoxLengthAngleConstraints(lengthRange, angleRange); }
private BoxLengthAngleConstraints(Range lengthBoundary, Range angleBoundary) { Debug.Assert(!lengthBoundary.Outside); this.LengthBoundary = lengthBoundary; this.AngleBoundary = angleBoundary; }
public void AddInterestRange(Range range) { AddRange(range, this.interestRanges); }