Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Optische Verkürzung (https://www.delphipraxis.net/143462-optische-verkuerzung.html)

CarpeNoctem 16. Nov 2009 23:50


Optische Verkürzung
 
Hallo.
Erstmal vorweg: Mein Problem ist mathematisch.
Und Zwar möchte ich auf ein Image mit Canvas ein Schachbrett zeichnen, allerdings optisch 3 Dimensional. Jetzt hab ich aber Probleme mit dem Faktor, um den der Y-Wert abnimmt, wenn man in die Tiefe geht.

Mein Ansatz:

Delphi-Quellcode:
Procedure TForm1.Gitter;
var i:Integer;
    a,b,a1,b1,x,y:Extended;
begin
  Image.Canvas.Pen.Color := rgb(0, 0, 0);
  b := Image.Width;
  a := 1/2 * sqrt(power(Image.Height,2) + power((1/2 * Image.Width),2));
  for I := 0 to 10 do
  begin
    Image.Canvas.MoveTo(i * round(b / 10), Image.Height);
    Image.Canvas.LineTo(round(I * b / 20 + Image.Height / 4), round(Image.Height / 2));
  end;
  for I := 0 to 10 do
  begin
      x := 1/2 * (Image.Width - b);
      b1 := b / 10;
      a1 := a * (x / b);
      y := sqrt(power(a1,2) - power((1/2 * x),2));
      Image.Canvas.MoveTo(round(x),round(Image.Height - y));
      Image.Canvas.LineTo(Image.Width, round(Image.Height - y));
      b := b - b1;
      a := a - a1;
  end;
end;
Allerdings bekomme ich beim Ausführen eine Fehlermeldung mit dem Inhalt: "ungültige Gleitkommaoperation". Soweit ich weiß heist das ja, dass ich durch 0 teilen würde oder eine Variable nicht richtig initialisiert worden ist.

Ich wäre dankbar für einen Lösungsvorschlag oder verbesserung des Ansatzes.

MFG

v2afrank 17. Nov 2009 06:24

Re: Optische Verkürzung
 
Das Problem ist diese Zeile
Delphi-Quellcode:
y := sqrt(power(a1,2) - power((1/2 * x),2));
Je nach Größe des Images wird power((1/2 * x),2) größer als power(a1,2), so dass Du die Wurzel aus einer negativen Zahl ziehst

jfheins 17. Nov 2009 08:17

Re: Optische Verkürzung
 
Ich würde an das Problem folgendermaßen drangehen (hab im Moment übrigens ein sehr ähnliches Problem, nur ohne Schachbrett)

1. Trapezverzerrung (damit die Linien zu einem Fluchtpunkt zusammenlaufen)
2. Drehung um die waagerechte Achse, sodass die Ebene schief im Raum liegt.
3. Parallelproketion, um wieder ein 2-dimensionales Bild zu bekommen
Die ersten beiden Schritte sollten auch vertauschbar sein.

Jetzt ist da natürlich erstmal die Frage, ob du dir was darunter vorstellen kannst :stupid:

CarpeNoctem 17. Nov 2009 22:09

Re: Optische Verkürzung
 
Liste der Anhänge anzeigen (Anzahl: 1)
Erst einmal Danke für die Antworten.

Die Sache wird wohl etwas komplizierter, als ich angenommen habe :? ...

Zitat:

Zitat von jfheins
1. Trapezverzerrung (damit die Linien zu einem Fluchtpunkt zusammenlaufen)
2. Drehung um die waagerechte Achse, sodass die Ebene schief im Raum liegt.
3. Parallelproketion, um wieder ein 2-dimensionales Bild zu bekommen
Die ersten beiden Schritte sollten auch vertauschbar sein.

Jetzt ist da natürlich erstmal die Frage, ob du dir was darunter vorstellen kannst :stupid:

Also zumindestens Punkt 1 und 2 kann ich mir vorstellen - hoff ich (siehe Anhang) aber den 3. Punkt versteh ich leider nicht so direkt :gruebel:.

jfheins 18. Nov 2009 09:43

Re: Optische Verkürzung
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hab dir da mal was gecodet

Ist jetzt zwar Q&D und es hat auch ein bisschen gedauert bis das einigermaßen hingehauen hat - aber es dürfte deinen Anforderungen schon nahe kommen ;)

