It is currently Thu May 23, 2013 7:19 pm

All times are UTC + 1 hour




Post new topic Reply to topic  [ 9 posts ] 
Author Message
 Post subject: Calculate real 3D coordinates from 2D
PostPosted: Mon Mar 26, 2012 9:30 pm 
Offline
Addict
Addict
User avatar

Joined: Thu Feb 09, 2006 11:27 pm
Posts: 1716
I will have some 3D images of rectangle areas of the earth, and I will know the valid earth coordinates of the 4 corners. I am working to get additional information, for example the center of the given rectangle to know the perspective distortion, but first of all my general problem:
I want to calculate the earth coordinates from the screen coordinates, the altitude has to be ignored.

Code:
; Define

   #W=640
   #H=480

   Global Dim Polygon(7)
   
   Polygon(0)=40
   Polygon(1)=40
   Polygon(2)=340
   Polygon(3)=30
   Polygon(4)=550
   Polygon(5)=300
   Polygon(6)=100
   Polygon(7)=440
   
   Global Dim Real.f(7)
   
   Real(0)=-100
   Real(1)=-100
   Real(2)=100
   Real(3)=-100
   Real(4)=100
   Real(5)=100
   Real(6)=-100
   Real(7)=100

; EndDefine

Procedure.b IsPointInsideTriangle2D(x0.f,y0.f,x1.f,y1.f,x2.f,y2.f,px.f,py.f)
   
   Protected V1x.f=x1-x0
   Protected V1y.f=y1-y0
   Protected V2x.f=x2-x1
   Protected V2y.f=y2-y1
   Protected V3x.f=x0-x2
   Protected V3y.f=y0-y2
   
   If V1y*(px-x0)>=V1x*(py-y0)
      If V2y*(px-x1)>=V2x*(py-y1) And V3y*(px-x2)>=V3x*(py-y2)
         ProcedureReturn #True
      EndIf
   Else
      If V2y*(px-x1)<V2x*(py-y1) And V3y*(px-x2)<V3x*(py-y2)
         ProcedureReturn #True
      EndIf
   EndIf
   
   ProcedureReturn #False
   
EndProcedure

