假如一个坐标分别为A(171,145),B(853,145),C(853,473),D(171,473)组成的矩形,在矩形中任意指定一点O,鼠标P在矩形框中移动时自动生成以OP为最初入射线矩形边为水平面的反射线PQ,然后再以PQ为入射线,以此类推,实现四次以上的反射线条,请问如何实现?分不够再加,希望您能指点,谢谢说明:O点是任意指定的,P是随鼠标移动动态变化的,生成线条也是动态变化的

解决方案 »

  1.   

    窗口程序本身不复杂,关键是判断射线是否和特定线段相交,如果相交如何计算反射角等。所附的代码可以直接编译和运行,供你参考和讨论。我没有写很多注释,如果你对向量几何熟悉的话,所附代码你应该可以看的很清楚。
    如果你不熟悉的话,我三言两语也说不清楚,你可以边看书边参考代码。代码分两部分,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;
    }