using CoreUnit.Common; using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Text.Json; using System.Windows.Forms; using System.Xml; namespace CoreUnit.Control.UserControl.Canvas { public class SnowMan : DrawObjectBase, IDrawObject, ISerialize { UnitPoint m_p1, m_p2; [Browsable(false)] public UnitPoint Center { get { return new UnitPoint(MiddlePoint); } set { MiddlePoint = ((UnitPoint)value).Point; } } [Browsable(false)] public UnitPoint P1 { get { return m_p1; } set { m_p1 = value; } } [Browsable(false)] public UnitPoint P2 { get { return m_p2; } set { m_p2 = value; } } public static string ObjectType { get { return "SnowMan"; } } public SnowMan() { } public SnowMan(UnitPoint point, UnitPoint endpoint, float width, Color color) { P1 = point; P2 = endpoint; Width = width; Color = color; Selected = false; m_circumferenceHead = CalculateCircumference(Rh1, Rw1); m_circumferenceBody = CalculateCircumference(Rh2, Rw2); CreateWobbelVectorPointList(); } public override void InitializeFromModel(UnitPoint point, DrawingLayer layer, ISnapPoint snap) { P1 = P2 = point; Width = layer.Width; Color = layer.Color; Selected = true; } static int ThresholdPixel = 6; static float ThresholdWidth(ICanvas canvas, float objectwidth) { return ThresholdWidth(canvas, objectwidth, ThresholdPixel); } public static float ThresholdWidth(ICanvas canvas, float objectwidth, float pixelwidth) { double minWidth = canvas.ToUnit(pixelwidth); double width = Math.Max(objectwidth / 2, minWidth); return (float)width; } public virtual void Copy(SnowMan acopy) { base.Copy(acopy); P1 = acopy.P1; P2 = acopy.P2; Type = acopy.Type; m_no = acopy.m_no; //마킹객체에 대한 속성 복사 ScannerParamNo = acopy.ScannerParamNo; Enabled = acopy.Enabled; Selected = acopy.Selected; //Snowman 속성 TiltingAngle = acopy.TiltingAngle; m_horizontalRadiusofHead = acopy.Rh1; m_verticalRadiusofHead = acopy.Rw1; m_horizontalRadiusofBody = acopy.Rh2; m_verticalRadiusofBody = acopy.Rw2; m_velocityOfHead = acopy.HeadSpeed; m_velocityOfBody = acopy.BodySpeed; m_controlType = acopy.ControlType; m_drawWay = acopy.DrawWay; m_vectorCount = acopy.VectorCount; m_circumferenceHead = CalculateCircumference(Rh1, Rw1); m_circumferenceBody = CalculateCircumference(Rh2, Rw2); CreateWobbelVectorPointList(); } #region IDrawObject Members #region 마킹객체에 대한 속성 bool m_enabled = true; [Browsable(true)] [ReadOnly(false)] [Category("3. Marking Parameter")] [DisplayName("용접 작업 유무")] [Description("용접 작업 진행 여부")] [XmlSerializable] public bool Enabled { get { return m_enabled; } set { m_enabled = value; } } int m_scannerParamNo = 0; [Browsable(false)] [ReadOnly(false)] [Category("3. Marking Parameter")] [DisplayName("용접 조건 번호")] [Description("용접 조건(스캔속도 및 레이저 파워 값등..) 번호 설정")] [XmlSerializable] public int ScannerParamNo { get { return m_scannerParamNo; } set { m_scannerParamNo = value; } } [Browsable(true)] [ReadOnly(false)] [Category("3. Marking Parameter")] [DisplayName("용접 조건 ID")] [Description("용접 조건(스캔속도 및 레이저 파워 값등..) ID 설정")] [XmlSerializable] public int ScannerParamID { get { return m_scannerParamNo + 1; } set { m_scannerParamNo = value - 1; } } [Browsable(true)] [ReadOnly(false)] [Category("Pen")] [DisplayName("Parameter ID")] [Description("Welding Paramter ID")] [Editor(typeof(WeldingParameterIDEditor.WeldingParamterNoUITypeEditor), typeof(System.Drawing.Design.UITypeEditor))] [XmlSerializable] public WeldingParameterIDEditor.eWeldingParamterID WeldingParameterID { get { return (WeldingParameterIDEditor.eWeldingParamterID)ScannerParamID; } set { ScannerParamID = (int)value; } } #endregion #region 드로잉 객체에 대한 속성 int m_no; [Browsable(false)] [XmlSerializable] public int No { get { return m_no; } set { m_no = value; } } string m_type; [Browsable(true)] [ReadOnly(true)] [Category("1. 객체")] [DisplayName("종류")] [Description("드로잉 객체 종류")] [XmlSerializable] public string Type { get { m_type = SnowMan.ObjectType; return m_type; } set { m_type = value; } } [Browsable(true)] [ReadOnly(false)] [Category("2. GEOMETRY")] [DisplayName("1.시작점[X,Y](mm)")] [Description("드로잉 객체의 시작점")] [TypeConverter(typeof(PointFConverter))] [XmlSerializable] public PointF PF1 { get { lock (this) { return P1.Point; } } set { lock (this) { P1 = new UnitPoint(value); } } } [Browsable(true)] [ReadOnly(false)] [Category("2. GEOMETRY")] [DisplayName("2.종료점[X,Y](mm)")] [Description("드로잉 객체의 종료점")] [TypeConverter(typeof(PointFConverter))] [XmlSerializable] public PointF PF2 { get { lock (this) { return P2.Point; } } set { lock (this) { P2 = new UnitPoint(value); } } } [Browsable(true)] [ReadOnly(false)] [Category("2. GEOMETRY")] [DisplayName("3.중심점[X,Y](mm)")] [Description("드로잉 객체의 중심점")] [TypeConverter(typeof(PointFConverter))] public PointF MiddlePoint { get { return HitUtil.LineMidpoint(P1, P2).Point; } set { PointF offset = new PointF(); offset.X = (value.X - MiddlePoint.X); offset.Y = (value.Y - MiddlePoint.Y); Move(new UnitPoint(offset)); } } [Browsable(true)] [ReadOnly(false)] [Category("2. GEOMETRY")] [DisplayName("4.각도(˚)")] [Description("드로잉 객체의 각도")] public float Angle { get { return (float)Math.Round(HitUtil.RadiansToDegrees(HitUtil.LineAngleR(P1, P2, 0)), 3); } set { float angle = value - Angle; Rotate(angle, Center); } } [Browsable(true)] [ReadOnly(true)] [Category("Boundary")] [DisplayName("Left,Bottom,Right,Top")] [Description("Boundary of Object")] [TypeConverter(typeof(RectangleFConverter))] public RectangleF ClientRect { get { lock (this) { return ScreenUtils.GetRect(P1, P2, 0); } } } [Browsable(true)] [ReadOnly(false)] [Category("2. GEOMETRY")] [DisplayName("6.길이(mm)")] [Description("드로잉 객체의 길이")] public double Distance { get { return Math.Round(HitUtil.Distance(P1, P2), 3); } set { double distance = value; MakeLength((float)distance); } } double m_tiltingAngle = 0; [Browsable(true)] [ReadOnly(false)] [Category("3. SnowMan")] [DisplayName("01.Angle(degree)")] [Description("Tilting Angle of SnowMan by degree")] [XmlSerializable] public double TiltingAngle { get { return m_tiltingAngle; } set { m_tiltingAngle = value; } } double m_horizontalRadiusofHead = 1; [Browsable(true)] [ReadOnly(false)] [Category("3. SnowMan")] [DisplayName("02.Rh1(mm)")] [Description("Horizontal Radius of Head Ellipse(0.1mm ~ 10mm)")] [XmlSerializable] public double Rh1 { get { return m_horizontalRadiusofHead; } set { m_horizontalRadiusofHead = value; m_circumferenceHead = CalculateCircumference(m_horizontalRadiusofHead, m_verticalRadiusofHead); CreateWobbelVectorPointList(); } } double m_verticalRadiusofHead = 1; [Browsable(true)] [ReadOnly(false)] [Category("3. SnowMan")] [DisplayName("03.Rw1(mm)")] [Description("Vertical Radius of Head Ellipse(0.1mm ~ 10mm)")] [XmlSerializable] public double Rw1 { get { return m_verticalRadiusofHead; } set { m_verticalRadiusofHead = value; m_circumferenceHead = CalculateCircumference(m_horizontalRadiusofHead, m_verticalRadiusofHead); CreateWobbelVectorPointList(); } } double m_horizontalRadiusofBody = 1; [Browsable(true)] [ReadOnly(false)] [Category("3. SnowMan")] [DisplayName("04.Rh2(mm)")] [Description("Horizontal Radius of Body Ellipse(0.1mm ~ 10mm)")] [XmlSerializable] public double Rh2 { get { return m_horizontalRadiusofBody; } set { m_horizontalRadiusofBody = value; m_circumferenceBody = CalculateCircumference(m_horizontalRadiusofBody, m_verticalRadiusofBody); CreateWobbelVectorPointList(); } } double m_verticalRadiusofBody = 1; [Browsable(true)] [ReadOnly(false)] [Category("3. SnowMan")] [DisplayName("05.Rw2(mm)")] [Description("Vertical Radius of Body Ellipse(0.1mm ~ 10mm)")] [XmlSerializable] public double Rw2 { get { return m_verticalRadiusofBody; } set { m_verticalRadiusofBody = value; m_circumferenceBody = CalculateCircumference(m_horizontalRadiusofBody, m_verticalRadiusofBody); CreateWobbelVectorPointList(); } } double m_velocityOfHead = 1; [Browsable(true)] [ReadOnly(false)] [Category("3. SnowMan")] [DisplayName("06.Head Speed")] [Description("Angular Speed Control : deg/s\nLine Speed Control : mm/s")] [XmlSerializable] public double HeadSpeed { get { return m_velocityOfHead; } set { m_velocityOfHead = value; CreateWobbelVectorPointList(); } } double m_velocityOfBody = 1; [Browsable(true)] [ReadOnly(false)] [Category("3. SnowMan")] [DisplayName("07.Body Speed")] [Description("Angular Speed Control : deg/s\nLine Speed Control : mm/s")] [XmlSerializable] public double BodySpeed { get { return m_velocityOfBody; } set { m_velocityOfBody = value; CreateWobbelVectorPointList(); } } public enum eControlType { AngularSpeedControl = 1, LineSpeedControl = 2 } eControlType m_controlType = eControlType.AngularSpeedControl; [Browsable(true)] [ReadOnly(false)] [Category("3. SnowMan")] [DisplayName("08.Control Type")] [Description("Control Type(Angular or Line)")] [XmlSerializable] public eControlType ControlType { get { return m_controlType; } set { m_controlType = value; CreateWobbelVectorPointList(); } } public enum eDrawWay { Left = 1, Right = 2 } eDrawWay m_drawWay = eDrawWay.Left; [Browsable(true)] [ReadOnly(false)] [Category("3. SnowMan")] [DisplayName("09.Draw Way")] [Description("Draw Way(Left or Right)")] [XmlSerializable] public eDrawWay DrawWay { get { return m_drawWay; } set { m_drawWay = value; CreateWobbelVectorPointList(); } } double m_circumferenceHead = 1; [Browsable(true)] [ReadOnly(true)] [Category("3. SnowMan")] [DisplayName("10.Ch")] [Description("Circumference length of Head")] public double Ch { get { return m_circumferenceHead; } } double m_circumferenceBody = 1; [Browsable(true)] [ReadOnly(true)] [Category("3. SnowMan")] [DisplayName("11.Cb")] [Description("Circumference length of Body")] public double Cb { get { return m_circumferenceBody; } } private double CalculateCircumference(double a, double b) { //타원의 둘레 길이 구하기 //타원의 적분은 일반적으로 할 수 없고, 근사값으로 구함 int iterationCount = 100000; double dx = a / iterationCount; double sum = 0; for (int i = 0; i < iterationCount - 1; i++) { double x = (i + 1) * dx; sum += dx * Math.Sqrt(1 + Math.Pow(b / a, 2) * Math.Pow(x, 2) / (Math.Pow(a, 2) - Math.Pow(x, 2))); } return 4 * sum; } [Browsable(true)] [ReadOnly(true)] [Category("3. SnowMan")] [DisplayName("13.Cycle Time of Head")] [Description("Cycle Time of Head")] public double HeadCycleTime { get { if (ControlType == eControlType.AngularSpeedControl) { return 360 / HeadSpeed; } else { return Ch / HeadSpeed; } } } [Browsable(true)] [ReadOnly(true)] [Category("3. SnowMan")] [DisplayName("14.Cycle Time of Body")] [Description("Cycle Time of Body")] public double BodyCycleTime { get { if (ControlType == eControlType.AngularSpeedControl) { return 360 / BodySpeed; } else { return Cb / BodySpeed; } } } [Browsable(true)] [ReadOnly(true)] [Category("3. SnowMan")] [DisplayName("15.Cycle Time of SnowMan")] [Description("Cycle Time of SnowMan")] public double SnowManCycleTime { get { return HeadCycleTime + BodyCycleTime; } } eVectorCount m_vectorCount = eVectorCount.C200; public enum eVectorCount { C50 = 50, C100 = 100, C150 = 150, C200 = 200 } [Browsable(true)] [ReadOnly(false)] [Category("3. SnowMan")] [DisplayName("16.Vector Count")] [Description("Head And Body can have Upto 256 Count")] [XmlSerializable] public eVectorCount VectorCount { get { return m_vectorCount; } set { m_vectorCount = value; CreateWobbelVectorPointList(); } } [Browsable(true)] [ReadOnly(true)] [Category("4. Head Wobbel Vector")] [DisplayName("1.Period")] [Description("period per Vector")] public double HeadPeriod { get { return (HeadCycleTime / (int)VectorCount) * 100 * 1000; } } [Browsable(true)] [ReadOnly(true)] [Category("4. Head Wobbel Vector")] [DisplayName("2.Vector Angle")] [Description("Vector Angle")] public double HeadVectorAngle { get { return 2 * Math.PI / (int)VectorCount; } } protected List m_headPoint = new List(); [Browsable(true)] [ReadOnly(true)] [Category("4. Head Wobbel Vector")] [DisplayName("3.Head Point")] [Description("X : dTrans, Y: dLong")] public List HeadPoint { get { return m_headPoint; } set { m_headPoint = value; } } [Browsable(true)] [ReadOnly(true)] [Category("5. Body Wobbel Vector")] [DisplayName("1.Period")] [Description("period per Vector")] public double BodyPeriod { get { return (BodyCycleTime / (int)VectorCount) * 100 * 1000; } } [Browsable(true)] [ReadOnly(true)] [Category("5. Body Wobbel Vector")] [DisplayName("2.Vector Angle")] [Description("Vector Angle")] public double BodyVectorAngle { get { return 2 * Math.PI / (int)VectorCount; } } protected List m_bodyPoint = new List(); [Browsable(true)] [ReadOnly(true)] [Category("5. Body Wobbel Vector")] [DisplayName("3.Body Point")] [Description("X : dTrans, Y: dLong")] public List BodyPoint { get { return m_bodyPoint; } set { m_bodyPoint = value; } } private void CreateWobbelVectorPointList() { m_headPoint.Clear(); m_bodyPoint.Clear(); double xPoint = 0; double yPoint = 0; double radius = 0; //각속도 제어 if (ControlType == eControlType.AngularSpeedControl) { m_headPoint.Add(new PointF(0, 0)); m_bodyPoint.Add(new PointF(0, 0)); //Head Wobbel vector 설정 for (int i = 0; i < (int)VectorCount; i++) { double term1 = (Math.Pow(Math.Cos((i + 1) * HeadVectorAngle), 2)) / (Math.Pow(Rh1, 2)); double term2 = (Math.Pow(Math.Sin((i + 1) * HeadVectorAngle), 2)) / (Math.Pow(Rw1, 2)); radius = Math.Sqrt(1 / (term1 + term2)); if (DrawWay == eDrawWay.Left) { xPoint = radius * Math.Cos((i + 1) * HeadVectorAngle) - Rh1; yPoint = radius * Math.Sin((i + 1) * HeadVectorAngle); } else { xPoint = radius * Math.Cos(Math.PI - (i + 1) * HeadVectorAngle) + Rh1; yPoint = radius * Math.Sin(Math.PI - (i + 1) * HeadVectorAngle); } m_headPoint.Add(new PointF((float)xPoint, (float)yPoint)); } //body Wobbel vector 설정 for (int i = 0; i < (int)VectorCount; i++) { double term1 = (Math.Pow(Math.Cos((i + 1) * BodyVectorAngle), 2)) / (Math.Pow(Rh2, 2)); double term2 = (Math.Pow(Math.Sin((i + 1) * BodyVectorAngle), 2)) / (Math.Pow(Rw2, 2)); radius = Math.Sqrt(1 / (term1 + term2)); if (DrawWay == eDrawWay.Left) { xPoint = radius * Math.Cos(Math.PI - (i + 1) * BodyVectorAngle) + Rh2; yPoint = radius * Math.Sin(Math.PI - (i + 1) * BodyVectorAngle); } else { xPoint = radius * Math.Cos((i + 1) * BodyVectorAngle) - Rh2; yPoint = radius * Math.Sin((i + 1) * BodyVectorAngle); } m_bodyPoint.Add(new PointF((float)xPoint, (float)yPoint)); } } else { if (DrawWay == eDrawWay.Left) { //Head m_headPoint.Add(new PointF(0, 0)); xLower = -2 * Rh1; xUpper = 0; int quadrant = 2; for (int i = 0; i < (int)VectorCount / 2 - 1; i++) { double x2, y2; x2 = FindX2(m_headPoint[i].X, m_headPoint[i].Y, Rh1, Rw1, Ch / (int)VectorCount, quadrant); y2 = FindY2(x2, quadrant, Rh1, Rw1); m_headPoint.Add(new PointF((float)x2, (float)y2)); } m_headPoint.Add(new PointF((float)(-2 * Rh1), 0)); xLower = -2 * Rh1; xUpper = 0; quadrant = 3; for (int i = (int)VectorCount / 2; i < (int)VectorCount; i++) { double x2, y2; x2 = FindX2(m_headPoint[i].X, m_headPoint[i].Y, Rh1, Rw1, Ch / (int)VectorCount, quadrant); y2 = FindY2(x2, quadrant, Rh1, Rw1); m_headPoint.Add(new PointF((float)x2, (float)y2)); } // Body m_bodyPoint.Add(new PointF(0, 0)); xLower = 0; xUpper = 2 * Rh2; quadrant = 1; for (int i = 0; i < (int)VectorCount / 2 - 1; i++) { double x2, y2; x2 = FindX2(m_bodyPoint[i].X, m_bodyPoint[i].Y, Rh2, Rw2, Cb / (int)VectorCount, quadrant); y2 = FindY2(x2, quadrant, Rh2, Rw2); m_bodyPoint.Add(new PointF((float)x2, (float)y2)); } m_bodyPoint.Add(new PointF((float)(2 * Rh2), 0)); xLower = 0; xUpper = 2 * Rh2; quadrant = 4; for (int i = (int)VectorCount / 2; i < (int)VectorCount; i++) { double x2, y2; x2 = FindX2(m_bodyPoint[i].X, m_bodyPoint[i].Y, Rh2, Rw2, Cb / (int)VectorCount, quadrant); y2 = FindY2(x2, quadrant, Rh2, Rw2); m_bodyPoint.Add(new PointF((float)x2, (float)y2)); } } else { //Head m_headPoint.Add(new PointF(0, 0)); xLower = 0; xUpper = 2 * Rh1; int quadrant = 1; for (int i = 0; i < (int)VectorCount / 2 - 1; i++) { double x2, y2; x2 = FindX2(m_headPoint[i].X, m_headPoint[i].Y, Rh1, Rw1, Ch / (int)VectorCount, quadrant); y2 = FindY2(x2, quadrant, Rh1, Rw1); m_headPoint.Add(new PointF((float)x2, (float)y2)); } m_headPoint.Add(new PointF((float)(2 * Rh1), 0)); xLower = 0; xUpper = 2 * Rh1; quadrant = 4; for (int i = (int)VectorCount / 2; i < (int)VectorCount; i++) { double x2, y2; x2 = FindX2(m_headPoint[i].X, m_headPoint[i].Y, Rh1, Rw1, Ch / (int)VectorCount, quadrant); y2 = FindY2(x2, quadrant, Rh1, Rw1); m_headPoint.Add(new PointF((float)x2, (float)y2)); } // Body m_bodyPoint.Add(new PointF(0, 0)); xLower = -2 * Rh2; xUpper = 0; quadrant = 2; for (int i = 0; i < (int)VectorCount / 2 - 1; i++) { double x2, y2; x2 = FindX2(m_bodyPoint[i].X, m_bodyPoint[i].Y, Rh2, Rw2, Cb / (int)VectorCount, quadrant); y2 = FindY2(x2, quadrant, Rh2, Rw2); m_bodyPoint.Add(new PointF((float)x2, (float)y2)); } m_bodyPoint.Add(new PointF((float)(-2 * Rh2), 0)); xLower = -2 * Rh2; xUpper = 0; quadrant = 3; for (int i = (int)VectorCount / 2; i < (int)VectorCount; i++) { double x2, y2; x2 = FindX2(m_bodyPoint[i].X, m_bodyPoint[i].Y, Rh2, Rw2, Cb / (int)VectorCount, quadrant); y2 = FindY2(x2, quadrant, Rh2, Rw2); m_bodyPoint.Add(new PointF((float)x2, (float)y2)); } } } } //수치해석용 변수 double xLower = 0; double xUpper = 0; private double FindX2(double x1, double y1, double A, double B, double L, int quadrant) { int i = 1; double xReal = xLower;//첫시작 double xRold; double error = 0; while (true) { double test = Function2(x1, y1, xLower, L, quadrant, A, B) * Function2(x1, y1, xUpper, L, quadrant, A, B); if (test > 0) { break; } else { xRold = xReal; xReal = (xLower + xUpper) / 2; //이분법에서 해는 구간 양끝의 중점 error = (xReal - xRold) / xReal; //근사오차 double test2 = Function2(x1, y1, xReal, L, quadrant, A, B) * Function2(x1, y1, xLower, L, quadrant, A, B); if (test2 < 0) { xUpper = xReal; } else { xLower = xReal; } string Check = string.Format("xLower = {0:f3}, xUpper = {1:f3}, xReal = {2:f3}, error = {3:f3}", xLower, xUpper, xReal, error); i = i + 1; } if ((i > 1000) || Math.Abs(error) < 0.00001)//iteration 최대치에 도달하거나 Error 가 허용오차보다 작은 경우 루프 탈출 { break; } } switch (quadrant) { case 1: xUpper = 2 * A; xLower = xReal; break; case 2: xUpper = xReal; xLower = -2 * A; break; case 3: xUpper = 0; xLower = xReal; break; case 4: xUpper = xReal; xLower = 0; break; } return xReal; } private double Function2(double x1, double y1, double x2, double length, int quadrant, double a, double b) { double y2 = 0; double f = 0; //사분면 정의 // | // 2 | 1 // | //--------------- // | // 3 | 4 // | switch (quadrant) { case 1: y2 = b * Math.Sqrt(1 - Math.Pow((x2 - a) / a, 2)); break; case 2: y2 = b * Math.Sqrt(1 - Math.Pow((x2 + a) / a, 2)); break; case 3: y2 = -b * Math.Sqrt(1 - Math.Pow((x2 + a) / a, 2)); break; case 4: y2 = -b * Math.Sqrt(1 - Math.Pow((x2 - a) / a, 2)); break; } f = Math.Sqrt(Math.Pow(x2 - x1, 2) + Math.Pow(y2 - y1, 2)) - length; return f; } private double FindY2(double x2, int quadrant, double a, double b) { double y2 = 0; switch (quadrant) { case 1: y2 = b * Math.Sqrt(1 - Math.Pow((x2 - a) / a, 2)); break; case 2: y2 = b * Math.Sqrt(1 - Math.Pow((x2 + a) / a, 2)); break; case 3: y2 = -b * Math.Sqrt(1 - Math.Pow((x2 + a) / a, 2)); break; case 4: y2 = -b * Math.Sqrt(1 - Math.Pow((x2 - a) / a, 2)); break; } return y2; } public void LoadWobbelVectorForHead(out List dTrans, out List dLong, int KFactor) { CreateWobbelVectorPointList(); dTrans = new List(); dLong = new List(); for (int i = 0; i < m_headPoint.Count - 1; i++) { dTrans.Add((m_headPoint[i + 1].X - m_headPoint[i].X) * KFactor / HeadPeriod);//dTrans = dx *kFactor /period dLong.Add((m_headPoint[i + 1].Y - m_headPoint[i].Y) * KFactor / HeadPeriod);//dTrans = dx *kFactor /period } } public void LoadWobbelVectorForBody(out List dTrans, out List dLong, int KFactor) { CreateWobbelVectorPointList(); dTrans = new List(); dLong = new List(); for (int i = 0; i < m_bodyPoint.Count - 1; i++) { dTrans.Add((m_bodyPoint[i + 1].X - m_bodyPoint[i].X) * KFactor / BodyPeriod);//dTrans = dx *kFactor /period dLong.Add((m_bodyPoint[i + 1].Y - m_bodyPoint[i].Y) * KFactor / BodyPeriod);//dTrans = dx *kFactor /period } } public virtual IDrawObject Clone() { SnowMan l = new SnowMan(); l.Copy(this); return l; } public RectangleF GetBoundingRect(ICanvas canvas) { float thWidth = ThresholdWidth(canvas, Width); return ScreenUtils.GetRect(P1, P2, thWidth); } private void DrawSnowMan(ICanvas canvas, Pen pen) { double angle = 0; if (DrawWay == eDrawWay.Left) { angle = (-Angle + 90 + TiltingAngle) * Math.PI / 180; } else { angle = (-Angle + 90 - TiltingAngle) * Math.PI / 180; } //1.SnowMan 그리기 for (int i = 0; i < m_headPoint.Count - 1; i++) { UnitPoint point1 = new UnitPoint(m_headPoint[i].X * Math.Cos(angle) + m_headPoint[i].Y * Math.Sin(angle) + P1.X, -m_headPoint[i].X * Math.Sin(angle) + m_headPoint[i].Y * Math.Cos(angle) + P1.Y); UnitPoint point2 = new UnitPoint(m_headPoint[i + 1].X * Math.Cos(angle) + m_headPoint[i + 1].Y * Math.Sin(angle) + P1.X, -m_headPoint[i + 1].X * Math.Sin(angle) + m_headPoint[i + 1].Y * Math.Cos(angle) + P1.Y); canvas.DrawLine(canvas, pen, point1, point2); } for (int i = 0; i < m_bodyPoint.Count - 1; i++) { UnitPoint point1 = new UnitPoint(m_bodyPoint[i].X * Math.Cos(angle) + m_bodyPoint[i].Y * Math.Sin(angle) + P1.X, -m_bodyPoint[i].X * Math.Sin(angle) + m_bodyPoint[i].Y * Math.Cos(angle) + P1.Y); UnitPoint point2 = new UnitPoint(m_bodyPoint[i + 1].X * Math.Cos(angle) + m_bodyPoint[i + 1].Y * Math.Sin(angle) + P1.X, -m_bodyPoint[i + 1].X * Math.Sin(angle) + m_bodyPoint[i + 1].Y * Math.Cos(angle) + P1.Y); canvas.DrawLine(canvas, pen, point1, point2); } //2. Head 표시하기 } public virtual void Draw(ICanvas canvas, RectangleF unitrect) { Color color = Color; color = WeldingParameterIDEditor.weldingColorList[(int)WeldingParameterID - 1]; Pen pen = canvas.CreatePen(color, Width); canvas.DrawLine(canvas, pen, P1, P2); if (canvas.CurrentObject == null) { DrawSnowMan(canvas, pen); DrawUtils.DrawArrowNode(canvas, P2, Angle, pen); } if (Highlighted) { canvas.DrawLine(canvas, DrawUtils.SelectedPen, P1, P2); } if (Selected) { canvas.DrawLine(canvas, DrawUtils.SelectedPen, P1, P2); if (P1.IsEmpty == false) { DrawUtils.DrawNode(canvas, P1); } if (P2.IsEmpty == false) { DrawUtils.DrawTriangleNode(canvas, P2); } } } UnitPoint MidPoint(ICanvas canvas, UnitPoint p1, UnitPoint p2, UnitPoint hitpoint) { UnitPoint mid = HitUtil.LineMidpoint(p1, p2); float thWidth = ThresholdWidth(canvas, Width); if (HitUtil.CircleHitPoint(mid, thWidth, hitpoint)) return mid; return UnitPoint.Empty; } public bool PointInObject(ICanvas canvas, UnitPoint point) { float thWidth = ThresholdWidth(canvas, Width); return HitUtil.IsPointInLine(P1, P2, point, thWidth); } public bool ObjectInRectangle(ICanvas canvas, RectangleF rect, bool anyPoint) { RectangleF boundingrect = GetBoundingRect(canvas); if (anyPoint) return HitUtil.LineIntersectWithRect(P1, P2, rect); return rect.Contains(boundingrect); } public virtual void OnMouseMove(ICanvas canvas, UnitPoint point) { P2 = point; } public virtual eDrawObjectMouseDown OnMouseDown(ICanvas canvas, UnitPoint point, ISnapPoint snappoint) { Selected = false; if (snappoint is PerpendicularSnapPoint && snappoint.Owner is Line) { Line src = snappoint.Owner as Line; P2 = HitUtil.NearestPointOnLine(src.P1, src.P2, P1, true); return eDrawObjectMouseDown.DoneRepeat; } if (snappoint is PerpendicularSnapPoint && snappoint.Owner is SnowMan) { SnowMan src = snappoint.Owner as SnowMan; P2 = HitUtil.NearestPointOnLine(src.P1, src.P2, P1, true); return eDrawObjectMouseDown.DoneRepeat; } if (snappoint is PerpendicularSnapPoint && snappoint.Owner is Dot) { Dot src = snappoint.Owner as Dot; P2 = HitUtil.NearestPointOnCircle(src.P1, src.Width, P1, 0); return eDrawObjectMouseDown.DoneRepeat; } if (snappoint is PerpendicularSnapPoint && snappoint.Owner is Spline) { Spline src = snappoint.Owner as Spline; P2 = HitUtil.NearestPointOnCircle(src.Center, src.Radius, P1, 0); return eDrawObjectMouseDown.DoneRepeat; } if (snappoint is PerpendicularSnapPoint && snappoint.Owner is Arc) { Arc src = snappoint.Owner as Arc; P2 = HitUtil.NearestPointOnCircle(src.Center, src.Radius, P1, 0); return eDrawObjectMouseDown.DoneRepeat; } if (System.Windows.Forms.Control.ModifierKeys == Keys.Control) point = HitUtil.OrthoPointD(P1, point, 45); P2 = point; return eDrawObjectMouseDown.DoneRepeat; } public void OnMouseUp(ICanvas canvas, UnitPoint point, ISnapPoint snappoint) { } public virtual void OnKeyDown(ICanvas canvas, KeyEventArgs e) { } [Browsable(false)] public UnitPoint RepeatStartingPoint { get { return P2; } } public INodePoint NodePoint(ICanvas canvas, UnitPoint point) { float thWidth = ThresholdWidth(canvas, Width); if (HitUtil.CircleHitPoint(P1, thWidth, point)) { return new NodePointSnowMan(this, NodePointSnowMan.ePoint.P1); } if (HitUtil.CircleHitPoint(P2, thWidth, point)) { return new NodePointSnowMan(this, NodePointSnowMan.ePoint.P2); } return null; } public ISnapPoint SnapPoint(ICanvas canvas, UnitPoint point, List otherobjs, Type[] runningsnaptypes, Type usersnaptype) { float thWidth = ThresholdWidth(canvas, Width); if (runningsnaptypes != null) { foreach (Type snaptype in runningsnaptypes) { if (snaptype == typeof(VertextSnapPoint)) { if (HitUtil.CircleHitPoint(P1, thWidth, point)) return new VertextSnapPoint(canvas, this, P1); if (HitUtil.CircleHitPoint(P2, thWidth, point)) return new VertextSnapPoint(canvas, this, P2); } if (snaptype == typeof(MidpointSnapPoint)) { UnitPoint p = MidPoint(canvas, P1, P2, point); if (p != UnitPoint.Empty) return new MidpointSnapPoint(canvas, this, p); } if (snaptype == typeof(IntersectSnapPoint)) { SnowMan otherline = Utils.FindObjectTypeInList(this, otherobjs, typeof(SnowMan)) as SnowMan; if (otherline == null) continue; UnitPoint p = HitUtil.LinesIntersectPoint(P1, P2, otherline.P1, otherline.P2); if (p != UnitPoint.Empty) return new IntersectSnapPoint(canvas, this, p); } } return null; } if (usersnaptype == typeof(MidpointSnapPoint)) return new MidpointSnapPoint(canvas, this, HitUtil.LineMidpoint(P1, P2)); if (usersnaptype == typeof(IntersectSnapPoint)) { SnowMan otherline = Utils.FindObjectTypeInList(this, otherobjs, typeof(SnowMan)) as SnowMan; if (otherline == null) return null; UnitPoint p = HitUtil.LinesIntersectPoint(P1, P2, otherline.P1, otherline.P2); if (p != UnitPoint.Empty) return new IntersectSnapPoint(canvas, this, p); } if (usersnaptype == typeof(VertextSnapPoint)) { double d1 = HitUtil.Distance(point, P1); double d2 = HitUtil.Distance(point, P2); if (d1 <= d2) return new VertextSnapPoint(canvas, this, P1); return new VertextSnapPoint(canvas, this, P2); } if (usersnaptype == typeof(NearestSnapPoint)) { UnitPoint p = HitUtil.NearestPointOnLine(P1, P2, point); if (p != UnitPoint.Empty) return new NearestSnapPoint(canvas, this, p); } if (usersnaptype == typeof(PerpendicularSnapPoint)) { UnitPoint p = HitUtil.NearestPointOnLine(P1, P2, point); if (p != UnitPoint.Empty) return new PerpendicularSnapPoint(canvas, this, p); } return null; } public void Move(UnitPoint offset) { m_p1.X += offset.X; m_p1.Y += offset.Y; m_p2.X += offset.X; m_p2.Y += offset.Y; } public void Rotate(float angle, UnitPoint center) { // UnitPoint mid = Center; P1 = HitUtil.RotatePoint(angle, P1, center); P2 = HitUtil.RotatePoint(angle, P2, center); } public void MakeLength(float distance) { float slope = 0; double gapX = 0; double gapY = 0; if (P1.X != P2.X) { slope = (float)((P2.Y - P1.Y) / (P2.X - P1.X)); gapX = distance / (2 * Math.Sqrt(Math.Pow(slope, 2) + 1)); gapY = (distance * slope) / (2 * Math.Sqrt(Math.Pow(slope, 2) + 1)); } else { gapY = distance * 0.5; } PointF pt1 = new PointF(); PointF pt2 = new PointF(); //수정-안오산-161017-길이 수정시 방향 전환 오류 수정 if (P1.X > P2.X) { pt1.X = (float)(MiddlePoint.X + gapX); pt2.X = (float)(MiddlePoint.X - gapX); } else { pt1.X = (float)(MiddlePoint.X - gapX); pt2.X = (float)(MiddlePoint.X + gapX); } if (P1.Y > P2.Y) { pt1.Y = (float)(MiddlePoint.Y + gapY); pt2.Y = (float)(MiddlePoint.Y - gapY); } else { pt1.Y = (float)(MiddlePoint.Y - gapY); pt2.Y = (float)(MiddlePoint.Y + gapY); } P1 = new UnitPoint(pt1.X, pt1.Y); P2 = new UnitPoint(pt2.X, pt2.Y); } public virtual string GetInfoAsString() { return string.Format("{1:D3} {0}@{2},{3} - L={4:f4} <{5:f4}", this.Type, No + 1, P1.PosAsString(), P2.PosAsString(), Distance, Angle); } #endregion #endregion #region ISerialize public void GetObjectData(XmlWriter wr) { wr.WriteStartElement("SnowMan"); XmlUtil.WriteProperties(this, wr); wr.WriteEndElement(); } public virtual string GetObjectData() { string jsonString = string.Empty; var options = new JsonSerializerOptions { WriteIndented = true }; try { jsonString += JsonSerializer.Serialize(this, options); } catch { } return jsonString; } public void AfterSerializedIn() { } #endregion } public class NodePointSnowMan : INodePoint { public enum ePoint { P1, P2, } static bool m_angleLocked = false; SnowMan m_owner; SnowMan m_clone; UnitPoint m_originalPoint; public UnitPoint OriginalPoint { get { lock (this) { return m_originalPoint; } } set { lock (this) { m_originalPoint = value; } } } UnitPoint m_endPoint; public UnitPoint EndPoint { get { lock (this) { return m_endPoint; } } set { lock (this) { m_endPoint = value; } } } ePoint m_pointId; public ePoint PointId { get { lock (this) { return m_pointId; } } set { lock (this) { m_pointId = value; } } } public NodePointSnowMan(SnowMan owner, ePoint id) { m_owner = owner; m_clone = m_owner.Clone() as SnowMan; m_pointId = id; m_originalPoint = GetPoint(m_pointId); } #region INodePoint Members public IDrawObject GetClone() { return m_clone; } public IDrawObject GetOriginal() { return m_owner; } public void SetPosition(UnitPoint pos) { if (System.Windows.Forms.Control.ModifierKeys == Keys.Control) pos = HitUtil.OrthoPointD(OtherPoint(m_pointId), pos, 45); if (m_angleLocked || System.Windows.Forms.Control.ModifierKeys == (Keys)(Keys.Control | Keys.Shift)) pos = HitUtil.NearestPointOnLine(m_owner.P1, m_owner.P2, pos, true); SetPoint(m_pointId, pos, m_clone); } public void Finish() { m_endPoint = GetPoint(m_pointId); m_owner.P1 = m_clone.P1; m_owner.P2 = m_clone.P2; m_clone = null; } public void Cancel() { } public void Undo() { SetPoint(m_pointId, m_originalPoint, m_owner); } public void Redo() { SetPoint(m_pointId, m_endPoint, m_owner); } public void OnKeyDown(ICanvas canvas, KeyEventArgs e) { if (e.KeyCode == Keys.L) { m_angleLocked = !m_angleLocked; e.Handled = true; } } #endregion protected UnitPoint GetPoint(ePoint pointid) { if (pointid == ePoint.P1) return m_clone.P1; if (pointid == ePoint.P2) return m_clone.P2; return m_owner.P1; } protected UnitPoint OtherPoint(ePoint currentpointid) { if (currentpointid == ePoint.P1) return GetPoint(ePoint.P2); return GetPoint(ePoint.P1); } protected void SetPoint(ePoint pointid, UnitPoint point, SnowMan snowMan) { if (pointid == ePoint.P1) snowMan.P1 = point; if (pointid == ePoint.P2) snowMan.P2 = point; } } public class SnowManEdit : SnowMan, IObjectEditInstance { protected PerpendicularSnapPoint m_perSnap; protected TangentSnapPoint m_tanSnap; protected bool m_tanReverse = false; protected bool m_singleSnowManSegment = true; public new string Type { get { if (m_singleSnowManSegment) return "SnowMan"; return "SnowMans"; } } public SnowManEdit(bool singleSnowMan) : base() { m_singleSnowManSegment = singleSnowMan; } public override void InitializeFromModel(UnitPoint point, DrawingLayer layer, ISnapPoint snap) { base.InitializeFromModel(point, layer, snap); m_perSnap = snap as PerpendicularSnapPoint; m_tanSnap = snap as TangentSnapPoint; } public override void OnMouseMove(ICanvas canvas, UnitPoint point) { if (m_perSnap != null) { MouseMovePerpendicular(canvas, point); return; } if (m_tanSnap != null) { MouseMoveTangent(canvas, point); return; } base.OnMouseMove(canvas, point); } public override eDrawObjectMouseDown OnMouseDown(ICanvas canvas, UnitPoint point, ISnapPoint snappoint) { if (m_tanSnap != null && System.Windows.Forms.Control.MouseButtons == MouseButtons.Right) { ReverseTangent(canvas); return eDrawObjectMouseDown.Continue; } if (m_perSnap != null || m_tanSnap != null) { if (snappoint != null) point = snappoint.SnapPoint; OnMouseMove(canvas, point); if (m_singleSnowManSegment) return eDrawObjectMouseDown.Done; return eDrawObjectMouseDown.DoneRepeat; } eDrawObjectMouseDown result = base.OnMouseDown(canvas, point, snappoint); if (m_singleSnowManSegment) return eDrawObjectMouseDown.Done; return eDrawObjectMouseDown.DoneRepeat; } public override void OnKeyDown(ICanvas canvas, KeyEventArgs e) { if (e.KeyCode == Keys.R && m_tanSnap != null) { ReverseTangent(canvas); e.Handled = true; } } protected virtual void MouseMovePerpendicular(ICanvas canvas, UnitPoint point) { if (m_perSnap.Owner is Line) { Line src = m_perSnap.Owner as Line; P1 = HitUtil.NearestPointOnLine(src.P1, src.P2, point, true); P2 = point; } if (m_perSnap.Owner is SnowMan) { SnowMan src = m_perSnap.Owner as SnowMan; P1 = HitUtil.NearestPointOnLine(src.P1, src.P2, point, true); P2 = point; } if (m_perSnap.Owner is Dot) { Dot src = m_perSnap.Owner as Dot; P1 = HitUtil.NearestPointOnCircle(src.P1, src.Width, point, 0); P2 = point; } if (m_perSnap.Owner is Spline) { IArc src = m_perSnap.Owner as IArc; P1 = HitUtil.NearestPointOnCircle(src.Center, src.Radius, point, 0); P2 = point; } if (m_perSnap.Owner is IArc) { IArc src = m_perSnap.Owner as IArc; P1 = HitUtil.NearestPointOnCircle(Center, src.Radius, point, 0); P2 = point; } } protected virtual void MouseMoveTangent(ICanvas canvas, UnitPoint point) { if (m_tanSnap.Owner is IArc) { IArc src = m_tanSnap.Owner as IArc; P1 = HitUtil.TangentPointOnCircle(Center, src.Radius, point, m_tanReverse); P2 = point; if (P1 == UnitPoint.Empty) P2 = P1 = Center; } } protected virtual void ReverseTangent(ICanvas canvas) { m_tanReverse = !m_tanReverse; MouseMoveTangent(canvas, P2); canvas.Invalidate(false); } public void Copy(SnowManEdit acopy) { base.Copy(acopy); m_perSnap = acopy.m_perSnap; m_tanSnap = acopy.m_tanSnap; m_tanReverse = acopy.m_tanReverse; m_singleSnowManSegment = acopy.m_singleSnowManSegment; } public override IDrawObject Clone() { SnowManEdit l = new SnowManEdit(false); l.Copy(this); return l; } #region IObjectEditInstance public IDrawObject GetDrawObject() { return new SnowMan(P1, P2, Width, Color); } #endregion } }