Calculating angles between lines with runtime draggable endpoints
Calculating angles between lines with runtime draggable endpoints
Calculating angles between lines with runtime draggable endpoints
Calculating angles between lines with runtime draggable endpoints
Calculating angles between lines with runtime draggable endpoints
Calculating angles between lines with runtime draggable endpoints Calculating angles between lines with runtime draggable endpoints Calculating angles between lines with runtime draggable endpoints Calculating angles between lines with runtime draggable endpoints Calculating angles between lines with runtime draggable endpoints Calculating angles between lines with runtime draggable endpoints Calculating angles between lines with runtime draggable endpoints Calculating angles between lines with runtime draggable endpoints
Calculating angles between lines with runtime draggable endpoints Calculating angles between lines with runtime draggable endpoints
Calculating angles between lines with runtime draggable endpoints
Go Back  Xtreme Visual Basic Talk > > > Calculating angles between lines with runtime draggable endpoints


Reply
 
Thread Tools Display Modes
  #1  
Old 02-24-2013, 07:16 PM
surfR2911 surfR2911 is offline
Contributor
 
Join Date: Oct 2009
Posts: 719
Default Calculating angles between lines with runtime draggable endpoints


Still trying to use texturebrushing to fill rotating 3D cube faces.

Towards that end, I'm looking to find the angle of the cube face edge to
do the matrix rotation of the texturebrush floodfill at the right angle.

Here is the screenshot I posted earlier of the texturebrushing at the wrong angle (basically unangled/horizontal)

After my recent "trigonmetry challenged" frustration post, I decided to forget about the cube for the moment,
& simplify the angles sub-task by looking around for some "merely" 2D angle calculation code.

For VB6 there are two good angles between lines examples (dot product, Law of Cosines), and after long searching I found
a roughly equivalent "Calculate the Angle Between Two Lines" VB.Net code snippet.

I hate dealing with bare code snippets so I made a test program to play around with moving the lines,
connected at a common endpoint, by dragging the non-vertex endpoints,
& seeing what happens with the calculation of the angles.

Since I'm posting this in the interface and graphics forum I guess I'll post enough of a drawing snippet
to understand what's going on with the rendering part:
Code:
Imports System.Math
Imports System.Drawing.Drawing2D
' Some non "magic" values to start off with..
Dim intYOffSet As Integer = 100
Dim intXOffSet As Integer = 50
' The grab handle we are dragging. This is  -1 when we are not dragging any handle.
Private m_DraggingHandle As Integer = -1
' The data points for centerpoints of the runtime draggable boxes
Private m_Points() As Point
' For drag boxes extents
Private Const HANDLE_WIDTH As Integer = 6
Private Const HANDLE_HALF_WIDTH As Integer = HANDLE_WIDTH \ 2
Private Const intTinyHandle As Integer = 1

' Create some initial point data.
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
      ' Make room.
      ReDim m_Points(2)
      ' Set initial points.
      m_Points(0).X = 125 + intXOffSet : m_Points(0).Y = 210 + intYOffSet
      m_Points(1).X = intXOffSet : m_Points(1).Y = 130 + intYOffSet
      m_Points(2).X = 125 + intXOffSet : m_Points(2).Y = 60 + intYOffSet
End Sub

' For drawing.. (duh!)
Private Sub DrawLinesAndText(ByVal gr As Graphics)
    'Clear out previous drawing
    gr.Clear(picCanvas.BackColor)
    'Smoothing is good
    gr.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
    'alternate smoothing mode
    'gr.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias

    'Draw lines that move as endpoint is dragged
    Dim ptX_Axis As New Point(600 + intXOffSet, 130 + intYOffSet)
    Dim MyPen1 As Pen = New Pen(Color.Black, 1)
    Dim MyPen1b As Pen = New Pen(Color.Red, 1)
    Dim mycap As CustomLineCap = New AdjustableArrowCap(5, 5)
    MyPen1b.EndCap = LineCap.ArrowAnchor
    MyPen1b.CustomEndCap = mycap
    gr.DrawLine(MyPen1b, m_Points(1), m_Points(0))
    gr.DrawLine(MyPen1b, m_Points(1), m_Points(2))
    gr.DrawLine(MyPen1, m_Points(1), m_Points(0))
    gr.DrawLine(MyPen1, m_Points(1), m_Points(2))
    'Draw the middle dash dot dividing line (between the two moveable lines)
    Dim MyPen2 As Pen = New Pen(Color.Blue, 2)
    MyPen2.DashStyle = Drawing.Drawing2D.DashStyle.DashDotDot
    gr.DrawLine(MyPen2, m_Points(1), ptX_Axis)

    ' Draw grab handles as white squares with black outlines
    Dim rectangles() As Rectangle
    ReDim rectangles(m_Points.GetUpperBound(0))
    For i As Integer = 0 To m_Points.GetUpperBound(0)
        With rectangles(i)
          If i <> 1 Then
            .X = m_Points(i).X - HANDLE_HALF_WIDTH
            .Y = m_Points(i).Y - HANDLE_HALF_WIDTH
            .Width = HANDLE_WIDTH
            .Height = HANDLE_WIDTH
          ElseIf i = 1 Then 'Set much smaller then the other drag handles
            .X = m_Points(i).X - intTinyHandle
            .Y = m_Points(i).Y - intTinyHandle
            .Width = intTinyHandle + 1 'barely visible..as visual indication it's not draggable
            .Height = intTinyHandle + 1 'barely visible..as visual indication it's not draggable
          End If
        End With
        'This "wedged in" sub-section draws text for outputting angles and x,y ccordinates
        Dim the_font As New Font("Microsoft Sans Serif", 12, _
        FontStyle.Regular, GraphicsUnit.Pixel)
        If i = 1 Then
          'Outputs x, y values for common (middle) non-draggable point
          gr.DrawString("pt " & i & " = " & _
           vbCrLf & "(" & m_Points(i).X & ", " & m_Points(i).Y & ")", _
                      the_font, Brushes.Black, m_Points(i).X - 50, m_Points(i).Y - 9)
          Dim dblAngle As Double
          Dim strAngle As String
          'Output total angle between moveable lines
          dblAngle = getAngleBetweenLinesVect(m_Points(1).X, m_Points(1).Y, _
                                          m_Points(0).X, m_Points(0).Y, _
                                            m_Points(2).X, m_Points(2).Y)
          'dblAngle = getRadianAngleBetweenLinesVect(m_Points(1).X, m_Points(1).Y, _
          '                                m_Points(0).X, m_Points(0).Y, _
          '                                  m_Points(2).X, m_Points(2).Y)
          strAngle = "Total Angle = " & vbCrLf & _
                                  CStr(dblAngle.ToString("#,##0.00")) & _
                                  vbCrLf & "degrees"
          gr.DrawString(strAngle, the_font, Brushes.Black, _
                        m_Points(i).X - 50, m_Points(i).Y - 70)

          'Outputs total angle between Top moveable line and x-axis aligned dash dotted dividing line
          dblAngle = getAngleBetweenLinesVect(m_Points(1).X, m_Points(1).Y, _
                                          m_Points(2).X, m_Points(2).Y, _
                                            ptX_Axis.X, ptX_Axis.Y)
          'dblAngle = getRadianAngleBetweenLinesVect(m_Points(1).X, m_Points(1).Y, _
          '                                m_Points(2).X, m_Points(2).Y, _
          '                                  ptX_Axis.X, ptX_Axis.Y)
          strAngle = "Top Angle = " & CStr(dblAngle.ToString("#,##0.00")) & " degrees"
          gr.DrawString(strAngle, the_font, Brushes.Black, _
                        m_Points(i).X + 27, m_Points(i).Y - 17)

          'Outputs total angle between bottom moveable line and x-axis aligned dash dotted dividing line
          dblAngle = getAngleBetweenLinesVect(m_Points(1).X, m_Points(1).Y, _
                                          m_Points(0).X, m_Points(0).Y, _
                                            ptX_Axis.X, ptX_Axis.Y)
          'dblAngle = getRadianAngleBetweenLinesVect(m_Points(1).X, m_Points(1).Y, _
          '                                m_Points(0).X, m_Points(0).Y, _
          '                                  ptX_Axis.X, ptX_Axis.Y)
          strAngle = "Bottom Angle = " & CStr(dblAngle.ToString("#,##0.00")) & " degrees"
          gr.DrawString(strAngle, the_font, Brushes.Black, _
                        m_Points(i).X + 27, m_Points(i).Y + 3)

        ElseIf i = 0 Then
          'Outputs x, y values for bottom line draggable endpoint
          gr.DrawString("pt " & i & "; " & "(" & m_Points(i).X & ", " & m_Points(i).Y & ")", _
                      the_font, Brushes.Black, m_Points(i).X + 1, m_Points(i).Y + 2)
        ElseIf i = 2 Then
          'Outputs x, y values for bottom line draggable endpoint
          gr.DrawString("pt " & i & "; " & "(" & m_Points(i).X & ", " & m_Points(i).Y & ")", _
                      the_font, Brushes.Black, m_Points(i).X + 1, m_Points(i).Y - 20)
        Else
          'Shouldsn't happen!
        End If
        the_font.Dispose()
        'end of sub-section drawing text for outputting angles and x,y ccordinates
    Next i
    gr.FillRectangles(Brushes.White, rectangles)
    gr.DrawRectangles(Pens.Black, rectangles)
    ' End of drawing draggable grab handles
End Sub

Private Sub picCanvas_Paint(ByVal sender As Object, _
                          ByVal e As System.Windows.Forms.PaintEventArgs) Handles picCanvas.Paint
    DrawLinesAndText(e.Graphics)
End Sub
..but you'll probably want to "view" (download) the attachment to also look at the "modAngleCalc" module code.

The "Public Function RadianToDegree" I'm using comes from here.
(without the "Shared" of course because it's not needed for module placement).

Since I don't understand the trig math involved (at all) I can do is attach
my semi-working copy & paste together "mash-up",
in hopes that someone can figure out why the angle calculation is going awry.

Quote:
Note (about where I'm eventually going with this):
The top line repsents the point (edge) at which the texturebrush fill starts,
and all the texturebrushing "rows" must be at a 90 degree angle to this line.

So the top line endpoints are 2 of the 4 points needed for the 4 point DrawImage call.
The third point is the bottom line endpoint.

The fourth point will be who-knows-where.
It could lie between the dashdot divider line & the top line endpoint,
but it could also be very close to the bottom line endpoint.

The angle between the top line & the bottom line could be very tiny
(due to perspective mapping) and while I don't think this will
effect a texturebrush fill of a quadrialteral it will probably be "challenging"
to passel's 4 point DrawImage warp as defined in this thread.
Attached Images
File Type: jpg screenshot_drag_points_calc_angle.JPG (29.2 KB, 20 views)
Attached Files
File Type: zip drag_points_calc_angle.zip (22.6 KB, 29 views)

Last edited by surfR2911; 02-24-2013 at 08:06 PM.
Reply With Quote
  #2  
Old 02-25-2013, 12:43 AM
passel's Avatar
passelCalculating angles between lines with runtime draggable endpoints passel is offline
Sinecure Expert

Super Moderator
* Guru *
 
Join Date: Jun 2003
Location: Upstate New York, usa
Posts: 8,028
Default

The link you said was a VB.Net snippet, isn't VB.Net. .Net has a Math.Acos function so you wouldn't need to write your own. And the snippet uses atn, not Atan.

If you're going to do perspective projections then filling with a texturebrush will never be able to align correctly.
If you're going to do an isometric projection, i.e. the faces of your cube will be parallelograms, then you should be able to rotate and skew a brush to fit the face of the cube, although I don't know the proper combination for a given set of points, off hand.

Another option for isometric cubes has been demonstrated before using plgblt (parallelogram blt) in vb6.
In .Net, the DrawImage method has overloads that replicate the action of plgblt, using 3 points to define three corners of the parallelogram (the fourth being easily determined so isn't needed as a parameter).
Using DrawImage would probably be slower than a rotated,skewed textureBrush, but I haven't tested it. It would be simpler at this point simply because of the plgblt examples that could be easily ported using DrawImage.
I originally used the "plgblt like" call of DrawImage to do 2-D rotations on my first graphical foray in .Net, but quickly dropped it once I found the graphics object transforms built in.
As for your angles calculations not making much sense, you should always double-check your parameters in your functions and subs since it is easy to reverse the order of things since the operations on X and Y axis tend to be quite similiar.
Look at the pairs of parameters below again.
Code:
  Public Function getAngleBetweenLinesVect(ByVal commonX As Single, _
                                     ByVal commonY As Single, _
                                     ByVal X1 As Single, _
                                     ByVal Y1 As Single, _
                                     ByVal Y2 As Single, _
                                     ByVal X2 As Single) As Double
Also, since the .Net Math class also already has an Atan2 function built in, I usually prefer to use that rather than law of Sines or Cosines to calculate angles since you don't need to compute the length of the hypoteneus by doing square root of the sum of the squares.
But I haven't done any timing experiments to see if one method is faster than the other.
In the case where you want the two angles from the X-axis and the total, then using Atan2 rather than cosines would be like this.
Code:
  Dim ang2 As Double = Atan2(Y2 - commonY, X2 - commonX) * (180 / PI)
  Dim ang1 As Double = Atan2(Y1 - commonY, X1 - commonX) * (180 / PI)
  Dim totalAng as Double =  ang2 - ang1
Since Y increases downward, these angle rotate clockwise from the X-axis.
If you want counterclockwise rotation, just put "-" in front of the Atan2.
Also, if you wanted the angle return in a particular range, i.e. 0 to 360, or -180 to 180, you would need to add more code to wrap totalAng into that range.
Atan2 will return -180 to 180 degree range (in radians, of course).
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.

Last edited by passel; 02-25-2013 at 01:36 AM.
Reply With Quote
  #3  
Old 02-25-2013, 11:03 PM
surfR2911 surfR2911 is offline
Contributor
 
Join Date: Oct 2009
Posts: 719
Default texturebrushing at an angle and moving towards skewing

Quote:
Originally Posted by passel
If you're going to do perspective projections then filling with a texturebrush will never be able to align correctly.
Is this because of the needed skewing?

Quote:
Originally Posted by passel
If you're going to do an isometric projection, i.e. the faces of your cube will be parallelograms,
then you should be able to rotate and skew a brush to fit the face of the cube,
although I don't know the proper combination for a given set of points, off hand.
The thing is that depending on how the cube is rotated the faces are always guaranteed to be quadrilaterals,
they are not always guaranteed to be parallelograms.

So, I'm thinking that the skewing might be produced by texturebrushing a rect
then use shifting (offset) lines of individual pixels to produce the skewing(?)

However if the lines are offset too much (from one line to another) there is a shearing effect seen.
What may be needed is some kind of per pixel interpolation to get the skewing (with maybe some warp-distortion) right.
Quote:
Originally Posted by passel
I originally used the "plgblt like" call of DrawImage to do 2-D rotations on my first graphical foray in .Net,
but quickly dropped it once I found the graphics object transforms built in.
We're talking matrix rotations, right?
That's what I was thinking.
Quote:
Originally Posted by passel
Also, since the .Net Math class also already has an Atan2 function built in, I usually prefer to use that
rather than law of Sines or Cosines to calculate angles since you don't need to compute
the length of the hypotenuse by doing square root of the sum of the squares.
That's the missing bit of math info I would never have come up with on my own.
Thanks. I will try to integrate your Atan2 code into the last attachment.
.
.
Quote:
edit (later) the updated working code:
Code:
'This code shows you how to calculate the angle between two lines using ATan2
Public Function getAngleBetweenLines1(ByVal commonX As Single, ByVal commonY As Single, _
                                     ByVal X1 As Single, ByVal Y1 As Single, _
                                     ByVal Y2 As Single, ByVal X2 As Single) As Double
    'To make sure return balue is set for all code paths
    getAngleBetweenLines1 = Nothing
    'check if both the lines are the same, if they are exit the function
    If (commonY = Y1 And commonX = X1) _
      Or (commonY = Y2 And commonX = X2) _
       Or (Y1 = Y2 And X1 = X2) Then
       'if both the lines are the same, exit the function and return nothing
    Else
      Dim differenceX1 As Double, differenceY1 As Double
      'set the variables 
      differenceX1 = X1 - commonX
      differenceY1 = Y1 - commonY
      'applying the angle between two lines vector rule, calculate the angle in radians and convert to degrees
      Dim ang As Double = -Atan2(Y1 - commonY, X1 - commonX) * (180 / PI)
      getAngleBetweenLines1 = ang
    End If
End Function

'DrawLinesAndText Sub revised code snippet: 
Dim dblAngle1 As Double, dblAngle2 As Double
Dim strAngle As String
'Outputs total angle between Top moveable line and x-axis aligned dash dotted dividing line
dblAngle1 = getAngleBetweenLines1(m_Points(1).X, m_Points(1).Y, _
                                m_Points(2).X, m_Points(2).Y, _
                                  ptX_Axis.X, ptX_Axis.Y)
strAngle = "Top Angle = " & CStr(dblAngle1.ToString("#,##0.00")) & " degrees"
gr.DrawString(strAngle, the_font, Brushes.Black, _
              m_Points(i).X + 27, m_Points(i).Y - 17)
'Outputs total angle between bottom moveable line and x-axis aligned dash dotted dividing line
dblAngle2 = Abs(getAngleBetweenLines1(m_Points(1).X, m_Points(1).Y, _
                                m_Points(0).X, m_Points(0).Y, _
                                  ptX_Axis.X, ptX_Axis.Y))
strAngle = "Bottom Angle = " & CStr(dblAngle2.ToString("#,##0.00")) & " degrees"
gr.DrawString(strAngle, the_font, Brushes.Black, _
              m_Points(i).X + 27, m_Points(i).Y + 3)
'Output total angle between moveable lines
Dim totalAng As Double = dblAngle2 + dblAngle1
strAngle = "Total" & vbCrLf & "Angle=" & vbCrLf & _
                        CStr(totalAng.ToString("#,##0.00")) & _
                        vbCrLf & "degrees"
gr.DrawString(strAngle, the_font, Brushes.Black, _
              m_Points(i).X - 50, m_Points(i).Y - 90)
ElseIf i = 0 Then
'Outputs x, y values for bottom line draggable endpoint
gr.DrawString("pt " & i & "; " & "(" & m_Points(i).X & ", " & m_Points(i).Y & ")", _
            the_font, Brushes.Black, m_Points(i).X + 1, m_Points(i).Y + 2)
ElseIf i = 2 Then
'Outputs x, y values for bottom line draggable endpoint
gr.DrawString("pt " & i & "; " & "(" & m_Points(i).X & ", " & m_Points(i).Y & ")", _
            the_font, Brushes.Black, m_Points(i).X + 1, m_Points(i).Y - 20)
Attached Images
File Type: jpg screenshot_drag_points_calc_angle2.JPG (27.1 KB, 12 views)
Attached Files
File Type: zip drag_points_calc_angle2.zip (22.4 KB, 84 views)

Last edited by surfR2911; 02-25-2013 at 11:55 PM.
Reply With Quote
  #4  
Old 02-26-2013, 09:57 PM
passel's Avatar
passelCalculating angles between lines with runtime draggable endpoints passel is offline
Sinecure Expert

Super Moderator
* Guru *
 
Join Date: Jun 2003
Location: Upstate New York, usa
Posts: 8,028
Default

Quote:
Originally Posted by surfR2911 View Post
Quote:
Originally Posted by passel
If you're going to do perspective projections then filling with a texturebrush will never be able to align correctly.
Is this because of the needed skewing?
I take you're using "skewing" in a generic way, but normally with graphics code and when using a matrix, skewing is an isometric operation (perhap affine means the same thing) that will apply to all points in the image. I guess technically that is called shearing but that is the only kind of skewing you can get with a texture brush, unless you break it down into multiple small "strokes" of the brush, varying the shear and possibly rotation as you work your way through the projection.
The skew ratio will cause the image to slant one way or another, but that slant will be the same across the whole image, so a square or rectangle will have parallel opposite sides and remain parallelograms when skewed.

With a typical isometric drawing, if you change your view so you see the left side and front of a cube, in a matrix of cubes all with the same orientation, you will see the left side and front of all the cubes, regardless of whether the cube is on the left side of the window or the right side of the window. And the size of a given cube would be the same size on the screen whether it was on the front row "nearest" you or somewhere toward the back.

Perspective, on the other hand, is going to show you more or less of the side of the cube as its position is viewed on the left side of the window or the right. And of course everything shrinks as it gets farther away from you, so parallel lines converge into the distance.
With Isometric, the parallel lines will always be parallel into the distance.
This causes an optical illusion sometimes, where a cube looks like the lines going "into the screen" are diverging slightly, the cube appears to be wider on the backside and the lines do not appear to be parallel because our brain knows parallel lines should be getting closer together as they move away from us.

Now that your example is using Atan2, the function name is a misnomer.
The function doesn't determine the angle between two lines, it determines the angle between two points.
You should see the third X,Y parameter pair is not used.
The Tangent function deals with the ratio of the opposite side of a right triangle over the adjacent side.
In the case of the base line (adjacent) being the X-axis, the opposite side is the Y value, so the tangent is Y/X.
This is why the reverse operation, Atan, passes the Y parameter first, then the X. This returns the angle relative to the X axis (0 degrees aligned with X axis), which is the way it is taught mathematically.
Of course, if you wanted 0 degrees on the Y axis, as in maps, then you could reverse the parameters and pass X first.
But, the Atan returns values in the range +/- 90, not +/- 180, so you don't get the full circle, which is why there is an Atan2 function, which will take into consideration the signs of the X,Y and return an angle that covers the full circle.

Since the Atan2 function will return 0 degrees, if the points are the same, or on the positive X axis, you don't really have to protect the function with a pre-check of the X,Y values.
So, you could rename your function and simplify as follows and it will still work the same, in your code (just don't pass the third set of coordinates).
Code:
  'This code returns the angle between two points
  Public Function getAngleBetweenTwoPoints(ByVal commonX As Single, ByVal commonY As Single, _
                                     ByVal X1 As Single, ByVal Y1 As Single) As Double
    'applying the angle between two points rule, calculate the angle in radians and convert to degrees
    Return -Atan2(Y1 - commonY, X1 - commonX) * (180 / PI)
  End Function
As I mentioned in the earlier post, if you were going to do an isometric type view, the plgblt could be replace with DrawImage in .Net. So I went ahead and ported the core of the old "matrix3" vb6 (originally VB3) example posted back in 2005, into .Net just to show the parallelogram version of DrawImage in action.
One big change from the VB6 version, is I couldn't conveniently use the arrow keys, so I changed the "motion" keys from the arrow keys to IJKL: "I" forward, "K" backwards, "J" turn left, "L" turn right.
The "A" tilt alway, and "Z" tilt back, are the same.
I didn't port the mouse steering code over so the keys are the only way to move. If you manage to get lost by moving outside the small "map" area, pressing the reset key will get you back.
Attached Files
File Type: zip matrix3port.zip (29.8 KB, 20 views)
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.

Last edited by passel; 02-26-2013 at 10:02 PM.
Reply With Quote
  #5  
Old 02-27-2013, 05:46 PM
surfR2911 surfR2911 is offline
Contributor
 
Join Date: Oct 2009
Posts: 719
Default isometric texturemapping of skewed, but non-perspective parallelograms

Quote:
Originally Posted by passel
So I went ahead and ported the core of the old "matrix3" vb6 (originally VB3) example posted back in 2005,
into .Net just to show the parallelogram version of DrawImage in action.
Thanks for tha attachment.
It's interesting even though it is not perspective mapped (which involves non-parallel quadrilaterals).

A few things about the attachment.
After clearing all the Option Strict warnings ("Unused local variable 'L' "),
right away I noticed some mutex using code:
Code:
Private Sub Panel1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Panel1.Paint
    gfxMutex.WaitOne()
    gfx.Render()
    gfxMutex.ReleaseMutex()
End Sub
So then I set the Checked property of the chkchkPlgblt checkbox ("Use Texture") to True at design time and tried to run it.

I got the following unhandled exception errors:
Quote:
System.InvalidOperationException was unhandled
HResult=-2146233079
Message=An error occurred creating the form. See Exception.InnerException for details.
The error is: Object reference not set to an instance of an object.

at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException: System.NullReferenceException
HResult=-2147467261
Message=Object reference not set to an instance of an object.
I'm guessing this is a threading thing --that everything didn't have a chance to initialize before it tried to start rendering.
Is there anyway to set a boolean (or adjust the mutex in some way) to avoid this?

I also noticed this piece of commented out code:
Code:
'If chkPlgBltMask.Value = vbChecked Then        'If "use masking" is selected Then
'  For i = 1 To 5 : tz(i) = True : Next           '  Enable all sides of the block to be drawn so we see the back sides through the front
'End If
..of course if you uncomment it it throws a bunch of errors:
Quote:
'chkPlgBltMask' is not declared. It may be inaccessible due to its protection level.
'vbChecked' is not declared. It may be inaccessible due to its protection level.
So I had to recreate the missing checkbox and update the code to clear the errors:
Code:
If chkPlgBltMask.Checked Then        'If "use masking" is selected Then
  For i = 1 To 5 : tz(i) = True : Next   '  Enable all sides of the block to be drawn so we see the back sides through the front
End If
However even then it didn't really do anything so I had to make adjustments to other parts of the code,
to enable seeing a difference when this new checkbox was checked.

The end result (updated version attached below) allows a visual exploration of the Painter's Algorithm.

Of course the following caveat-of-use applies:
Quote:
' The relative depth (Z axis is into the screen) of a given 3d quad is simply the sum of the z coordinate of four corners of the quad
' Since none of the quads in this program intersect with any other quads and the bounds of the blocks do not exceed
' a given grid spacing (so there is no overlap in depth between blocks) this is sufficient for determining the order the
' quads should be drawn, back to front.
From the included screenshot you'll also see I've a added a separate checkbox for showing the ground grid
(setting it apart from the "If..then" checking for nx = pi).

Besides the bufferedgraphics control code use it also features some My.Resources spritesheet sub-graphics extraction, using a bitmap cloning technique and
some tantalizing (if not really utilized) collision test code:
Code:
Private Sub CollisionTest()
    Dim i As Long, p As Long
    'In the future, if the world gets big, we won't want to do collision tests with every block footprint,
    'so will need a quick way to determine which blocks are in the immediate area.
    'This loops through all the 3d-blocks and passes the position of the four sides (footprint) of the block
    'to the CollisionCheck routine (LeftSide, RightSide, FrontSide, BackSide)
    'The sides are "expanded" by the radius of our "player" so that a collision is detected as soon as the "edge"
    'of the player crosses the "edge" of the side. (The "reference point" of the player is its center).
    'So, in this case, the "player" is 20 pixels in diamter, so we subtract 10 off the left side and add 10 to the right
    'side to "mark" where the center of the player can't go.
    For i = 0 To NumOfCubes - 1
      p = i * 8
      CollisionCheck(xo(p + LftBtmFrnt) - 10, _
                     xo(p + RghtBtmFrnt) + 10, _
                     zo(p + LftBtmFrnt) - 10, _
                     zo(p + LftBtmBck) + 10)
    Next
End Sub
Maybe this could be used to have a ball bouncing around (in amongst between) the buildings?


However..
It doesn't really demonstrate the case if the texturebrush tiling isn't used with a FillPolygon call directly.

..or in other words where the graphic to be tiled is small enough so it doesn't totally fill the polygon with a singlely tiled graphic.
Where you would want to see, instead, rows of skewed blocks (strips) inside the parallelograms.

For that case, would you have to create a sub buffer (for instance using a rect),
then texturebrush the tiling strips into the rect,
then use FillPolygon (with 3 pt Drawimage) to transfer the multi-striped texture (in a skewed way) into the parallelograms?

Quote:
Edit(later):
I did a little quickie annotation work in photoshop (using skew-distort-scale tranfoming)
to layer on some multi-tile-striped textures for two of the walls in one cube,
to give you an idea of what I'm talking about - see attached "multi-tile-striping_texture.jpg graphic)
Note: The rows of tiles would have to be created programmatically (at runtime) from a single smiley tile block.
Oh..one final note.
passel is using Randomize() in the Form Load to set up the cubes,
so exactly how you would extended this neat demo into an actual 3D cube editor
(where the cubes could be dragged and would snap to gridded positions on the floor) I couldn't imagine.
..and would the positional coordinate values be save-able out of such an editor into
a semi-standard 3D format like .dxf, .3ds, or Colada's .dae file format --who knows?
Attached Images
File Type: jpg screenshot_matrix3port.JPG (61.3 KB, 14 views)
File Type: jpg multi-tile-striping_texture.jpg (296.3 KB, 13 views)
Attached Files
File Type: zip matrix3port_PaintersAlgorithm_exploration_version.zip (31.9 KB, 15 views)

Last edited by surfR2911; 02-27-2013 at 06:31 PM.
Reply With Quote
  #6  
Old 02-28-2013, 10:35 PM
passel's Avatar
passelCalculating angles between lines with runtime draggable endpoints passel is offline
Sinecure Expert

Super Moderator
* Guru *
 
Join Date: Jun 2003
Location: Upstate New York, usa
Posts: 8,028
Default

Quote:
Originally Posted by surfR2911 View Post
...So then I set the Checked property of the chkchkPlgblt checkbox ("Use Texture") to True at design time and tried to run it.

I got the following unhandled exception errors:...
I'm guessing this is a threading thing --that everything didn't have a chance to initialize before it tried to start rendering.
Is there anyway to set a boolean (or adjust the mutex in some way) to avoid this?
It's not a threading thing, it is an initialization order thing.
One thing that VB.Net does, which has giving me issues before, is if you set a checkbox in the IDE, you will get a CheckedChanged event for the checkbox at startup before the Form_Load event has occured, so none of the initialization code in the load event handler or called from the Load event handler has been done.
The CheckedChanged event calls Draw() so you get the exception because nothing has been initialized that Draw() needs.

A fix is to add a class level boolean in the declarations area, and use it to guard the CheckChanged event.
Code:
 Dim LoadDone As Boolean

  Private Sub chkPlgblt_CheckedChanged(sender As System.Object, e As System.EventArgs) Handles chkPlgblt.CheckedChanged
    If LoadDone Then Draw()
  End Sub

'Bottom of Form_Load Event
  LoadDone = True
Or just initialize the check states at the end of the load event, rather than in the IDE.
Since the Draw routine is called from multiple places, you could put the guard there instead, in case the Paint event, or the Reset() call was done before everything was setup.

Quote:
Originally Posted by surfR2911 View Post
I also noticed this piece of commented out code:
Code:
'If chkPlgBltMask.Value = vbChecked Then        'If "use masking" is selected Then
'  For i = 1 To 5 : tz(i) = True : Next           '  Enable all sides of the block to be drawn so we see the back sides through the front
'End If
...
However even then it didn't really do anything so I had to make adjustments to other parts of the code,
to enable seeing a difference when this new checkbox was checked.
The plgblt allowed using a mask to make parts of the blit not occur, thus "transparent". The checkbox allowed toggling the use of the mask, or not, and thus needed the "backsides" drawn to see them through the holes.
While I didn't port that capability (which I would probably do with two versions of the bitmap, one with transparent pixels in it), you can see a different version of the transparency by uncommenting the line:
' Picture3(0).MakeTransparent()
If you uncomment that line, the first pixel in the bitmap is gray, so all the gray becomes transparent, leaving mostly the little green rectangles, and some other colors near the bottom.

Quote:
Originally Posted by surfR2911 View Post
Of course the following caveat-of-use applies: {in regard to depth order}
If you notice the comments on the following lines, you'll see they don't match the code.
Code:
'
    For c1 = 0 To 3 'lets create 4 cubes (8 points, 6 sides per cube)
      For c2 = 0 To 3  ' in a two by two matrix
        ls = c2 * 240 + 80 * Rnd() '240 units apart horizontally
        rs = ls + 120 + 40 * Rnd() '160 units wide
        bs = c1 * 240 + 80 * Rnd() '240 units apart vertically
The "matrix2" version of this code just had four blocks, evenly sized and space. I later changed the code to the 4 x 4 (16 blocks), but added the rnd() size offset to make the blocks smaller and place them in a random position, but within the bounds of their original footprint. That way they could not be drawn out of order with the simple depth calculation used.
In the "real world", long sides that may overlap shorter sides when rotated, would have to be subdivided into two or more sections so part of the side that is behind can be drawn, but the front section can be drawn later when it comes in front. Didn't want to deal with that for this simple test.

Quote:
Originally Posted by surfR2911 View Post
... and
some tantalizing (if not really utilized) collision test code:
...
Maybe this could be used to have a ball bouncing around (in amongst between) the buildings?
hmmm..., that is what it does. If you tilt the scene so you're looking at it from mostly above, you should see that it is the collision detection that keeps the ball from traveling through the buildings. It collides with the side, and moves along the side of the building it is colliding with. It can only move between the blocks, not through them.

Quote:
However..
It doesn't really demonstrate the case if the texturebrush tiling isn't used with a FillPolygon call directly.
That is true, it does not. It originally demonstrated the plgblt's ability to stretch an image to fill a parallelogram shape, using the placement of the coordinates to determine orientation and size of the parallelogram.
This example simply uses the capability of the DrawImage method to do the same thing.
I'm sure you can use the RotateTransform method of the brush to orient, and the ScaleTransform to skew (shear) the brush to replicate plgblt/DrawImage results, but haven't taken the time to try to figure out the algorithm.

Quote:
..or in other words where the graphic to be tiled is small enough so it doesn't totally fill the polygon with a singlely tiled graphic.
Where you would want to see, instead, rows of skewed blocks (strips) inside the parallelograms.
If you wanted the image content to be tiled, and not stretched to fill the parallelogram, that could probably be done by setting a clipping area around the parallelogram to trim overflow, and subdivide the parallelogram into a fixed number of smaller parallelograms (should be the same number for any orientation of the face of a given size, relative to the texture.), but that would probably be a lot slower than using a brush.
If I wasn't so busy (I shouldn't be typing this, as I have other critical things I should be doing), I might revisit trying to use a oriented scaled brush to fill a parallelogram. Of course, one requirement would be to know the size of the original rectangle the parallelogram is derived from so you know the ratio of the brush size to the rectangle size. The distortion of the rectangle into the paralleogram also has to be done to the brush, so the texture stays "fixed" to the surface, rather than slip.
The simple solution would be to not figure out how to distort the brush and fill a polygon. Just create an image of the original rectangle size, filled with the brush, then use the DrawImage method to draw that image to the parallelogram.
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.

Last edited by passel; 02-28-2013 at 10:41 PM.
Reply With Quote
  #7  
Old 03-01-2013, 05:17 PM
surfR2911 surfR2911 is offline
Contributor
 
Join Date: Oct 2009
Posts: 719
Default When we should be doing other things..

Quote:
Originally Posted by passel
If I wasn't so busy (I shouldn't be typing this, as I have other critical things I should be doing),
Thanks for taking the time to reply.
I too should be doing other things (I can only watch CodeCruncher's efforts to alter the 3D complex wireframe code I posted into his BSC project from a distance),
but I don't want to not follow thru on this important new piece of isometric skewing code.

Quote:
That way they could not be drawn out of order with the simple depth calculation used.
In the "real world", long sides that may overlap shorter sides when rotated, would have to be subdivided into two or more sections
so part of the side that is behind can be drawn, but the front section can be drawn later when it comes in front.
Didn't want to deal with that for this simple test.
I see a lot of potential to turn this from a simple demo into a full framework, but as you say,
the code would have to be restructured to make it more flexible.
We're almost moving into Wolfenstein/Doom territory if you thinking about storing the arrangement of blocks into a "level"
along the lines of a WAD (Where's the Data) file with its DEU equivalent.

Quote:
It collides with the side, and moves along the side of the building it is colliding with. It can only move between the blocks, not through them.
I noticed the orange ball was getting shuffled somewhow but sometimes it seemed to get "stuck" partly out of view (as I was playing with the code).

Your normally verbose commenting was abreviated in this VB6 conversion so I didn't know you're intention for how it placed itself.
I only notice it seems "erratic" so I moved it to the front in my version so it wouldn't play "peek-a-boo".
It doesn't bounce though (like a pong game) - that's what I thought the collision hit test was originally for in the VB6 version.

Quote:
Originally Posted by passel
It originally demonstrated the plgblt's ability to stretch an image to fill a parallelogram shape..this example
simply uses the capability of the DrawImage method to do the same thing.
What is the name of this capability?
I have decided to call it DIAP rendering.
D.I.A.P. = DrawImage As Plgblt.
("DIAP" is a good metatag word if I ever lose the bookmark for this thread and have to try to search for it).

Quote:
I might revisit trying to use a oriented scaled brush to fill a parallelogram..
The distortion of the rectangle into the parallelogram also has to be done to the brush, so the texture stays "fixed" to the surface, rather than slip.
There it is.
It's all about controlled distortion.
Except for the VB.Net code (both mine and yours) in the Imagewarper thread, this a topic that is wide open for exploration.

Quote:
The simple solution would be to not figure out how to distort the brush and fill a polygon.
Just create an image of the original rectangle size, filled with the brush,
then use the DrawImage method to draw that image to the parallelogram.
The simple solution, though, is only one waypoint along the path toward texture filling non-parallelogram quadrilaterals (in re: perspective mapping).
If it’s a necessary waypoint to pass thru (and get past) then maybe that's where to go to next..

In the meantime though I can think of a whole bunch of ways to built a framework out of your demo.
1.) It needs a mouse interface - maybe (at the very least) some autopan rect areas or "zones" along the edges of the panel.
2.) In post 27 of the Intersecting Lines thread I mention the "choose axis" gizmo/widget/control.
I'll repost the picture links(1, 2)
This allows you using a 2D mouse to move objects along the 3D axes in any 3D direction, one axis at a time for precision.
I would envision the red, green, or blue line (of the selected axis for movement) would thicken when selected.
Of course VB.Net doesn't have such a control built in so it would have to be "imagineered"
(though it would have to be as fancy as a full control just some graphics with a mouse hit test built in
and maybe a byte value to hold the axis selection).
3.) I would like to see a way to move/drag individual cubes around on the "floor" (with maybe a snap to grid?)
4.) I could even see a "room" --with two single-sided "planes" (acting as walls) whose bottom edges are tangental to the back edges of the floor,
extending to the top of the panel or include some kind of skybox.
The floor would then also be extended out (resized/scaled to completely fill the foreground at all rotation angles).

After which children's letter blocks/boxes could be placed in the center of the room with some isometric semi-transparent mapped shadows (1, 2)
..or maybe even try for some stencil shadowing.

I know it's probably asking a lot to mimic the stencil shadow volumes from Doom3 but there are links(1, 2, 3, 4).

I better stop there or I'll start to wish/hope for UE4 engine features.

I guess I just want to note in this post that the matrix3port code has "legs" and could further refactored/developed in a lot of different ways.

Last edited by surfR2911; 03-01-2013 at 05:51 PM.
Reply With Quote
  #8  
Old 03-02-2013, 03:16 PM
surfR2911 surfR2911 is offline
Contributor
 
Join Date: Oct 2009
Posts: 719
Default Looking ahead: Plan of action for code refactoring from demo to framework

Did you ever get to the point where you want to slam your keyboard into your forehead (repeatedly) out of frustration?

That's where I was at around 3am this morning trying to merge togther two large Linq-EntityFramework classses
which were designed to conglomerate a bunch of temp queue tables with a bunch of
stored procedure queries in a series of table joins passing through a series of RegEx filters
in order to take multiple flat databases and and create this massively complex relational database.

Anyway I had to take a break.

For "relaxation", I took a brief look at what might be necessary to turn passel's DIAP render demo into a more structured framework.

Here's my initial assessment - it's going to take some major refactoring due to many issues (shortcomings) in the way it's designed.

Issue 1:
NumOfCubes constant inflexibility

If you try to change this line:
Code:
Const NumOfCubes = 16
..to this:
Code:
Const NumOfCubes = 1
..then when the run is pressed I get the screenshot below showing the panel control with a big red "X" --that
people who work with graphics in VB.Net know all to well.

So this begs the important question:
Quote:
How does one quickly/easily adjust the matrix3port code to go from using 16 "cubes" (actually "blocks" would be more appropriate)
to being able to draw just a single 3D cube-block?
Anyway, I changed it back to 16 ( to get rid of the big red "X") and I set a breakpoint at this line:
Code:
For i = 1 To NumOfQuads
..and it shows NumofQuads is 96. Hmmm...

This left me scratching my head for a moment (), then I realized:
16 cube-blocks times 6 faces/cube = 96 total faces to be DIAP rendered
(what DIAP stands for is in my last post immediately preceding this one..)

Which brings us to..
Issue 2:
Wrong level of encapsulation for cube/block faces

Here's the pseudo-code way I thought things were structured
(and really the way I need things to be structured):
Code:
Private Sub DrawAllCubes(ByVal TopRightCornerPoints As Point())
 For i  = 0 to NumOfCubes 'where the cube "zero" is backmost..
  DrawCube(i, x(i), y(i))
 Next
End Sub

Private Sub DrawCube(ByVal numCubeIndex As Integer, _
                               ByVal  XTopRightCornerOffSet As Integer,  _
                               ByVal  YTopRightCornerOffset As Integer)

 For i = 0 to NumOfFaces  '  ..or possibly NumofQuads?
  DrawAllFaces(numCubeIndex, i, XTopRightOffSet, YTopRightOffSet)
 Next
End Sub

Private Sub DrawAllFaces(ByVal indexCubeBlock As Integer,
                                   ByVal arrFaces() as Boolean, _
                                   ByVal intX As Integer, _
                                   ByVal intX As Integer)
    For i = 0 to 5
      If arrFaces(i) Then 'uses boolean array for faces-to-be-drawn test
        'Some DrawFace (or possibly "DrawQuad") sub call code here..
      End If
   Next
End Sub
..structuring things along those lines definitely would be more convenient.

Maybe even throw in a texture bitmap parameter(s), that could hold different
designated textures for each face of each cube-block..?

Note: In the above pseudocode-ish snippet wouldn't have to use a VB6-ish (old style) arrays, you could use a List or some other .Net "holder" of info.
Just something that could be easily looped through.

Issues 3 and 4:
Non-random positioning and missing scaling factor.

passel already posted this code snippet above but I'll post it again
because it's the source of both magic number brittleness and unwanted imprecision:
Code:
ls = c2 * 240 + 80 * Rnd() '240 units apart horizontally
rs = ls + 120 + 40 * Rnd() '160 units wide
bs = c1 * 240 + 80 * Rnd() '240 units apart vertically
ts = bs + 120 + 40 * Rnd()
rh = -(10 + 240 * Rnd())
First of all we need to lose the Rnd().

It's alright for a quickie demo but for a framework we need to locate the cube-blocks with precision.
Ideally we want to load the positions from a file.

Secondly, all the magic numbers (240, 120, 40, 80) should to be put into a variables:
Code:
Dim value1 As Int16 = 240
Dim value2 As Int16 = 120
Dim value3 As Int16 = 40
Dim value4 As Int16 = 80
..then we can assign a ScaleFactor:
Code:
Dim intSF As int16 = 10 'ScaleFactor
Dim value1 As Int16 = 24 * intSF
Dim value2 As Int16 = 12 * intSF
Dim value3 As Int16 = 4 * intSF
Dim value4 As Int16 = 8 * intSF
Eventually everything will be moved to a "Load_All_Levels" file
(cube-block spacing/positioning/scaling, face dimensions, and textures-per-face to be used).

Which brings us to the next bit of awkwardness..
Issue 5:

Code:
p1g = Panel1.CreateGraphics
Since this was a quickie VB Classic to .Net conversion, passel probably didn't have time
to avoid the use of CreateGraphics, but a future update should try to make use of
the DrawToBuffer sub in passel's new Bufferedgraphics control class from this thread.



There are probably more adjustments to the code that will be needed
but that's what I spotted after about 15 minutes of looking at (and working with) the code.

By subtracting 90 faces from the 96 NumOfQuads and manually setting which tz() boolean indices were True
I was also able to get the other screenshot attached below, showing possible "walls" for a 3D "room".

Hopefully passel will have some thoughts in the next week or so (if he has time)
on the important render single block question (Issue 1 above),
and (maybe possibly, but less important) the nested calling of a DrawAllFaces sub from inside a DrawAllCubes sub.

If I get some time next week I'll try to perform major surgery, and refactor the matrix3port code to use the BufferGraphics control class.

Last edited by surfR2911; 03-02-2013 at 04:17 PM.
Reply With Quote
  #9  
Old 03-03-2013, 06:40 AM
passel's Avatar
passelCalculating angles between lines with runtime draggable endpoints passel is offline
Sinecure Expert

Super Moderator
* Guru *
 
Join Date: Jun 2003
Location: Upstate New York, usa
Posts: 8,028
Default

I agree that if this concept was to actually be turned into something useful that it should be completely redone. This is essentially VB3 code. I ported it to VB6 at some point to test using plgblt, and later posted it here, as part of a fill polygon question example.

I was definitely thinking that the parallel arrays should probably go, and related items grouped into classes, but just grouping the drawing into a hierarchy based on the object itself doesn't work because you can't draw the object as a whole. Depending on the viewing angle you may an object whose position is further back than another block, so would be drawn first, but one (or more) of the faces is actually in front of part of an object that is technically closer. The closer object when drawn would look like it is poking through the object drawn earlier.
So, in this particular example, we don't draw the "cubes", we draw the "sides" of the cubes, and the sides have been sorted in Z-order, and are drawn in that order irrespective of which cube they are a part of.
And of course the sides themselves are made of points, and each point is common to three sides (at the corner of the cube), so we don't want to treat each side as a separate object when doing rotation calculations, otherwise we would calculate the rotation for each point three times, would would be a waste.
But, still, a lot of the data could be gathered into more managable classes, and the drawing modified to pull the internal pieces, eg. the sides of the block, into a sorted list (which has to be done in any case) for drawing order.

Quote:
I noticed the orange ball was getting shuffled somewhow but sometimes it seemed to get "stuck" partly out of view (as I was playing with the code).
...
It doesn't bounce though (like a pong game) - that's what I thought the collision hit test was originally for in the VB6 version.
You do know that the "A" and "Z" key tilt the view. If you tilt the view so that you are looking "top down" you should see clearly the ball working its way through the "alleys" between the blocks. It "stalls" when the forward movement is close to perpendicular to a wall. It will usually have some small side motion as it slides against the wall, unless you happen to be perfectly perpendicular.
Also the black ring around the perimeter of the orange was drawn last, so that as the orange disappeared behind (peeking out from the edges) an object, the ring would always be visible so you knew where the ball was as it travelled out of LOS (Line of Sight).

Quote:
Issue 1:
NumOfCubes constant inflexibility

Issues 3 and 4:
Non-random positioning and missing scaling factor.
These issues are related, and why changing one (NumOfCubes) gave you the redX.
Because this was a quick exercise, long ago, I didn't want to spend time creating a lot of initial positions by hand or spend the time to create an editor to allow manually creating and positioning the test objects.
So, NumOfCubes is there just to allocate the proper amount of storage in the various arrays and structures to support that number of blocks (were cubes originally) needed to support whatever layout was going to be generated.
Then, the code in the Form Load is there to initialize the blocks into some desired configuration. The initialization code can be changed to initialize the blocks in whatever fashion the coder desires. Perhaps you want to create a wall of blocks around a perimeter, or in a circle, or a checkerboard pattern.
In my case, I was going for a grid layout, so have the nested loops to lay out the blocks in a grid. The grid wouldn't necessarily have to be square, but in my case it is.
So the number of blocks wouldn't necessarily dictate the layout, but how you lay them out would tie back to how many blocks you need. As the person laying them out, you would need to know how many blocks you need and update that value (NumOfCubes) to match the number you initialize.
Of course, with easily expandable lists of type, and gathering of more of the data into a single class in .Net, you could make the number of blocks purely a dynamic number, with count and allocation being incremented as you define the blocks in the layout, not pre-determined.
Currently, if I change the initalize loops to do a 7x7 array, I need to change the NumOfCubes to match ( 49) to allocate the storage.
Likewise, if you change NumOfCubes to 1, you need to change the two initialization loops to go 0 to 0 so you do a 1x1 matrix.

Some of the "issues" with Issue 2 is addressed above when I talked about heirarchy of cube to faces to points. In this particular example, since the cubes are placed and sized so that sides of a deeper object can't overlap the sides of a nearer object, we could probably get away width depth sorting the cube objects themself and drawing them as a whole, but that probably wouldn't be the case where a user was allowed to position longer blocks arbitrarily.

Issue 5:
Quote:
Since this was a quickie VB Classic to .Net conversion, passel probably didn't have time
to avoid the use of CreateGraphics, but a future update should try to make use of
the DrawToBuffer sub in passel's new Bufferedgraphics control class ...
If you look at that class, you will see that CreateGraphics is also used there. It is used in every example of BufferedGraphics class that I've done, because passing a graphics object as the first parameter when you have the manager allocate a BufferedGraphics object is a requirement. The screen area associated with that graphics object passed is the default rendering space of the BufferedGraphics object.
The class that I wrote as an example is not complete. My personal opion is that a local class variable should be set to the graphics object returned from the CreateGraphics call so that you can dispose of it, after you dispose of the BufferedGraphics object itself when you're done with the BufferedGraphics object.
Using CreateGraphics method as a parameter to the Allocate method, as I did there, is common in quick examples, but in practice, I don't think should be done as you can't clean up the graphics object yourself later since you don't keep a reference to it.

On another subject, I though I had an "intuitive" approach to determining the rotation and shearing of a texture brush to fill a parallelogram, but it didn't pan out.
I figured the rotation part was easy, just do an Atan2 on the delta between the two "upper" coordinates of the parallelogram to get the rotation angle for the brush, and that works.
The part that didn't pan out was the shearing. The shearing is done by changing the X and Y scale, so my "intuitive" notion was that if I scaled the texture brushes X and Y by the ratio of the parallograms width (length of first vector (first point to second point) over original width, and height (length of third vector (first point to third point) over original height, that would shear the brush appropriately. But a few tries, doing the shear pre-rotation and after rotation, and other variations, still had the texture creeping about as you changed the point of view. So I gave up on that investigation for now, but since I was already in the code, went ahead and tested the "simple" method I mentioned in my last post, of just doing the texturing in a rectangular image, then use Drawimage to do the parallogram mapping.
As expected, this slows things down since we're now creating an image, texturing it, drawing it, then disposing of it for every face drawn.
The simple speed up solution there is, as you mentioned, just use a lot more memory and allocate a texture for each face as part of the face object so it is always at hand to be used.
In any case, even though the code is just as archaic as it has always been, I'll attach the textureBrush version. So the "building" face and "stone" face textures are turned into texture brushes and used to dynamically fill a dynamically created face image for DrawImage to use.

p.s. About 2000 characters left, so I'll keep this short. You may have notices the Out of Memory exception handlers around some of the Draw Image calls. I would get Out of Memory exceptions periodically, and when I ran the exe outside the executable, when I got an exception a dialog box would popup asking what I wanted to do, but the window with the blocks in it would be spinning away merrily in the background, so I kind of guessed that we were not actually out of memory. Looking at resources and memory and threads, I couldn't see that we were overly consumming anything, so just put the exception handlers in as a stop gap. While adding the textureBrush mod, I realized that the meory exceptions occur whenever a parallogram collapsed enough to be essentially a line (1-D figure instead of 2-D). So I tried to figure how I could test for this condition and reverted to DaftasBrush's distance of a point from a line calculation to filter out drawing the quad when it approached being a line.
The mutex was added originally becaue I would sometimes get an object in use error on the BufferedGraphics' Graphics object. I was callng the draw from the timer tics and from the paint event, both I figured should be on the GUI thread and not interruptable to each other, but I don't know. Anyway, in this version, I move the Draw call in the timer so that it is always called, and removed it from the Paint Event, since it is unecessary as we are constantly updating the screen from the timer. Didn't remove the mutex, but I presume it may not be necessary any longer.
Attached Files
File Type: zip matrix3portTextureBrush.zip (30.6 KB, 8 views)
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.

Last edited by passel; 03-03-2013 at 07:04 AM.
Reply With Quote
  #10  
Old 03-04-2013, 07:54 PM
surfR2911 surfR2911 is offline
Contributor
 
Join Date: Oct 2009
Posts: 719
Default orienting toward future progress..

Quote:
Originally Posted by passel
I was definitely thinking that the parallel arrays should probably go, and related items grouped into classes..
Thank you.

You probably don't think about this much, passel, but your examples on this forum set the standard for VB.Net graphics.
That's why the attachments in this thread, even if they are quickie VB3/VB6 to VB.Net code upgrades,
really deserve some extra time and attention to try to get them up to your usual high quality standard.

Quote:
Originally Posted by passel
Of course, with easily expandable lists of type, and gathering of more of the data into a single class in .Net,
you could make the number of blocks purely a dynamic number, with count and allocation being incremented
as you define the blocks in the layout, not pre-determined.
This definitely sounds interesting, but I struggled with List(of T) in my stupid question thread so I don't know if I would do any better this time around.

Quote:
..we could probably get away width depth sorting the cube objects themselves and drawing them as a whole..
Yes!

Quote:
..but that probably wouldn't be the case where a user was allowed to position longer blocks arbitrarily.
What if each block "owned" the pixel rows it occupied?
No other block could sit immediately to the left or to the right of the range of Y values the cube-block occupies (in a 2D display sense).

If this rule were in place then you could expand the cube-block width to fill (cover) the floor from left to right/
Alternately you could slide-drag the blocks from left to right or vice versa, like sliding a row of beads on an abacus.
I think it would be a good thing if the user could drag the blocks into new positions at runtime.

Quote:
The part that didn't pan out was the shearing..still had the texture creeping about as you changed the point of view.
Yes.
That's what I was trying to allude to earlier about shearing.
It will tend to "creep" as you change the point of view, unless it is constrained somehow and maybe some kind of per pixel interpolation is used for "patching".

Quote:
Likewise, if you change NumOfCubes to 1, you need to change the two initialization loops to go 0 to 0 so you do a 1x1 matrix.
So basically set NumOfCubes = 1, cx = 0, and cy = 0 and forget about the For..Next looping.

However, even with one cube there are unhandled exception errors if you try to add any more than a small value to a block face:
Code:
face = q + CubeFront 'Front Face
'values 1 thru 4 doesn't cause exception, but 5 or more does
'values 1 and 2 cause an interesting effect
Dim intValue As Integer = 1
QuadList(face) = New QuadType
With QuadList(face)
  .corner(0) = FrontRightBottomCorner +  intValue '2-4 doesn't cause excpetion but 5 or more does
  .corner(1) = FrontRightTopCorner +  intValue
  .corner(2) = FrontLeftTopCorner +  intValue
  .corner(3) = FrontLeftBottomCorner +  intValue
  .Colr = Color.Red
  .Width = (xo(FrontRightBottomCorner) - xo(FrontLeftBottomCorner)) + 1
  .Height = (yo(FrontRightBottomCorner) - yo(FrontRightTopCorner)) + 1
End With

Quote:
Originally Posted by passel
So I tried to figure how I could test for this condition and reverted to DaftasBrush's distance of a point from a line calculation
to filter out drawing the quad when it approached being a line.
Are you talking VB6 code or VB.Net code?
I don't remember DaftasBrush ever posting any VB.Net code along those lines,
but I do remember this VB6 code post for distance from point to line function.
Quote:
Originally Posted by passel

Didn't remove the mutex..
Sorry, but it's gone!
Added a some LoadDone boolean tests before the drawing (just for safety) and it seems to work fine under VB.Net Express 2010.
Code:
'in form paint
If LoadDone Then  '  in place of "gfxMutex.WaitOne()"
 gfx.Render()
End If  ' in place of 'gfxMutex.ReleaseMutex()
'In Draw() sub
If LoadDone Then   '  in place of "gfxMutex.WaitOne()"
'..all the draw sub code sandwiched in here..
End If   '  in place of 'gfxMutex.ReleaseMutex()
Spending another 15 minutes on the new attachment I'm wondering:
Quote:
How would you do a mouse hit test such that you could tell which cube-blocks,
(and how many..considering z-depth), and even which textures,
are under any user selected at runtime mouse's X, Y mousedown event e.location?



Quote:
edit (later):
The MSDN BufferedGraphicsContext.Allocate Method page says it just needs a Graphics object and a Rectangle.

So theoretically it doesn't necessarily need a CreateGraphics call..or does it?
(Especially if another way can generated the needed Graphics object)

I tried the alternate method of using Graphics.FromImage,
(see the attachment below).

The weird part is that it seems to kind of work somewhat..

The checkerboard texturebrush fills the background but
the DrawString function only works with Allocate using CreateGraphics, not with Allocate using Graphics.FromImage.

How unusual - some kind of BufferedGraphics strangeness?
No unhandled exception errors happen either way so..

Note: The code in the ResizeHandler sub is only called if one of the
controls is resized, so I bottom docked the panel control.
Please resize the form to call (and/or test) the ResizeHandler code for the panel control.

For comparision purposes (of doing essentially the same Graphics.FromImage call,
but not using Bufferedgraphics and have the DrawString call actually work)
see the "_Mouse_events_rendered_in_class.zip" attachment to post #51 of the Viewer thread.
Attached Files
File Type: zip BG_Class2--testing_allocate_without_creategraphics.zip (19.4 KB, 9 views)

Last edited by surfR2911; 03-05-2013 at 05:09 AM.
Reply With Quote
  #11  
Old 03-08-2013, 04:30 AM
surfR2911 surfR2911 is offline
Contributor
 
Join Date: Oct 2009
Posts: 719
Default Moving toward a room with a rotatable 3D cube..

Well its been a few days and I imagine passel has entirely forgotten about this thread, but I have not.

Possibly these two attachments can be combined so the corner of the room can be
moved in a coordinated fashion with rotation of the 3D block placed inside the room?
Attached Images
File Type: jpg screenshot_DIAP-Render_SingleBlock_NoMutex.JPG (61.4 KB, 6 views)
File Type: jpg screenshot_textured_walls-n-floor_usingDrawImage--3pt-n-4_point.JPG (157.3 KB, 9 views)
Attached Files
File Type: zip DIAPrenderSingleBlockNoMutex.zip (30.1 KB, 13 views)
File Type: zip TexturedWalls_n_Floor.zip (566.7 KB, 15 views)
Reply With Quote
  #12  
Old 03-08-2013, 04:38 AM
CodeCruncher CodeCruncher is offline
Junior Contributor
 
Join Date: Jul 2006
Posts: 355
Default

"I too should be doing other things (I can only watch CodeCruncher's efforts to alter the 3D complex wireframe code I posted into his BSC project from a distance),
but I don't want to not follow thru on this important new piece of isometric skewing code."

Please don't rush this which is important to you to get back to mine... I'm stuck on a few things, so it will be a while before my next example post.
Reply With Quote
  #13  
Old 03-08-2013, 08:46 PM
surfR2911 surfR2911 is offline
Contributor
 
Join Date: Oct 2009
Posts: 719
Default multi-prioritizing and hopefulness for the future..

Quote:
Originally Posted by CodeCruncher
I'm stuck on a few things, so it will be a while before my next example post.
I still have the Intersecting Lines thread bookmarked and am still optimistic
about the direction that your BSC is going..but I'm constantly dealing with shifting priorities.

However, I'm glad you found this thread.

Even a 3D wireframe objects viewer can benefit from a pseudo-3D "wraparound" environment.
Hopefully at some point it may lead to being able to distortion warping of textures around perspective mapped 3D objects.
Reply With Quote
  #14  
Old 03-09-2013, 01:12 AM
CodeCruncher CodeCruncher is offline
Junior Contributor
 
Join Date: Jul 2006
Posts: 355
Default

Likewise I received a job offer from an old distributor yesterday out of the blue, and it sounds very attractive. I am also currently trying to find and buy some acreage, so coding is getting on and off attention, but I will get there.

I have been watching this thread from the start to see how it is going but I haven't been trying to follow it. Hopefully at the end when the best method has been determined and a final answer is available I will read it then in one go to help follow it. Good luck and I hope the help you are getting continues.
Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off

Forum Jump

Advertisement:





Free Publications
The ASP.NET 2.0 Anthology
101 Essential Tips, Tricks & Hacks - Free 156 Page Preview. Learn the most practical features and best approaches for ASP.NET.
subscribe
Programmers Heaven C# School Book -Free 338 Page eBook
The Programmers Heaven C# School book covers the .NET framework and the C# language.
subscribe
Build Your Own ASP.NET 3.5 Web Site Using C# & VB, 3rd Edition - Free 219 Page Preview!
This comprehensive step-by-step guide will help get your database-driven ASP.NET web site up and running in no time..
subscribe
Calculating angles between lines with runtime draggable endpoints
Calculating angles between lines with runtime draggable endpoints
Calculating angles between lines with runtime draggable endpoints Calculating angles between lines with runtime draggable endpoints
Calculating angles between lines with runtime draggable endpoints
Calculating angles between lines with runtime draggable endpoints
Calculating angles between lines with runtime draggable endpoints Calculating angles between lines with runtime draggable endpoints Calculating angles between lines with runtime draggable endpoints Calculating angles between lines with runtime draggable endpoints Calculating angles between lines with runtime draggable endpoints Calculating angles between lines with runtime draggable endpoints Calculating angles between lines with runtime draggable endpoints
Calculating angles between lines with runtime draggable endpoints
Calculating angles between lines with runtime draggable endpoints
 
Calculating angles between lines with runtime draggable endpoints
Calculating angles between lines with runtime draggable endpoints
 
-->