print large triangular outline using multiple sheets, possible?

print large triangular outline using multiple sheets, possible?

Post by Mike Sciro » Mon, 29 Oct 2007 08:43:10


I wrote a program that calculates a single 'leaf' of a parabolic
reflector, basically a triangle with two slightly curved sides. The
program lets the user enter the top radius, number of leaves, and focal
length, then calculates the (x, y) coordinates of the edges of a leaf.
When the leaves are joined a parabolic curve is formed where the edges
meet. A leaf is basically a triangle with two curved sides.

I'd like to let the user print a 'template' of a single leaf. The
trouble is that the leaves are larger than a single sheet, usually in
both width and height, so I would need to calculate how many pieces of
paper were needed, and start a line on each new page where the end of
the line on the last page ended. So when they're all joined together a
complete leaf template outline would be formed. A leaf might be three
feet long and over a foot wide, so that would take maybe 6 or 7 8.5x11"
sheets, including printer margins.

I only care about printing the edges of the leaf, printing blank sheets
doesn't make any sense. Is there any existing code that I can look at
for printing things a lot larger than one sheet of paper?

TIA,
Mike
 
 
 

print large triangular outline using multiple sheets, possible?

Post by Larry Serf » Mon, 29 Oct 2007 14:49:20

"Mike Scirocco" < XXXX@XXXXX.COM > wrote

You already know how to draw the shape you want, all you really
nned to do is scale it up. To do that you'd put a grid over your
current drawing in the shape of the laid out pages, and keep track
of their upper left corner, in relation to the drawing.

For example, to draw your triangle, let's suppose you draw two
arcs and a line. Those arcs have a center point and size, and the
line has two points to mark begin and end. You still use those
points, only you have to offset them to reflect the position of
the current page.

FWIW, it will get a bit trickier when you want to overlap pages,
but the same principle holds true, keep track of the upper left
corner of the grid cells, overlapped or not.

For a short example add a Picturebox to a new form and paste
in the code below. Clicking on the red grid shows that page
in the picturebox.

LFS

Option Explicit
Dim LY1, CX1, CX2, CY1, CY2, OFSX, OFSY

Private Sub Form_Load()
Picture1.Move 0, 0, 1700, 2200
Picture1.BackColor = vbWhite
Picture1.Scale (0, 0)-(850, 1100)
Picture1.ForeColor = &H8000&
Picture1.DrawWidth = 3
AutoRedraw = True
InitArt
End Sub

Private Sub Form_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
' Draw to Picturebox (Reduce to point at upper left corner of grid cell)
DrawArt Picture1, ((X - OFSX) \ 850) * 850, ((Y - OFSY) \ 1100) * 1100
End Sub

Private Sub InitArt()
Dim X, Y, OX, OY
' Graphic points
CX1 = 1000
CY1 = 1000
CX2 = 5000
CY2 = 1000
LY1 = 5000
' Grid offset
OFSX = 1725
OFSY = 1000
' Render drawing to form
DrawArt Form1, -OFSX, -OFSY
' Draw red grid
For X = 0 To 1700 Step 850
For Y = 0 To 3300 Step 1100
Line (OFSX + X, OFSY + Y)-Step(850, 1100), vbRed, B
Next Y, X
End Sub

Sub DrawArt(Dst As Object, X, Y)
Dim dLY1, dCX1, dCX2, dCY1, dCY2

dLY1 = LY1 - Y - OFSY
dCX1 = CX1 - X - OFSX
dCX2 = CX2 - X - OFSX
dCY1 = CY1 - Y - OFSY
dCY2 = CY2 - Y - OFSY

Dst.BackColor = vbWhite
Dst.Line (0, dLY1)-(Dst.ScaleWidth, dLY1)
Dst.Circle (dCX1, dCY1), 6000, , 0.000002, 0.000001, 3
Dst.Circle (dCX2, dCY2), 6000, , 0.000002, 0.000001, 3
End Sub





 
 
 

print large triangular outline using multiple sheets, possible?

Post by Mike Sciro » Mon, 29 Oct 2007 15:02:41

arry Serflaten wrote:

Larry, sounds good... to do this I'll probably want to read the printer
margins from Windows to know the size of the printable area of a page,
and 'slide' a rectangle that size over the outline of the entire shape,
printing each section, one page at a time. The user will just have to
connect the pages together so that the lines touch. Very nice approach!

Thanks,
Mike
 
 
 

print large triangular outline using multiple sheets, possible?

Post by Mike Willi » Mon, 29 Oct 2007 17:34:20


I see that you've already got some very nice code from Larry to perform the
drawing and to print it over multiple sheets, and you obviously already know
all about the "printable area" stuff so you'll have no problems with that.
The only other thing you need is to detect the blank pages so that you do
not print them. You can easily do that by scanning each "page" of the
drawing looking for the first pixel that is "not white" (if you're drawing
onto a white background which I assume you will be) and printing only those
pages where you find one. This can either be done very simply by scanning
across and down in "pixels" ScaleMode using the VB Point method (or the
slightly faster GetPixel API function) or very quickly by transferring the
drawn bitmap data of the page to a VB array of Longs (GetDIBits) and
scanning the array.

An alternative approach, which is only really worth considering if you
require a higher resolution in the printed output than the current approach
will give you, is to draw your stuff into a memory metafile (instead of or
as well as to the display) and to then draw the individual "pages" of that
metafile to the printer, using a similar technique to calculate the "page"
coordinates in the metafile. For your own current requirement you probably
won't need that sort of resolution, but if you do want to consider it then
you'll find a very interesting threads in this group over the last few weeks
dealing with metafiles (just search the recent group content for threads
with the text "metafile" in them). It's a fair amount of extra work of
course, and it's only really worth you taking that approach if you really
need to (which you almost certainly don't in this case) but it might still
be worth looking at.

Mike
 
 
 

print large triangular outline using multiple sheets, possible?

Post by Larry Serf » Tue, 30 Oct 2007 00:43:44


"Mike Williams" < XXXX@XXXXX.COM > wrote

A quick way of determining if some part of a page is not white is to
(in essence) fold it in half repeatedly; ANDing half of the image to the
other half. White pixels will stay white but any other colors will be
something other than white.

10 to 15 folds will bring an image down so that the test grid need not
be very big at all. You could go down to 1 X 1 pixel to make the test
just one call to Point(0, 0).

For a demo, add 2 command buttons and a picturebox to a new form
and paste in the code below. Each click of the Fold button does one
fold. In practice you would repeatedly fold the image until the determination
was made....

LFS

Option Explicit
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type

Private Page As RECT

Private Sub Command1_Click()
Set Picture1.Picture = Nothing
Picture1.BackColor = vbWhite
Picture1.Picture = Picture1.Image
Page.Right = Picture1.ScaleWidth
Page.Bottom = Picture1.ScaleHeight
End Sub

Private Sub Command2_Click()
Fold
End Sub

Private Sub Form_Load()
Command1.Caption = "Reset"
Command2.Caption = "Fold"
Picture1.AutoRedraw = True
Command1.Value = True
End Sub

Private Sub Picture1_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
Picture1.PSet (X, Y), vbBlack
End Sub

Sub Fold()
Dim wid!, hgt!
If FindInk Then Exit Sub
Set Picture1.Picture = Picture1.Image
wid = Page.Right \ 2 + 1
hgt = Page.Bottom \ 2 + 1
If wid > hgt Then
' fold sideways
Picture1.PaintPicture Picture1.Picture, 0, 0, wid, Page.Bottom, wid, 0, wid, Page.Bottom, vbSrcAnd
' Yellow added for demo (comment out to test for no ink)
Picture1.Line (wid + 1, 0)-Step(wid, Page.Bottom), vbYellow, BF
Page.Right = wid + 1

Else
' fold vertically
Picture1.PaintPicture Picture1.Picture, 0, 0, Page.Right, hgt, 0, hgt, Page.Right, hgt, vbSrcAnd
' Yellow added for demo (comment out to test for no ink)
Picture1.Line (0, hgt + 1)-Step(Page.Right, hgt), vbYellow, BF
Page.Bottom = hgt + 1
End If

End Sub


Function FindInk() As Boolean
Dim found As Boolean
Dim small As Boolean
' Catch ink
If Picture1.Point(0, 0) <> vbWhite Then
MsgBox "Ink was found on this page"
found = True
End If
' Avoid going too small
If Picture1.ScaleX(Page.Right, Picture1.ScaleMode, vbPixels) < 2 Then
small = True
End If
If Picture1.ScaleY(Page.Bottom, Picture1.ScaleMode, vbPixels) < 2 Then
small = True
End If

If Not found Then
If small Then
MsgBox "No ink was found on this page"
End If
End If
FindInk = found Or small

End Function
 
 
 

print large triangular outline using multiple sheets, possible?

Post by Mike Willi » Tue, 30 Oct 2007 05:17:36


Well, I've got to say Larry that I very rarely find solutions that I just
know I would never have thought of myself, no matter how long I spent
looking at the problem, but this is very definitely one of them. Superb
stuff! It's almost the equivalent of a binary search in an ordered array, or
a "repeatedly cut the problem in half until it no longer exists" Quicksort
algorithm. Really, really nice code. The basic "divide and rule" idea is of
course a very old one, but it is something I just would never have thought
of applying to this specific problem. Absolutely brilliant! Do you mind if I
steal it? ;-)

Mike
 
 
 

print large triangular outline using multiple sheets, possible?

Post by Larry Serf » Tue, 30 Oct 2007 07:28:23


"Mike Williams" < XXXX@XXXXX.COM > wrote

You can use it if you want, but I have to warn you, it was a quick demo
and it very probably isn't pixel perfect. I purposely overscanned the source
side of the equation due to working with Long types:

wid = Page.Right \ 2 + 1
hgt = Page.Bottom \ 2 + 1

While it may be fine for an entire page, trying to fit that algorithm into
a specific rectangle would require a bit of tweaking.

LFS
 
 
 

print large triangular outline using multiple sheets, possible?

Post by Mike Willi » Tue, 30 Oct 2007 07:44:43


Yes. I realised that when I discovered that it sometimes returned the wrong
result (probably because I had changed the size of the picbox). But
nevertheless the basic idea behind it is sound, and I'm sure it can be
truned into a very useful general purpose routine.

Mike
 
 
 

print large triangular outline using multiple sheets, possible?

Post by Larry Serf » Tue, 30 Oct 2007 08:11:05


"Mike Williams" < XXXX@XXXXX.COM > wrote



I haven't got time to try it now, but a second method might be to
StretchBlt the entire page into one pixel, using the BlackOnWhite
mode. From the docs: (SetStretchBltMode)

"Performs a Boolean AND operation using the color values for the eliminated
and existing pixels."

If it ANDs them all together, then the result should be the same as the folding
algorithm. I'll have to try that tomorrow to see if it performs as stated....

LFS
 
 
 

print large triangular outline using multiple sheets, possible?

Post by Mike Sciro » Tue, 30 Oct 2007 14:37:39


Mike and Larry,

Thanks for all of the information. I don't mind extra coding if I come
up with a really solid solution. Right now I'm finishing two midterms so
I'll have to dig into this when things quiet down. When (not if) I run
into snags I'll post again here.

Thank to both of you,
Mike
 
 
 

print large triangular outline using multiple sheets, possible?

Post by Mike Willi » Tue, 30 Oct 2007 22:36:12


That doesn't actually work, Larry. The result depends on how many "non
white" pixels there are where they happen to be positioned. It is however
still a good idea and can probably be made to work if stretching to a size
that is larger than one pixel and checking all the resultant pixels in the
small image. It would need testing out properly, though, to see what size it
is possible to get away with. I think your "repeated folding" idea is
probably the best though.

Mike
 
 
 

print large triangular outline using multiple sheets, possible?

Post by Larry Serf » Tue, 30 Oct 2007 23:55:57


"Mike Williams" < XXXX@XXXXX.COM > wrote


You were correct, the smallest I could go was to a 5 X 5 grid and still see
individual pixels. But that method left out the pixels on the edge. What
does work is to reduce the image by some percentage, and then again by
some smaller percentage, repeatedly until you can make the determination.

While I had to work to get it to pick up the pixel in the lower right corner,
most everything I tried did fairly well. I finally found if I first bring all the
edges in a couple pixels, I could get it to work in all the cases I tried.
Obviously I could not try all sizes, but this seems to work.

Due to the stretching (reduction) of the whole image every time however,
a straight BitBlt folding algorithm will probably be quicker. I'll have to try
that next.

LFS

Option Explicit
Private Declare Function StretchBlt Lib "gdi32" (ByVal hdc As Long, ByVal X As Long, ByVal Y As Long, _
ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, _
ByVal xSrc As Long, ByVal ySrc As Long, ByVal nSrcWidth As Long, ByVal nSrcHeight As Long, _
ByVal dwRop As Long) As Long

Private Sub Command1_Click()
Set Picture1.Picture = Nothing
End Sub

Private Sub Command2_Click()
If IsBlank(Picture1) Then
MsgBox "The page is blank"
Else
MsgBox "The page is not blank"
End If
End Sub

Private Sub Form_Load()
Picture1.AutoRedraw = True
Picture1.BackColor = vbWhite
Command1.Caption = "Reset"
Command2.Caption = "Find"
End Sub

Private Sub Picture1_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
Picture1.PSet (X, Y), vbBlack
End Sub


Private Function IsBlank(Pic As PictureBox) As Boolean
Dim sav As StdPicture
Dim wid&, hgt&, div&, siz As Long
Dim ink As Boolean

Set Pic.Picture = Pic.Image
Set sav = Pic.Picture
wid = Pic.ScaleX(Pic.ScaleWidth, Pic.ScaleMode, vbPixels)
hgt = Pic.ScaleY(Pic.ScaleHeight, Pic.ScaleMode, vbPixels)
siz = wid
If hgt < wid Then
siz = hgt
End If

StretchBlt Pic.hdc, 2, 2, wid - 4, hgt - 4, Pic.hdc, 0, 0, wid, hgt, vbSrcAnd
div = 1
Do While (div < siz) And (ink = False)
StretchBlt Pic.hdc, 0, 0, wid \ div, hgt \ div, Pic.hdc, 0, 0, wid, hgt, vbSrcAnd
div = div * 4
ink = (Pic.Point(0, 0) <> vbWhite)
Loop

IsBlank = Not ink
Pic.PaintPicture sav, 0, 0
End Function