public bool MinimumTranslationVectorWithContainment(Vector2[] vertices1, Vector2[] vertices2, out MinimumTranslationVector?mtv) { double overlap = Double.PositiveInfinity; Vector2 smallest = default(Vector2); Vector2[] axes1 = GetAxes(vertices1); Vector2[] axes2 = GetAxes(vertices2); bool MTVWC(Vector2[] axes) { for (int i = 0; i < axes.Length; i++) { Vector2 axis = axes[i]; Projection p1 = Project(vertices1, axis); Projection p2 = Project(vertices2, axis); if (!p1.Overlap(p2)) { return(false); } else { double o = p1.GetOverlap(p2); if (p1.Contains(p2) || p2.Contains(p1)) { double mins = Math.Abs(p1.Min - p2.Min); double maxs = Math.Abs(p1.Max - p2.Max); o += mins < maxs ? mins : maxs; } if (o < overlap) { overlap = o; smallest = axis; } } } return(true); } if (MTVWC(axes1) == false) { mtv = default(MinimumTranslationVector?); return(false); } if (MTVWC(axes2) == false) { mtv = default(MinimumTranslationVector?); return(false); } mtv = new MinimumTranslationVector(smallest, overlap); return(true); }
private XYNode HorizontalCut(XYLeaf leaf, double minimumWidth, Func <IEnumerable <Letter>, double> dominantFontWidthFunc, Func <IEnumerable <Letter>, double> dominantFontHeightFunc, int level = 0) { // Order words bottom to top var words = leaf.Words.OrderBy(w => w.BoundingBox.Normalise().Bottom).ToArray(); if (words.Length == 0) { return(new XYNode(null)); } // Create new leaf with non-whitespace words. leaf = new XYLeaf(words); if (leaf.CountWords() <= 1) { // We stop cutting if // - only one word remains return(leaf); } // Determine dominant font height double dominantFontHeight = dominantFontHeightFunc(words.SelectMany(x => x.Letters)); List <Projection> projectionProfile = new List <Projection>(); var firstWordBound = words[0].BoundingBox.Normalise(); Projection currentProjection = new Projection(firstWordBound.Bottom, firstWordBound.Top); int wordsCount = words.Length; for (int i = 1; i < wordsCount; i++) { var currentWordBound = words[i].BoundingBox.Normalise(); if (currentProjection.Contains(currentWordBound.Bottom) || currentProjection.Contains(currentWordBound.Top)) { // It is overlapping if (currentWordBound.Bottom >= currentProjection.LowerBound && currentWordBound.Bottom <= currentProjection.UpperBound && currentWordBound.Top > currentProjection.UpperBound) { currentProjection.UpperBound = currentWordBound.Top; } } else { // No overlap if (currentWordBound.Bottom - currentProjection.UpperBound <= dominantFontHeight) { // If gap too small -> don't cut // |____| |____| currentProjection.UpperBound = currentWordBound.Top; } else { // If gap big enough -> cut! // |____| | |____| if (i != wordsCount - 1) // Will always add the last one after { projectionProfile.Add(currentProjection); currentProjection = new Projection(currentWordBound.Bottom, currentWordBound.Top); } } } if (i == wordsCount - 1) { projectionProfile.Add(currentProjection); } } if (projectionProfile.Count == 1) { if (level >= 1) { return(leaf); } else { level++; } } var newLeavesEnums = projectionProfile.Select(p => leaf.Words.Where(w => { // Get words that are contained in each projection profiles var normalisedBB = w.BoundingBox.Normalise(); return(normalisedBB.Bottom >= p.LowerBound && normalisedBB.Top <= p.UpperBound); })); var newLeaves = newLeavesEnums.Where(e => e.Any()).Select(e => new XYLeaf(e)); var newNodes = newLeaves.Select(l => VerticalCut(l, minimumWidth, dominantFontWidthFunc, dominantFontHeightFunc, level)).ToList(); var lost = leaf.Words.Except(newLeavesEnums.SelectMany(x => x)).Where(x => !string.IsNullOrWhiteSpace(x.Text)).ToList(); if (lost.Count > 0) { newNodes.AddRange(lost.Select(w => new XYLeaf(w))); } return(new XYNode(newNodes)); }
public void Run(TestConfig config) { int i; IDatabase db = config.GetDatabase(); config.Result = new TestResult(); Root root = new Root(); var arr = db.CreateArray<FromRec>(45); root.arr = arr; db.Root = root; db.Commit(); int projectedEls = 45; for (i = 0; i < projectedEls; i++) { arr.Add(new FromRec(db, i)); } arr[0].toEl = null; db.Commit(); var p1 = new Projection<FromRec, ToRec>("list"); Tests.Assert(p1.Count == 0); Tests.Assert(p1.Length == 0); Tests.Assert(!p1.IsReadOnly); Tests.Assert(!p1.IsSynchronized); Tests.Assert(null == p1.SyncRoot); p1.Project(arr); Tests.Assert(p1.Count == projectedEls * 5); var arrTmp = p1.ToArray(); Tests.Assert(arrTmp.Length == p1.Length); p1.Reset(); p1.Project(arr[0]); Tests.Assert(p1.Length == 5); p1.Reset(); var arr3 = arr.ToArray(); p1.Project(arr3); Tests.Assert(p1.Length == projectedEls * 5); p1.Clear(); IEnumerator<FromRec> e1 = arr.GetEnumerator(); p1.Project(e1); Tests.Assert(p1.Length == projectedEls * 5); var p2 = new Projection<FromRec, ToRec>("list2"); p2.Project(arr); Tests.Assert(p2.Length == projectedEls * 5); var p3 = new Projection<FromRec, ToRec>("toEl"); p3.Project(arr); Tests.Assert(p2.Length == projectedEls * 5); p1.Join<FromRec>(p2); Tests.Assert(p1.GetEnumerator() != null); IEnumerator eTmp = ((IEnumerable)p1).GetEnumerator(); Tests.Assert(eTmp != null); ToRec[] res = new ToRec[p3.Count]; p3.CopyTo(res, 0); foreach (var tmp in res) { Tests.Assert(p3.Contains(tmp)); p3.Remove(tmp); Tests.Assert(!p3.Contains(tmp)); } Tests.Assert(0 == p3.Length); db.Commit(); db.Close(); }
private XYNode VerticalCut(XYLeaf leaf, double minimumWidth, Func <IEnumerable <Letter>, double> dominantFontWidthFunc, Func <IEnumerable <Letter>, double> dominantFontHeightFunc, int level = 0) { // Order words left to right var words = leaf.Words.OrderBy(w => w.BoundingBox.Normalise().Left).ToArray(); if (words.Length == 0) { return(new XYNode(null)); } // Create new leaf with non-whitespace words. leaf = new XYLeaf(words); if (leaf.CountWords() <= 1 || leaf.BoundingBox.Width <= minimumWidth) { // We stop cutting if // - only one word remains // - width is too small return(leaf); } // Determine dominant font width double dominantFontWidth = dominantFontWidthFunc(words.SelectMany(x => x.Letters)); List <Projection> projectionProfile = new List <Projection>(); var firstWordBound = words[0].BoundingBox.Normalise(); Projection currentProjection = new Projection(firstWordBound.Left, firstWordBound.Right); int wordsCount = words.Length; for (int i = 1; i < wordsCount; i++) { var currentWordBound = words[i].BoundingBox.Normalise(); if (currentProjection.Contains(currentWordBound.Left) || currentProjection.Contains(currentWordBound.Right)) { // It is overlapping if (currentWordBound.Left >= currentProjection.LowerBound && currentWordBound.Left <= currentProjection.UpperBound && currentWordBound.Right > currentProjection.UpperBound) { // |____| // |____| // |_______| <- updated currentProjection.UpperBound = currentWordBound.Right; } // We ignore the following cases: // |____| // |____| (not possible because of OrderBy) // // |____| //|___________| (not possible because of OrderBy) // // |____| // |_| } else { // No overlap if (currentWordBound.Left - currentProjection.UpperBound <= dominantFontWidth) { // If gap too small -> don't cut // |____| |____| currentProjection.UpperBound = currentWordBound.Right; } else if (currentProjection.UpperBound - currentProjection.LowerBound < minimumWidth) { // Still too small currentProjection.UpperBound = currentWordBound.Right; } else { // If gap big enough -> cut! // |____| | |____| if (i != wordsCount - 1) // Will always add the last one after { projectionProfile.Add(currentProjection); currentProjection = new Projection(currentWordBound.Left, currentWordBound.Right); } } } if (i == wordsCount - 1) { projectionProfile.Add(currentProjection); } } var newLeavesEnums = projectionProfile.Select(p => leaf.Words.Where(w => { // Get words that are contained in each projection profiles var normalisedBB = w.BoundingBox.Normalise(); return(normalisedBB.Left >= p.LowerBound && normalisedBB.Right <= p.UpperBound); })); var newLeaves = newLeavesEnums.Where(e => e.Any()).Select(e => new XYLeaf(e)); var newNodes = newLeaves.Select(l => HorizontalCut(l, minimumWidth, dominantFontWidthFunc, dominantFontHeightFunc, level)).ToList(); var lost = leaf.Words.Except(newLeavesEnums.SelectMany(x => x)).Where(x => !string.IsNullOrWhiteSpace(x.Text)).ToList(); if (lost.Count > 0) { newNodes.AddRange(lost.Select(w => new XYLeaf(w))); } return(new XYNode(newNodes)); }