public void TestAngleAbsDifference() { const double eps = 1e-10; Assert.AreEqual(0, MathHelper.AngleAbsDifference(0, 0), eps); Assert.AreEqual(0, MathHelper.AngleAbsDifference(Math.PI, -Math.PI), eps); Assert.AreEqual(Math.PI * 0.5, MathHelper.AngleAbsDifference(Math.PI * 0.75, Math.PI * 0.25), eps); Assert.AreEqual(Math.PI * 0.5, MathHelper.AngleAbsDifference(-Math.PI * 0.75, -Math.PI * 0.25), eps); Assert.AreEqual(Math.PI * 0.5, MathHelper.AngleAbsDifference(Math.PI * 0.75, -Math.PI * 0.75), eps); Assert.AreEqual(Math.PI * 0.5, MathHelper.AngleAbsDifference(-Math.PI * 0.75, Math.PI * 0.75), eps); }
public double CalculateEdgePairAngleEnergyTerm(int edgeIndex1, int edgeIndex2, Vector edge1Vector, Vector edge2Vector) { Tuple <int, int> pair = new Tuple <int, int>(edgeIndex1, edgeIndex2); ShapeEdgePairParams pairParams; if (!this.edgePairParams.TryGetValue(pair, out pairParams)) { throw new ArgumentException("Given edge pair has no common pairwise constraints."); } double angle = Vector.AngleBetween(edge1Vector, edge2Vector); double angleDiff = MathHelper.AngleAbsDifference(angle, pairParams.MeanAngle); double angleTerm = angleDiff * angleDiff / (2 * pairParams.AngleDeviation * pairParams.AngleDeviation); return(angleTerm); }
public static ShapeModel Learn(IEnumerable <Shape> shapes, IEnumerable <Tuple <int, int> > constrainedEdgePairs) { if (shapes == null) { throw new ArgumentNullException("shapes"); } if (constrainedEdgePairs == null) { throw new ArgumentNullException("constrainedEdgePairs"); } int shapeCount = shapes.Count(); if (shapeCount <= 1) { throw new ArgumentException("Can't learn from less than two shapes.", "shapes"); } ShapeStructure structure = shapes.First().Structure; if (!shapes.All(s => s.Structure == structure)) { throw new ArgumentException("All the shapes should have the same structure.", "shapes"); } // Learn root edge double rootEdgeLengthDeviation = Double.PositiveInfinity; double rootEdgeMeanLength = 0; int rootEdgeIndex = -1; for (int i = 0; i < structure.Edges.Count; ++i) { double lengthSum = 0, lengthSumSqr = 0; foreach (Shape shape in shapes) { double edgeLength = shape.GetEdgeVector(i).Length; lengthSum += edgeLength; lengthSumSqr += edgeLength * edgeLength; } double meanLength = lengthSumSqr / lengthSum; double lengthRatioDiffSqrSum = 0; foreach (Shape shape in shapes) { double edgeLength = shape.GetEdgeVector(i).Length; double lengthRatioDiff = edgeLength / meanLength - 1; lengthRatioDiffSqrSum += lengthRatioDiff * lengthRatioDiff; } double lengthDeviation = Math.Sqrt(lengthRatioDiffSqrSum / shapeCount); if (rootEdgeIndex == -1 || lengthDeviation < rootEdgeLengthDeviation) { rootEdgeLengthDeviation = lengthDeviation; rootEdgeMeanLength = meanLength; rootEdgeIndex = i; } } // Learn edge params List <ShapeEdgeParams> shapeEdgeParams = new List <ShapeEdgeParams>(); for (int i = 0; i < structure.Edges.Count; ++i) { double sum = 0, sumSqr = 0; foreach (Shape shape in shapes) { double edgeLength = shape.GetEdgeVector(i).Length; double ratio = shape.EdgeWidths[i] / edgeLength; sum += ratio; sumSqr += ratio * ratio; } double meanWidthToLengthRatio = sum / shapeCount; double widthToLengthRatioDeviation = Math.Sqrt(sumSqr / shapeCount - meanWidthToLengthRatio * meanWidthToLengthRatio); shapeEdgeParams.Add(new ShapeEdgeParams(meanWidthToLengthRatio, widthToLengthRatioDeviation)); } // Learn edge pair params Dictionary <Tuple <int, int>, ShapeEdgePairParams> shapeEdgePairParams = new Dictionary <Tuple <int, int>, ShapeEdgePairParams>(); foreach (Tuple <int, int> edgePair in constrainedEdgePairs) { if (edgePair.Item1 < 0 || edgePair.Item1 >= structure.Edges.Count || edgePair.Item2 < 0 || edgePair.Item2 >= structure.Edges.Count) { throw new ArgumentOutOfRangeException("constrainedEdgePairs", "Set of constrained edge pairs contains invalid edge index."); } ShapeEdge edge1 = structure.Edges[edgePair.Item1]; ShapeEdge edge2 = structure.Edges[edgePair.Item2]; if (edge1.Index1 != edge2.Index1 && edge1.Index2 != edge2.Index1 && edge1.Index1 != edge2.Index2 && edge1.Index2 != edge2.Index2) { throw new ArgumentException("Constrained edge pairs should be connected.", "constrainedEdgePairs"); } // Learn means double lengthProdSum = 0, lengthSqrSum = 0; double meanAngle = 0; int shapesConsidered = 0; foreach (Shape shape in shapes) { ++shapesConsidered; Vector edge1Vec = shape.GetEdgeVector(edgePair.Item1); Vector edge2Vec = shape.GetEdgeVector(edgePair.Item2); double length1 = edge1Vec.Length; double length2 = edge2Vec.Length; lengthProdSum += length1 * length2; lengthSqrSum += length2 * length2; double angle = Vector.AngleBetween(edge1Vec, edge2Vec); meanAngle = MathHelper.InterpolateAngle(meanAngle, angle, 1.0 / shapesConsidered); } double meanLengthRatio = lengthProdSum / lengthSqrSum; // Learn deviations double angleAbsDiffSqrSum = 0; double lengthDiffSqrSum = 0; foreach (Shape shape in shapes) { Vector edge1Vec = shape.GetEdgeVector(edgePair.Item1); Vector edge2Vec = shape.GetEdgeVector(edgePair.Item2); double length1 = edge1Vec.Length; double length2 = edge2Vec.Length; double lengthDiff = length1 - meanLengthRatio * length2; lengthDiffSqrSum += lengthDiff * lengthDiff; double angle = Vector.AngleBetween(edge1Vec, edge2Vec); double angleDiff = MathHelper.AngleAbsDifference(meanAngle, angle); angleAbsDiffSqrSum += angleDiff * angleDiff; } double lengthDiffDeviation = Math.Sqrt(lengthDiffSqrSum / shapeCount); double angleDeviation = Math.Sqrt(angleAbsDiffSqrSum / shapeCount); if (shapeEdgePairParams.ContainsKey(edgePair) || shapeEdgePairParams.ContainsKey(new Tuple <int, int>(edgePair.Item2, edgePair.Item1))) { throw new ArgumentException("Same pair of edges is constrained more than once.", "constrainedEdgePairs"); } shapeEdgePairParams.Add(edgePair, new ShapeEdgePairParams(meanAngle, meanLengthRatio, angleDeviation, lengthDiffDeviation)); } return(new ShapeModel(structure, shapeEdgeParams, shapeEdgePairParams, rootEdgeIndex, rootEdgeMeanLength, rootEdgeLengthDeviation)); }