Code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace Test_1
{
    public partial class Form1 : Form
    {
        RectangleF Outline;
        byte Rows = 8;
        byte Cols = 8;

        Pen pen;

        public Form1()
        {
            InitializeComponent();

            pen = new Pen(Color.Black, 2);

            Outline = new RectangleF(-200, 0, 400, 400);
        }

        private PointF DisplayTransform(PointF coord)
        {
            PointF Result = new PointF();
            Result.X = coord.X + pictureBox1.Width / 2;
            Result.Y = coord.Y + pictureBox1.Height * 0.8f;
            return Result;
        }

        private PointF Transform(PointF coord)
        {
            // Trapezverzerrung

            coord.X = coord.X * ( 1 - coord.Y * ((float)trackBar3.Value / 10000f));

            // Rotation um die x-Achse
            // gleichzeitug: Parallelprojektion
            // (Im Grunde geht man kurz in den 3D-Raum um dann die Z-Komponente wegzuwerfen,
            // da kann man sich die aber auch direkt sparen)
            coord.Y = coord.Y * (float)Math.Sin(trackBar1.Value * Math.PI / 180);

            return coord;
        }

        private void Transform(ref PointF[] coords)
        {
            for (int i = 0; i < coords.Length; i++)
            {
                coords[i] = DisplayTransform(Transform(coords[i]));
            }
        }

        private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;

            float colwidth = Outline.Width / (float)Cols;
            float rowheight = Outline.Height / (float)Rows;

            PointF[] Feld = new PointF[4];

            Brush farbe;

            for (int row = 0; row < Rows; row++)
            {
                for (int col = 0; col < Cols; col++)
                {
                    var left = Outline.Left + col * colwidth;
                    var top = Outline.Top + row * rowheight;

                    Feld[0] = new PointF(left, top);
                    Feld[1] = new PointF(left + colwidth, top);
                    Feld[2] = new PointF(left + colwidth, top + rowheight);
                    Feld[3] = new PointF(left, top + rowheight);

                    Transform(ref Feld);

                    if ((row + col + 1) % 2 == 0)
                        farbe = Brushes.Black;
                    else
                        farbe = Brushes.White;

                    e.Graphics.FillPolygon(farbe, Feld);
                }
            }


            Feld[0] = new PointF(Outline.Left, Outline.Top);
            Feld[1] = new PointF(Outline.Left + Outline.Width, Outline.Top);
            Feld[2] = new PointF(Outline.Left + Outline.Width, Outline.Top + Outline.Height);
            Feld[3] = new PointF(Outline.Left, Outline.Top + Outline.Height);

            Transform(ref Feld);

            e.Graphics.DrawPolygon(pen, Feld);
        }

        private void trackBar1_Scroll(object sender, EventArgs e)
        {
            var a = 10 * Math.Cos((360 - trackBar1.Value) * Math.PI / 180);
            trackBar3.Value = (int)a;
            pictureBox1.Invalidate();
        }

        private void trackBar3_Scroll(object sender, EventArgs e)
        {
            pictureBox1.Invalidate();

        }
        private void Form1_SizeChanged(object sender, EventArgs e)
        {
            pictureBox1.Invalidate();
        } 
    }
}
Der ober Schieber steuert die "Drehung" und der untere steuert die Trapezverzerrung. Um eine ordentliche Perspektive hinzubekommen müssen diese beiden passend gekoppelt sein. Hab das jetzt einfach mal probiert (wenn man den oberen Schiber bewegt, wird der untere auch angepasst)

Programm im Anahng ;)


Alle Zeitangaben in WEZ +1. Es ist jetzt 15:33 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz