前回の記事
bravememo.hatenablog.com
完成図
点の追加ボタンを4回押して2つ目の点を選択した状態です
点の追加機能
点の追加はAddPoint()で行っています。
点の生成場所は最後の開始点と終了点の間に生成しており、位置は最後の開始点のX+30に位置に生成しています。
さらに点の移動機能も改良しており、いままではY軸の移動だけでしたが、一番最初の開始点以外はX軸の動きを出来るようにしました。
ここでとくに大事になってくるのは追加前の最後の線(開始点と終了点)の扱いについてです。
これをうまくやらないと思ったような線を描画できません。
制御点の移動制限
制御点の位置は線ごとの開始点と終了の間にいないとX軸が同じ線が出てしまうので制御点の位置に制限をかけないといけません
OrganizeControlPoint()で生成時の調整MoveControl1Point()で移動時の制限をかけていて単純にClampを使って制限をかけているだけです。
Formクラスまで書くと長くなるので追加した部分だけ掲載します。
<summary>
</summary>
class CurvePointControl
{
struct BezierPoint
{
public Point startPoint;
public Point controlPoint1;
public Point controlPoint2;
public Point endPoint;
}
enum SelectMode
{
SelectStart,
SelectEnd,
None,
}
List<BezierPoint> m_list = new List<BezierPoint>();
const int ScrrenRightPosX = 600;
const int ScrrenBottomPosY = 310;
const int ScrrenLeftPosX = 0;
const int ScrrenTopPosY = 10;
const int ScrrenCenterpPosY = 160;
int m_SelectPoint = 0;
const float m_cpSize = 8;
bool m_isMoveStartPoint = false;
bool m_isMoveEndPoint = false;
bool m_isMoveControl1Point = false;
bool m_isMoveControl2Point = false;
SelectMode m_SelectMode = SelectMode.None;
GraphicsPath m_path = new GraphicsPath();
GraphicsPath m_path2 = new GraphicsPath();
Brush m_PointColor = new SolidBrush(Color.FromArgb(255, 255, 0, 0));
Pen m_PointLineColor = new Pen(Color.FromArgb(200, 245, 245, 245),4);
Pen m_CPointLineColor = new Pen(Color.FromArgb(125, 245, 245, 245), 4);
Pen m_pen = new Pen(Color.White, 1.5f);
Pen m_pen2 = new Pen(Color.FromArgb(125, 245, 245, 245), 2.5f);
<summary>
</summary>
public CurvePointControl()
{
BezierPoint startBezirPoint = new BezierPoint();
startBezirPoint.startPoint = new Point(ScrrenLeftPosX, ScrrenCenterpPosY);
startBezirPoint.endPoint = new Point(ScrrenRightPosX, ScrrenTopPosY);
startBezirPoint.controlPoint1 = new Point(ScrrenLeftPosX + 10, ScrrenCenterpPosY + 30);
startBezirPoint.controlPoint2 = new Point(ScrrenLeftPosX + 10, ScrrenCenterpPosY - 30);
m_list.Add(startBezirPoint);
}
<summary>
<summary>
public void PointrPaint(PaintEventArgs e)
{
var pontcnt = m_list.Count();
for(int i = 0; i < pontcnt; i++)
{
e.Graphics.FillEllipse(m_PointColor, m_list[i].startPoint.X - m_cpSize / 2, m_list[i].startPoint.Y - m_cpSize / 2, m_cpSize, m_cpSize);
}
int lastpoint = pontcnt - 1;
e.Graphics.FillEllipse(m_PointColor, m_list[lastpoint].endPoint.X - m_cpSize / 2, m_list[lastpoint].endPoint.Y - m_cpSize / 2, m_cpSize, m_cpSize);
}
<summary>
<summary>
public void SelectPointrPaint(PaintEventArgs e)
{
switch (m_SelectMode)
{
case SelectMode.SelectStart:
e.Graphics.DrawEllipse(m_PointLineColor, m_list[m_SelectPoint].startPoint.X - m_cpSize / 2, m_list[m_SelectPoint].startPoint.Y - m_cpSize / 2, m_cpSize, m_cpSize);
e.Graphics.DrawEllipse(m_CPointLineColor, m_list[m_SelectPoint].controlPoint1.X - m_cpSize / 2, m_list[m_SelectPoint].controlPoint1.Y - m_cpSize / 2, m_cpSize, m_cpSize);
e.Graphics.DrawEllipse(m_CPointLineColor, m_list[m_SelectPoint].controlPoint2.X - m_cpSize / 2, m_list[m_SelectPoint].controlPoint2.Y - m_cpSize / 2, m_cpSize, m_cpSize);
break;
case SelectMode.SelectEnd:
int LastNum = m_list.Count() - 1;
e.Graphics.DrawEllipse(m_PointLineColor, m_list[LastNum].endPoint.X - m_cpSize / 2, m_list[LastNum].endPoint.Y - m_cpSize / 2, m_cpSize, m_cpSize);
break;
case SelectMode.None:
break;
default:
Debug.Assert(false, "選択状態がおかしいよ!");
break;
}
}
<summary>
<summary>
public void ControlPaint(PaintEventArgs e)
{
if (m_SelectMode != SelectMode.SelectStart) return;
e.Graphics.FillEllipse(m_PointColor, m_list[m_SelectPoint].controlPoint1.X - m_cpSize / 2, m_list[m_SelectPoint].controlPoint1.Y - m_cpSize / 2, m_cpSize, m_cpSize);
e.Graphics.FillEllipse(m_PointColor, m_list[m_SelectPoint].controlPoint2.X - m_cpSize / 2, m_list[m_SelectPoint].controlPoint2.Y - m_cpSize / 2, m_cpSize, m_cpSize);
}
<summary>
<summary>
public void BezierPaint(PaintEventArgs e)
{
m_path.Reset();
m_path2.Reset();
foreach (BezierPoint item in m_list)
{
Point[] p = new Point[4];
p[0] = item.startPoint;
p[1] = item.controlPoint1;
p[2] = item.controlPoint2;
p[3] = item.endPoint;
m_path.AddBeziers(p);
}
m_path2.AddLine(m_list[m_SelectPoint].startPoint, m_list[m_SelectPoint].controlPoint1);
m_path2.AddLine(m_list[m_SelectPoint].startPoint, m_list[m_SelectPoint].controlPoint2);
e.Graphics.DrawPath(m_pen, m_path);
if (m_SelectMode != SelectMode.SelectStart) return;
e.Graphics.DrawPath(m_pen2, m_path2);
}
<summary>
</summary>
<param name="p"></param>
public void AddPoint(Point p)
{
}
<summary>
</summary>
public void AddPoint()
{
var LastCnt = m_list.Count() - 1;
BezierPoint startBezirPoint = new BezierPoint();
const int ofsetX = 30;
startBezirPoint.startPoint = new Point(Math.Min( m_list[LastCnt].startPoint.X + ofsetX, ScrrenRightPosX), m_list[LastCnt].startPoint.Y);
startBezirPoint.endPoint = new Point(m_list[LastCnt].endPoint.X, m_list[LastCnt].endPoint.Y);
var cpointX = Clamp(startBezirPoint.startPoint.X + 10, ScrrenLeftPosX, ScrrenRightPosX);
startBezirPoint.controlPoint1 = new Point(cpointX, m_list[LastCnt].startPoint.Y + 30);
startBezirPoint.controlPoint2 = new Point(cpointX, m_list[LastCnt].startPoint.Y - 30);
m_list.Add(startBezirPoint);
BezierPoint BezirPoint = new BezierPoint();
BezirPoint = m_list[LastCnt];
BezirPoint.endPoint = m_list[LastCnt + 1].startPoint;
m_list[LastCnt] = BezirPoint;
}
<summary>
</summary>
<param name="mouse"></param>
public void MovePoint(MouseEventArgs mouse)
{
if (m_isMoveStartPoint)
{
MoveStartPoint(mouse);
}
else if (m_isMoveControl1Point)
{
MoveControl1Point(mouse);
}
else if (m_isMoveControl2Point)
{
MoveControl2Point(mouse);
}
else if(m_isMoveEndPoint)
{
MoveEndPoint(mouse);
}
}
<summary>
</summary>
<param name="mouse"></param>
public void MoveStartPoint(MouseEventArgs mouse)
{
BezierPoint sp = m_list[m_SelectPoint];
sp.startPoint.Y = Clamp(mouse.Y, ScrrenTopPosY, ScrrenBottomPosY);
if (!isSelectFirstStartPoint())
{
sp.startPoint.X = Clamp(mouse.X, ScrrenLeftPosX, ScrrenRightPosX);
var BeforeSelectPoint = m_SelectPoint - 1;
BezierPoint sp2 = m_list[BeforeSelectPoint];
sp2.endPoint = sp.startPoint;
m_list[BeforeSelectPoint] = sp2;
}
m_list[m_SelectPoint] = sp;
}
<summary>
</summary>
<param name="mouse"></param>
public void MoveControl1Point(MouseEventArgs mouse)
{
BezierPoint sp = m_list[m_SelectPoint];
sp.controlPoint1.X = Clamp(mouse.X, ScrrenLeftPosX, ScrrenRightPosX);
sp.controlPoint1.Y = Clamp(mouse.Y, ScrrenTopPosY, ScrrenBottomPosY);
if (!isSelectFirstStartPoint())
{
sp.controlPoint1.X = Clamp(sp.controlPoint1.X, m_list[m_SelectPoint - 1].endPoint.X, ScrrenRightPosX);
}
if (!(isSelectLastEndPoint()))
{
sp.controlPoint1.X = Clamp(sp.controlPoint1.X, ScrrenLeftPosX, m_list[m_SelectPoint + 1].startPoint.X);
}
m_list[m_SelectPoint] = sp;
}
<summary>
</summary>
<param name="mouse"></param>
public void MoveControl2Point(MouseEventArgs mouse)
{
BezierPoint sp = m_list[m_SelectPoint];
sp.controlPoint2.X = Clamp(mouse.X, ScrrenLeftPosX, ScrrenRightPosX);
sp.controlPoint2.Y = Clamp(mouse.Y, ScrrenTopPosY, ScrrenBottomPosY);
if (!isSelectFirstStartPoint())
{
sp.controlPoint2.X = Clamp(sp.controlPoint2.X, m_list[m_SelectPoint - 1].endPoint.X, ScrrenRightPosX);
}
if (!isSelectLastEndPoint())
{
sp.controlPoint2.X = Clamp(sp.controlPoint2.X, ScrrenLeftPosX, m_list[m_SelectPoint + 1].startPoint.X);
}
m_list[m_SelectPoint] = sp;
}
<summary>
</summary>
<param name="mouse"></param>
public void MoveEndPoint(MouseEventArgs mouse)
{
int LastNum = m_list.Count() - 1;
BezierPoint sp = m_list[LastNum];
sp.endPoint.Y = Clamp(mouse.Y, ScrrenTopPosY, ScrrenBottomPosY); ;
m_list[LastNum] = sp;
}
<summary>
</summary>
<param name="mouse"></param>
public void SearchSelectPoint(MouseEventArgs mouse)
{
var pontcnt = m_list.Count();
for (int i = 0; i < pontcnt; i++)
{
if(isSearchSelectStartPoint(mouse, i))
{
m_SelectPoint = i;
m_isMoveStartPoint = true;
m_SelectMode = SelectMode.SelectStart;
return;
}
}
if (isSearchSelectControlPoint(mouse))
{
m_isMoveControl1Point = true;
return;
}
if (isSearchSelectContro2Point(mouse))
{
m_isMoveControl2Point = true;
return;
}
if (isSearchSelectEndPoint(mouse))
{
m_isMoveEndPoint = true;
m_SelectMode = SelectMode.SelectEnd;
return;
}
m_isMoveStartPoint = false;
m_isMoveEndPoint = false;
m_SelectMode = SelectMode.None;
}
<summary>
</summary>
public void OrganizeControlPoint()
{
int ListMax = m_list.Count();
int LastNum = m_list.Count() - 1;
for (int i = 0; i < ListMax; i++)
{
BezierPoint sp = m_list[i];
if (i != 0)
{
sp.controlPoint1.X = Clamp(sp.controlPoint1.X, m_list[i - 1].endPoint.X, ScrrenRightPosX);
sp.controlPoint2.X = Clamp(sp.controlPoint2.X, m_list[i - 1].endPoint.X, ScrrenRightPosX);
}
if (i != LastNum)
{
sp.controlPoint1.X = Clamp(sp.controlPoint1.X, ScrrenLeftPosX, m_list[i + 1].startPoint.X);
sp.controlPoint2.X = Clamp(sp.controlPoint2.X, ScrrenLeftPosX, m_list[i + 1].startPoint.X);
}
m_list[i] = sp;
}
}
<summary>
</summary>
public void CancelMovePoint()
{
m_isMoveStartPoint = false;
m_isMoveEndPoint = false;
m_isMoveControl1Point = false;
m_isMoveControl2Point = false;
}
<summary>
</summary>
<param name="mouse"></param>
<returns></returns>
public bool isSearchSelectStartPoint(MouseEventArgs mouse,int num)
{
float SelectPointSize = m_cpSize + 20;
if (mouse.X >= m_list[num].startPoint.X - SelectPointSize / 2 && mouse.X < m_list[num].startPoint.X + SelectPointSize / 2)
{
if (mouse.Y >= m_list[num].startPoint.Y - SelectPointSize / 2 && mouse.Y < m_list[num].startPoint.Y + SelectPointSize / 2)
{
return true;
}
}
return false;
}
<summary>
</summary>
<param name="mouse"></param>
<returns></returns>
public bool isSearchSelectControlPoint(MouseEventArgs mouse)
{
if (m_SelectMode != SelectMode.SelectStart) return false;
float SelectPointSize = m_cpSize + 20;
if (mouse.X >= m_list[m_SelectPoint].controlPoint1.X - SelectPointSize / 2 && mouse.X < m_list[m_SelectPoint].controlPoint1.X + SelectPointSize / 2)
{
if (mouse.Y >= m_list[m_SelectPoint].controlPoint1.Y - SelectPointSize / 2 && mouse.Y < m_list[m_SelectPoint].controlPoint1.Y + SelectPointSize / 2)
{
return true;
}
}
return false;
}
<summary>
</summary>
<param name="mouse"></param>
<param name="num"></param>
<returns></returns>
public bool isSearchSelectContro2Point(MouseEventArgs mouse)
{
if (m_SelectMode != SelectMode.SelectStart) return false;
float SelectPointSize = m_cpSize + 25;
if (mouse.X >= m_list[m_SelectPoint].controlPoint2.X - SelectPointSize / 2 && mouse.X < m_list[m_SelectPoint].controlPoint2.X + SelectPointSize / 2)
{
if (mouse.Y >= m_list[m_SelectPoint].controlPoint2.Y - SelectPointSize / 2 && mouse.Y < m_list[m_SelectPoint].controlPoint2.Y + SelectPointSize / 2)
{
return true;
}
}
return false;
}
<summary>
</summary>
<param name="mouse"></param>
<returns></returns>
public bool isSearchSelectEndPoint(MouseEventArgs mouse)
{
float SelectPointSize = m_cpSize + 25;
int LastNum = m_list.Count() - 1;
if (mouse.X >= m_list[LastNum].endPoint.X - SelectPointSize / 2 && mouse.X < m_list[LastNum].endPoint.X + SelectPointSize / 2)
{
if (mouse.Y >= m_list[LastNum].endPoint.Y - SelectPointSize / 2 && mouse.Y < m_list[LastNum].endPoint.Y + SelectPointSize / 2)
{
return true;
}
}
return false;
}
<summary>
</summary>
<returns></returns>
bool isSelectFirstStartPoint()
{
return m_SelectPoint == 0;
}
<summary>
</summary>
<returns></returns>
bool isSelectLastEndPoint()
{
var LastCnt = m_list.Count() - 1;
return m_SelectPoint == LastCnt;
}
<summary>
</summary>
<param name="x"></param>
<param name="minVal"></param>
<param name="maxVal"></param>
<returns></returns>
public int Clamp(int x, int minVal, int maxVal)
{
return Math.Min(Math.Max(minVal, x), maxVal);
}
}
終わりに
次は点の削除機能の実装をしたい。
あとは開始点の移動範囲をどうするかきめないといけない。開始点が終了点より右にいってしまうときに点を入れ替えるか、そもそも超えないようにするか。まあとりあえずは開始点の動きに制限書けるほうが楽そう。
次の記事
bravememo.hatenablog.com