public void drawDesign(CScriptFEMM femm) { CFace face = null; foreach (CNode node in NodeList) { if (node.GetType().BaseType.Name == "CParts") { CParts nodeParts = (CParts)node; face = nodeParts.Face; if (null != face) { nodeParts.Face.drawFace(femm, nodeParts.MovingPart); } else { CNotice.printTraceID("YATT1"); } } } femm.zoomFit(); }
public void setBlockPropCurrent(CScriptFEMM femm, double dCurrent, double dMeshSize) { CPoint blockPoint = null; blockPoint = this.Face.getBlockPoint(); if (blockPoint == null) { CNotice.printTraceID("NBPF"); return; } string strMaterialName = this.m_strMaterial; string strCircuit = NodeName + "_current"; if (CurrentDirection == EMCurrentDirection.OUT) { dCurrent = -dCurrent; } femm.addCircuitProp(strCircuit, dCurrent); femm.setBlockProp(blockPoint, strMaterialName, dMeshSize, strCircuit, 0, MovingPart, Turns); }
/// <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); } } }
/// <summary> /// FEMM 에 Face 를 그린다. /// /// FEMM 에 형상을 그릴 때는 절대좌표를 사용해야 한다. /// </summary> /// <param name="femm">FEMM</param> /// <param name="emMoving">Line 의 Group 를 결정하기 위한 동작부 여부</param> public bool drawFace(CScriptFEMM femm, EMMoving emMoving = EMMoving.FIXED) { double x1, y1, x2, y2; bool bDirectionArc = false; if (m_listRelativePoint.Count < MIN_POINT_COUNT) { CNotice.printLogID("YATT2"); return(false); } /// 매번 생성하는 Property 이기 때문에 /// LineList 는 새로운 List에 담는 동작 한번만 호출하고, 사용은 새로운 List 를 사용한다. List <CPoint> listAbsolutePoint = new List <CPoint>(); listAbsolutePoint = AbsolutePointList; // Face 에 저장될 때는 Rectangle 도 4개의 직선으로 저장되기 때문에 // Face 를 그릴 때는 모두 다각형으로 취급한다. for (int i = 0; i < listAbsolutePoint.Count; i++) { // 마지막 Point 만 제외한다. if (i < listAbsolutePoint.Count - 1) { x1 = listAbsolutePoint[i].X; y1 = listAbsolutePoint[i].Y; x2 = listAbsolutePoint[i + 1].X; y2 = listAbsolutePoint[i + 1].Y; } // 마지막 선은 끝점과 첫점을 있는다 else { x1 = listAbsolutePoint[i].X; y1 = listAbsolutePoint[i].Y; x2 = listAbsolutePoint[0].X; y2 = listAbsolutePoint[0].Y; } if (listAbsolutePoint[i].LineKind == EMLineKind.ARC) { bDirectionArc = (listAbsolutePoint[i].DirectionArc == EMDirectionArc.BACKWARD ? true : false); femm.drawArc(x1, y1, x2, y2, bDirectionArc, emMoving); } else { femm.drawLine(x1, y1, x2, y2, emMoving); } } return(true); }
/// <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); } } }
public void setBoundary(CScriptFEMM femm, double dMeshSizePercent, double dPlusMovingStroke, double dMinusMovingStroke) { const int iPaddingPercent = 200; double minX, minY, maxX, maxY; minX = minY = maxX = maxY = 0; this.getModelMinMaxX(ref minX, ref maxX); this.getModelMinMaxY(ref minY, ref maxY); double lengthX = Math.Abs(maxX - minX); double lengthY = Math.Abs(maxY - minY); // MeshSizePercent 에 문제가 있으면 1% 로 초기화 한다. if (dMeshSizePercent <= 0) { dMeshSizePercent = 1; } // Mesh Size 는 길이단위이기 때문에 면적을 루트 취한 값과 곱하고 있다. double dMeshSize = Math.Sqrt(this.calcShapeModelArea()) * dMeshSizePercent / 100.0f; double padLengthX = lengthX * iPaddingPercent / 100.0f; double padLengthY = lengthY * iPaddingPercent / 100.0f; /// - 긴방향의 길이로 Pad 량을 결정한다. /// - 100.0f 는 Percent 를 배수로 환산한다. double padLength = (padLengthX > padLengthY) ? padLengthX : padLengthY; CFace face = new CFace(); /// 외부 Region 을 생성 및 경계조건을 부여한다. /// - X min 값 : 0 /// - Mesh : AutoMesh face.setOutsideBoundary(femm, 0, maxY + padLength + dPlusMovingStroke, maxX + padLength, minY - padLength + dMinusMovingStroke, 0); /// 내부 Region 은 경계조건과 상관없이 메쉬만를 위해 추가하였다. /// 내부 Region 의 메쉬 크기는 기본 메쉬의 3배로 설정한다. const double dRatioRegion = 5.0f; /// 내부 Region 을 생성한다. /// - X min 값 : 0 /// - Mesh : 지정메쉬 * 3.0f face.setInsideRegion(femm, 0, maxY + padLengthY / dRatioRegion + dPlusMovingStroke, maxX + padLengthX / dRatioRegion, minY - padLengthY / dRatioRegion + dMinusMovingStroke, dMeshSize * 3.0f); }
public void setBlockProp(CScriptFEMM femm, double dMeshSize) { CPoint blockPoint = null; blockPoint = this.Face.getBlockPoint(); if (blockPoint == null) { CNotice.printTraceID("NBPF"); return; } string strMaterialName = this.m_strMaterial; femm.setBlockProp(blockPoint, strMaterialName, dMeshSize, "none", 0, MovingPart, 0); }
public void drawDesign(CScriptFEMM femm) { foreach (CDataNode node in GetNodeList) { if (node.GetType().BaseType.Name == "CShapeParts") { CShapeParts nodeParts = (CShapeParts)node; if (null != nodeParts.Face) nodeParts.Face.drawFace(femm, nodeParts.MovingPart); else CNotice.printLogID("YATT1"); } } femm.zoomFit(); }
public void setBlockPropeties(CScriptFEMM femm, double dVolt, double dMeshSizePercent) { // MeshSizePercent 에 문제가 있으면 1% 로 초기화 한다. if (dMeshSizePercent <= 0) { dMeshSizePercent = 1; } // Mesh Size 는 길이단위이기 때문에 면적을 루트 취한 값과 곱하고 있다. double dMeshSize = Math.Sqrt(this.calcShapeModelArea()) * dMeshSizePercent / 100.0f; foreach (CNode node in NodeList) { switch (node.m_kindKey) { case EMKind.COIL: double dCurrent; double dResistance = getSerialResistance(); // 전류 계산 if (dResistance != 0.0f) { dCurrent = dVolt / dResistance; } else { dCurrent = 0.0f; } ((CCoil)node).setBlockPropCurrent(femm, dCurrent, dMeshSize); break; case EMKind.MAGNET: ((CMagnet)node).setBlockProp(femm, dMeshSize); break; case EMKind.STEEL: ((CSteel)node).setBlockProp(femm, dMeshSize); break; default: break; } } }
/// <summary> /// 해석 모델안으로 사용하는 재질들을 추가한다. /// </summary> /// <param name="femm"></param> public void addMaterials(CScriptFEMM femm) { // 겹치는 재질을 제외하기 위해 사용한다. List<string> listTempMaterial = new List<string>(); string strMaterial = "Air"; bool bCheck; // Air 는 무조건 사용하기 때문에 여기서 우선적으로 추가해 둔다. femm.addMaterial(strMaterial); listTempMaterial.Add(strMaterial); foreach (CDataNode node in GetNodeList) { bCheck = false; if (node.GetType().BaseType.Name == "CShapeParts") { strMaterial = ((CShapeParts)node).getMaterial(); /// 현 파트의 재료가 기존에 저장된 Material 과 겹치는지를 확인한다. foreach (string strTemp in listTempMaterial) if (strTemp == strMaterial) bCheck = true; // 겹치지 않는 재료만 추가한다. if (bCheck == false) { femm.addMaterial(strMaterial); listTempMaterial.Add(strMaterial); // 발생해서는 안되는 상황이 발생하는 경우 if(strMaterial == "") { CNotice.printLog("재질이 설정되지 않는 파트가 존재해 해석 오류가 발생한다."); } } } } }
public void setBlockProp(CScriptFEMM femm, double dMeshSize) { CPoint blockPoint = null; blockPoint = this.Face.getBlockPoint(); if (blockPoint == null) { CNotice.printTraceID("NBPF"); return; } string strMaterialName = this.m_strMaterial; double dMagnetAngle = 0; switch (emMagnetDirection) { case EMMagnetDirection.RIGHT: dMagnetAngle = 0; break; case EMMagnetDirection.UP: dMagnetAngle = 90; break; case EMMagnetDirection.LEFT: dMagnetAngle = 180; break; case EMMagnetDirection.DOWN: dMagnetAngle = 270; break; default: break; } femm.setBlockProp(blockPoint, strMaterialName, dMeshSize, "none", dMagnetAngle, MovingPart, 0); }
public void changeCurrent(CScriptFEMM femm, double dCurrent, double dMeshSizePercent) { // MeshSizePercent 에 문제가 있으면 1% 로 초기화 한다. if (dMeshSizePercent <= 0) dMeshSizePercent = 1; // Mesh Size 는 길이단위이기 때문에 면적을 루트 취한 값과 곱하고 있다. double dMeshSize = Math.Sqrt(this.calcShapeModelAverageArea()) * dMeshSizePercent / 100.0f; foreach (CDataNode node in GetNodeList) { switch (node.KindKey) { case EMKind.COIL: ((CCoil)node).setBlockPropCurrent(femm, dCurrent, dMeshSize); break; default: break; } } }
public void getMaterial(CScriptFEMM femm) { List <string> listMaterial = new List <string>(); string strMaterial = "Air"; CParts nodeParts = null; bool bCheck; femm.getMaterial(strMaterial); listMaterial.Add(strMaterial); foreach (CNode node in NodeList) { bCheck = false; if (node.GetType().BaseType.Name == "CParts") { nodeParts = (CParts)node; strMaterial = nodeParts.getMaterial(); /// 현 파트의 재료가 기존에 저장된 Material 과 겹치는지를 확인한다. foreach (string strTemp in listMaterial) { if (strTemp == strMaterial) { bCheck = true; } } // 겹치지 않는 재료만 추가한다. if (bCheck == false) { listMaterial.Add(strMaterial); femm.getMaterial(nodeParts.getMaterial()); } } } }
/// <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); } }
public void buttonDraw_Click(object sender, EventArgs e) { try { /// 완벽한 입력인 상태에서만 Draw 가 가능한다. bool retOK = isInputDataOK(); if (retOK == false) { return; } /// [문제] /// - Form 에서는 Parent를 사용할 수 없어 Owner 속성을 사용하지만 /// 종종 Owner 가 null 로 넘어오는 문제가 발생한다. /// [해결] /// - PopupShape 창을 생성하기 전에 Owner 속성을 FormMain 으로 초기화 해 두어야 /// 확실하게 FormMain 을 얻을 수 있다. FormMain formMain = ((FormMain)this.Owner); if (formMain == null) { CNotice.printLogID("CNGM"); return; } /// 형상 유효성 확인을 위해 임시로 생성한다. /// CFace faceTemp = makeFaceInPopup(); if (faceTemp == null) { CNotice.noticeWarningID("TWAP1"); return; } if (false == faceTemp.isShapeOK()) { CNotice.printLogID("TWAP3"); return; } CScriptFEMM femm = formMain.m_femm; 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); } } } // FEMM 을 최상위로 올린다. CProgramFEMM.showFEMM(); // 혹시 FEMM 의 화면이 닫힌 경우 FEMM 의 화면을 복원합니다. formMain.reopenFEMM(); /// 2. 작업중인 Face 형상 그리기 faceTemp.drawFace(femm); } catch (Exception ex) { CNotice.printLog(ex.Message); } }
public void redrawDesign(CScriptFEMM femm) { femm.deleteAll(); drawDesign(femm); }