Procedure UpdateImage()

   Protected x,y,color

   x=WindowMouseX(0)
   y=WindowMouseY(0)

   StartDrawing(ImageOutput(0))
   Box(0,0,#W,#H,#Black)
   
   DrawingMode(#PB_2DDrawing_Transparent)
   For i=0 To 3
      LineXY(Polygon(i<<1&7),Polygon(i<<1&7+1),Polygon((i<<1+2)&7),Polygon((i<<1+3)&7),#White)
      DrawText(Polygon(i<<1&7),Polygon(i<<1&7+1),Str(Real(i<<1&7))+"|"+Str(Real(i<<1&7+1)),#Blue)
   Next i
   
   
   LineXY((Polygon(0)+Polygon(6))>>1,(Polygon(1)+Polygon(7))>>1,(Polygon(2)+Polygon(4))>>1,(Polygon(3)+Polygon(5))>>1,#Gray)
   LineXY((Polygon(0)+Polygon(2))>>1,(Polygon(1)+Polygon(3))>>1,(Polygon(6)+Polygon(4))>>1,(Polygon(7)+Polygon(5))>>1,#Gray)
   
   
   color=#Red
   If IsPointInsideTriangle2D(Polygon(0),Polygon(1),Polygon(2),Polygon(3),Polygon(4),Polygon(5),x,y)
      color=#Green
   EndIf
   If IsPointInsideTriangle2D(Polygon(4),Polygon(5),Polygon(6),Polygon(7),Polygon(0),Polygon(1),x,y)
      color=#Yellow
   EndIf
   
   LineXY(x-29,y,x+29,y,color)
   LineXY(x,y-29,x,y+29,color)

   ; ============================   
   ; x_ and y_ have to be calculated here...
   ; ============================   
   DrawText(x+10,y-25,Str(x_)+" | "+Str(y_),#Blue)
   
   StopDrawing()
   SetGadgetState(0,ImageID(0))

EndProcedure

OpenWindow(0,0,0,#W,#H,"")
ImageGadget(0,0,0,#W,#H,0)
CreateImage(0,#W,#H,24)
UpdateImage()

Repeat
   Select WaitWindowEvent()
   Case #WM_MOUSEMOVE
      UpdateImage()
   Case #WM_CHAR
      End
   EndSelect
ForEver


The above example only demonstrate the distorted rectangle and the "real" coordinates (-100|-100 to 100|100). The grey cross are drawn by using the median, but the center wouldn't be identical with the real center (0|0) because of the perspective. I am quite sure, I will also have the correct 2D coordinates of the center 0|0 (let's say, it will be 260|160 in the given example).

But how to calculate the earth coordinates when the mouse is within the rectangle?


Top
 Profile  
 
 Post subject: Re: Calculate real 3D coordinates from 2D
PostPosted: Mon Mar 26, 2012 11:18 pm 
Offline
Addict
Addict
User avatar

Joined: Mon Jul 25, 2005 3:51 pm
Posts: 2401
Location: Utah, USA
Michael Vogel wrote:
But how to calculate the earth coordinates when the mouse is within the rectangle?


Use the intersection of two opposite corners of the earth rectangle.

Here's your code that is modified to show the center as an 'X':

Code:
; Define

#W=640
#H=480

Global Dim polygon(7)
   
polygon(0)=40
polygon(1)=40
polygon(2)=340
polygon(3)=30
polygon(4)=550
polygon(5)=300
polygon(6)=100
polygon(7)=440
   
Global Dim Real.f(7)
   
Real(0)=-100
Real(1)=-100
Real(2)=100
Real(3)=-100
Real(4)=100
Real(5)=100
Real(6)=-100
Real(7)=100

; EndDefine

Procedure.b IsPointInsideTriangle2D(x0.f,y0.f,x1.f,y1.f,x2.f,y2.f,px.f,py.f)
 
  Protected V1x.f=x1-x0
  Protected V1y.f=y1-y0
  Protected V2x.f=x2-x1
  Protected V2y.f=y2-y1
  Protected V3x.f=x0-x2
  Protected V3y.f=y0-y2
 
  If V1y*(px-x0)>=V1x*(py-y0)
    If V2y*(px-x1)>=V2x*(py-y1) And V3y*(px-x2)>=V3x*(py-y2)
      ProcedureReturn #True
    EndIf
  Else
    If V2y*(px-x1)<V2x*(py-y1) And V3y*(px-x2)<V3x*(py-y2)
      ProcedureReturn #True
    EndIf
  EndIf
 
  ProcedureReturn #False
 
EndProcedure

Structure POINT_f
  x.f
  y.f
EndStructure

Procedure rectangleCenterPoint(*center.POINT_f, *TL.POINT, *TR.POINT, *BR.POINT, *BL.POINT)
  Protected dy1.f = *TL\y - *BR\y
  Protected dy2.f = *TR\y - *BL\y
  Protected dx1.f = *TL\x - *BR\x
  Protected dx2.f = *TR\x - *BL\x
 
 
  If dx1 = 0 Or dx2 = 0
    ;one of the sides is vertical, use this simplified formula instead
    *center\x =  (*TR\x + *BR\x) / 2
    *center\y =  (*TR\y + *BR\y) / 2
  Else
    Protected m1.f = dy1 / dx1
    Protected m2.f = dy2 / dx2
    Protected b1.f = *TL\y - m1 * *TL\x
    Protected b2.f = *TR\y - m2 * *TR\x
    *center\x = (b2 - b1) / (m1 - m2)
    *center\y = m1 * *center\x + b1
  EndIf
EndProcedure

Procedure UpdateImage()
 
  Protected x,y,color
 
  x=WindowMouseX(0)
  y=WindowMouseY(0)
 
  StartDrawing(ImageOutput(0))
    Box(0,0,#W,#H,#Black)
   
    DrawingMode(#PB_2DDrawing_Transparent)
    For i=0 To 3
      LineXY(polygon(i<<1&7),polygon(i<<1&7+1),polygon((i<<1+2)&7),polygon((i<<1+3)&7),#White)
      DrawText(polygon(i<<1&7),polygon(i<<1&7+1),Str(Real(i<<1&7))+"|"+Str(Real(i<<1&7+1)),#Blue)
    Next i
   
   
    LineXY((polygon(0)+polygon(6))>>1,(polygon(1)+polygon(7))>>1,(polygon(2)+polygon(4))>>1,(polygon(3)+polygon(5))>>1,#Gray)
    LineXY((polygon(0)+polygon(2))>>1,(polygon(1)+polygon(3))>>1,(polygon(6)+polygon(4))>>1,(polygon(7)+polygon(5))>>1,#Gray)
   
    ;draw actual center point
    Protected center.POINT_f
    rectangleCenterPoint(center, @polygon(0), @polygon(2), @polygon(4), @polygon(6))
    LineXY(center\x - 5, center\y - 5, center\x + 5, center\y + 5, RGB(255, 255, 0))
    LineXY(center\x + 5, center\y - 5, center\x - 5, center\y + 5, RGB(255, 255, 0))
   
   
    color=#Red
    If IsPointInsideTriangle2D(polygon(0),polygon(1),polygon(2),polygon(3),polygon(4),polygon(5),x,y)
      color=#Green
    EndIf
    If IsPointInsideTriangle2D(polygon(4),polygon(5),polygon(6),polygon(7),polygon(0),polygon(1),x,y)
      color=#Yellow
    EndIf
   
    LineXY(x-29,y,x+29,y,color)
    LineXY(x,y-29,x,y+29,color)
   
    ; ============================   
    ; x_ and y_ have to be calculated here...
    ; ============================   
    DrawText(x+10,y-25,Str(x_)+" | "+Str(y_),#Blue)
   
  StopDrawing()
  SetGadgetState(0,ImageID(0))
 
EndProcedure

OpenWindow(0,0,0,#W,#H,"")
ImageGadget(0,0,0,#W,#H,0)
CreateImage(0,#W,#H,24)
UpdateImage()

Repeat
  Select WaitWindowEvent()
    Case #WM_MOUSEMOVE
      UpdateImage()
    Case #WM_CHAR
      End
  EndSelect
ForEver

_________________
Image


Top
 Profile  
 
 Post subject: Re: Calculate real 3D coordinates from 2D
PostPosted: Tue Mar 27, 2012 6:37 am 
Offline
Addict
Addict
User avatar

Joined: Thu Feb 09, 2006 11:27 pm
Posts: 1716
Hm,
your code calculates the center, but how to get the correct values for x_|y_ ?

I tried to use your center function to iterate the values, but failed. It's also not clear for me, how to calculate the appropriate centers of the four lines around the rectangle according to the calculated center...

Code:
; Define

   #W=640
   #H=480

   Structure POINT_f
      x.f
      y.f
   EndStructure

   Global Dim Polygon(7)
   Global Dim Real.f(7)

   Global M.POINT_f
   Global A.POINT_f
   Global B.POINT_f
   Global C.POINT_f
   Global D.POINT_f

; EndDefine
Procedure InitValues()

   Polygon(0)=40
   Polygon(1)=40
   Polygon(2)=340
   Polygon(3)=30
   Polygon(4)=550
   Polygon(5)=300
   Polygon(6)=100
   Polygon(7)=440

   Real(0)=-100
   Real(1)=-100
   Real(2)=100
   Real(3)=-100
   Real(4)=100
   Real(5)=100
   Real(6)=-100
   Real(7)=100

EndProcedure
Procedure.i IsPointInsideTriangle2D(x0.f,y0.f,x1.f,y1.f,x2.f,y2.f,px.f,py.f)

   Protected V1x.f=x1-x0
   Protected V1y.f=y1-y0
   Protected V2x.f=x2-x1
   Protected V2y.f=y2-y1
   Protected V3x.f=x0-x2
   Protected V3y.f=y0-y2

   If V1y*(px-x0)>=V1x*(py-y0)
      If V2y*(px-x1)>=V2x*(py-y1) And V3y*(px-x2)>=V3x*(py-y2)
         ProcedureReturn #True
      EndIf
   Else
      If V2y*(px-x1)<V2x*(py-y1) And V3y*(px-x2)<V3x*(py-y2)
         ProcedureReturn #True
      EndIf
   EndIf

   ProcedureReturn #False

EndProcedure
Procedure.i IsPointInsideRectancle2D(x0.f,y0.f,x1.f,y1.f,x2.f,y2.f,x3.f,y3.f,x.f,y.f)
   
   LineXY(x0,y0,x1,y1,RGB(80,80,80))
   LineXY(x0,y0,x3,y3,RGB(80,80,80))
   LineXY(x2,y2,x1,y1,RGB(80,80,80))
   LineXY(x2,y2,x3,y3,RGB(80,80,80))
   
   If IsPointInsideTriangle2D(x0,y0,x1,y1,x2,y2,x,y)
      ProcedureReturn 1
   EndIf
   If IsPointInsideTriangle2D(x2,y2,x3,y3,x0,y0,x,y)
      ProcedureReturn 2
   EndIf

   ProcedureReturn 0

EndProcedure
Procedure Cross(x,y,size,color)
   LineXY(x-size,y-size,x+size,y+size,color)
   LineXY(x+size,y-size,x-size,y+size,color)
EndProcedure
Procedure rectangleCenterPoint(*center.POINT_f, *TL.POINT, *TR.POINT, *BR.POINT, *BL.POINT)

   Protected dy1.f = *TL\y - *BR\y
   Protected dy2.f = *TR\y - *BL\y
   Protected dx1.f = *TL\x - *BR\x
   Protected dx2.f = *TR\x - *BL\x


   If dx1 = 0 Or dx2 = 0
      ;one of the sides is vertical, use this simplified formula instead
      *center\x =  (*TR\x + *BR\x) / 2
      *center\y =  (*TR\y + *BR\y) / 2
   Else
      Protected m1.f = dy1 / dx1
      Protected m2.f = dy2 / dx2
      Protected b1.f = *TL\y - m1 * *TL\x
      Protected b2.f = *TR\y - m2 * *TR\x
      *center\x = (b2 - b1) / (m1 - m2)
      *center\y = m1 * *center\x + b1
   EndIf

EndProcedure
Procedure UpdateImage()

   Protected x,y,color

   x=WindowMouseX(0)
   y=WindowMouseY(0)

   InitValues()

   StartDrawing(ImageOutput(0))
   Box(0,0,#W,#H,#Black)

   DrawingMode(#PB_2DDrawing_Transparent)
   For i=0 To 3
      LineXY(Polygon(i<<1&7),Polygon(i<<1&7+1),Polygon((i<<1+2)&7),Polygon((i<<1+3)&7),#White)
      DrawText(Polygon(i<<1&7),Polygon(i<<1&7+1),Str(Real(i<<1&7))+"|"+Str(Real(i<<1&7+1)),#Blue)
   Next i

   LineXY((Polygon(0)+Polygon(6))>>1,(Polygon(1)+Polygon(7))>>1,(Polygon(2)+Polygon(4))>>1,(Polygon(3)+Polygon(5))>>1,#Gray)
   LineXY((Polygon(0)+Polygon(2))>>1,(Polygon(1)+Polygon(3))>>1,(Polygon(6)+Polygon(4))>>1,(Polygon(7)+Polygon(5))>>1,#Gray)

   Select IsPointInsideRectancle2D(Polygon(0),Polygon(1),Polygon(2),Polygon(3),Polygon(4),Polygon(5),Polygon(6),Polygon(7),x,y)
   Case 0
      color=#Red
   Case 1
      color=#Green
   Case 2
      color=#Yellow
   EndSelect

   LineXY(x-29,y,x+29,y,color)
   LineXY(x,y-29,x,y+29,color)

   ; ============================
   ; x_ and y_ have to be calculated here...
   ; ============================

   If color<>#Red

      Protected iteration=10

      While iteration
         iteration-1
         
         RectangleCenterPoint(M,@Polygon(0),@Polygon(2),@Polygon(4),@Polygon(6))
         Cross(M\x,M\y,iteration,RGB(160,160,160))

         RectangleCenterPoint(A,@Polygon(0),@Polygon(2),@Polygon(0),@Polygon(2))
         RectangleCenterPoint(B,@Polygon(0),@Polygon(6),@Polygon(0),@Polygon(6))
         RectangleCenterPoint(C,@Polygon(2),@Polygon(4),@Polygon(2),@Polygon(4))
         RectangleCenterPoint(D,@Polygon(4),@Polygon(6),@Polygon(4),@Polygon(6))
         
         If IsPointInsideRectancle2D(Polygon(0),Polygon(1),A\x,A\y,M\x,M\y,B\x,B\y,x,y)
            Cross(A\x,A\y,2,RGB(160,160,160))
            Cross(B\x,B\y,2,RGB(160,160,160))
            Real(2)=(Real(0)+Real(2))/2
            Real(3)=(Real(1)+Real(3))/2
            Real(4)=(Real(0)+Real(2))/2
            Real(5)=(Real(2)+Real(4))/2
            Real(6)=(Real(0)+Real(6))/2
            Real(7)=(Real(1)+Real(7))/2
            Polygon(2)=A\x
            Polygon(3)=A\y
            Polygon(4)=M\x
            Polygon(5)=M\y
            Polygon(6)=B\x
            Polygon(7)=B\y
            
         ElseIf IsPointInsideRectancle2D(A\x,A\y,Polygon(2),Polygon(3),C\x,C\y,M\x,M\y,x,y)
            Cross(A\x,A\y,2,RGB(160,160,160))
            Cross(C\x,C\y,2,RGB(160,160,160))
            Real(0)=(Real(0)+Real(2))/2
            Real(1)=(Real(1)+Real(3))/2
            Real(4)=(Real(0)+Real(2))/2
            Real(5)=(Real(2)+Real(4))/2
            Real(6)=(Real(0)+Real(6))/2
            Real(7)=(Real(1)+Real(7))/2
            Polygon(0)=A\x
            Polygon(1)=A\y
            Polygon(4)=C\x
            Polygon(5)=C\y
            Polygon(6)=M\x
            Polygon(7)=M\y
            
         ElseIf IsPointInsideRectancle2D(M\x,M\y,C\x,C\y,Polygon(4),Polygon(5),D\x,D\y,x,y)
            Cross(C\x,C\y,2,RGB(160,160,160))
            Cross(D\x,D\y,2,RGB(160,160,160))
            Real(0)=(Real(0)+Real(2))/2
            Real(1)=(Real(1)+Real(3))/2
            Real(2)=(Real(2)+Real(4))/2
            Real(3)=(Real(3)+Real(5))/2
            Real(4)=(Real(4)+Real(6))/2
            Real(5)=(Real(5)+Real(7))/2
            Polygon(0)=M\x
            Polygon(1)=M\y
            Polygon(2)=C\x
            Polygon(3)=C\y
            Polygon(6)=D\x
            Polygon(7)=D\y
            
         ElseIf IsPointInsideRectancle2D(B\x,B\y,M\x,M\y,D\x,D\y,Polygon(6),Polygon(7),x,y)
            Cross(B\x,B\y,2,RGB(160,160,160))
            Cross(D\x,D\y,2,RGB(160,160,160))
            Real(0)=(Real(0)+Real(6))/2
            Real(1)=(Real(1)+Real(7))/2
            Real(2)=(Real(0)+Real(2))/2
            Real(3)=(Real(2)+Real(4))/2
            Real(4)=(Real(6)+Real(4))/2
            Real(5)=(Real(7)+Real(5))/2
            Polygon(0)=B\x
            Polygon(1)=B\y
            Polygon(2)=M\x
            Polygon(3)=M\y
            Polygon(4)=D\x
            Polygon(5)=D\y
         Else
            iteration=0
         EndIf
      Wend

      For i=0 To 3
         If x=Polygon(i<<1) And y=Polygon(i<<1+1)
            x_=Real(i<<1)
            y_=Real(i<<1+1)
         EndIf
      Next i

      x_=(Real(0)+Real(4)) / 2
      y_=(Real(1)+Real(5)) / 2

      DrawText(x+10,y-25,Str(x_)+" | "+Str(y_),$FF4040)

   EndIf

   StopDrawing()
   SetGadgetState(0,ImageID(0))

EndProcedure

OpenWindow(0,0,0,#W,#H,"")
ImageGadget(0,0,0,#W,#H,0)
CreateImage(0,#W,#H,24)
UpdateImage()

Repeat
   Select WaitWindowEvent()
   Case #WM_MOUSEMOVE
      UpdateImage()
   Case #WM_CHAR
      End
   EndSelect
ForEver


Top
 Profile  
 
 Post subject: Re: Calculate real 3D coordinates from 2D
PostPosted: Tue Mar 27, 2012 6:06 pm 
Offline
Addict
Addict
User avatar

Joined: Thu Feb 09, 2006 11:27 pm
Posts: 1716
Eliminiated some bugs, but I've still no idea how to straighten the lines for a homogenous grid...
Another strange issue, the calculated x|y values seem to be completely wrong when moving the mouse cursor directly on a grid line.

Code:
; Define

   #W=640
   #H=480

   Structure POINT_f
      x.f
      y.f
   EndStructure

   Global Dim Polygon(7)
   Global Dim Real.f(7)

   Global M.POINT_f
   Global A.POINT_f
   Global B.POINT_f
   Global C.POINT_f
   Global D.POINT_f

; EndDefine
Procedure InitValues()

   Polygon(0)=40
   Polygon(1)=40
   Polygon(2)=340
   Polygon(3)=30
   Polygon(4)=550
   Polygon(5)=300
   Polygon(6)=100
   Polygon(7)=440

   Real(0)=-100
   Real(1)=-100
   Real(2)=100
   Real(3)=-100
   Real(4)=100
   Real(5)=100
   Real(6)=-100
   Real(7)=100

EndProcedure
Procedure.i IsPointInsideTriangle2D(x0.f,y0.f,x1.f,y1.f,x2.f,y2.f,px.f,py.f)

   Protected V1x.f=x1-x0
   Protected V1y.f=y1-y0
   Protected V2x.f=x2-x1
   Protected V2y.f=y2-y1
   Protected V3x.f=x0-x2
   Protected V3y.f=y0-y2

   If V1y*(px-x0)>=V1x*(py-y0)
      If V2y*(px-x1)>=V2x*(py-y1) And V3y*(px-x2)>=V3x*(py-y2)
         ProcedureReturn #True
      EndIf
   Else
      If V2y*(px-x1)<V2x*(py-y1) And V3y*(px-x2)<V3x*(py-y2)
         ProcedureReturn #True
      EndIf
   EndIf

   ProcedureReturn #False

EndProcedure
Procedure.i IsPointInsideRectancle2D(x0.f,y0.f,x1.f,y1.f,x2.f,y2.f,x3.f,y3.f,x.f,y.f)
   
   LineXY(x0,y0,x1,y1,RGB(60,80,60))
   LineXY(x0,y0,x3,y3,RGB(60,80,60))
   LineXY(x2,y2,x1,y1,RGB(60,80,60))
   LineXY(x2,y2,x3,y3,RGB(60,80,60))
   
   If IsPointInsideTriangle2D(x0,y0,x1,y1,x2,y2,x,y)
      ProcedureReturn 1
   EndIf
   If IsPointInsideTriangle2D(x2,y2,x3,y3,x0,y0,x,y)
      ProcedureReturn 2
   EndIf

   ProcedureReturn 0

EndProcedure
Procedure Cross(x,y,size,color)
   LineXY(x-size,y-size,x+size,y+size,color)
   LineXY(x+size,y-size,x-size,y+size,color)
EndProcedure
Procedure rectangleCenterPoint(*center.POINT_f, *TL.POINT, *TR.POINT, *BR.POINT, *BL.POINT)

   Protected dy1.f = *TL\y - *BR\y
   Protected dy2.f = *TR\y - *BL\y
   Protected dx1.f = *TL\x - *BR\x
   Protected dx2.f = *TR\x - *BL\x


   If dx1 = 0 Or dx2 = 0
      ;one of the sides is vertical, use this simplified formula instead
      *center\x =  (*TR\x + *BR\x) / 2
      *center\y =  (*TR\y + *BR\y) / 2
   Else
      Protected m1.f = dy1 / dx1
      Protected m2.f = dy2 / dx2
      Protected b1.f = *TL\y - m1 * *TL\x
      Protected b2.f = *TR\y - m2 * *TR\x
      *center\x = (b2 - b1) / (m1 - m2)
      *center\y = m1 * *center\x + b1
   EndIf

EndProcedure
Procedure UpdateImage()

   Protected x,y,color,quadrant.s

   x=WindowMouseX(0)
   y=WindowMouseY(0)

   InitValues()

   StartDrawing(ImageOutput(0))
   Box(0,0,#W,#H,#Black)

   DrawingMode(#PB_2DDrawing_Transparent)
   For i=0 To 3
      LineXY(Polygon(i<<1&7),Polygon(i<<1&7+1),Polygon((i<<1+2)&7),Polygon((i<<1+3)&7),#White)
      DrawText(Polygon(i<<1&7),Polygon(i<<1&7+1),Str(Real(i<<1&7))+"|"+Str(Real(i<<1&7+1)),#Blue)
   Next i

   LineXY((Polygon(0)+Polygon(6))>>1,(Polygon(1)+Polygon(7))>>1,(Polygon(2)+Polygon(4))>>1,(Polygon(3)+Polygon(5))>>1,RGB(40,40,40))
   LineXY((Polygon(0)+Polygon(2))>>1,(Polygon(1)+Polygon(3))>>1,(Polygon(6)+Polygon(4))>>1,(Polygon(7)+Polygon(5))>>1,RGB(40,40,40))

   Select IsPointInsideRectancle2D(Polygon(0),Polygon(1),Polygon(2),Polygon(3),Polygon(4),Polygon(5),Polygon(6),Polygon(7),x,y)
   Case 0
      color=#Red
   Case 1
      color=#Green
   Case 2
      color=#Yellow
   EndSelect

   LineXY(x-29,y,x+29,y,color)
   LineXY(x,y-29,x,y+29,color)

   ; ============================
   ; x_ and y_ have to be calculated here...
   ; ============================

   If color<>#Red

      Protected iteration=10

      While iteration
         iteration-1
         
         RectangleCenterPoint(M,@Polygon(0),@Polygon(2),@Polygon(4),@Polygon(6))
         Cross(M\x,M\y,iteration,RGB(160,160,160))

         RectangleCenterPoint(A,@Polygon(0),@Polygon(2),@Polygon(0),@Polygon(2))
         RectangleCenterPoint(B,@Polygon(0),@Polygon(6),@Polygon(0),@Polygon(6))
         RectangleCenterPoint(C,@Polygon(2),@Polygon(4),@Polygon(2),@Polygon(4))
         RectangleCenterPoint(D,@Polygon(4),@Polygon(6),@Polygon(4),@Polygon(6))
         
         If IsPointInsideRectancle2D(Polygon(0),Polygon(1),A\x,A\y,M\x,M\y,B\x,B\y,x,y)
            Cross(A\x,A\y,2,RGB(160,160,160))
            Cross(B\x,B\y,2,RGB(160,160,160))
            Real(2)=(Real(0)+Real(2))/2
            Real(3)=(Real(1)+Real(3))/2
            Real(4)=(Real(0)+Real(4))/2
            Real(5)=(Real(1)+Real(5))/2
            Real(6)=(Real(0)+Real(6))/2
            Real(7)=(Real(1)+Real(7))/2
            Polygon(2)=A\x
            Polygon(3)=A\y
            Polygon(4)=M\x
            Polygon(5)=M\y
            Polygon(6)=B\x
            Polygon(7)=B\y
            quadrant="A"
            
         ElseIf IsPointInsideRectancle2D(A\x,A\y,Polygon(2),Polygon(3),C\x,C\y,M\x,M\y,x,y)
            Cross(A\x,A\y,2,RGB(160,160,160))
            Cross(C\x,C\y,2,RGB(160,160,160))
            Real(0)=(Real(0)+Real(2))/2
            Real(1)=(Real(1)+Real(3))/2
            Real(4)=(Real(2)+Real(4))/2
            Real(5)=(Real(3)+Real(5))/2
            Real(6)=(Real(2)+Real(6))/2
            Real(7)=(Real(3)+Real(7))/2
            Polygon(0)=A\x
            Polygon(1)=A\y
            Polygon(4)=C\x
            Polygon(5)=C\y
            Polygon(6)=M\x
            Polygon(7)=M\y
            quadrant="B"
            
         ElseIf IsPointInsideRectancle2D(M\x,M\y,C\x,C\y,Polygon(4),Polygon(5),D\x,D\y,x,y)
            Cross(C\x,C\y,2,RGB(160,160,160))
            Cross(D\x,D\y,2,RGB(160,160,160))
            Real(0)=(Real(0)+Real(4))/2
            Real(1)=(Real(1)+Real(5))/2
            Real(2)=(Real(2)+Real(4))/2
            Real(3)=(Real(3)+Real(5))/2
            Real(6)=(Real(4)+Real(6))/2
            Real(7)=(Real(5)+Real(7))/2
            Polygon(0)=M\x
            Polygon(1)=M\y
            Polygon(2)=C\x
            Polygon(3)=C\y
            Polygon(6)=D\x
            Polygon(7)=D\y
            quadrant="C"
            
         ElseIf IsPointInsideRectancle2D(B\x,B\y,M\x,M\y,D\x,D\y,Polygon(6),Polygon(7),x,y)
            Cross(B\x,B\y,2,RGB(160,160,160))
            Cross(D\x,D\y,2,RGB(160,160,160))
            Real(0)=(Real(0)+Real(6))/2
            Real(1)=(Real(1)+Real(7))/2
            Real(2)=(Real(0)+Real(2))/2
            Real(3)=(Real(2)+Real(4))/2
            Real(4)=(Real(6)+Real(4))/2
            Real(5)=(Real(7)+Real(5))/2
            Polygon(0)=B\x
            Polygon(1)=B\y
            Polygon(2)=M\x
            Polygon(3)=M\y
            Polygon(4)=D\x
            Polygon(5)=D\y
            quadrant="D"
         Else
            iteration=0
            quadrant="-"
         EndIf
         
         DrawText(600,200-iteration*20,Str(iteration)+": "+quadrant)
      Wend

      For i=0 To 3
         If x=Polygon(i<<1) And y=Polygon(i<<1+1)
            x_=Real(i<<1)
            y_=Real(i<<1+1)
         EndIf
      Next i

      x_=(Real(0)+Real(4)) / 2
      y_=(Real(1)+Real(5)) / 2

      DrawText(x+10,y-25,Str(x_)+" | "+Str(y_),$FF4040)

   EndIf

   StopDrawing()
   SetGadgetState(0,ImageID(0))

EndProcedure

OpenWindow(0,0,0,#W,#H,"")
ImageGadget(0,0,0,#W,#H,0)
CreateImage(0,#W,#H,24)
UpdateImage()

Repeat
   Select WaitWindowEvent()
   Case #WM_MOUSEMOVE
      UpdateImage()
   Case #WM_CHAR
      End
   EndSelect
ForEver


Top
 Profile  
 
 Post subject: Re: Calculate real 3D coordinates from 2D
PostPosted: Mon Apr 02, 2012 10:07 am 
Offline
Addict
Addict
User avatar

Joined: Mon Jul 25, 2005 3:51 pm
Posts: 2401
Location: Utah, USA
I have found a solution using projection mapping. Which allows the mapping of an arbitrary quadrilateral to another quadrilateral. I translated some code that I found published on the internet from the University of California in 1989 entitled "Fundamentals of texture Mapping and Image Warping". It is easy to locate the document with an internet search if you want to see what it contains. This method works much better than subdividing the original polygon, which I see you did and I admit that I was tempted to do as well.

I would like to clean it up a little by whittling away anything that is unnecessary to your use. Of course I may just take the easy way out and let you do that. :wink:

I have a few more question before I share it. What kind of situations are you going to be using it for? Is it always going to be used for polygons and rectangle/squares of the same size? How are you determining the dimensions of the polygon and rectangle/map, are they from a map source?

_________________
Image


Top
 Profile  
 
 Post subject: Re: Calculate real 3D coordinates from 2D
PostPosted: Fri Apr 13, 2012 5:39 pm 
Offline
Addict
Addict
User avatar

Joined: Thu Feb 09, 2006 11:27 pm
Posts: 1716
Demivec wrote:
I have found a solution using projection mapping. Which allows the mapping of an arbitrary quadrilateral to another quadrilateral. I translated some code that I found published on the internet from the University of California in 1989 entitled "Fundamentals of texture Mapping and Image Warping". It is easy to locate the document with an internet search if you want to see what it contains. This method works much better than subdividing the original polygon, which I see you did and I admit that I was tempted to do as well.

I would like to clean it up a little by whittling away anything that is unnecessary to your use. Of course I may just take the easy way out and let you do that. :wink:

I have a few more question before I share it. What kind of situations are you going to be using it for? Is it always going to be used for polygons and rectangle/squares of the same size? How are you determining the dimensions of the polygon and rectangle/map, are they from a map source?


Hi, I've been on holiday for a while, that's why this message has been a little bit delayed :wink:

I give you some information what I am doing (and what is my actual workaround for solving the problem above): I have written a program to do reports for sport activities which also shows GPS tracks in 3D. for doing this, I multiply matrices to convert 3D geo coordinates into 2D screen coordinates. Now I wanted to set waypoints (POIs) by doing a mouse click somewhere on the screen.

As I was not able to reverse the 3D–>2D conversion, I actually calculate the 2D coordinates for n×n geo coordinates, check which is the nearest to the mouse position, calculate n×n geo coordinates near this point and so on – not the best approach, but at least working.


Top
 Profile  
 
 Post subject: Re: Calculate real 3D coordinates from 2D
PostPosted: Sat Apr 14, 2012 8:47 pm 
Offline
Addict
Addict
User avatar

Joined: Mon Jul 25, 2005 3:51 pm
Posts: 2401
Location: Utah, USA
Michael Vogel wrote:
As I was not able to reverse the 3D–>2D conversion, I actually calculate the 2D coordinates for n×n geo coordinates, check which is the nearest to the mouse position, calculate n×n geo coordinates near this point and so on – not the best approach, but at least working.


I cleaned up this code a little but I think you could probably tune it to your individual case better than I could. It converts between the coordinates of the screen point (sx, sy) and a texture point (u, v). In your case the texture is the geo cordinates.

projection_map.pbi
Code:
EnableExplicit
;Projection mapping routines translated from code presented in
;"Fundamentals of texture Mapping and Image Warping" by Paul S. Heckbert for his
;Master's Thesis at the University of California in 1989.
;
;Coded in PureBasic and adapted by Demivec.

Structure POINT_d
  x.d
  y.d
EndStructure

Structure poly_vert  ;a polygon vetex
  u.d                ;texture space coordinates
  v.d
  sx.d               ;screen space coordinates
  sy.d
EndStructure

Structure poly_quad       ;a polygon, specifically a quadrilateral
  vert.poly_vert[4]  ;vertices
EndStructure

;pmap return codes
Enumeration -1
  #PMAP_BAD        ;mapping doesn't exist (bad correspondence)
  #PMAP_AFFINE     ;mapping is affine
  #PMAP_PROJECTIVE ;mapping is projective
EndEnumeration

;-matrix code
;Routines for manipulating 3 x 3 matrices
;These matrices are used to represent a 2-D projective mapping.

;Determinate for a 2x2 matrix.
Macro det2(a, b, c, d)
  ((a) * (d) - (b) * (c))
EndMacro

Procedure.d mx3d_adjoint(Array a.d(2), Array b.d(2))
  ;b = adjoint(a), returns determinant(a)
  b(0, 0) = det2(a(1, 1), a(1, 2), a(2, 1), a(2, 2))
  b(1, 0) = det2(a(1, 2), a(1, 0), a(2, 2), a(2, 0))
  b(2, 0) = det2(a(1, 0), a(1, 1), a(2, 0), a(2, 1))
  b(0, 1) = det2(a(2, 1), a(2, 2), a(0, 1), a(0, 2))
  b(1, 1) = det2(a(2, 2), a(2, 0), a(0, 2), a(0, 0))
  b(2, 1) = det2(a(2, 0), a(2, 1), a(0, 0), a(0, 1))
  b(0, 2) = det2(a(0, 1), a(0, 2), a(1, 1), a(1, 2))
  b(1, 2) = det2(a(0, 2), a(0, 0), a(1, 2), a(1, 0))
  b(2, 2) = det2(a(0, 0), a(0, 1), a(1, 0), a(1, 1))
 
  ;If matrix is non-invertable the determinant will equal zero.
  ;The determinatnt may also equal zero due to floating point rounding errors.
  ProcedureReturn a(0, 0) * b(0, 0) + a(0, 1) * b(0, 1) + a(0, 2) * b(0, 2)
EndProcedure
 
Procedure mx3d_mul(Array a.d(2), Array b.d(2), Array c.d(2))
  ;matrix multiply: c = a * b
  c(0, 0) = a(0, 0) * b(0, 0) + a(0, 1) * b(1, 0) + a(0, 2) * b(2, 0)
  c(0, 1) = a(0, 0) * b(0, 1) + a(0, 1) * b(1, 1) + a(0, 2) * b(2, 1)
  c(0, 2) = a(0, 0) * b(0, 2) + a(0, 1) * b(1, 2) + a(0, 2) * b(2, 2)
  c(1, 0) = a(1, 0) * b(0, 0) + a(1, 1) * b(1, 0) + a(1, 2) * b(2, 0)
  c(1, 1) = a(1, 0) * b(0, 1) + a(1, 1) * b(1, 1) + a(1, 2) * b(2, 1)
  c(1, 2) = a(1, 0) * b(0, 2) + a(1, 1) * b(1, 2) + a(1, 2) * b(2, 2)
  c(2, 0) = a(2, 0) * b(0, 0) + a(2, 1) * b(1, 0) + a(2, 2) * b(2, 0)
  c(2, 1) = a(2, 0) * b(0, 1) + a(2, 1) * b(1, 1) + a(2, 2) * b(2, 1)
  c(2, 2) = a(2, 0) * b(0, 2) + a(2, 1) * b(1, 2) + a(2, 2) * b(2, 2)
EndProcedure

Procedure mx3d_transform(Array p.d(1), Array a_matrix.d(2), Array q.d(1)) ;the p & q matrices are 1x3
  ;transform point p by matrix a_Matrix: q = p * a_Matrix
  q(0) = p(0) * a_matrix(0, 0) + p(1) * a_matrix(1, 0) + p(2) * a_matrix(2, 0)
  q(1) = p(0) * a_matrix(0, 1) + p(1) * a_matrix(1, 1) + p(2) * a_matrix(2, 1)
  q(2) = p(0) * a_matrix(0, 2) + p(1) * a_matrix(1, 2) + p(2) * a_matrix(2, 2)
EndProcedure

;-general projective mapping code
;General routines for 2-D projective mappings.
;These routines, pmap_quad_rect and pmap_square_quad,
;are independent of the poly_quad structure, so we do not
;think in terms of texture and screen space.
#TOLERANCE = 1e-13
; Macro zero(x): ((x) < #TOLERANCE And (x) > -#TOLERANCE): EndMacro ;used in conditionals

Procedure pmap_square_quad(Array quadVertex.POINT_d(1), Array sq_matrix.d(2))
  ;Find mapping between unit square and quadrilateral
  ;The correspondence is:
  ;
  ;  (0, 0) --> quadVertex(0)
  ;  (1, 0) --> quadVertex(1)
  ;  (1, 1) --> quadVertex(2)
  ;  (0, 1) --> quadVertex(3)
 
  ;quadVertex: vertices of quadrilateral
  ;sq  : square->quad transform (returned)
  Protected.d px, py
 
  px = quadVertex(0)\x - quadVertex(1)\x + quadVertex(2)\x - quadVertex(3)\x
  py = quadVertex(0)\y - quadVertex(1)\y + quadVertex(2)\y - quadVertex(3)\y
 
  If (px < #TOLERANCE And px > -#TOLERANCE) And (py < #TOLERANCE And py > -#TOLERANCE) ;affine
    sq_matrix(0, 0) = quadVertex(1)\x - quadVertex(0)\x
    sq_matrix(1, 0) = quadVertex(2)\x - quadVertex(1)\x
    sq_matrix(2, 0) = quadVertex(0)\x
    sq_matrix(0, 1) = quadVertex(1)\y - quadVertex(0)\y
    sq_matrix(1, 1) = quadVertex(2)\y - quadVertex(1)\y
    sq_matrix(2, 1) = quadVertex(0)\y
    sq_matrix(0, 2) = 0
    sq_matrix(1, 2) = 0
    sq_matrix(2, 2) = 1
    ProcedureReturn #PMAP_AFFINE
  Else                     ;projective
    Protected.d dx1, dx2, dy1, dy2, del
   
    dx1 = quadVertex(1)\x - quadVertex(2)\x
    dx2 = quadVertex(3)\x - quadVertex(2)\x
    dy1 = quadVertex(1)\y - quadVertex(2)\y
    dy2 = quadVertex(3)\y - quadVertex(2)\y
    del = det2(dx1, dx2, dy1, dy2)
   
    If del = 0
      MessageRequester("Error", "pmap_square_quad: bad mapping")
      ProcedureReturn #PMAP_BAD
    EndIf
   
    sq_matrix(0, 2) = det2(px, dx2, py, dy2) / del
    sq_matrix(1, 2) = det2(dx1, px, dy1, py) / del
    sq_matrix(2, 2) = 1
    sq_matrix(0, 0) = quadVertex(1)\x - quadVertex(0)\x + sq_matrix(0, 2) * quadVertex(1)\x
    sq_matrix(1, 0) = quadVertex(3)\x - quadVertex(0)\x + sq_matrix(1, 2) * quadVertex(3)\x
    sq_matrix(2, 0) = quadVertex(0)\x
    sq_matrix(0, 1) = quadVertex(1)\y - quadVertex(0)\y + sq_matrix(0, 2) * quadVertex(1)\y
    sq_matrix(1, 1) = quadVertex(3)\y - quadVertex(0)\y + sq_matrix(1, 2) * quadVertex(3)\y
    sq_matrix(2, 1) = quadVertex(0)\y
   
    ProcedureReturn #PMAP_PROJECTIVE
  EndIf
 
EndProcedure

Procedure pmap_quad_rect(u0.d, v0.d, u1.d, v1.d, Array quadVertex.POINT_d(1), Array qr_matrix.d(2))
  ;Find mapping between quadrilateral and rectangle.
  ;The correspondence is:
  ;
  ;  quadVertex(0) --> (u0, v0)
  ;  quadVertex(1) --> (u1, v0)
  ;  quadVertex(2) --> (u1, v1)
  ;  quadVertex(3) --> (u0, v1)
  ;
  ;This method of computing the adjoint is numericaly cheaper than
  ;computing it symbolically.
 
  ;u0, v0, u1, v1: bounds of rectangle
  ;quadVertex():   vertices of quadrilateral
  ;qr_Matrix():    quad->rect transform (returned)
 
  Protected ret, du.d, dv.d
  Protected Dim rq_matrix.d(2, 2) ;rect->quad transform
 
  du = u1 - u0
  dv = v1 - v0
  If du = 0 Or dv = 0
    MessageRequester("Error", "pmap_quad_rect: null rectangle")
    ProcedureReturn #PMAP_BAD
  EndIf
 
  ;first find mapping from unit uv square to xy quadrilateral
  ret = pmap_square_quad(quadVertex(), rq_matrix())
  If ret = #PMAP_BAD: ProcedureReturn #PMAP_BAD: EndIf
 
  ;concatenate transform from uv rectangle (u0, v0, u1, v1) to unit square
  rq_matrix(0, 0) / du
  rq_matrix(1, 0) / dv
  rq_matrix(2, 0) - rq_matrix(0, 0) * u0 + rq_matrix(1, 0) * v0
  rq_matrix(0, 1) / du
  rq_matrix(1, 1) / dv
  rq_matrix(2, 1) - rq_matrix(0, 1) * u0 + rq_matrix(1, 1) * v0
  rq_matrix(0, 2) / du
  rq_matrix(1, 2) / dv
  rq_matrix(2, 2) - rq_matrix(0, 2) * u0 + rq_matrix(1, 2) * v0
 
  ;now rq_Matrix is transform from uv rectangle to xy quadrilateral
  ;qr_Matrix = inverse transform, which maps xy to uv
  If mx3d_adjoint(rq_matrix(), qr_matrix()) = 0
    MessageRequester("Warning", "pmap_quad_rect: determinate = 0")
  EndIf
 
  ProcedureReturn ret
EndProcedure

;-projective mapping code
Procedure pmap_quad_quad(*p.poly_quad, Array st_matrix.d(2))
  ;Find the projective mapping st from screen to texture space
  ;given the screen and texture coordinates at the vertices of a polygon (specifically a quadrilateral).
  ;
  ;Method: concatenate screen_quad->mid_square and
  ;mid_square->texture_quad transform matrices.
  ;The alternative method, solving an 8x8 system of equations, takes longer.
 
  Protected i, type1, type2
  Protected Dim quadVertex.POINT_d(3) ;screen_quad vertices
  Protected Dim ms_matrix.d(2, 2)     ;mid_square->screen transform matrix
  Protected Dim sm_matrix.d(2, 2)     ;screen->mid transform matrix
  Protected Dim mt_matrix.d(2, 2)     ;mid->texture transform matrix
 
  ;prepare mid_square->screen transform matrix
  For i = 0 To 3
    quadVertex(i)\x = *p\vert[i]\sx: quadVertex(i)\y = *p\vert[i]\sy
  Next
  type1 = pmap_square_quad(quadVertex(), ms_matrix())
 
  If mx3d_adjoint(ms_matrix(), sm_matrix()) = 0
    MessageRequester("Warning", "pmap_quad_quad: determinant = 0")
  EndIf
 
  ;prepare mid->texture transform matrix
  For i = 0 To 3
    quadVertex(i)\x = *p\vert[i]\u: quadVertex(i)\y = *p\vert[i]\v
  Next
  type2 = pmap_square_quad(quadVertex(), mt_matrix())
 
  If type1 = #PMAP_BAD Or type2 = #PMAP_BAD
    ProcedureReturn #PMAP_BAD
  EndIf
 
  mx3d_mul(sm_matrix(), mt_matrix(), st_matrix())
  ProcedureReturn type1 | type2 ;#PMAP_PROJECTIVE prevails over #PMAP_AFFINE
EndProcedure


Procedure pmap_poly(*p.poly_quad, Array st_matrix.d(2))
  ;Find the projective mapping st from screen to texture space
  ;given the screen and texture coordinates at the vertices of a polygon (specifically a quadrilateral),
  ;which are passed in the fields (sx, sy) and (u, v) of p\vert[i], respectively.
  Protected Dim screenQuad.POINT_d(3) ;vertices of screen quadrilateral
  With *p
    If \vert[0]\v = \vert[1]\v And \vert[2]\v = \vert[3]\v And \vert[1]\u = \vert[2]\u And \vert[3]\u = \vert[0]\u
      ;edges 0-1 and 2-3 are horz, so 1-2 and 3-0 are vert
      screenQuad(0)\x = \vert[0]\sx: screenQuad(0)\y = \vert[0]\sy
      screenQuad(1)\x = \vert[1]\sx: screenQuad(1)\y = \vert[1]\sy
      screenQuad(2)\x = \vert[2]\sx: screenQuad(2)\y = \vert[2]\sy
      screenQuad(3)\x = \vert[3]\sx: screenQuad(3)\y = \vert[3]\sy
      ProcedureReturn pmap_quad_rect(\vert[0]\u, \vert[0]\v, \vert[2]\u, \vert[2]\v, screenQuad(), st_matrix())
   
    ElseIf \vert[0]\u = \vert[1]\u And \vert[2]\u = \vert[3]\u And \vert[1]\v = \vert[2]\v And \vert[3]\v = \vert[0]\v
      ;edges 0-1 and 2-3 are vert, so 1-2 and 3-0 are horz
      screenQuad(0)\x = \vert[1]\sx: screenQuad(0)\y = \vert[1]\sy
      screenQuad(1)\x = \vert[2]\sx: screenQuad(1)\y = \vert[2]\sy
      screenQuad(2)\x = \vert[3]\sx: screenQuad(2)\y = \vert[3]\sy
      screenQuad(3)\x = \vert[0]\sx: screenQuad(3)\y = \vert[0]\sy
      ProcedureReturn pmap_quad_rect(\vert[1]\u, \vert[1]\v, \vert[3]\u, \vert[3]\v, screenQuad(), st_matrix())
 
    Else
      ;texture is not an orthogonally-oriented rectangle
      ProcedureReturn pmap_quad_quad(*p, st_matrix())
    EndIf
  EndWith
EndProcedure

DisableExplicit


Test code:
Code:
; Define
#mcolor = $E0E0E0 ;$8A8A8A
#ncolor = $FFD0D0 ;$4C804C
#pcolor = $D0D0FF ;$343434
#W=640
#H=480
XIncludeFile "projection_map.pbi"

Global Dim polygon(7)
Global Dim Real.d(7)
Global screenQuad.poly_quad
Global Dim screenToGeo.d(2, 2)
Global Dim geoToScreen.d(2, 2)
Global Dim screenCoord.d(2)
Global Dim screenCoord2.d(2)
Global Dim geoCoord.d(2)
Global Dim geoCoord2.d(2)

Procedure InitValues()
 
  polygon(0)=40: polygon(1)=40
  polygon(2)=340: polygon(3)=30
  polygon(4)=550: polygon(5)=300
  polygon(6)=100: polygon(7)=440
 
  ;test case 1 for another arbitrary polygon
  ; polygon(0)=66: polygon(1)=39
  ; polygon(2)=444: polygon(3)=33
  ; polygon(4)=300: polygon(5)=457
  ; polygon(6)=17: polygon(7)=440
 
  Real(0)=-100: Real(1)=-100
  Real(2)=100: Real(3)=-100
  Real(4)=100: Real(5)=100
  Real(6)=-100: Real(7)=100
 
  ;test case 1
  ;Other arbitrary rectangles used as geo coordinates, to test robustness of methods.
  ; Real(0)=-20: Real(1)=-30
  ; Real(2)=60: Real(3)=-30
  ; Real(4)=60: Real(5)=40 
  ; Real(6)=-20: Real(7)=40
 
  ;test case 2
  ; Real(0)=-20: Real(1)=30
  ; Real(2)=60: Real(3)=30
  ; Real(4)=60: Real(5)=40 
  ; Real(6)=-20: Real(7)=40

  ;set (sx, sy) for each vertex of screen quadrilateral along with the corresponding (u, v) geo points
  With screenQuad
    ;The following values is used for a reflection transformation to adjust for y axis being flipped
    ;between the screen and the geo cordinates. The value has only been tested based on a rectangular
    ;or square quadrilateral that is being used for the geo cordinates.
    Protected dy.d = - Real(3) * 2 ;The least y value of the rectangle needs to be used for the reflection adjustment.
    \vert[0]\u = Real(0): \vert[0]\v = Real(1) + dy: \vert[0]\sx = polygon(0): \vert[0]\sy = polygon(1)
    \vert[1]\u = Real(2): \vert[1]\v = Real(3) + dy: \vert[1]\sx = polygon(2): \vert[1]\sy = polygon(3)
    \vert[2]\u = Real(4): \vert[2]\v = Real(5) + dy: \vert[2]\sx = polygon(4): \vert[2]\sy = polygon(5)
    \vert[3]\u = Real(6): \vert[3]\v = Real(7) + dy: \vert[3]\sx = polygon(6): \vert[3]\sy = polygon(7)
  EndWith
 
EndProcedure

Procedure.i IsPointInsideTriangle2D(x0.d,y0.d,x1.d,y1.d,x2.d,y2.d,px.d,py.d)
 
  Protected V1x.d=x1-x0
  Protected V1y.d=y1-y0
  Protected V2x.d=x2-x1
  Protected V2y.d=y2-y1
  Protected V3x.d=x0-x2
  Protected V3y.d=y0-y2
 
  If V1y*(px-x0)>=V1x*(py-y0)
    If V2y*(px-x1)>=V2x*(py-y1) And V3y*(px-x2)>=V3x*(py-y2)
      ProcedureReturn #True
    EndIf
  Else
    If V2y*(px-x1)<V2x*(py-y1) And V3y*(px-x2)<V3x*(py-y2)
      ProcedureReturn #True
    EndIf
  EndIf
 
  ProcedureReturn #False
 
EndProcedure

Procedure.i IsPointInsideRectancle2D(x0.d,y0.d,x1.d,y1.d,x2.d,y2.d,x3.d,y3.d,x.d,y.d)
 
  LineXY(x0,y0,x1,y1,#ncolor)
  LineXY(x0,y0,x3,y3,#ncolor)
  LineXY(x2,y2,x1,y1,#ncolor)
  LineXY(x2,y2,x3,y3,#ncolor)
 
  If IsPointInsideTriangle2D(x0,y0,x1,y1,x2,y2,x,y)
    ProcedureReturn 1
  EndIf
  If IsPointInsideTriangle2D(x2,y2,x3,y3,x0,y0,x,y)
    ProcedureReturn 2
  EndIf
 
  ProcedureReturn 0
 
EndProcedure

Procedure Cross(x,y,size,color)
  LineXY(x-size,y-size,x+size,y+size,color)
  LineXY(x+size,y-size,x-size,y+size,color)
EndProcedure

Procedure UpdateImage()
 
  Protected x,y,color
 
  x=WindowMouseX(0)
  y=WindowMouseY(0)
 
  ;InitValues()
 
  StartDrawing(ImageOutput(0))
    Box(0,0,#W,#H,#Black)
   
    DrawingMode(#PB_2DDrawing_Transparent)
    For i=0 To 3
      LineXY(polygon(i<<1&7),polygon(i<<1&7+1),polygon((i<<1+2)&7),polygon((i<<1+3)&7),#White)
      DrawText(polygon(i<<1&7),polygon(i<<1&7+1),Str(Real(i<<1&7))+"|"+Str(Real(i<<1&7+1)),#Yellow)
    Next i
   
    ;center point
    geoCoord(0) = (Real(0) + Real(4)) / 2: geoCoord(1) = (Real(3) + Real(7)) / 2: geoCoord(2) = 1
    mx3d_transform(geoCoord(), geoToScreen(), screenCoord())
    Cross(screenCoord(0) / screenCoord(2), screenCoord(1) / screenCoord(2), 5, #pcolor)
   
   
    Select IsPointInsideRectancle2D(polygon(0),polygon(1),polygon(2),polygon(3),polygon(4),polygon(5),polygon(6),polygon(7),x,y)
      Case 0
        color=#Red
      Case 1
        color=#Green
      Case 2
        color=#Yellow
    EndSelect
   
    ;cross hairs
    LineXY(x-29,y,x+29,y,color)
    LineXY(x,y-29,x,y+29,color)
   
   
   
    If color<>#Red
     
      ; x_ and y_ are calculated here...
      screenCoord(0) = x: screenCoord(1) = y: screenCoord(2) = 1
      mx3d_transform(screenCoord(), screenToGeo(), geoCoord())
      Protected.d x_, y_
      x_ = geoCoord(0) / geoCoord(2)
      y_ = geoCoord(1) / geoCoord(2)
     
      ;horizontal line
      geoCoord(0) = Real(0): geoCoord(1) = y_: geoCoord(2) = 1
      mx3d_transform(geoCoord(), geoToScreen(), screenCoord())
      geoCoord2(0) = Real(4): geoCoord2(1) = y_: geoCoord2(2) = 1
      mx3d_transform(geoCoord2(), geoToScreen(), screenCoord2())
      LineXY(screenCoord(0) / screenCoord(2), screenCoord(1) / screenCoord(2), screenCoord2(0) / screenCoord2(2), screenCoord2(1) / screenCoord2(2), #White)
     
      ;vertical line
      geoCoord(0) = x_: geoCoord(1) = Real(3): geoCoord(2) = 1
      mx3d_transform(geoCoord(), geoToScreen(), screenCoord())
      geoCoord2(0) = x_: geoCoord2(1) = Real(7): geoCoord2(2) = 1
      mx3d_transform(geoCoord2(), geoToScreen(), screenCoord2())
      LineXY(screenCoord(0) / screenCoord(2), screenCoord(1) / screenCoord(2), screenCoord2(0) / screenCoord2(2), screenCoord2(1) / screenCoord2(2), #White)
       
      DrawText(x+10,y-25,Str(x_)+" | "+Str(y_), #Yellow)
     
    EndIf
   
  StopDrawing()
  SetGadgetState(0,ImageID(0))
 
EndProcedure

OpenWindow(0,0,0,#W,#H,"")
ImageGadget(0,0,0,#W,#H,0)
CreateImage(0,#W,#H,24)
InitValues()

;compute screen to geo transform
pmap_poly(screenQuad, screenToGeo())
If Not mx3d_adjoint(screenToGeo(), geoToScreen()): End: EndIf

UpdateImage()

Repeat
  Select WaitWindowEvent()
    Case #WM_MOUSEMOVE
      UpdateImage()
    Case #WM_CHAR
      End
  EndSelect
ForEver


I believe this does what you wanted. :)

I had one small problem that required some additional work to resolve. I setup two quadrilaterals with the coordinates you gave (Real(), and Polygon()). I then use the routines to create the transform matrices to convert between the two sets of coordinates. The problem that occurs required me to reflect the Real() coordinates to account for the flipping of the Y axis betwen the quadrilaterals defined by the Polygon() and the Real() coordinates. Either set of coordinates could probably have been used and so I chose the Real() ones because they were rectangular and thereby easier to do.

I'm going to see if I can add the reflective transformation, in a separate procedure call, that combines it as a matrix with the transformation matrix that has already been produced. This would allow referencing the original coordinates without them becoming distorted by the way the reflection transformation is in the current code.

This change distorts the copy of the coordinates because the reflected Y values are not the same as the originals. This means if you want to reference them, such as for displaying them for instance, you need to look to another copy of them (i.e. the ones stored in Real()). I do this when positioning things on the screen polygon based on the geo coordinates when displaying the center point and lines traversing the polygon based on the mouse position.

I did enough testing to recommend this as a good solution. I am going to explore other useful aspects of the projection mapping routines and possibly post them in the Tips & Tricks forum because of their usefullness.

@Edit: updated code, and explanatory test

_________________
Image


Top
 Profile  
 
 Post subject: Re: Calculate real 3D coordinates from 2D
PostPosted: Wed Apr 18, 2012 6:13 pm 
Offline
Addict
Addict
User avatar

Joined: Thu Feb 09, 2006 11:27 pm
Posts: 1716
Demivec,
thanks for your posting – it will take a while until I can play with it, actually I have have to work around 30 hours a day*, but I will check your code as soon as possible.

___
*) actually I don't care about number representations, even in an octal world


Top
 Profile  
 
 Post subject: Re: Calculate real 3D coordinates from 2D
PostPosted: Wed Apr 18, 2012 9:24 pm 
Offline
Addict
Addict
User avatar

Joined: Mon Jul 25, 2005 3:51 pm
Posts: 2401
Location: Utah, USA
Michael Vogel wrote:
thanks for your posting – it will take a while until I can play with it, actually I have have to work around 30 hours a day*, but I will check your code as soon as possible.

You sound like you are working way too much, slow down to only 29 or maybe 28 hours a day. :wink:


Here's a final update. I had thought that what was needed was a reflective transform, which I had added manually before. It turns out it wasn't needed and what I actually was doing was a translation transform. I have added a procedure to the example code that performs this and adds it to the transformations already present in the projection mapping (it's added before them). This modification will leave the original coordinates of both the polygon and its corresponding geo mapped coordinates at their original values so that they can be referred to as needed. This means that you wouldn't need a separate variable for either the Polygon() or the Real() coordinates if you didn't want to, all coordinate changes that are needed are in the transformation matrices.

The include file 'projection map.pbi' remains unchanged.

Here is the changed example code:
Code:
; Define
#mcolor = $E0E0E0 ;$8A8A8A
#ncolor = $FFD0D0 ;$4C804C
#pcolor = $D0D0FF ;$343434
#W=640
#H=480
XIncludeFile "projection_map.pbi"

Global Dim polygon(7)
Global Dim Real.d(7)
Global screenQuad.poly_quad
Global Dim screenToGeo.d(2, 2)
Global Dim geoToScreen.d(2, 2)
Global Dim screenCoord.d(2)
Global Dim screenCoord2.d(2)
Global Dim geoCoord.d(2)
Global Dim geoCoord2.d(2)

Procedure InitValues()
 
  polygon(0)=40: polygon(1)=40
  polygon(2)=340: polygon(3)=30
  polygon(4)=550: polygon(5)=300
  polygon(6)=100: polygon(7)=440
 
  ;test case 1 for another arbitrary polygon
  ; polygon(0)=66: polygon(1)=39
  ; polygon(2)=444: polygon(3)=33
  ; polygon(4)=300: polygon(5)=457
  ; polygon(6)=17: polygon(7)=440
 
  Real(0)=-100: Real(1)=-100
  Real(2)=100: Real(3)=-100
  Real(4)=100: Real(5)=100
  Real(6)=-100: Real(7)=100
 
  ;test case 1
  ;Other arbitrary rectangles used as geo coordinates, to test robustness of methods.
  ; Real(0)=-20: Real(1)=-30
  ; Real(2)=60: Real(3)=-30
  ; Real(4)=60: Real(5)=40 
  ; Real(6)=-20: Real(7)=40
 
  ;test case 2, minimum Y > 0
  ; Real(0)=-20: Real(1)=30
  ; Real(2)=60: Real(3)=30
  ; Real(4)=60: Real(5)=40 
  ; Real(6)=-20: Real(7)=40
 
  ;test case 3, maximum Y < 0 and Y axis reversed compared to polygon
   ; Real(0)=-20: Real(1)=-30
   ; Real(2)=60: Real(3)=-30
   ; Real(4)=60: Real(5)=-40 
   ; Real(6)=-20: Real(7)=-40

  ;set (sx, sy) for each vertex of screen quadrilateral along with the corresponding (u, v) geo points
  With screenQuad
    \vert[0]\u = Real(0): \vert[0]\v = Real(1): \vert[0]\sx = polygon(0): \vert[0]\sy = polygon(1)
    \vert[1]\u = Real(2): \vert[1]\v = Real(3): \vert[1]\sx = polygon(2): \vert[1]\sy = polygon(3)
    \vert[2]\u = Real(4): \vert[2]\v = Real(5): \vert[2]\sx = polygon(4): \vert[2]\sy = polygon(5)
    \vert[3]\u = Real(6): \vert[3]\v = Real(7): \vert[3]\sx = polygon(6): \vert[3]\sy = polygon(7)
  EndWith
 
EndProcedure

Procedure.i IsPointInsideTriangle2D(x0.d,y0.d,x1.d,y1.d,x2.d,y2.d,px.d,py.d)
 
  Protected V1x.d=x1-x0
  Protected V1y.d=y1-y0
  Protected V2x.d=x2-x1
  Protected V2y.d=y2-y1
  Protected V3x.d=x0-x2
  Protected V3y.d=y0-y2
 
  If V1y*(px-x0)>=V1x*(py-y0)
    If V2y*(px-x1)>=V2x*(py-y1) And V3y*(px-x2)>=V3x*(py-y2)
      ProcedureReturn #True
    EndIf
  Else
    If V2y*(px-x1)<V2x*(py-y1) And V3y*(px-x2)<V3x*(py-y2)
      ProcedureReturn #True
    EndIf
  EndIf
 
  ProcedureReturn #False
 
EndProcedure

Procedure.i IsPointInsideRectancle2D(x0.d,y0.d,x1.d,y1.d,x2.d,y2.d,x3.d,y3.d,x.d,y.d)
 
  LineXY(x0,y0,x1,y1,#ncolor)
  LineXY(x0,y0,x3,y3,#ncolor)
  LineXY(x2,y2,x1,y1,#ncolor)
  LineXY(x2,y2,x3,y3,#ncolor)
 
  If IsPointInsideTriangle2D(x0,y0,x1,y1,x2,y2,x,y)
    ProcedureReturn 1
  EndIf
  If IsPointInsideTriangle2D(x2,y2,x3,y3,x0,y0,x,y)
    ProcedureReturn 2
  EndIf
 
  ProcedureReturn 0
 
EndProcedure

Procedure Cross(x,y,size,color)
  LineXY(x-size,y-size,x+size,y+size,color)
  LineXY(x+size,y-size,x-size,y+size,color)
EndProcedure

Procedure UpdateImage()
 
  Protected x,y,color
 
  x=WindowMouseX(0)
  y=WindowMouseY(0)
 
  ;InitValues()
  With screenQuad
    StartDrawing(ImageOutput(0))
      Box(0,0,#W,#H,#Black)
     
      DrawingMode(#PB_2DDrawing_Transparent)
      For i=0 To 3
        LineXY(polygon(i<<1&7),polygon(i<<1&7+1),polygon((i<<1+2)&7),polygon((i<<1+3)&7),#White)
        DrawText(polygon(i<<1&7),polygon(i<<1&7+1),Str(Real(i<<1&7))+"|"+Str(Real(i<<1&7+1)),#Yellow)
      Next i
     
      ;center point
     
      ;geoCoord(0) = (Real(0) + Real(4)) / 2: geoCoord(1) = (Real(3) + Real(7)) / 2: geoCoord(2) = 1
      geoCoord(0) = (\vert[0]\u + \vert[2]\u) / 2: geoCoord(1) = (\vert[1]\v + \vert[3]\v) / 2: geoCoord(2) = 1
      mx3d_transform(geoCoord(), geoToScreen(), screenCoord())
      Cross(screenCoord(0) / screenCoord(2), screenCoord(1) / screenCoord(2), 5, #pcolor)
     
     
      Select IsPointInsideRectancle2D(polygon(0),polygon(1),polygon(2),polygon(3),polygon(4),polygon(5),polygon(6),polygon(7),x,y)
        Case 0
          color=#Red
        Case 1
          color=#Green
        Case 2
          color=#Yellow
      EndSelect
     
      ;cross hairs
      LineXY(x-29,y,x+29,y,color)
      LineXY(x,y-29,x,y+29,color)
     
     
     
      If color<>#Red
       
        ; x_ and y_ are calculated here...
        screenCoord(0) = x: screenCoord(1) = y: screenCoord(2) = 1
        mx3d_transform(screenCoord(), screenToGeo(), geoCoord())
        Protected.d x_, y_
        x_ = geoCoord(0) / geoCoord(2)
        y_ = geoCoord(1) / geoCoord(2)
       
        ;horizontal line
        geoCoord(0) = \vert[0]\u: geoCoord(1) = y_: geoCoord(2) = 1
        mx3d_transform(geoCoord(), geoToScreen(), screenCoord())
        geoCoord2(0) = \vert[2]\u: geoCoord2(1) = y_: geoCoord2(2) = 1
        mx3d_transform(geoCoord2(), geoToScreen(), screenCoord2())
        LineXY(screenCoord(0) / screenCoord(2), screenCoord(1) / screenCoord(2), screenCoord2(0) / screenCoord2(2), screenCoord2(1) / screenCoord2(2), #White)
       
        ;vertical line
        geoCoord(0) = x_: geoCoord(1) = \vert[1]\v: geoCoord(2) = 1
        mx3d_transform(geoCoord(), geoToScreen(), screenCoord())
        geoCoord2(0) = x_: geoCoord2(1) = \vert[3]\v: geoCoord2(2) = 1
        mx3d_transform(geoCoord2(), geoToScreen(), screenCoord2())
        LineXY(screenCoord(0) / screenCoord(2), screenCoord(1) / screenCoord(2), screenCoord2(0) / screenCoord2(2), screenCoord2(1) / screenCoord2(2), #White)
       
        DrawText(x+10,y-25,Str(x_)+" | "+Str(y_), #Yellow)
       
      EndIf
     
    StopDrawing()
  EndWith
  SetGadgetState(0,ImageID(0))
 
EndProcedure

Procedure translationTransform(*p.poly_quad, Array t.d(2)) ;t() is a matrix to update by adding a translation transform to it
  Protected dy.d = *p\vert[1]\v * 2
  Protected Dim t2.d(2, 2)
  Protected Dim r.d(2, 2)
  CopyArray(t(), t2()) ;this allows us to output the original matrix with our changes
  r(0, 0) = 1: r(1, 0) =  0: r(2, 0) = 0
  r(0, 1) = 0: r(1, 1) = 1: r(2, 1) = dy
  r(0, 2) = 0: r(1, 2) =  0: r(2, 2) = 1
  mx3d_mul(t2(), r(), t())
EndProcedure

OpenWindow(0,0,0,#W,#H,"")
ImageGadget(0,0,0,#W,#H,0)
CreateImage(0,#W,#H,24)
InitValues()

;compute screen to geo transform
pmap_poly(screenQuad, screenToGeo())
translationTransform(screenQuad, screenToGeo()) ;add translation transform
If Not mx3d_adjoint(screenToGeo(), geoToScreen()): End: EndIf ;Abort, transforms can't be inverted

UpdateImage()

Repeat
  Select WaitWindowEvent()
    Case #WM_MOUSEMOVE
      UpdateImage()
    Case #WM_CHAR
      End
  EndSelect
ForEver


One interesting to note is that as a result of adding the translation transform the code will actually peform a reflection along the Y axis if needed. I provided a test case to prove it. I think that should provide most, if not all of what you need. Let me know how things turn out.

_________________
Image


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 9 posts ] 

All times are UTC + 1 hour


Who is online

Users browsing this forum: No registered users and 4 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
Jump to:  

 


Powered by phpBB © 2008 phpBB Group
subSilver+ theme by Canver Software, sponsor Sanal Modifiye