最近做了个图形学的大作业。一开始还不知道怎么把一个三维存储的图形呈现到平面内,一天内,确实只有一天内就完成了基本的投影和消隐算法,颇有成就感!
其实在投影上作了很大的简化,仅仅把图像投影到xy平面,可想有多简单了吧~取xy坐标值即可。
消隐的实现还是破费周折的,主要步骤是:计算平面上凸包,凸包上的点标记为边界点;与边界点相连的点,通过向量的计算确定是可见内点还是不可见内点;最后递归的把可见内点的相邻点标为可见点,不可见内点的相邻点标为不可见点;任意线段根据两端的端点类型(可见内点、不可见内点、边界点)标识线段是否可见。
消隐的代码如下:
private void HideLines(Graphics g)
{
int i;
for (i = 0; i < Points.Count; ++i)
((_3DPoint)Points[i]).type = 0;
ArrayList EdgePoints = new ArrayList();
GetEdges(EdgePoints);
//for (i = 0; i < EdgePoints.Count-1; ++i)
// g.DrawString(i + " ", new Font("Arial", 20), Brushes.Blue, new PointF(((_3DPoint)EdgePoints[i]).X, ((_3DPoint)EdgePoints[i]).Y));
for (i = 1; i < EdgePoints.Count - 1; ++i)
{
_3DPoint vector1 = (_3DPoint)EdgePoints[i - 1] - (_3DPoint)EdgePoints[i],
vector2 = (_3DPoint)EdgePoints[i + 1] - (_3DPoint)EdgePoints[i];
for (int j = 0; j < Points.Count; ++j)
{
_3DPoint p = (_3DPoint)Points[j];
if (p.type != 0)
continue;
int index = Lines.IndexOf(new _3DLine(p, (_3DPoint)EdgePoints[i]));
if (index == -1)
continue;
_3DPoint vector3 = p - (_3DPoint)EdgePoints[i];
double test = vector1.CrossProduct(vector2).DotProduct(vector3);
if (test.CompareTo(0.0) > 0)
p.type = 2;
else if (test.CompareTo(0.0) < 0)
p.type = -1;
}
}
Queue q = new Queue();
for (i = 0; i < Points.Count; ++i)
{
_3DPoint p = (_3DPoint)Points[i];
if (p.type == 2 || p.type == -1)
q.Enqueue(p);
}
while (q.Count > 0)
{
_3DPoint p = (_3DPoint)q.Dequeue();
for (int j = 0; j < Points.Count; ++j)
{
_3DPoint p1 = (_3DPoint)Points[j];
if (p1.type != 0)
continue;
if (Lines.IndexOf(new _3DLine(p, p1)) >= 0)
{
p1.type = p.type;
q.Enqueue(p1);
}
}
}
//for (i = 0; i < Points.Count; ++i)
//{
// _3DPoint p = (_3DPoint)Points[i];
// g.DrawString(p.type + " ", new Font("Arial", 20), Brushes.Blue, new PointF(p.X, p.Y));
//}
for (i = 0; i < Lines.Count; ++i)
{
_3DLine l = (_3DLine)Lines[i];
int t1 = l.Vertex1.type, t2 = l.Vertex2.type;
if (t1 == 2 || t2 == 2)
{
l.Visible = true;
continue;
}
else if (t1 == -1 || t2 == -1)
{
l.Visible = false;
continue;
}
else
l.Visible = true;
}
}
private void GetEdges(ArrayList ps)
{
int i ;
_3DPoint topest = (_3DPoint)Points[0];
for (i = 1; i < Points.Count; ++i)
{
if (((_3DPoint)Points[i]).Y > topest.Y)
topest = (_3DPoint)Points[i];
}
ps.Add(topest);
topest.type = 1;
_3DPoint nextEdge = topest, candidate, p;
double minAngle, lastAngle = -2 * Math.PI-1, angle;
while (true)
{
minAngle = 2 * Math.PI + 1;
candidate = null;
for (i = 0; i < Points.Count; ++i)
{
p = (_3DPoint)Points[i];
if (p == nextEdge || (p.type == 1 && p != topest))
continue;
angle = Math.Atan2(p.Y - nextEdge.Y, p.X - nextEdge.X);
if (angle > lastAngle && angle < minAngle)
{
candidate = p;
minAngle = angle;
}
}
if (candidate == null) break;
lastAngle = Math.Atan2(candidate.Y - nextEdge.Y, candidate.X - nextEdge.X);
candidate.type = 1;
nextEdge = candidate;
ps.Add(candidate);
if (nextEdge == topest) break;
}
ps.Add((_3DPoint)ps[1]);
}
|
效果颇为满意,上传个截图:
阅读(518) | 评论(0) | 转发(0) |