public CPointControl(CPoint point) { InitializeComponent(); StrCoordX = point.m_dX.ToString(); StrCoordY = point.m_dY.ToString(); IsArc = (point.m_emLineKind == EMLineKind.ARC) ? true : false; IsArcDirection = (point.m_emDirectionArc == EMDirectionArc.BACKWARD) ? true : false; }
public CPointUI(CPoint point) { InitializeComponent(); StrCoordX = point.X.ToString(); StrCoordZ = point.Y.ToString(); IsArc = (point.LineKind == EMLineKind.ARC) ? true : false; IsArcDirection = (point.DirectionArc == EMDirectionArc.BACKWARD) ? true : false; }
public CLine(CPoint start, CPoint end) { m_startPoint.X = start.X; m_startPoint.Y = start.Y; m_endPoint.X = end.X; m_endPoint.Y = end.Y; /// Line 정보는 Start 점에 담겨있는 정보를 사용한다. m_startPoint.LineKind = start.LineKind; m_startPoint.DirectionArc = start.DirectionArc; }
/// <summary> /// 경계조건의 부여되는 외각 Region 을 그리고 경계조건을 부여한다. /// </summary> /// <param name="femm">FEMM</param> /// <param name="x1">사각형 첫점의 X 좌표</param> /// <param name="y1">사각형 첫점의 Y 좌표</param> /// <param name="x2">사각형 둘째점의 X 좌표</param> /// <param name="y2">사각형 둘째점의 Y 좌표</param> /// <param name="dMeshSize"></param> public void setOutsideBoundary(CScriptFEMM femm, double x1, double y1, double x2, double y2, double dMeshSize = 0) { femm.addBoundaryConditon(); setRectanglePoints(x1, y1, x2, y2); double maxX = (x1 > x2) ? x1 : x2; double maxY = (y1 > y2) ? y1 : y2; double width = Math.Abs(x2 - x1); double height = Math.Abs(y2 - y1); CPoint blockPoint = new CPoint(); // 좌상단 구석에 block point 좌표를 얻어낸다. // Region 은 무조건 직사각형이기 때문에 촤상단 점의 근접점이 내부점이 될 수 있다. blockPoint.X = maxX - width / 1000.0f; blockPoint.Y = maxY - height / 1000.0f; femm.setRegionBlockProp(blockPoint, dMeshSize); double sx, sy, ex, ey; /// 매번 생성하는 Property 이기 때문에 /// LineList 는 새로운 List에 담는 동작 한번만 호출하고, 사용은 새로운 List 를 사용한다. List <CPoint> listAbsolutePoint = new List <CPoint>(); listAbsolutePoint = AbsolutePointList; // 좌변을 제외하고 하변, 상변, 우변에만 경계조건이 부여된다. for (int i = 0; i < listAbsolutePoint.Count; i++) { // 마지막 Point 만 제외한다. if (i < listAbsolutePoint.Count - 1) { sx = listAbsolutePoint[i].X; sy = listAbsolutePoint[i].Y; ex = listAbsolutePoint[i + 1].X; ey = listAbsolutePoint[i + 1].Y; femm.drawBoundaryLine(sx, sy, ex, ey); } /// 마지막 선은 끝점과 첫점을 있는다 /// 마지막 선은 좌변 라인으로 경계조건이 필요 없다. else { sx = listAbsolutePoint[i].X; sy = listAbsolutePoint[i].Y; ex = listAbsolutePoint[0].X; ey = listAbsolutePoint[0].Y; femm.drawLine(sx, sy, ex, ey); } } }
public CLine(CPoint start, CPoint end) { m_startPoint.m_dX = start.m_dX; m_startPoint.m_dY = start.m_dY; m_endPoint.m_dX = end.m_dX; m_endPoint.m_dY = end.m_dY; /// Line 정보는 Start 점에 담겨있는 정보를 사용한다. m_startPoint.m_emLineKind = start.m_emLineKind; m_startPoint.m_emDirectionArc = start.m_emDirectionArc; }
/// <summary> /// 경계조건의 부여되지 않는 내부 Region 을 그린다. (단, 경계조건은 부여하지 않음) /// </summary> /// <param name="femm">FEMM</param> /// <param name="x1">사각형 첫점의 X 좌표</param> /// <param name="y1">사각형 첫점의 Y 좌표</param> /// <param name="x2">사각형 둘째점의 X 좌표</param> /// <param name="y2">사각형 둘째점의 Y 좌표</param> /// <param name="dMeshSize">Mesh Size (0 이면 Auto Mesh)</param> public void setInsideRegion(CScriptFEMM femm, double x1, double y1, double x2, double y2, double dMeshSize = 0) { setRectanglePoints(x1, y1, x2, y2); double maxX = (x1 > x2) ? x1 : x2; double maxY = (y1 > y2) ? y1 : y2; double width = Math.Abs(x2 - x1); double height = Math.Abs(y2 - y1); CPoint blockPoint = new CPoint(); // 좌상단 구석에 block point 좌표를 얻어낸다. blockPoint.m_dX = maxX - width / 100.0f; blockPoint.m_dY = maxY - height / 100.0f; femm.setRegionBlockProp(blockPoint, dMeshSize); double sx, sy, ex, ey; /// 매번 생성하는 Property 이기 때문에 /// LineList 는 새로운 List에 담는 동작 한번만 호출하고, 사용은 새로운 List 를 사용한다. List <CPoint> listAbsolutePoint = new List <CPoint>(); listAbsolutePoint = AbsolutePointList; // 좌변을 제외하고 하변, 상변, 우변에만 경계조건이 부여된다. for (int i = 0; i < listAbsolutePoint.Count; i++) { // 마지막 Point 만 제외한다. if (i < listAbsolutePoint.Count - 1) { sx = listAbsolutePoint[i].m_dX; sy = listAbsolutePoint[i].m_dY; ex = listAbsolutePoint[i + 1].m_dX; ey = listAbsolutePoint[i + 1].m_dY; /// 경계조건은 부여하지 않음 femm.drawLine(sx, sy, ex, ey); } // 마지막 선은 끝점과 첫점을 있는다 else { sx = listAbsolutePoint[i].m_dX; sy = listAbsolutePoint[i].m_dY; ex = listAbsolutePoint[0].m_dX; ey = listAbsolutePoint[0].m_dY; femm.drawLine(sx, sy, ex, ey); } } }
/// <summary> /// Face 안의 부품의 속성을 입력하기 위한 BlockPoint 를 얻어낸다. /// /// 절대좌표의 내부 블럭점을 찾는 것이기 때문에 절대 좌표를 사용해야 한다. /// </summary> /// <returns>Block Point</returns> public CPoint getBlockPoint() { CPoint blockPoint = new CPoint(); double sumX = 0; double sumY = 0; /// Rectangle 은 4 좌표의 평균점을 사용한다. if (FaceType == EMFaceType.RECTANGLE) { /// 매번 생성하는 Property 이기 때문에 /// LineList 는 새로운 List에 담는 동작 한번만 호출하고, 사용은 새로운 List 를 사용한다. List <CPoint> listAbsolutePoint = new List <CPoint>(); listAbsolutePoint = AbsolutePointList; foreach (CPoint point in listAbsolutePoint) { sumX += point.X; sumY += point.Y; } blockPoint.X = sumX / listAbsolutePoint.Count; blockPoint.Y = sumY / listAbsolutePoint.Count; } else { double minX, maxX, minY, maxY; minX = maxX = minY = maxY = 0; getMinMaxX(ref minX, ref maxX); getMinMaxY(ref minY, ref maxY); CPoint retBlockPoint = m_shapeTools.findInsidePoint(this, minX, maxX, minY, maxY); if (retBlockPoint != null) { blockPoint = retBlockPoint; } else { // 예외 처리를 한다. blockPoint.X = 0; blockPoint.Y = 0; } } return(blockPoint); }
/// <summary> /// Face 안의 부품의 속성을 입력하기 위한 BlockPoint 를 얻어낸다. /// /// 절대좌표의 내부 블럭점을 찾는 것이기 때문에 절대 좌표를 사용해야 한다. /// </summary> /// <returns>Block Point</returns> public CPoint getBlockPoint() { CPoint blockPoint = new CPoint(); double sumX = 0; double sumY = 0; /// Rectangle 은 4 좌표의 평균점을 사용한다. if (FaceType == EMFaceType.RECTANGLE) { /// 매번 생성하는 Property 이기 때문에 /// LineList 는 새로운 List에 담는 동작 한번만 호출하고, 사용은 새로운 List 를 사용한다. List <CPoint> listAbsolutePoint = new List <CPoint>(); listAbsolutePoint = AbsolutePointList; foreach (CPoint point in listAbsolutePoint) { sumX += point.m_dX; sumY += point.m_dY; } blockPoint.m_dX = sumX / listAbsolutePoint.Count; blockPoint.m_dY = sumY / listAbsolutePoint.Count; } else { double minX, maxX, minY, maxY; minX = maxX = minY = maxY = 0; getMinMaxX(ref minX, ref maxX); getMinMaxY(ref minY, ref maxY); blockPoint = m_shapeTools.findInsidePoint(this, minX, maxX, (minY + maxY) / 2.0f); /// 기준 높이 Base Y 에 Face 의 절점이 위치하면, /// 내부점을 찾지 못해서 null 이 넘어오면 Base Y 값을 변경하여 다시 한번 시도해 본다. /// 만약, 두번째의 시도에도 null 이 넘어오면 Block Point 의 재질을 입력하지 않도록 null 을 그대로 리턴한다. if (blockPoint == null) { blockPoint = m_shapeTools.findInsidePoint(this, minX, maxX, (minY + maxY) / 2.0f + (minY - maxY) / 10.0f); } } return(blockPoint); }
/// <summary> /// 형상 입력때나 수정때 형상을 다시 그린다 /// - 수정 부품만 빼고 타 부품들은 다시 그리고, 수정 부품은 창에 기록된 값을 그린다. /// </summary> /// <param name="pointControl">좌표점 PointControl</param> /// <param name="bRedraw">형상 수정이 없어도 강제로 ARC 변경때 강제로 수정함</param> internal void drawTemporaryFace(CPointUI pointControl, bool bRedraw = false) { try { /// [문제] /// - Form 에서는 Parent를 사용할 수 없어 Owner 속성을 사용하지만 /// 종종 Owner 가 null 로 넘어오는 문제가 발생한다. /// [해결] /// - PopupShape 창을 생성하기 전에 Owner 속성을 FormMain 으로 초기화 해 두어야 /// 확실하게 FormMain 을 얻을 수 있다. FormMain formMain = ((FormMain)this.Owner); if (formMain == null) { CNotice.printLogID("CNGM"); return; } CScriptFEMM femm = formMain.m_femm; CDataNode nodeParts = formMain.m_design.getNode(m_strPartName); /// 0. 해당 좌표점의 수정이 있었는지를 판단한다. /// - 수정이 있는 경우만 다시 그리기 위해서이다. bool retCheck = false; /// 초기 생성때는 이전 nodeParts 가 없음으로 사용하지 않고, 기존 노드의 수정때만 사용한다. if (nodeParts != null) { /// 좌표 Control 에 빈칸이 존재하는 지를 확인함 for (int i = 0; i < ListPointUI.Count; i++) { /// 해당 좌표점만 비교한다. /// 만약, Parts 의 모든 좌표점을 비교하면 다른 좌표점이 수정되었을때 나머지 좌표점의 수정이 없어도 다시 그리기가 된다. if (ListPointUI[i] == pointControl) { if (((CShapeParts)nodeParts).Face.RelativePointList[i].X != Double.Parse(ListPointUI[i].StrCoordX.Trim())) { retCheck = true; } if (((CShapeParts)nodeParts).Face.RelativePointList[i].Y != Double.Parse(ListPointUI[i].StrCoordZ.Trim())) { retCheck = true; } } } } // Arc 관련 이벤트 호출이면 강제로 다시그리기를 한다. if (bRedraw == true) { retCheck = true; } if (retCheck == true) { femm.deleteAll(); /// 1. 혹시 수정중이라면, 현재 작업 중인 Face 를 제외하고 형상 그리기 foreach (CDataNode node in formMain.m_design.GetNodeList) { if (node.GetType().BaseType.Name == "CShapeParts") { if (node.NodeName != m_strPartName) { ((CShapeParts)node).Face.drawFace(femm); } } } } /// 2. 현재 수정중이거나 생성중인 Face 의 형상 그리기 retCheck = true; /// 좌표 Control 에 빈칸이 존재하는 지를 확인함 for (int i = 0; i < ListPointUI.Count; i++) { if (ListPointUI[i].StrCoordX.Trim().Length == 0) { retCheck = false; } if (ListPointUI[i].StrCoordZ.Trim().Length == 0) { retCheck = false; } } double dBase_X, dBase_Y; dBase_X = dBase_Y = 0; dBase_X = Double.Parse(textBoxBaseX.Text.Trim()); dBase_Y = Double.Parse(textBoxBaseY.Text.Trim()); // 모든 데이터가 입력된 경우는 폐곡선의 정상적인 Face 를 그린다. if (retCheck == true) { CFace faceTemp = makeFaceInPopup(); if (null != faceTemp) { faceTemp.drawFace(femm); } else { CNotice.printLogID("TSWN"); } } // 모든 데이터가 아직 입력되지 않은 상태는 입력중인 데이터만으로 그림을 그린다. else { double dP1_X, dP1_Y, dP2_X, dP2_Y; bool bArc, bArcDirection; dP1_X = dP1_Y = dP2_X = dP2_Y = 0; bArc = bArcDirection = false; for (int i = 0; i < ListPointUI.Count; i++) { retCheck = true; if (ListPointUI[i].StrCoordX.Trim().Length == 0) { retCheck = false; } else { dP1_X = Double.Parse(ListPointUI[i].StrCoordX.Trim()) + dBase_X; } if (ListPointUI[i].StrCoordZ.Trim().Length == 0) { retCheck = false; } else { dP1_Y = Double.Parse(ListPointUI[i].StrCoordZ.Trim()) + dBase_Y; } /// X, Y 값이 모두 입력된 Point Control 인 경우 if (retCheck == true) { if (i == 0) { /// 사각형, 다각형 모두 적용된다. femm.drawPoint(dP1_X, dP1_Y); } else { if (this.FaceType == EMFaceType.RECTANGLE) { CNotice.printLogID("ATTW"); } /// 다각형만 적용된다. /// 만약 사각형의 경우 i = 1 까지 모두 채워지면 모두 입력된 상태로 if 문의 위에처 처리되기 때문이다. bArc = ListPointUI[i].IsArc; bArcDirection = ListPointUI[i].IsArcDirection; if (bArc == true) { femm.drawArc(dP2_X, dP2_Y, dP1_X, dP1_Y, bArcDirection); } else { femm.drawLine(dP2_X, dP2_Y, dP1_X, dP1_Y); } } // 이번 점을 이전 점으로 저장한다. dP2_X = dP1_X; dP2_Y = dP1_Y; } /// 채워지지 않은 좌표값을 발견하면 바로 빠져 나간다 else { break; } } } /// 선택된 좌표점을 붉은 색으로 표시한다. /// /// Base X, Y 변경 할때나 Leave 이벤트는 제외해야 함으로 null 을 넘겨오도록 되어 있다. if (pointControl != null) { /// XY 값 모두 들어 있는 경우에만 표시를 한다. if (pointControl.StrCoordX != "" && pointControl.StrCoordZ != "") { CPoint selectedPoint = new CPoint(); selectedPoint.X = Double.Parse(pointControl.StrCoordX) + dBase_X; selectedPoint.Y = Double.Parse(pointControl.StrCoordZ) + dBase_Y; femm.clearSelected(); femm.selectPoint(selectedPoint); } } } catch (Exception ex) { CNotice.printLog(ex.Message); } }
// Base Point 와 상대좌표로 좌표값이 저장되는 Face 가 생성된다. public CFace makeFaceInPopup() { try { CFace face = new CFace(); face.BasePoint.X = Double.Parse(textBoxBaseX.Text); face.BasePoint.Y = Double.Parse(textBoxBaseY.Text); if (FaceType == EMFaceType.RECTANGLE) { if (ListPointUI.Count != 2) { CNotice.printLogID("TATP1"); return(null); } double x1, y1, x2, y2; x1 = Double.Parse(ListPointUI[0].StrCoordX); y1 = Double.Parse(ListPointUI[0].StrCoordZ); x2 = Double.Parse(ListPointUI[1].StrCoordX); y2 = Double.Parse(ListPointUI[1].StrCoordZ); face.setRectanglePoints(x1, y1, x2, y2); } else { if (ListPointUI.Count < 4) { CNotice.printLogID("TANM"); return(null); } // PartType 가 코일이고 Polygon 형상을 가지고 있는 경우라면 (DXF로 읽어드리고 코일로 지정하는 경우) // Rectangle 로 바꾸어 저장한다. // 만약, Retangle 조건이 아니라면 지나쳐서 Polygon 으로 저장한다. if (PartType == EMKind.COIL) { CFace retFace = makeRectangleFaceInPopup(); if (retFace != null) { return(retFace); } } List <CPoint> listPoint = new List <CPoint>(); foreach (CPointUI pointControl in ListPointUI) { // 매번 신규로 생성을 해야 한다. CPoint point = new CPoint(); point.X = Double.Parse(pointControl.StrCoordX); point.Y = Double.Parse(pointControl.StrCoordZ); if (pointControl.IsArc == true) { point.LineKind = EMLineKind.ARC; } else { point.LineKind = EMLineKind.STRAIGHT; } if (pointControl.IsArcDirection == true) { point.DirectionArc = EMDirectionArc.BACKWARD; } else { point.DirectionArc = EMDirectionArc.FORWARD; } listPoint.Add(point); } face.setPolygonPoints(listPoint); } return(face); } catch (Exception ex) { CNotice.printLog(ex.Message); return(null); } }
/// <summary> /// 선 위에 다른 점이 올라가 있는 지를 검사한다. /// </summary> public bool isPerchedOnLine(CLine line, CPoint point) { double dL_P1_X = line.m_startPoint.X; double dL_P1_Y = line.m_startPoint.Y; double dL_P2_X = line.m_endPoint.X; double dL_P2_Y = line.m_endPoint.Y; double dP_X = point.X; double dP_Y = point.Y; /// 라인의 X 구간 double dBigX = Math.Max(dL_P1_X, dL_P2_X); double dSmallX = Math.Min(dL_P1_X, dL_P2_X); /// 라인의 Y 구간 double dBigY = Math.Max(dL_P1_Y, dL_P2_Y); double dSmallY = Math.Min(dL_P1_Y, dL_P2_Y); /// 직선이 수직선인 경우는 예외 처리한다. if (isEqual(dL_P2_X, dL_P1_X)) { /// 점의 X 좌표가 직선의 X 좌표와 일치하면 라인 위의 점이다. if (isEqual(dL_P1_X, dP_X)) { if (roundDigitOfShape(dBigY) >= roundDigitOfShape(dP_Y) && roundDigitOfShape(dSmallY) <= roundDigitOfShape(dP_Y)) { return(true); } } } /// 직선이 수평선인 경우는 예외 처리한다. else if (isEqual(dL_P2_Y, dL_P1_Y)) { /// 점의 Y 좌표가 직선의 Y 좌표와 일치하면 라인 위의 점이다. if (isEqual(dL_P1_Y, dP_Y)) { if (roundDigitOfShape(dBigX) >= roundDigitOfShape(dP_X) && roundDigitOfShape(dSmallX) <= roundDigitOfShape(dP_X)) { return(true); } } } else { /// 라인의 직선방정식 기울기와 Y 절편을 계산한다. double dL_A = (dL_P2_Y - dL_P1_Y) / (dL_P2_X - dL_P1_X); double dL_B = dL_P1_Y - dL_A * (dL_P1_X); /// 라인의 직선방정식에 점의 X 값을 입력하여 Y 값을 계산한다. double dP_Calc_Y = dL_A * dP_X + dL_B; /// 계산된 Y 값과 좌표 Y 값이 일치하면 직선의 방정식위에 있는 점이다. if (isEqual(dP_Calc_Y, dP_Y)) { /// 직선의 방정식 위에 있는 점 중에서 실제 라인 위에 있는 점인지를 판단한다. if ((roundDigitOfShape(dBigX) >= roundDigitOfShape(dP_X) && roundDigitOfShape(dSmallX) <= roundDigitOfShape(dP_X)) && (roundDigitOfShape(dBigY) >= roundDigitOfShape(dP_Y) && roundDigitOfShape(dSmallY) <= roundDigitOfShape(dP_Y))) { return(true); } } } return(false); }
public bool readObject(List <string> listStringLines) { string strTemp; string[] arrayString; try { CPoint point = null; // 형상 라인을 처리한다. foreach (string strLine in listStringLines) { strTemp = strLine.Trim('\t'); arrayString = strTemp.Split('='); /// 각 줄의 String 배열은 항상 2개이여야 한다. if (arrayString.Length != 2) { CNotice.noticeWarningID("TIAP5"); return(false); } switch (arrayString[0]) { case "BasePointX": BasePoint.X = Double.Parse(arrayString[1]); break; case "BasePointY": BasePoint.Y = Double.Parse(arrayString[1]); break; case "FaceType": FaceType = (EMFaceType)Enum.Parse(typeof(EMFaceType), arrayString[1]); break; case "PointX": // PointX 키워드를 만날때 새로운 CPoint 생성하고, // ArcDriction 키워드를 만날때 생성된 CPoint 를 Face 에 추가한다. // 따라서 저장될때 X, Y, LineKind, ArcDriction 의 순서로 꼭 저장 되어야 한다. point = new CPoint(); point.X = Double.Parse(arrayString[1]); break; case "PointY": if (point != null) { point.Y = Double.Parse(arrayString[1]); } else { CNotice.noticeWarningID("YCWX"); return(false); } break; case "LineKind": if (point != null) { point.LineKind = (EMLineKind)Enum.Parse(typeof(EMLineKind), arrayString[1]); } else { CNotice.noticeWarningID("TIAP9"); return(false); } break; case "ArcDriction": if (point != null) { point.DirectionArc = (EMDirectionArc)Enum.Parse(typeof(EMDirectionArc), arrayString[1]); } else { CNotice.noticeWarningID("TIAP10"); return(false); } // ArcDriction 에서 point 을 저장한다. addPoint(point); break; default: break; } } } catch (Exception ex) { CNotice.printLog(ex.Message); return(false); } return(true); }
public bool addPoint(CPoint point) { m_listRelativePoint.Add(point); return(true); }
/// <summary> /// 재귀호출을 사용해서 FACE 내부점을 찾아낸다. /// 재질 블럭점을 찾는 것이기 때문에 절대좌표를 사용해야 한다. /// /// 참고 사이트 : http://bowbowbow.tistory.com/24 /// </summary> /// <param name="minX">내부점을 찾는 구간의 X 점 최소값</param> /// <param name="maxX">내부점을 찾는 구간의 X 점 최대값</param> /// <param name="baseY">내부 좌표값을 찾은 Y 위치 </param> /// <returns></returns> public CPoint findInsidePoint(CFace face, double minX, double maxX, double minY, double maxY) { int nRightIntersection = 0; int nLeftIntersection = 0; int nRightPerchedPointOnCheckLine = 0; int nLeftPerchedPointOnCheckLine = 0; int nPerchedCenterPointOnFaceLine = 0; CLine rightCheckLine = new CLine(); CLine leftCheckLine = new CLine(); CPoint centerPoint = new CPoint(); double baseY = (minY + maxY) / 2.0f; double centerX = (minX + maxX) / 2.0f; //// 너무 작은 소수점 이하는 정리한다. minX = roundDigitOfShape(minX); maxX = roundDigitOfShape(maxX); baseY = roundDigitOfShape(baseY); // 중심점을 만든다. centerPoint.X = centerX; centerPoint.Y = baseY; /// create a right check line rightCheckLine.m_startPoint.X = centerX; rightCheckLine.m_startPoint.Y = baseY; rightCheckLine.m_endPoint.X = maxX + 10.0f; // 오른 검색선의 끝을 maxX 보다 10 크게 한다. rightCheckLine.m_endPoint.Y = baseY; /// create a left check line leftCheckLine.m_startPoint.X = centerX; leftCheckLine.m_startPoint.Y = baseY; leftCheckLine.m_endPoint.X = minX - 10.0f; // 오른 검색선의 끝을 minX 보다 10 작게 한다. leftCheckLine.m_endPoint.Y = baseY; /// 매번 생성하는 Property 이기 때문에 /// LineList 는 새로운 List에 담는 동작 한번만 호출하고, 사용은 새로운 List 를 사용한다. List <CLine> listAbsoluteLine = new List <CLine>(); listAbsoluteLine = face.AbsoluteLineList; foreach (CLine line in listAbsoluteLine) { /// Face 선들과 검색 선의 교차 횟수 확인 if (true == isIntersected(line, rightCheckLine)) { nRightIntersection++; } if (true == isIntersected(line, leftCheckLine)) { nLeftIntersection++; } /// Face 선의 양점이 검색 선 위에 올라가 있는지 확인 if (true == isPerchedOnLine(rightCheckLine, line.m_startPoint)) { nRightPerchedPointOnCheckLine++; } if (true == isPerchedOnLine(rightCheckLine, line.m_endPoint)) { nRightPerchedPointOnCheckLine++; } if (true == isPerchedOnLine(leftCheckLine, line.m_startPoint)) { nLeftPerchedPointOnCheckLine++; } if (true == isPerchedOnLine(leftCheckLine, line.m_endPoint)) { nLeftPerchedPointOnCheckLine++; } /// Face 선위에 중심점이 올라가 있는지 확인 if (true == isPerchedOnLine(line, centerPoint)) { nPerchedCenterPointOnFaceLine++; } } //------------------------------------------------------------------- // 내부점 판단 // // 내부점을 만족하면 Point 를 리턴하고, // 만족하지 못하면 측정 면적을 수정하고 재귀호출을 통해 Point 를 찾아낸다. //------------------------------------------------------------------ // CPoint point = new CPoint(); // Center 점이 Face Line 위에 올라가 있으면 우측 1/2 사각형에서 내부점을 찾는다. if (nPerchedCenterPointOnFaceLine > 0) { return(findInsidePoint(face, centerX, maxX, minY, maxY)); } // Face Line 의 양점이 우측 검색 라인에 올라가는 경우는 상측 1/2 사각형에서 내부점을 찾는다. if (nRightPerchedPointOnCheckLine > 0 || nLeftPerchedPointOnCheckLine > 0) { return(findInsidePoint(face, minX, maxX, baseY, maxY)); } // 양측이 홀수이면 Inside Point 이다. if (EMNumberKind.ODD == getNumberKind(nRightIntersection) && EMNumberKind.ODD == getNumberKind(nLeftIntersection)) { point.X = centerX; point.Y = baseY; return(point); } /// 왼쪽이 짝수이면 X 값의 최소값과 중심값 사이의 중점을 다시 확인한다. else if (EMNumberKind.EVEN == getNumberKind(nLeftIntersection)) { return(findInsidePoint(face, minX, centerX, minY, maxY)); } /// 오른쪽이 짝수이면 X 값의 중심값과 최대값 사이의 중점을 다시 확인한다. else if (EMNumberKind.EVEN == getNumberKind(nRightIntersection)) { return(findInsidePoint(face, centerX, maxX, minY, maxY)); } else { /// Block Point 를 찾기 위해서 findInsidePoint() 를 호출할 때 /// Face 형상의 문제로 오류가 발생하여 Face 바깥의 지점으로 계산이 리턴되면 /// Block Point 가 추가되지 못해서 /// FEMM 에서 Block Point 에 재질 인가 할 때 다른 Block Point 에 인가되는 문제가 발생한다. /// /// 따라서 findInsidePoint() 에서 내부점을 찾지 못할 때는 /// 중심의 좌표값을 넘기지 않고 null 을 리턴하여 Block Point 재질 설정 동작을 막는다. CNotice.noticeWarningID("FTCT"); return(null); } }
// Base Point 와 상대좌표로 좌표값이 저장되는 Face 가 생성된다. public CFace makeFace() { try { CFace face = new CFace(); face.BasePoint.m_dX = Double.Parse(textBoxBaseX.Text); face.BasePoint.m_dY = Double.Parse(textBoxBaseY.Text); if (FaceType == EMFaceType.RECTANGLE) { if (ListPointControl.Count != 2) { CNotice.printTraceID("TATP1"); return(null); } double x1, y1, x2, y2; x1 = Double.Parse(ListPointControl[0].StrCoordX); y1 = Double.Parse(ListPointControl[0].StrCoordY); x2 = Double.Parse(ListPointControl[1].StrCoordX); y2 = Double.Parse(ListPointControl[1].StrCoordY); face.setRectanglePoints(x1, y1, x2, y2); } else { if (ListPointControl.Count < 4) { CNotice.printTraceID("TANM"); return(null); } List <CPoint> listPoint = new List <CPoint>(); foreach (CPointControl pointControl in ListPointControl) { // 매번 신규로 생성을 해야 한다. CPoint point = new CPoint(); point.m_dX = Double.Parse(pointControl.StrCoordX); point.m_dY = Double.Parse(pointControl.StrCoordY); if (pointControl.IsArc == true) { point.m_emLineKind = EMLineKind.ARC; } else { point.m_emLineKind = EMLineKind.STRAIGHT; } if (pointControl.IsArcDirection == true) { point.m_emDirectionArc = EMDirectionArc.BACKWARD; } else { point.m_emDirectionArc = EMDirectionArc.FORWARD; } listPoint.Add(point); } face.setPolygonPoints(listPoint); } return(face); } catch (Exception ex) { CNotice.printTrace(ex.Message); return(null); } }
/// <summary> /// 재귀호출을 사용해서 FACE 내부점을 찾아낸다. /// 재질 블럭점을 찾는 것이기 때문에 절대좌표를 사용해야 한다. /// /// 참고 사이트 : http://bowbowbow.tistory.com/24 /// </summary> /// <param name="minX">내부점을 찾는 구간의 X 점 최소값</param> /// <param name="maxX">내부점을 찾는 구간의 X 점 최대값</param> /// <param name="baseY">내부 좌표값을 찾은 Y 위치 </param> /// <returns></returns> public CPoint findInsidePoint(CFace face, double minX, double maxX, double baseY) { int nRightIntersection = 0; int nLeftIntersection = 0; int nRightPerchedPoint = 0; int nLeftPerchedPoint = 0; // 자리수 정리 minX = round(minX); maxX = round(maxX); baseY = round(baseY); double centerX = (minX + maxX) / 2.0f; CLine rightLine = new CLine(); CLine leftLine = new CLine(); /// create a right check line rightLine.m_startPoint.m_dX = centerX; rightLine.m_startPoint.m_dY = baseY; rightLine.m_endPoint.m_dX = maxX + 10.0f; // 오른 검색선의 끝을 maxX 보다 10 크게 한다. rightLine.m_endPoint.m_dY = baseY; /// create a left check line leftLine.m_startPoint.m_dX = centerX; leftLine.m_startPoint.m_dY = baseY; leftLine.m_endPoint.m_dX = minX - 10.0f; // 오른 검색선의 끝을 minX 보다 10 작게 한다. leftLine.m_endPoint.m_dY = baseY; /// 매번 생성하는 Property 이기 때문에 /// LineList 는 새로운 List에 담는 동작 한번만 호출하고, 사용은 새로운 List 를 사용한다. List <CLine> listAbsoluteLine = new List <CLine>(); listAbsoluteLine = face.AbsoluteLineList; /// Face 의 선과 검색선의 교차점을 찾는다. foreach (CLine line in listAbsoluteLine) { if (true == isIntersected(line, rightLine)) { nRightIntersection++; } if (true == isIntersected(line, leftLine)) { nLeftIntersection++; } } /// 교차를 검사할때 Face 선의 양점은 고려하지 않는다. /// 따라서 검색선에 Face 선의 점을 지나치는 경우는 교차점이 인식되지 못한다. /// 라인의 양점이 검색선에 올가가는지도 추가로 검색한다. /// foreach (CLine line in listAbsoluteLine) { // 만약 시작과 끝이 같이 올라간 경우라면 검색선에 Face 선이 올라간 경우로 검색에서 제외한다. // 라인의 한점만 올라간 경우를 Perched Point 로 사용한다. if (true == isPerchedOnLine(rightLine, line.m_startPoint) && true == isPerchedOnLine(rightLine, line.m_endPoint)) { nRightPerchedPoint += 0; } else if (true == isPerchedOnLine(rightLine, line.m_startPoint)) { nRightPerchedPoint++; } else if (true == isPerchedOnLine(rightLine, line.m_endPoint)) { nRightPerchedPoint++; } if (true == isPerchedOnLine(leftLine, line.m_startPoint) && true == isPerchedOnLine(leftLine, line.m_endPoint)) { nLeftPerchedPoint += 0; } else if (true == isPerchedOnLine(leftLine, line.m_startPoint)) { nLeftPerchedPoint++; } else if (true == isPerchedOnLine(leftLine, line.m_endPoint)) { nLeftPerchedPoint++; } } if ((nRightPerchedPoint % 2 != 0) || (nLeftPerchedPoint % 2 != 0)) { CNotice.printTrace("findInsidePoint 에서 PerchedPoint 값이 홀수가 되었습니다."); } /// 점이 올라가는 경우 두점이 같이 올라가기 때문에 한번 교차에 두번 카운팅이 된다. /// 따라서 1/2 로 처리한다. /// nRightIntersection += (int)(nRightPerchedPoint / 2.0f); nLeftIntersection += (int)(nLeftPerchedPoint / 2.0f); CPoint point = new CPoint(); /// 양측이 홀수이면 Inside Point 이다. if (EMNumberKind.ODD == getNumberKind(nRightIntersection) && EMNumberKind.ODD == getNumberKind(nLeftIntersection)) { point.m_dX = centerX; point.m_dY = baseY; return(point); } /// 왼쪽이 짝수이면 X 값의 최소값과 중심값 사이의 중점을 다시 확인한다. else if (EMNumberKind.EVEN == getNumberKind(nLeftIntersection)) { return(findInsidePoint(face, minX, centerX, baseY)); } /// 오른쪽이 짝수이면 X 값의 중심값과 최대값 사이의 중점을 다시 확인한다. else if (EMNumberKind.EVEN == getNumberKind(nRightIntersection)) { return(findInsidePoint(face, centerX, maxX, baseY)); } else { /// Block Point 를 찾기 위해서 findInsidePoint() 를 호출할 때 /// Face 형상의 문제로 오류가 발생하여 Face 바깥의 지점으로 계산이 리턴되면 /// Block Point 가 추가되지 못해서 /// FEMM 에서 Block Point 에 재질 인가 할 때 다른 Block Point 에 인가되는 문제가 발생한다. /// /// 따라서 findInsidePoint() 에서 내부점을 찾지 못할 때는 /// 중심의 좌표값을 넘기지 않고 null 을 리턴하여 Block Point 재질 설정 동작을 막는다. CNotice.noticeWarningID("FTCT"); return(null); } }