窗口程序本身不复杂,关键是判断射线是否和特定线段相交,如果相交如何计算反射角等。所附的代码可以直接编译和运行,供你参考和讨论。我没有写很多注释,如果你对向量几何熟悉的话,所附代码你应该可以看的很清楚。 如果你不熟悉的话,我三言两语也说不清楚,你可以边看书边参考代码。代码分两部分,Form1.cs(窗口类) 和 Geometry.cs(几何辅助类),你可以建C#工程或用此命令行编译: csc.exe /t:winexe Form1.cs Geometry.csForm1.cs// Form1.cs // // compile with: csc /t:winexe Form1.cs Geometry.cs using System; using System.Drawing; using System.Windows.Forms;public class Form1 : Form { static void Main() { Application.Run(new Form1()); } public Form1() { this.Size = new Size(1000, 600); lines[0] = new Line(A, B); lines[1] = new Line(B, C); lines[2] = new Line(C, D); lines[3] = new Line(D, A); } protected override void OnMouseMove(MouseEventArgs e) { P = new Vec2(e.X, e.Y); Invalidate(); } protected override void OnPaint(PaintEventArgs e) { foreach (Line l in lines) { l.DrawTo(e.Graphics); } Vec2 start = O; Vec2 end = P - O; for (int i = 0; i < 4; i++) { Line line = Bump(ref start, ref end); line.DrawTo(e.Graphics, new Pen(Color.FromArgb(i * 40, i * 50, i * 60))); } } // Test whether an array hits the line, also calculate the length of the ray when hit bool Shoot(Vec2 start, Vec2 dir, Line line, ref float hit) { Vec2 n = line.Normal(); float denom = n * dir; if (Math.Abs(denom) > 1.0E-32) { hit = n * (line.p1 - start) / denom; } return denom < 0.0f; } // Get the line up to the boundary. Reflected line (start point + direction) is calculated. Line Bump(ref Vec2 start, ref Vec2 dir) { int hitLine = -1; float hit = 0, miniHit = 1.0E+32F; for (int i = 0; i < lines.Length; i++) { if (Shoot(start, dir, lines[i], ref hit)) { if (hit > 0 && hit < miniHit) { miniHit = hit; hitLine = i; } } } if (hitLine >= 0) { Line ray = new Line(start, start + dir * miniHit); // calculate the reflection Vec2 n = lines[hitLine].Normal(); float d = dir * n; n = n * d * 2; start = start + dir * miniHit; dir = dir - n; return ray; } return new Line(start, dir); } Vec2 A = new Vec2(171, 145); Vec2 B = new Vec2(853, 145); Vec2 C = new Vec2(853, 473); Vec2 D = new Vec2(171, 473); Vec2 O = new Vec2(300, 300); Vec2 P = new Vec2(306, 308); Line[] lines = new Line[4]; }Geometry.cs// Geometry.cs // using System; using System.Drawing;// representation of a point, or a 2D vector class Vec2 { public Vec2() { } public Vec2(float x, float y) { this.x = x; this.y = y; } public float Length() { return (float)Math.Sqrt(x * x + y * y); } public static Vec2 operator +(Vec2 v1, Vec2 v2) { return new Vec2(v1.x + v2.x, v1.y + v2.y); } public static Vec2 operator -(Vec2 v1, Vec2 v2) { return new Vec2(v1.x - v2.x, v1.y - v2.y); } public static Vec2 operator *(Vec2 v1, float scale) { return new Vec2(v1.x * scale, v1.y * scale); } public static Vec2 operator /(Vec2 v1, float scale) { return new Vec2(v1.x / scale, v1.y / scale); } public static Vec2 operator !(Vec2 v) { // pert() operation: get a vector that is orthogonal to this vector return new Vec2(-v.y, v.x); } public static float operator *(Vec2 v1, Vec2 v2) { // dot product return v1.x * v2.x + v1.y * v2.y; } public float x, y; }// representation of a line class Line { public Line(Vec2 p1, Vec2 p2) { this.p1 = p1; this.p2 = p2; } public Vec2 Normal() { Vec2 v = p2 - p1; return !v / v.Length(); } public float Length() { return (p2 - p1).Length(); } public void DrawTo(Graphics g, Pen p) { g.DrawLine(p, p1.x, p1.y, p2.x, p2.y); } public void DrawTo(Graphics g) { DrawTo(g, Pens.Black); } public Vec2 p1, p2; }
如果你不熟悉的话,我三言两语也说不清楚,你可以边看书边参考代码。代码分两部分,Form1.cs(窗口类) 和 Geometry.cs(几何辅助类),你可以建C#工程或用此命令行编译:
csc.exe /t:winexe Form1.cs Geometry.csForm1.cs// Form1.cs
//
// compile with: csc /t:winexe Form1.cs Geometry.cs
using System;
using System.Drawing;
using System.Windows.Forms;public class Form1 : Form
{
static void Main()
{
Application.Run(new Form1());
}
public Form1()
{
this.Size = new Size(1000, 600);
lines[0] = new Line(A, B);
lines[1] = new Line(B, C);
lines[2] = new Line(C, D);
lines[3] = new Line(D, A);
}
protected override void OnMouseMove(MouseEventArgs e)
{
P = new Vec2(e.X, e.Y);
Invalidate();
}
protected override void OnPaint(PaintEventArgs e)
{
foreach (Line l in lines)
{
l.DrawTo(e.Graphics);
} Vec2 start = O;
Vec2 end = P - O;
for (int i = 0; i < 4; i++)
{
Line line = Bump(ref start, ref end);
line.DrawTo(e.Graphics, new Pen(Color.FromArgb(i * 40, i * 50, i * 60)));
}
} // Test whether an array hits the line, also calculate the length of the ray when hit
bool Shoot(Vec2 start, Vec2 dir, Line line, ref float hit)
{
Vec2 n = line.Normal();
float denom = n * dir;
if (Math.Abs(denom) > 1.0E-32)
{
hit = n * (line.p1 - start) / denom;
}
return denom < 0.0f;
} // Get the line up to the boundary. Reflected line (start point + direction) is calculated.
Line Bump(ref Vec2 start, ref Vec2 dir)
{
int hitLine = -1;
float hit = 0, miniHit = 1.0E+32F;
for (int i = 0; i < lines.Length; i++)
{
if (Shoot(start, dir, lines[i], ref hit))
{
if (hit > 0 && hit < miniHit)
{
miniHit = hit;
hitLine = i;
}
}
}
if (hitLine >= 0)
{
Line ray = new Line(start, start + dir * miniHit); // calculate the reflection
Vec2 n = lines[hitLine].Normal();
float d = dir * n;
n = n * d * 2; start = start + dir * miniHit;
dir = dir - n;
return ray;
}
return new Line(start, dir);
} Vec2 A = new Vec2(171, 145);
Vec2 B = new Vec2(853, 145);
Vec2 C = new Vec2(853, 473);
Vec2 D = new Vec2(171, 473); Vec2 O = new Vec2(300, 300);
Vec2 P = new Vec2(306, 308); Line[] lines = new Line[4];
}Geometry.cs// Geometry.cs
//
using System;
using System.Drawing;// representation of a point, or a 2D vector
class Vec2
{
public Vec2()
{
}
public Vec2(float x, float y)
{
this.x = x;
this.y = y;
}
public float Length()
{
return (float)Math.Sqrt(x * x + y * y);
}
public static Vec2 operator +(Vec2 v1, Vec2 v2)
{
return new Vec2(v1.x + v2.x, v1.y + v2.y);
}
public static Vec2 operator -(Vec2 v1, Vec2 v2)
{
return new Vec2(v1.x - v2.x, v1.y - v2.y);
}
public static Vec2 operator *(Vec2 v1, float scale)
{
return new Vec2(v1.x * scale, v1.y * scale);
}
public static Vec2 operator /(Vec2 v1, float scale)
{
return new Vec2(v1.x / scale, v1.y / scale);
}
public static Vec2 operator !(Vec2 v)
{
// pert() operation: get a vector that is orthogonal to this vector
return new Vec2(-v.y, v.x);
}
public static float operator *(Vec2 v1, Vec2 v2)
{
// dot product
return v1.x * v2.x + v1.y * v2.y;
}
public float x, y;
}// representation of a line
class Line
{
public Line(Vec2 p1, Vec2 p2)
{
this.p1 = p1;
this.p2 = p2;
}
public Vec2 Normal()
{
Vec2 v = p2 - p1;
return !v / v.Length();
}
public float Length()
{
return (p2 - p1).Length();
}
public void DrawTo(Graphics g, Pen p)
{
g.DrawLine(p, p1.x, p1.y, p2.x, p2.y);
}
public void DrawTo(Graphics g)
{
DrawTo(g, Pens.Black);
} public Vec2 p1, p2;
}