using CoreUnit.Common; using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Text.Json; using System.Text.Json.Serialization; using System.Windows.Forms; using System.Xml; namespace CoreUnit.Control.UserControl.Canvas { interface IArc { UnitPoint Center { get; } float Radius { get; } float StartAngle { get; } float EndAngle { get; } } class NodePointArcCenter : INodePoint { protected Arc m_owner; protected Arc m_clone; protected UnitPoint m_originalPoint; protected UnitPoint m_endPoint; public NodePointArcCenter(Arc owner) { m_owner = owner; m_clone = m_owner.Clone() as Arc; m_originalPoint = m_owner.Center; } #region INodePoint Members public IDrawObject GetClone() { return m_clone; } public IDrawObject GetOriginal() { return m_owner; } public virtual void SetPosition(UnitPoint pos) { m_clone.Center = pos; } public virtual void Finish() { m_endPoint = m_clone.Center; m_owner.Center = m_clone.Center; m_owner.Radius = m_clone.Radius; m_owner.Selected = true; m_clone = null; } public void Cancel() { m_owner.Selected = true; } public virtual void Undo() { m_owner.Center = m_originalPoint; } public virtual void Redo() { m_owner.Center = m_endPoint; } public void OnKeyDown(ICanvas canvas, KeyEventArgs e) { } #endregion } class NodePointArcRadius : INodePoint { protected Arc m_owner; protected Arc m_clone; protected float m_originalValue; protected float m_endValue; public NodePointArcRadius(Arc owner) { m_owner = owner; m_clone = m_owner.Clone() as Arc; m_clone.CurrentPoint = m_owner.CurrentPoint; m_originalValue = m_owner.Radius; } #region INodePoint Members public IDrawObject GetClone() { return m_clone; } public IDrawObject GetOriginal() { return m_owner; } public virtual void SetPosition(UnitPoint pos) { m_clone.OnMouseMove(null, pos); } public virtual void Finish() { m_endValue = m_clone.Radius; m_owner.Radius = m_clone.Radius; m_owner.Selected = true; m_clone = null; } public void Cancel() { m_owner.Selected = true; } public virtual void Undo() { m_owner.Radius = m_originalValue; } public virtual void Redo() { m_owner.Radius = m_endValue; } public void OnKeyDown(ICanvas canvas, KeyEventArgs e) { } #endregion } class NodePointArcAngle : INodePoint { protected Arc m_owner; protected Arc m_clone; protected float m_originalA1; protected float m_endA1; protected float m_originalA2; protected float m_endA2; public NodePointArcAngle(Arc owner) { m_owner = owner; m_clone = m_owner.Clone() as Arc; m_clone.CurrentPoint = m_owner.CurrentPoint; m_originalA1 = m_owner.StartAngle; m_originalA2 = m_owner.EndAngle; m_owner.Selected = false; } #region INodePoint Members public IDrawObject GetClone() { return m_clone; } public IDrawObject GetOriginal() { return m_owner; } public virtual void SetPosition(UnitPoint pos) { // Node가 변경될 경우에 drawingMode로 취급함. m_clone.drawingNodeSet = true; m_clone.OnMouseMove(null, pos); } public virtual void Finish() { m_endA1 = m_clone.StartAngle; m_endA2 = m_clone.EndAngle; m_owner.Copy(m_clone); // Node가 변경이 완료될 경우에는 SweepAngle을 EndAngle - StartAngle 변경. m_owner.SweepAngle = m_clone.EndAngle - m_clone.StartAngle; m_clone = null; } public void Cancel() { m_owner.Selected = true; } public virtual void Undo() { m_owner.StartAngle = m_originalA1; m_owner.EndAngle = m_originalA2; } public virtual void Redo() { m_owner.StartAngle = m_endA1; m_owner.EndAngle = m_endA2; } public void OnKeyDown(ICanvas canvas, KeyEventArgs e) { } #endregion } public class Arc : DrawObjectBase, IArc, IDrawObject, ISerialize { public const int FLAG_INNER_ARC = 7123; public enum eDirection { CW, CCW, } UnitPoint m_center; float m_radius; float m_startAngle = 0; float m_endAngle = 0; float m_absSweepAngle = 0; float m_sweepAngle = 0; float m_length = 0; private List _hatchObjects = new List(); public List GetHatchObjects() { return _hatchObjects; } eDirection m_direction = eDirection.CCW; [Browsable(true)] [ReadOnly(false)] [CustomSortedCategory("Geometry", 3, 6)] [CustomSortedDisplayName("Direction", 6, 8)] [Description("unit : CW(ClockWise) / CCW(CounterClockWise)")] [XmlSerializable] public eDirection Direction { get { return m_direction; } set { eDirection beforeDirection = m_direction; m_direction = value; if (beforeDirection != value) { if ((m_direction == eDirection.CCW && SweepAngle < 0) || (m_direction == eDirection.CW && SweepAngle > 0)) { SweepAngle = -1 * SweepAngle; } if (m_useHatching && !_isLoading) { GenerateHatch(); } } } } bool m_reverse = false; [Browsable(true)] [ReadOnly(false)] [CustomSortedCategory("Geometry", 3, 6)] [CustomSortedDisplayName("Reverse", 6, 8)] [Description("Reverse")] [XmlSerializable] public bool Reverse { get { return m_reverse; } set { m_reverse = value; } } public static string ObjectType { get { return "Arc"; } } public Arc() { } public Arc(eArcType type) { m_arcType = type; m_curPoint = eCurrentPoint.p1; if (m_arcType == eArcType.typeCenterRadius) m_curPoint = eCurrentPoint.center; } public override void InitializeFromModel(UnitPoint point, DrawingLayer layer, ISnapPoint snap) { Width = layer.Width; Color = layer.Color; OnMouseDown(null, point, snap); Selected = true; _isLoading = false; } public void Copy(Arc acopy) { base.Copy(acopy); // Hatching 에서 사용 _isLoading = true; // 이 부분은 Clone 시 활용되는 부분임. // Direction에 따라, StartAngle/EndAngle의 값이 달라지기 때문에 매일 처음에 초기화함. __ 210526 이준혁 Direction = acopy.Direction; Center = acopy.Center; Radius = acopy.Radius; // EndAngle 및 StartAngle의 값은 SweepAngle에 종속되있으므로 SweepAngle을 맨 처음으로 진행 필요 SweepAngle = acopy.SweepAngle; StartAngle = acopy.StartAngle; EndAngle = acopy.EndAngle; Selected = acopy.Selected; Direction = acopy.Direction; m_arcType = acopy.m_arcType; m_curPoint = acopy.m_curPoint; Type = acopy.Type; m_no = acopy.m_no; ScannerParamNo = acopy.ScannerParamNo; Enabled = acopy.Enabled; WeldingParameterID = acopy.WeldingParameterID; m_reverse = acopy.m_reverse; m_lock = acopy.m_lock; m_RCCArc = acopy.m_RCCArc; m_MadebyRCC = acopy.m_MadebyRCC; m_RCC_PowerRatio = acopy.m_RCC_PowerRatio; // Hatching 에서 사용 m_useHatching = acopy.m_useHatching; m_hatchFillingType = acopy.m_hatchFillingType; m_hatchMarkType = acopy.m_hatchMarkType; m_hatchLineDir = acopy.m_hatchLineDir; m_hatchinnerradius = acopy.m_hatchinnerradius; m_hatchmarjin = acopy.m_hatchmarjin; m_hatchInterval = acopy.m_hatchInterval; _isLoading = false; if (m_useHatching) { GenerateHatch(); } } #region IDrawObject Members #region 마킹객체에 대한 속성 [Browsable(true)] [ReadOnly(true)] [CustomSortedCategory("Boundary", 1, 6)] [CustomSortedDisplayName("↖Left,Bottom,↘Right,Top", 1, 1)] [Description("Boundary of Object")] [TypeConverter(typeof(RectangleFConverter))] public RectangleF ClientRect { get { List RectanglePoint = new List(); // 360도 이상일 경우, 보정되지 않았었음. if (Math.Abs(SweepAngle) >= 360) { RectanglePoint.Add(new UnitPoint(Center.X - Radius, Center.Y + Radius)); RectanglePoint.Add(new UnitPoint(Center.X - Radius, Center.Y - Radius)); RectanglePoint.Add(new UnitPoint(Center.X + Radius, Center.Y + Radius)); RectanglePoint.Add(new UnitPoint(Center.X + Radius, Center.Y - Radius)); return ScreenUtils.GetRect(RectanglePoint, 0); } RectanglePoint.Add(StartAnglePoint); RectanglePoint.Add(EndAnglePoint); int[] dx = new int[] { 0, -1, 0, 1 }; int[] dy = new int[] { 1, 0, -1, 0 }; int startQuad, endQuad; if (StartAngle >= 0) startQuad = (int)StartAngle / 90; else startQuad = (int)((StartAngle + 360) / 90); if (EndAngle >= 0) endQuad = (int)EndAngle / 90; else endQuad = (int)((EndAngle + 360) / 90); int iter = 0, dir = 0; int positiveNumberVariable = 0; if (startQuad != endQuad) { if (Direction == eDirection.CCW) { if (startQuad > endQuad) iter = endQuad - startQuad + 4; else iter = endQuad - startQuad; dir = 1; positiveNumberVariable = 4; } if (Direction == eDirection.CW) { if (startQuad < endQuad) iter = -endQuad + startQuad + 4; else iter = -endQuad + startQuad; dir = -1; positiveNumberVariable = 3; } for (int i = 0; i < iter; i++) { int index = (startQuad + dir * i + positiveNumberVariable) % 4; if (index < 0) index += 4; // 음수 값을 양수로 변환 float xAxis = (float)(Center.X) + Radius * dx[index]; float yAxis = (float)(Center.Y) + Radius * dy[index]; RectanglePoint.Add(new UnitPoint(xAxis, yAxis)); } } return ScreenUtils.GetRect(RectanglePoint, 0); //lock (this) { return ScreenUtils.GetRect(Center, Radius, 0); } } } bool m_enabled = true; [Browsable(true)] [ReadOnly(false)] [CustomSortedCategory("Geometry", 3, 6)] // 용접 파라미터 [CustomSortedDisplayName("Enable Mark", 8, 8)] // 용접 작업 유무 [Description("Enable Mark")] // 용접 작업 진행 여부 [XmlSerializable] public bool Enabled { get { return m_enabled; } set { m_enabled = value; } } bool m_lock = false; [Browsable(true)] [ReadOnly(false)] [CustomSortedCategory("Geometry", 3, 6)] [CustomSortedDisplayName("Lock", 7, 8)] [Description("Lock")] [XmlSerializable] public bool Lock { get { return m_lock; } set { m_lock = value; } } bool m_RCCArc = false; [Browsable(true)] [ReadOnly(false)] [CustomSortedCategory("Geometry", 3, 6)] [CustomSortedDisplayName("RCC Mode", 9, 8)] [Description("RCC Arc Mode")] [XmlSerializable] public bool RCCArc { get { return m_RCCArc; } set { m_RCCArc = value; } } bool m_MadebyRCC = false; [Browsable(false)] [ReadOnly(false)] public bool MadebyRCC { // RCC 로 생성된 object 만 true 로 바꿔준다. 코드내에서만 사용함. // Ramping 에 대한 예외처리에 필요하다. get { return m_MadebyRCC; } set { m_MadebyRCC = value; } } float m_RCC_PowerRatio = 1; [Browsable(false)] [ReadOnly(false)] public float RCC_PowerRatio { // RCC 로 생성된 object 만 true 로 바꿔준다. 코드내에서만 사용함. // Ramping 에 대한 예외처리에 필요하다. get { return m_RCC_PowerRatio; } set { m_RCC_PowerRatio = value; } } int m_scannerParamNo = 0; [Browsable(false)] [ReadOnly(false)] [Category("용접 파라미터")] [DisplayName("용접 조건 번호")] [Description("용접 조건(스캔속도 및 레이저 파워 값등..) 번호 설정")] [XmlSerializable] public int ScannerParamNo { get { return m_scannerParamNo; } set { m_scannerParamNo = value; } } [Browsable(false)] [ReadOnly(false)] [Category("용접 파라미터")] [DisplayName("용접 조건 ID")] [Description("용접 조건(스캔속도 및 레이저 파워 값등..) ID 설정")] [XmlSerializable] public int ScannerParamID { get { return m_scannerParamNo + 1; } set { m_scannerParamNo = value - 1; } } [Browsable(true)] [ReadOnly(false)] [CustomSortedCategory("Pen", 2, 6)] [CustomSortedDisplayName("Parameter ID", 2, 2)] [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; } } public enum eAlignType { XY_ANGLE, XY_OFFSET, X_OFFSET, Y_OFFSET, ABSOLUTE_XY } eAlignType m_alignType = eAlignType.ABSOLUTE_XY; [Browsable(true)] [ReadOnly(false)] [CustomSortedCategory("Vision Align", 5, 6)] [CustomSortedDisplayName("Align Type", 1, 2)] [Description("Align Type")] [XmlSerializable] public eAlignType AlignType { get { return m_alignType; } set { m_alignType = value; } } int m_alignID = -1; [Browsable(true)] [ReadOnly(false)] [CustomSortedCategory("Vision Align", 5, 6)] [CustomSortedDisplayName("Align ID", 2, 2)] [Description("Align ID")] [XmlSerializable] public int AlignID { get { return m_alignID; } set { m_alignID = value; } } // Hatching 에서 사용 [Browsable(false)] private bool _isLoading = true; int m_innerarcflag = 0; [Browsable(false)] [XmlSerializable] public int InnerArcFlag { get { return m_innerarcflag; } set { m_innerarcflag = value; } } bool m_useHatching = false; [Browsable(true)] [ReadOnly(false)] [Category("Hatching Option")] [DisplayName("Use Hatching")] [Description("해칭 기능을 활성화합니다.")] [XmlSerializable] public bool UseHatching { get { return m_useHatching; } set { m_useHatching = value; GenerateHatch(); } } public enum eHatchFillingType { Filling_Lines, Filling_Arcs } eHatchFillingType m_hatchFillingType = eHatchFillingType.Filling_Lines; [Browsable(true)] [ReadOnly(false)] [Category("Hatching Option")] [DisplayName("Filling Type")] [Description("채우기 방식 (선형 / 동심원)")] [XmlSerializable] public eHatchFillingType HatchFillingType { get { return m_hatchFillingType; } set { m_hatchFillingType = value; if (m_useHatching) { GenerateHatch(); } } } public enum eHatchMarkType { Outline_and_Hatch, Hatch_and_Outline, Hatch_Only } eHatchMarkType m_hatchMarkType = eHatchMarkType.Outline_and_Hatch; [Browsable(true)] [ReadOnly(false)] [Category("Hatching Option")] [DisplayName("Mark Order")] [Description("가공 순서 설정")] [XmlSerializable] public eHatchMarkType HatchMarkType { get { return m_hatchMarkType; } set { m_hatchMarkType = value; } } public enum eHatchLineDir { ZigZag, LeftToRight, RightToLeft } eHatchLineDir m_hatchLineDir = eHatchLineDir.ZigZag; [Browsable(true)] [ReadOnly(false)] [Category("Hatching Option")] [DisplayName("Line Direction")] [Description("해칭 라인의 진행 방향을 설정합니다. (지그재그/단방향)")] [XmlSerializable] public eHatchLineDir HatchLineDir { get { return m_hatchLineDir; } set { m_hatchLineDir = value; if (m_useHatching) GenerateHatch(); } } float m_hatchinnerradius = 0; [Browsable(true)] [ReadOnly(false)] [Category("Hatching Option")] [DisplayName("Inner Radius(mm)")] [Description("도넛 모양을 만들기 위한 내부 반지름 (0이면 꽉 채움)")] [XmlSerializable] public float HatchInnerRadius { get { return m_hatchinnerradius; } set { if (_isLoading) { m_hatchinnerradius = value; return; } if (value < 0) { return; } if (value >= Radius) { return; } m_hatchinnerradius = value; if (m_useHatching) { GenerateHatch(); } } } float m_hatchmarjin = 0; [Browsable(true)] [ReadOnly(false)] [Category("Hatching Option")] [DisplayName("Margin(mm)")] [Description("외곽선과 해칭 사이의 간격")] [XmlSerializable] public float HatchMarjin { get { return m_hatchmarjin; } set { if (value < 0) { return; } m_hatchmarjin = value; if (m_useHatching) { GenerateHatch(); } } } float m_hatchInterval = 1.0f; [Browsable(true)] [ReadOnly(false)] [Category("Hatching Option")] [DisplayName("Interval(mm)")] [Description("해칭 간격")] [XmlSerializable] public float HatchInterval { get { return m_hatchInterval; } set { if (value <= 0) { return; } m_hatchInterval = value; if (m_useHatching) { GenerateHatch(); } } } #endregion #region 드로잉 객체에 대한 속성 int m_no; [Browsable(false)] [XmlSerializable] public int No { get { return m_no; } set { m_no = value; } } string m_type; [Browsable(false)] [ReadOnly(true)] [Category("객체")] [DisplayName("종류")] [Description("드로잉 객체 종류")] [XmlSerializable] public string Type { get { m_type = Arc.ObjectType; return m_type; } set { m_type = value; } } [Browsable(false)] [ReadOnly(false)] [JsonIgnore] public UnitPoint Center { get { return m_center; } set { m_center = value; m_lastPoint = m_center; if (m_useHatching && !_isLoading) { GenerateHatch(); } } } [Browsable(true)] [ReadOnly(false)] [CustomSortedCategory("Geometry", 3, 6)] [CustomSortedDisplayName("Center[X,Y](mm)", 1, 8)] [Description("Center Of Drawing Object")] [TypeConverter(typeof(PointFConverter))] [XmlSerializable] public PointF CenterPointF { get { lock (this) { return Center.Point; } } set { lock (this) { Center = new UnitPoint(value); } } } [Browsable(true)] [ReadOnly(false)] [CustomSortedCategory("Geometry", 3, 6)] [CustomSortedDisplayName("Radius", 2, 8)] [Description("Radius Of Arc")] [JsonIgnore] public float Radius { get { return m_radius; } set { m_radius = value; if (m_useHatching && !_isLoading) { GenerateHatch(); } } } [Browsable(false)] [ReadOnly(false)] [JsonIgnore] public PointF MiddlePoint { get { return m_center.Point; } set { m_center = new UnitPoint(value); } } [Browsable(true)] [ReadOnly(false)] [CustomSortedCategory("Geometry", 3, 6)] [CustomSortedDisplayName("Start Angle", 3, 8)] [Description("Start Angle")] [JsonIgnore] public float StartAngle { get { return m_startAngle; } set { m_startAngle = value; while (0 > m_startAngle) { m_startAngle += 360; } while (m_startAngle >= 360) { m_startAngle -= 360; } if (drawingNodeSet) { // 그리는 모드일 때에는 방향에 따라서 시작점 / 종료점 관계에 따라서 서로 값 동기화 필요 if (Direction == eDirection.CCW) { if (EndAngle < StartAngle) m_endAngle += 360; else if (EndAngle > StartAngle + 360) m_endAngle -= 360; else; } else if (Direction == eDirection.CW) { if (StartAngle < EndAngle) m_endAngle -= 360; else if (EndAngle - StartAngle < -360) m_endAngle += 360; else; } else; m_sweepAngle = EndAngle - StartAngle; drawingNodeSet = false; } else m_endAngle = SweepAngle + m_startAngle; if (m_useHatching && !_isLoading) { GenerateHatch(); } } } [Browsable(false)] [ReadOnly(false)] [Category("Geometry")] [DisplayName("End Angle")] [Description("End Angle")] [JsonIgnore] public float EndAngle { get { return m_endAngle; } set { if (Direction == eDirection.CCW) { if (value < StartAngle) m_endAngle = 360 + value; else m_endAngle = value; } else if (Direction == eDirection.CW) { if (value > StartAngle) m_endAngle = -360 + value; else m_endAngle = value; } else m_endAngle = value; // Drawing 중일 때에만 Sweep Angle 변경해줄 수 있도록 변경 if (drawingNodeSet) { m_sweepAngle = m_endAngle - m_startAngle; } } } [Browsable(true)] [ReadOnly(true)] [CustomSortedCategory("Geometry", 3, 6)] [CustomSortedDisplayName("Start Point [X,Y](mm)", 1, 3)] [Description("Start Point")] [TypeConverter(typeof(PointFConverter))] [XmlSerializable] public PointF PF1 { get { return StartAnglePoint.Point; } set { StartAnglePoint = new UnitPoint(value); StartAngle = (float)HitUtil.RadiansToDegrees(HitUtil.AngleROncircle(m_center, new UnitPoint(value))); } } [Browsable(true)] [ReadOnly(true)] [CustomSortedCategory("Geometry", 3, 6)] [CustomSortedDisplayName("End Point [X,Y](mm)", 2, 3)] [Description("End Point")] [TypeConverter(typeof(PointFConverter))] [XmlSerializable] public PointF PF2 { get { return EndAnglePoint.Point; } set { EndAnglePoint = new UnitPoint(value); } } #endregion float m_angle; [Browsable(false)] [JsonIgnore] public float Angle { get { return StartAngle - EndAngle; } set { m_angle = (float)value; } } public virtual IDrawObject Clone() { Arc a = new Arc(); a.Copy(this); return a; } [Browsable(true)] [ReadOnly(false)] [CustomSortedCategory("Geometry", 3, 6)] [CustomSortedDisplayName("Sweep Angle[deg]", 4, 8)] [Description("unit : degree / Positive Number")] [JsonIgnore] public float AbsSweepAngle { get { m_absSweepAngle = Math.Abs(SweepAngle); return m_absSweepAngle; } set { // Sweep Angle을 양수로 입력할 때만 동작 if (value > 0) { m_absSweepAngle = value; if (Direction == eDirection.CCW) SweepAngle = m_absSweepAngle; if (Direction == eDirection.CW) SweepAngle = -m_absSweepAngle; } } } [Browsable(false)] [ReadOnly(true)] [CustomSortedCategory("Geometry", 3, 6)] [CustomSortedDisplayName("Sweep Angle[deg]", 4, 8)] [Description("unit : degree")] [XmlSerializable] public float SweepAngle { get { return m_sweepAngle; } set { m_sweepAngle = value; m_length = m_radius * value * (float)Math.PI / 180; bool ispositive = m_sweepAngle >= 0 ? true : false; if (ispositive && Direction == eDirection.CCW) { if (m_sweepAngle <= 3600) m_endAngle = StartAngle + m_sweepAngle; else m_endAngle = StartAngle + 3600; } if (!ispositive && Direction == eDirection.CW) { if (-3600 <= m_sweepAngle) m_endAngle = StartAngle + m_sweepAngle; else m_endAngle = StartAngle - 3600; } } } [Browsable(true)] [ReadOnly(false)] [CustomSortedCategory("Geometry", 3, 6)] [CustomSortedDisplayName("Length[mm]", 5, 8)] [Description("unit : mm / Positive Number")] [JsonIgnore] public float Length { get { // 심플하게 보이기 위해, 소수 5번째 자리에서 반올림. m_length = (float)Math.Round(Math.Abs(SweepAngle) * (Radius * (float)Math.PI / 180), 5); return m_length; } set { if (value > 0) { m_length = Math.Abs(value); if (Direction == eDirection.CCW) SweepAngle = m_length / (Radius * (float)Math.PI / 180); if (Direction == eDirection.CW) SweepAngle = -m_length / (Radius * (float)Math.PI / 180); } } } public RectangleF GetBoundingRect(ICanvas canvas) { float thWidth = Line.ThresholdWidth(canvas, Width, ThresholdPixel); if (thWidth < Width) thWidth = Width; float r = m_radius + thWidth / 2; RectangleF rect = HitUtil.CircleBoundingRect(m_center, r); // if drawing either angle then include the mouse point in the ractangle - this is to redraw (erase) the line drawn // from center point to mouse point if (m_curPoint == eCurrentPoint.startAngle || m_curPoint == eCurrentPoint.endAngle) rect = RectangleF.Union(rect, new RectangleF(m_lastPoint.Point, new SizeF(0, 0))); return rect; } public virtual void Draw(ICanvas canvas, RectangleF unitrect) { Action drawHatch = () => { if (m_useHatching) { foreach (var obj in _hatchObjects) { // HatchOnly 모드 일 때, 내부원 그리지 않음 if (m_hatchMarkType == eHatchMarkType.Hatch_Only) { if (obj is Arc arcObj && arcObj.InnerArcFlag == FLAG_INNER_ARC) { continue; } } obj.Draw(canvas, unitrect); } } }; Action drawOutline = () => { Color color = WeldingParameterIDEditor.weldingColorList[(int)WeldingParameterID - 1]; Pen pen = canvas.CreatePen(color, Width); canvas.DrawArc(canvas, pen, m_center, m_radius, StartAngle, SweepAngle); if (m_direction == eDirection.CCW) { DrawUtils.DrawArrowNode(canvas, EndAnglePoint, EndAngle + 90, pen); } else { DrawUtils.DrawArrowNode(canvas, EndAnglePoint, EndAngle - 90, pen); } }; if (!m_useHatching) { drawOutline(); } switch (m_hatchMarkType) { case eHatchMarkType.Outline_and_Hatch: drawOutline(); drawHatch(); break; case eHatchMarkType.Hatch_and_Outline: drawHatch(); drawOutline(); break; case eHatchMarkType.Hatch_Only: drawHatch(); break; } if (Selected) { canvas.DrawArc(canvas, DrawUtils.SelectedPen, m_center, m_radius, StartAngle, SweepAngle); DrawUtils.DrawNode(canvas, m_center); DrawNodes(canvas); } } private void GenerateHatch() { _hatchObjects.Clear(); if (!m_useHatching) { return; } if (HatchInnerRadius > 0 && HatchInnerRadius < Radius) { Arc innerArc = new Arc(this.m_arcType); innerArc.Center = this.Center; innerArc.Radius = this.HatchInnerRadius; innerArc.StartAngle = this.StartAngle; innerArc.EndAngle = this.EndAngle; innerArc.SweepAngle = this.SweepAngle; innerArc.Direction = this.Direction; innerArc.Color = this.Color; innerArc.Width = this.Width; innerArc.UseLayerColor = false; innerArc.UseLayerWidth = false; innerArc.InnerArcFlag = FLAG_INNER_ARC; innerArc.ScannerParamNo = this.ScannerParamNo; innerArc.WeldingParameterID = this.WeldingParameterID; innerArc.Enabled = this.Enabled; _hatchObjects.Add(innerArc); } if (m_hatchFillingType == eHatchFillingType.Filling_Lines) { GenerateLineHatch(); } else { GenerateArcHatch(); } } //private void GenerateLineHatch() //{ // float outerR = Radius - HatchMarjin; // float innerR = (HatchInnerRadius > 0) ? HatchInnerRadius + HatchMarjin : 0; // if (outerR <= innerR) { // return; // } // float top = (float)(Center.Y + outerR); // float bottom = (float)(Center.Y - outerR); // float interval = (m_hatchInterval < 0.01f) ? 0.01f : m_hatchInterval; // bool isLeftToRight = true; // for (float currentY = top; currentY >= bottom; currentY -= interval) { // List validXs = new List(); // validXs.AddRange(GetCircleIntersections(outerR, currentY)); // if (innerR > 0) { // validXs.AddRange(GetCircleIntersections(innerR, currentY)); // } // validXs.Sort(); // for (int i = 0; i < validXs.Count - 1; i += 2) { // float x1 = validXs[i]; // float x2 = validXs[i + 1]; // if (Math.Abs(x1 - x2) < 0.001) continue; // UnitPoint p1 = new UnitPoint(x1, currentY); // UnitPoint p2 = new UnitPoint(x2, currentY); // Line hatchLine; // if (isLeftToRight) { // hatchLine = new Line(p1, p2, 0.01f, Color.Yellow); // } // else { // hatchLine = new Line(p2, p1, 0.01f, Color.Yellow); // } // hatchLine.UseLayerColor = false; // hatchLine.UseLayerWidth = false; // _hatchObjects.Add(hatchLine); // } // isLeftToRight = !isLeftToRight; // } //} private void GenerateLineHatch() { float outerR = Radius - HatchMarjin; float innerR = (HatchInnerRadius > 0) ? HatchInnerRadius + HatchMarjin : 0; if (outerR <= innerR) { return; } float top = (float)(Center.Y + outerR); float bottom = (float)(Center.Y - outerR); float interval = (m_hatchInterval < 0.01f) ? 0.01f : m_hatchInterval; bool isZigZagToggle = true; for (float currentY = top; currentY >= bottom; currentY -= interval) { List validXs = new List(); validXs.AddRange(GetCircleIntersections(outerR, currentY)); if (innerR > 0) { validXs.AddRange(GetCircleIntersections(innerR, currentY)); } validXs.Sort(); for (int i = 0; i < validXs.Count - 1; i += 2) { float x1 = validXs[i]; float x2 = validXs[i + 1]; if (Math.Abs(x1 - x2) < 0.001) { continue; } UnitPoint p1 = new UnitPoint(x1, currentY); UnitPoint p2 = new UnitPoint(x2, currentY); bool currentDirIsLeft = true; switch (m_hatchLineDir) { case eHatchLineDir.ZigZag: currentDirIsLeft = isZigZagToggle; break; case eHatchLineDir.LeftToRight: currentDirIsLeft = true; break; case eHatchLineDir.RightToLeft: currentDirIsLeft = false; break; } Line hatchLine; if (currentDirIsLeft) { hatchLine = new Line(p1, p2, 0.01f, Color.Yellow); } else { hatchLine = new Line(p2, p1, 0.01f, Color.Yellow); } hatchLine.UseLayerColor = false; hatchLine.UseLayerWidth = false; hatchLine.ScannerParamNo = this.ScannerParamNo; hatchLine.WeldingParameterID = this.WeldingParameterID; hatchLine.Enabled = this.Enabled; _hatchObjects.Add(hatchLine); } isZigZagToggle = !isZigZagToggle; } } private List GetCircleIntersections(float r, float y) { List xs = new List(); double dy = y - Center.Y; if (Math.Abs(dy) > r) { return xs; } double term = r * r - dy * dy; if (term < 0) { term = 0; } double dx = Math.Sqrt(term); float[] candidates = new float[] { (float)(Center.X - dx), (float)(Center.X + dx) }; foreach (float x in candidates) { if (IsAngleInArc(x, y)) { xs.Add(x); } } return xs; } private void GenerateArcHatch() { float outerR = Radius - HatchMarjin; float innerR = (HatchInnerRadius > 0) ? HatchInnerRadius + HatchMarjin : 0; float interval = (m_hatchInterval < 0.01f) ? 0.01f : m_hatchInterval; if (outerR <= innerR) { return; } bool cw = (Direction == eDirection.CW); // Inner Radius 있으면 내부에서 외부로 (Inside -> Outside) if (HatchInnerRadius > 0) { for (float r = innerR; r <= outerR; r += interval) { CreateHatchArc(r, ref cw); } } // Inner Radius 없으면 외부에서 내부로 (Outside -> Inside) else { for (float r = outerR; r >= innerR; r -= interval) { CreateHatchArc(r, ref cw); } } } private void CreateHatchArc(float r, ref bool cw) { Arc hatchArc = new Arc(eArcType.typeCenterRadius); hatchArc.Center = this.Center; hatchArc.Radius = r; hatchArc.StartAngle = this.StartAngle; hatchArc.EndAngle = this.EndAngle; hatchArc.Direction = cw ? eDirection.CW : eDirection.CCW; cw = !cw; // 다음 아크를 위해 반전 hatchArc.Color = Color.Yellow; hatchArc.UseLayerColor = false; hatchArc.UseLayerWidth = false; hatchArc.Width = 0.01f; hatchArc.SweepAngle = this.SweepAngle; hatchArc.ScannerParamNo = this.ScannerParamNo; hatchArc.WeldingParameterID = this.WeldingParameterID; hatchArc.Enabled = this.Enabled; _hatchObjects.Add(hatchArc); } private bool IsAngleInArc(float x, float y) { if (this is Circle || Math.Abs(SweepAngle) >= 360) { return true; } double angleRad = Math.Atan2(y - Center.Y, x - Center.X); float angleDeg = (float)(angleRad * 180.0 / Math.PI); if (angleDeg < 0) { angleDeg += 360; } angleDeg %= 360; float start = StartAngle % 360; if (start < 0) start += 360; float end = EndAngle % 360; if (end < 0) end += 360; bool isCCW = (Direction == eDirection.CCW); if (!isCCW) { float temp = start; start = end; end = temp; } float tolerance = 0.1f; if (start <= end) { return angleDeg >= start - tolerance && angleDeg <= end + tolerance; } else { return angleDeg >= start - tolerance || angleDeg <= end + tolerance; } } public bool drawingNodeSet = false; public virtual void OnMouseMove(ICanvas canvas, UnitPoint point) { // 처음 drawing 할 때, (완료되면 이 곳으로 들어오지 않음.) drawingNodeSet = true; m_lastPoint = point; if (m_curPoint == eCurrentPoint.p1) { m_point = point; return; } if (m_curPoint == eCurrentPoint.p2) { StartAngle = 0; EndAngle = 360; m_center = HitUtil.LineMidpoint(m_point, point); m_radius = (float)HitUtil.Distance(m_center, point); return; } if (m_curPoint == eCurrentPoint.center) { m_center = point; } if (m_curPoint == eCurrentPoint.radius) { //StartAngle = 0; //EndAngle = 360; m_radius = (float)HitUtil.Distance(m_center, point); } double angleToRound = 0; if (System.Windows.Forms.Control.ModifierKeys == Keys.Control) angleToRound = HitUtil.DegressToRadians(45); if (m_curPoint == eCurrentPoint.startAngle) { StartAngle = (float)HitUtil.RadiansToDegrees(HitUtil.LineAngleR(m_center, point, angleToRound)); } if (m_curPoint == eCurrentPoint.endAngle) { EndAngle = (float)HitUtil.RadiansToDegrees(HitUtil.LineAngleR(m_center, point, angleToRound)); } } public virtual eDrawObjectMouseDown OnMouseDown(ICanvas canvas, UnitPoint point, ISnapPoint snappoint) { OnMouseMove(canvas, point); if (m_arcType == eArcType.type2point) { if (m_curPoint == eCurrentPoint.p1) { m_curPoint = eCurrentPoint.p2; return eDrawObjectMouseDown.Continue; } if (m_curPoint == eCurrentPoint.p2) { m_curPoint = eCurrentPoint.startAngle; return eDrawObjectMouseDown.Continue; } if (m_curPoint == eCurrentPoint.startAngle) { m_curPoint = eCurrentPoint.endAngle; return eDrawObjectMouseDown.Continue; } if (m_curPoint == eCurrentPoint.endAngle) { m_curPoint = eCurrentPoint.done; OnMouseMove(canvas, point); // 완료되면, drawingNode로 취급하지 않음. drawingNodeSet = false; Selected = false; return eDrawObjectMouseDown.Done; } } if (m_arcType == eArcType.typeCenterRadius) { if (m_curPoint == eCurrentPoint.center) { m_curPoint = eCurrentPoint.radius; return eDrawObjectMouseDown.Continue; } if (m_curPoint == eCurrentPoint.radius) { m_curPoint = eCurrentPoint.startAngle; return eDrawObjectMouseDown.Continue; } if (m_curPoint == eCurrentPoint.startAngle) { m_curPoint = eCurrentPoint.endAngle; return eDrawObjectMouseDown.Continue; } if (m_curPoint == eCurrentPoint.endAngle) { m_curPoint = eCurrentPoint.done; OnMouseMove(canvas, point); Selected = false; // 완료되면, drawingNode로 취급하지 않음. drawingNodeSet = false; return eDrawObjectMouseDown.Done; } } return eDrawObjectMouseDown.Done; } public virtual void OnMouseUp(ICanvas canvas, UnitPoint point, ISnapPoint snappoint) { } public virtual void OnKeyDown(ICanvas canvas, KeyEventArgs e) { if (e.KeyCode == Keys.D && (m_curPoint == eCurrentPoint.startAngle || m_curPoint == eCurrentPoint.endAngle)) { if (Direction == eDirection.CW) Direction = eDirection.CCW; else Direction = eDirection.CW; e.Handled = true; } if (e.KeyCode == Keys.C) // switch to centerRadius mode {/* m_center = UnitPoint.Empty; m_radius = 0; m_startAngle = 0; m_endAngle = 0; m_arcType = eArcType.typeCenterRadius; m_curPoint = eCurrentPoint.center; e.Handled = true; canvas.Invalidate(false);*/ } if (e.KeyCode == Keys.D2) // switch to 2 pointmode { m_center = UnitPoint.Empty; m_radius = 0; m_startAngle = 0; m_endAngle = 0; m_arcType = eArcType.type2point; m_curPoint = eCurrentPoint.p1; e.Handled = true; canvas.Invalidate(false); } } public virtual bool PointInObject(ICanvas canvas, UnitPoint point) { RectangleF boundingrect = GetBoundingRect(canvas); if (boundingrect.Contains(point.Point) == false) return false; float thWidth = Line.ThresholdWidth(canvas, Width, ThresholdPixel); if (HitUtil.PointInPoint(m_center, point, thWidth)) return true; return HitUtil.IsPointInArc(m_center, m_radius, point, thWidth / 2, ClientRect); } public virtual bool ObjectInRectangle(ICanvas canvas, RectangleF rect, bool anyPoint) { float r = m_radius + Width / 2; //RectangleF boundingrect = HitUtil.CircleBoundingRect(m_center, r); RectangleF boundingrect = ClientRect; if (anyPoint) { UnitPoint lp1 = new UnitPoint(rect.Left, rect.Top); UnitPoint lp2 = new UnitPoint(rect.Left, rect.Bottom); if (HitUtil.CircleIntersectWithLine(m_center, m_radius, lp1, lp2)) return true; lp1 = new UnitPoint(rect.Left, rect.Bottom); lp2 = new UnitPoint(rect.Right, rect.Bottom); if (HitUtil.CircleIntersectWithLine(m_center, m_radius, lp1, lp2)) return true; lp1 = new UnitPoint(rect.Left, rect.Top); lp2 = new UnitPoint(rect.Right, rect.Top); if (HitUtil.CircleIntersectWithLine(m_center, m_radius, lp1, lp2)) return true; lp1 = new UnitPoint(rect.Left, rect.Top); lp2 = new UnitPoint(rect.Right, rect.Top); if (HitUtil.CircleIntersectWithLine(m_center, m_radius, lp1, lp2)) return true; lp1 = new UnitPoint(rect.Right, rect.Top); lp2 = new UnitPoint(rect.Right, rect.Bottom); if (HitUtil.CircleIntersectWithLine(m_center, m_radius, lp1, lp2)) return true; } return rect.Contains(boundingrect); } [Browsable(false)] [ReadOnly(false)] public virtual UnitPoint RepeatStartingPoint { get { return UnitPoint.Empty; } } public virtual INodePoint NodePoint(ICanvas canvas, UnitPoint point) { float thWidth = Line.ThresholdWidth(canvas, Width, ThresholdPixel); if (HitUtil.PointInPoint(m_center, point, thWidth)) return new NodePointArcCenter(this); if (HitUtil.PointInPoint(StartAnglePoint, point, thWidth)) { m_curPoint = eCurrentPoint.startAngle; m_lastPoint = m_center; return new NodePointArcAngle(this); } if (HitUtil.PointInPoint(EndAnglePoint, point, thWidth)) { m_curPoint = eCurrentPoint.endAngle; m_lastPoint = m_center; return new NodePointArcAngle(this); } if (HitUtil.PointInPoint(RadiusPoint, point, thWidth)) { m_curPoint = eCurrentPoint.radius; m_lastPoint = m_center; return new NodePointArcRadius(this); } return null; } public virtual ISnapPoint SnapPoint(ICanvas canvas, UnitPoint point, List otherobj, Type[] runningsnaptypes, Type usersnaptype) { float thWidth = Line.ThresholdWidth(canvas, Width, ThresholdPixel); if (runningsnaptypes != null) { foreach (Type snaptype in runningsnaptypes) { if (snaptype == typeof(QuadrantSnapPoint)) { UnitPoint p = HitUtil.NearestPointOnCircle(m_center, m_radius, point, 90); if (p != UnitPoint.Empty && HitUtil.PointInPoint(p, point, thWidth)) return new QuadrantSnapPoint(canvas, this, p); } if (snaptype == typeof(DivisionSnapPoint)) { double angle = 360 / Divisions; UnitPoint p = HitUtil.NearestPointOnCircle(m_center, m_radius, point, angle); if (p != UnitPoint.Empty && HitUtil.PointInPoint(p, point, thWidth)) return new DivisionSnapPoint(canvas, this, p); } if (snaptype == typeof(CenterSnapPoint)) { if (HitUtil.PointInPoint(m_center, point, thWidth)) return new CenterSnapPoint(canvas, this, m_center); } if (snaptype == typeof(VertextSnapPoint)) { if (HitUtil.PointInPoint(StartAnglePoint, point, thWidth)) return new VertextSnapPoint(canvas, this, StartAnglePoint); if (HitUtil.PointInPoint(EndAnglePoint, point, thWidth)) return new VertextSnapPoint(canvas, this, EndAnglePoint); } } return null; } if (usersnaptype == typeof(NearestSnapPoint)) { UnitPoint p = HitUtil.NearestPointOnCircle(m_center, m_radius, point, 0); if (p != UnitPoint.Empty) return new NearestSnapPoint(canvas, this, p); } if (usersnaptype == typeof(PerpendicularSnapPoint)) { UnitPoint p = HitUtil.NearestPointOnCircle(m_center, m_radius, point, 0); if (p != UnitPoint.Empty) return new PerpendicularSnapPoint(canvas, this, p); } if (usersnaptype == typeof(QuadrantSnapPoint)) { UnitPoint p = HitUtil.NearestPointOnCircle(m_center, m_radius, point, 90); if (p != UnitPoint.Empty) return new QuadrantSnapPoint(canvas, this, p); } if (usersnaptype == typeof(DivisionSnapPoint)) { double angle = 360 / Divisions; UnitPoint p = HitUtil.NearestPointOnCircle(m_center, m_radius, point, angle); if (p != UnitPoint.Empty) return new DivisionSnapPoint(canvas, this, p); } if (usersnaptype == typeof(TangentSnapPoint)) { IDrawObject drawingObject = canvas.CurrentObject; UnitPoint p = UnitPoint.Empty; if (drawingObject is LineEdit) { UnitPoint mousepoint = point; point = ((LineEdit)drawingObject).P1; UnitPoint p1 = HitUtil.TangentPointOnCircle(m_center, m_radius, point, false); UnitPoint p2 = HitUtil.TangentPointOnCircle(m_center, m_radius, point, true); double d1 = HitUtil.Distance(mousepoint, p1); double d2 = HitUtil.Distance(mousepoint, p2); if (d1 <= d2) return new TangentSnapPoint(canvas, this, p1); else return new TangentSnapPoint(canvas, this, p2); } //if (p != PointF.Empty) return new TangentSnapPoint(canvas, this, p); } if (usersnaptype == typeof(CenterSnapPoint)) { return new CenterSnapPoint(canvas, this, m_center); } return null; } public virtual void Move(UnitPoint offset) { m_center.X += offset.X; m_center.Y += offset.Y; m_lastPoint = m_center; if (m_useHatching) { GenerateHatch(); } } public void Rotate(float angle, UnitPoint center) { double angleFromCenterToStart = 0, angleFromCenterToEnd = 0, angleFromOriginToCenter = 0; UnitPoint m_pf1 = new UnitPoint(); UnitPoint m_pf2 = new UnitPoint(); // 1. Center Line에서 StartPoint와 EndPoint 각도. UnitPoint v1 = Center - center; UnitPoint v2 = new UnitPoint(PF1.X - Center.X, PF1.Y - Center.Y); UnitPoint v3 = new UnitPoint(PF2.X - Center.X, PF2.Y - Center.Y); // 2. 중심 회전시킴. Center = HitUtil.RotatePoint(angle, Center, center); // 3. 중심 회전 후, 중심 기준으로 point 정의. angleFromOriginToCenter = Math.Atan2(Center.Y - center.Y, Center.X - center.X) - Math.PI / 2;// + Math.PI/2; if (angleFromOriginToCenter > Math.PI) { angleFromOriginToCenter -= 2 * Math.PI; } else if (angleFromOriginToCenter <= -Math.PI) { angleFromOriginToCenter += 2 * Math.PI; } //else; if (angleFromOriginToCenter != -Math.PI / 2) { angleFromCenterToStart = Math.Atan2(v2.Y, v2.X) - Math.Atan2(v1.Y, v1.X); angleFromCenterToEnd = Math.Atan2(v3.Y, v3.X) - Math.Atan2(v1.Y, v1.X); if (angleFromCenterToStart > Math.PI) { angleFromCenterToStart -= 2 * Math.PI; } else if (angleFromCenterToStart <= -Math.PI) { angleFromCenterToStart += 2 * Math.PI; } //else; if (angleFromCenterToEnd > Math.PI) { angleFromCenterToEnd -= 2 * Math.PI; } else if (angleFromCenterToEnd <= -Math.PI) { angleFromCenterToEnd += 2 * Math.PI; } //else; m_pf1 = PointToAngles(Center, Radius, angleFromOriginToCenter, angleFromCenterToStart); m_pf2 = PointToAngles(Center, Radius, angleFromOriginToCenter, angleFromCenterToEnd); } else { m_pf1 = HitUtil.RotatePoint(angle, StartAnglePoint, center); m_pf2 = HitUtil.RotatePoint(angle, EndAnglePoint, center); } PF1 = new PointF((float)m_pf1.X, (float)m_pf1.Y); PF2 = new PointF((float)m_pf2.X, (float)m_pf2.Y); if (m_useHatching) { GenerateHatch(); } } public UnitPoint PointToAngles(UnitPoint center, double length, double angle0, double angle1) { UnitPoint p1 = new UnitPoint(); p1.X = center.X - length * Math.Cos(angle0) * Math.Sin(angle1) - length * Math.Sin(angle0) * Math.Cos(angle1); p1.Y = center.Y - length * Math.Sin(angle0) * Math.Sin(angle1) + length * Math.Cos(angle0) * Math.Cos(angle1); return p1; } public void MakeLength(float distance) { } public virtual string GetInfoAsString() { return string.Format("{1:D3} {0}@{2}, r={3:f4}, A1={4:f4}, A2={5:f4}", this.Type, No + 1, Center.PosAsString(), Radius, StartAngle, EndAngle); } #endregion #region ISerialize public virtual void GetObjectData(XmlWriter wr) { wr.WriteStartElement(Type); Common.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 protected static int ThresholdPixel = 6; protected static int Divisions = 8; public enum eCurrentPoint { p1, p2, center, radius, startAngle, endAngle, done, } [Browsable(false)] [ReadOnly(false)] public eCurrentPoint CurrentPoint { get { return m_curPoint; } set { m_curPoint = value; } } public enum eArcType { typeCenterRadius, type2point, } protected virtual void DrawNodes(ICanvas canvas) { if (m_curPoint == eCurrentPoint.startAngle && m_lastPoint != UnitPoint.Empty) canvas.DrawLine(canvas, DrawUtils.SelectedPen, m_center, m_lastPoint); if (m_curPoint == eCurrentPoint.endAngle && m_lastPoint != UnitPoint.Empty) canvas.DrawLine(canvas, DrawUtils.SelectedPen, m_center, m_lastPoint); DrawUtils.DrawNode(canvas, StartAnglePoint); DrawUtils.DrawNode(canvas, EndAnglePoint); DrawUtils.DrawNode(canvas, RadiusPoint); } protected UnitPoint AnglePoint(float angle) { return HitUtil.PointOncircle(m_center, m_radius, HitUtil.DegressToRadians(angle)); } protected UnitPoint RadiusPoint { get { float angle = StartAngle + SweepAngle / 2; return AnglePoint(angle); } } protected UnitPoint StartAnglePoint { get { return AnglePoint(StartAngle); } set { // StartAnglePoint를 set하기 전 StartAngle을 이미 바꾸어줌. PF1 참고. //StartAngle = (float)HitUtil.RadiansToDegrees(HitUtil.AngleROncircle(m_center, value)); m_radius = (float)HitUtil.Distance(m_center, value); } } protected UnitPoint EndAnglePoint { get { return AnglePoint(EndAngle); } set { // EndAngle을 제어하지 않는 방향으로 수정. //EndAngle = (float)HitUtil.RadiansToDegrees(HitUtil.AngleROncircle(m_center, value)); m_radius = (float)HitUtil.Distance(m_center, value); } } protected eArcType m_arcType = eArcType.type2point; protected eCurrentPoint m_curPoint = eCurrentPoint.p1; protected UnitPoint m_lastPoint; protected UnitPoint m_point; } public class Circle : Arc { public Circle() : base() { } public Circle(Arc.eArcType type) : base(type) { } public new static string ObjectType { get { return "Circle"; } } public new string Type { get { return ObjectType; } } public override IDrawObject Clone() { Circle a = new Circle(); a.Copy(this); return a; } public override eDrawObjectMouseDown OnMouseDown(ICanvas canvas, UnitPoint point, ISnapPoint snappoint) { OnMouseMove(canvas, point); if (m_arcType == eArcType.type2point) { if (m_curPoint == eCurrentPoint.p1) { m_curPoint = eCurrentPoint.p2; return eDrawObjectMouseDown.Continue; } if (m_curPoint == eCurrentPoint.p2) { m_curPoint = eCurrentPoint.done; OnMouseMove(canvas, point); Selected = false; return eDrawObjectMouseDown.Done; } } if (m_arcType == eArcType.typeCenterRadius) { if (m_curPoint == eCurrentPoint.center) { m_curPoint = eCurrentPoint.radius; return eDrawObjectMouseDown.Continue; } if (m_curPoint == eCurrentPoint.radius) { m_curPoint = eCurrentPoint.done; OnMouseMove(canvas, point); Selected = false; return eDrawObjectMouseDown.Done; } } return eDrawObjectMouseDown.Done; } protected override void DrawNodes(ICanvas canvas) { DrawUtils.DrawNode(canvas, AnglePoint(0)); DrawUtils.DrawNode(canvas, AnglePoint(90)); DrawUtils.DrawNode(canvas, AnglePoint(180)); DrawUtils.DrawNode(canvas, AnglePoint(270)); } public override INodePoint NodePoint(ICanvas canvas, UnitPoint point) { float thWidth = Line.ThresholdWidth(canvas, Width, ThresholdPixel); if (HitUtil.PointInPoint(Center, point, thWidth)) return new NodePointArcCenter(this); bool radiushit = HitUtil.PointInPoint(AnglePoint(0), point, thWidth); if (radiushit == false) radiushit = HitUtil.PointInPoint(AnglePoint(90), point, thWidth); if (radiushit == false) radiushit = HitUtil.PointInPoint(AnglePoint(180), point, thWidth); if (radiushit == false) radiushit = HitUtil.PointInPoint(AnglePoint(270), point, thWidth); if (radiushit) { m_curPoint = eCurrentPoint.radius; m_lastPoint = Center; return new NodePointArcRadius(this); } return null; } public override string GetInfoAsString() { return string.Format("{1:D3} {0}@{2}, r={3:f4}", this.Type, No + 1, Center.PosAsString(), Radius); } } }