public CrossPoint(bool existTopLine, bool existLeftLine, int index, int rowIndex, int columnIndex, int x, int y, CellLine horizontal, CellLine vertical) { ExistTopLine = existTopLine; ExistLeftLine = existLeftLine; Index = index; RowIndex = rowIndex; ColumnIndex = columnIndex; X = x; Y = y; Horizontal = horizontal; Vertical = vertical; }
static CellLines GetVerticalAllInBox(CellLine top, CellLine bottom, CellLine left, CellLine right, CellLines verticals, int lineDistance, ref Dictionary <int, int> duplicateDic) { CellLines verticalsAll = new CellLines(); foreach (CellLine line in verticals) { if (!duplicateDic.ContainsKey(line.Index) && line.StartX >= left.StartX && line.EndX <= right.EndX && line.StartY >= top.StartY - lineDistance && line.EndY <= bottom.StartY + lineDistance) { verticalsAll.Add(line); } } return(verticalsAll); }
static bool ExistBottomLine(int topIndex, CellLine verticalLeft, CellLine verticalRight, CellLines horizontals, int lineDistance, ref Dictionary <int, int> duplicateDic, out CellLine bottom) { bottom = new CellLine(); foreach (CellLine horizontal in horizontals) { if (!duplicateDic.ContainsKey(horizontal.Index) && horizontal.Index != topIndex) { // 두 수직선과 끝점이 만나야 함 if (Math.Abs(horizontal.StartX - verticalLeft.StartX) <= lineDistance && Math.Abs(horizontal.EndX - verticalRight.EndX) <= lineDistance && Math.Abs(horizontal.StartY - verticalLeft.EndY) <= lineDistance && Math.Abs(horizontal.EndY - verticalRight.EndY) <= lineDistance) { bottom = horizontal; return(true); } } } return(false); }
static void RemoveNoiseLine(CellLine top, CellLine bottom, CellLine left, CellLine right, CellLines innerHorizontals, CellLines innerVerticals, int lineDistance, ref Dictionary <int, int> duplicateDic, out CellLines horizontalsFinal, out CellLines verticalsFinal) { // 최종적으로 찾은 것을 duplicateDic에 추가한다. (이렇게 하면 박스 안의 박스는 별도로 처리 가능) horizontalsFinal = new CellLines(); verticalsFinal = new CellLines(); CellLines horizontals = new CellLines(); CellLines verticals = new CellLines(); CellLines horizontalFirst = new CellLines(); CellLines verticalFirst = new CellLines(); // 일단 가장 외각선과 맞닿는 부분이 있는 라인만 인정한다. foreach (CellLine line in innerHorizontals) { if (Math.Abs(line.StartX - left.StartX) <= lineDistance || Math.Abs(line.EndX - right.EndX) <= lineDistance) { horizontals.Add(line); } else { horizontalFirst.Add(line); } } // 일단 가장 외각선과 맞닿는 부분이 있는 라인만 인정한다. foreach (CellLine line in innerVerticals) { if (Math.Abs(line.StartY - top.StartY) <= lineDistance || Math.Abs(line.EndY - bottom.EndY) <= lineDistance) { verticals.Add(line); } else { verticalFirst.Add(line); } } // 가장 외각선과 맞닿는 부분이 있는 라인과 맞닿은 라인은 인정한다. // Data Sheet 같이 복잡한 테이블을 처리하기 위해 4번 돌린다. CellLines horizontalSecond, verticalSecond, horizontalThird, verticalThird, horizontalFourth, verticalFourth; GetInsideLine(horizontalSamples: horizontalFirst, verticalSamples: verticalFirst, lineDistance: lineDistance, horizontals: ref horizontals, verticals: ref verticals, horizontalRests: out horizontalSecond, verticalRests: out verticalSecond); GetInsideLine(horizontalSamples: horizontalSecond, verticalSamples: verticalSecond, lineDistance: lineDistance, horizontals: ref horizontals, verticals: ref verticals, horizontalRests: out horizontalThird, verticalRests: out verticalThird); GetInsideLine(horizontalSamples: horizontalThird, verticalSamples: verticalThird, lineDistance: lineDistance, horizontals: ref horizontals, verticals: ref verticals, horizontalRests: out horizontalFourth, verticalRests: out verticalFourth); bool matchStart, matchEnd; // top, bottom을 수평선에 추가한다. horizontals.Add(top); horizontals.Add(bottom); // left, right를 수직선에 추가한다. verticals.Add(left); verticals.Add(right); // 양 끝점이 모두 vertical과 붙어 있어야 line으로 인정한다. Data Sheet의 경우 단순 밑줄이 마치 Line처럼 잡힘 foreach (CellLine horizontal in horizontals) { matchStart = false; matchEnd = false; foreach (CellLine vertical in verticals) { if (horizontal.StartY >= vertical.StartY && horizontal.EndY <= vertical.EndY) { if (Math.Abs(horizontal.StartX - vertical.StartX) <= lineDistance) { matchStart = true; } else if (Math.Abs(horizontal.EndX - vertical.EndX) <= lineDistance) { matchEnd = true; } } if (matchStart && matchEnd) { horizontalsFinal.Add(horizontal); // top, bottom이 추가 되었기 때문에 체크 if (!duplicateDic.ContainsKey(horizontal.Index)) { duplicateDic.Add(horizontal.Index, horizontal.Index); } break; } } } // 양 끝점이 모두 horizontal과 붙어 있어야 line으로 인정한다. Data Sheet의 경우 단순 밑줄이 마치 Line처럼 잡힘 foreach (CellLine vertical in verticals) { matchStart = false; matchEnd = false; foreach (CellLine horizontal in horizontals) { if (vertical.StartX >= horizontal.StartX && vertical.EndX <= horizontal.EndX) { if (Math.Abs(vertical.StartY - horizontal.StartY) <= lineDistance) { matchStart = true; } else if (Math.Abs(vertical.EndY - horizontal.EndY) <= lineDistance) { matchEnd = true; } } if (matchStart && matchEnd) { verticalsFinal.Add(vertical); // left, right가 추가 되었기 때문에 체크 if (!duplicateDic.ContainsKey(vertical.Index)) { duplicateDic.Add(vertical.Index, vertical.Index); } break; } } } }
static CellBoxes DetectCellBoxes(int lineDistance, ref CellLines horizontals, ref CellLines verticals) { CellBoxes cellBoxes = new CellBoxes(); CellLines horizontalsFinal, verticalsFinal; CellLine left = new CellLine(); CellLine right = new CellLine(); CellLine top, bottom; bool findLeft, findRight; int index = 0; Dictionary <int, int> duplicateDic = new Dictionary <int, int>(); // 위에서부터 아래로 찾는다. foreach (CellLine horizontal in horizontals) { if (!duplicateDic.ContainsKey(horizontal.Index)) { findLeft = findRight = false; foreach (CellLine vertical in verticals) { if (!duplicateDic.ContainsKey(vertical.Index)) { if (horizontal.MinX <= vertical.MaxX && horizontal.MaxX >= vertical.MinX && horizontal.MinY <= vertical.MaxY && horizontal.MaxY >= vertical.MinY) { // 현재 라인의 왼쪽과 같은 위치에서 시작되는 수직 라인을 찾는다. if (Math.Abs(horizontal.StartX - vertical.StartX) <= lineDistance) { findLeft = true; left = vertical; } // 현재 라인의 오른쪽과 같은 위치에서 시작되는 수직 라인을 찾는다. else if (Math.Abs(horizontal.EndX - vertical.StartX) <= lineDistance) { findRight = true; right = vertical; } } // 두 라인을 찾으면 if (findLeft && findRight) { // 두 라인을 이용해서 두 수직 라인의 하단과 이어지는 수평 라인을 찾는다. if (ExistBottomLine(topIndex: horizontal.Index, lineDistance: lineDistance, verticalLeft: left, verticalRight: right, horizontals: horizontals, duplicateDic: ref duplicateDic, bottom: out bottom)) { top = horizontal; duplicateDic.Add(top.Index, top.Index); duplicateDic.Add(bottom.Index, bottom.Index); duplicateDic.Add(left.Index, left.Index); duplicateDic.Add(right.Index, right.Index); horizontals = GetHorizonsAllInBox(lineDistance: lineDistance, top: top, bottom: bottom, left: left, right: right, horizontals: horizontals, duplicateDic: ref duplicateDic); verticals = GetVerticalAllInBox(lineDistance: lineDistance, top: top, bottom: bottom, left: left, right: right, verticals: verticals, duplicateDic: ref duplicateDic); RemoveNoiseLine(lineDistance: lineDistance, top: top, bottom: bottom, left: left, right: right, innerHorizontals: horizontals, innerVerticals: verticals, duplicateDic: ref duplicateDic, horizontalsFinal: out horizontalsFinal, verticalsFinal: out verticalsFinal); cellBoxes.Add(new CellBox(index: index++, horizontals: new CellLines(horizontalsFinal.OrderBy(line => line.StartY)), verticals: new CellLines(verticalsFinal.OrderBy(line => line.StartX)))); break; } } } } } } return(cellBoxes); }