110,577
社区成员
发帖
与我相关
我的任务
分享
// 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
//
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;
}