Build Better Software. Faster.
Visit our company site at: www.techsoft3d.com
 

White Papers Index

Resolving Common Printing Problems
Gavin

WYSIWYG Printing

Getting WYSIWYG printing in your application typically means that everything that is currently visible on the screen appears on the printout. However because the aspect ratio (window width versus window height) of the drawing area on a print page and on your display window are typically different we need to modify the camera field on the print page so that it matches the world space width and height of the display window. The other camera settings (position, target, up-vector and projection) are set to the same values that are used by the camera viewing the scene on the display window.

To set the camera correctly we simply need to determine the width and height of the display window and set that as the camera field. Determining the width and height of the display window is relatively straight-forward and involves using the Compute_Coordinates(…) function which helps you translate points between the various coordinate systems. The lower-left corner of a window in window-space is (-1,-1,0) while the upper-right corner is (1,1,0). Thus, to determine the camera width and field the pseudo code would look something like:

HPoint LowerLeft, UpperRight; LowerLeft.Set(-1.0,-1.0,0.0); UpperRight.Set(1.0,1.0,1.0); HC_Open_Segment_By_Key(view->GetSceneKey()); HC_Compute_Coordinates(“.”, “local window”, LowerLeft, ”world”, LowerLeft); HC_Compute_Coordinates(“.”, “local window”, UpperRight, ”world”, UpperRight); HC_Close_Segment(); float width, height; width = (abs)(LowerLeft.x – UpperRight.x); height = (abs)(LowerLeft.y – UpperRight.y); Now all we have to do is use thiswidth and height as the camera field settings on our print driver. HC_Open_Segment(“/msw/printer/myPrintout”); HC_Set_Camera_Field(width, height); // Now we do all out other work which includes // setting the other camera settings, setting // the appropriate driver settings, including // the segment tree and calling HC_Update_Display() ..

Note, since the aspect ratio changes in many cases geometry that was previously clips from the viewport will now be visible.

Printing my data with accurate scale

Though HOOPS uses a Cartesian coordinate system it is a unitless system. By this we mean that 1 unit in the 3dGS system does not map over to a specific physical unit. It is up to the user to decide whether one unit in their scene graph is 1 mile, 1 kilometer, 1 foot, 1 inch or 1 centimeter. Thus when a developer is outputting their data to a physical device and they want 1 centimeter (say) to be 1 cm on the printout then they must do some work to query the physical size of the printer page and then set their camera accordingly. Specifically, they must set the camera field to match the exact physical size of the page. On Windows you determine the physical size of a printable area via CDC:: GetDeviceCaps(). To get accurate scale printing all you should need to do is set the camera field so that the width and height match over to the physical width and height of the printable area. The pseudo code for getting 1 to 1 printing on Windows looks like this:

// HORZRES and VERTRES return the width and height // of the printable area in millimeters int width =pDC->GetDeviceCaps(HORZRES); int height =pDC->GetDeviceCaps(VERTRES); // so now if 1 unit in our model is meant to be 1 centimeter // then we would need to take this value into account when // we set the camera field. float scaleFactor = 10.0f; HC_Open_Segment(“/msw/printer/myPrintout”); HC_Set_Camera_Field(width*scaleFactor, height*scaleFactor); // now you set the camera position, target and // up_vector to get the required geometry drawn // on the page . . . . HC_Include_Segment_By_Key(myData); HC_Close_Segment()

Vector versus Raster Printouts and how to create Printouts that contain both

To get high quality printing of text, edge and line data a printer needs to be sent vector rather than raster data and so when in wireframe or hidden line rendered scenes developers set their hidden surface removal algorithm to one of HOOPS’ vector based sorting algorithms. In the wireframe case this can be either “z-sort” or “painters” while in the hidden-line case it is “hidden line”. Z-sort and painters could both be used for all printing however they are extremely slow when dealing with large scenes and since they send all the geometry down to the printer they are pretty memory intensive. Furthermore, printers do not have vector primitives for lit geometry and consequently to ensure the printout looks correct HOOPS must do the lighting calculations and send this geometry down in a pixel-by-pixel fashion. Thus, for scenes which contain a lot of lit geometry we use a different, framebuffer-based approach to print them. Using this approach results in fast printing which uses the minimum amount of memory.

The method is quite simple. We create an image of the scene which has the same aspect ratio of the print page, set this as the background image in the driver and then print the page. The pseudo code for doing this is as follows:

 

int width = pDC->GetDeviceCaps(HORZRES); int height = pDC->GetDeviceCaps(VERTRES); // here is where we set the DPI of the image we’re going to blit // to the printer int image_dpi=150; // there are 25.4 millimeters in a single inch width *= image_dpi/25.4; height *= image_dpi/25.4; //prepare image for rendering HC_Open_Segment ("?driver/null/1"); HC_KEY imageKey = HC_KInsert_Image(0.0,0.0,0.0, "rgb, name=background",
width, height, NULL); HC_Close_Segment (); bool useOpenGLImageGeneration = true; long debug=0L; if (useOpenGLImageGeneration) { sprintf(imageDriver, "/driver/opengl/image"); debug |= 0x00100000; debug |= DEBUG_FORCE_SOFTWARE; } else sprintf(imageDriver, "?driver/image/1"); // now let’s create the image HC_Open_Segment (imageDriver); sprintf (buffer, "use window id = %s%p, isolated, debug=%d",
H_EXTRA_POINTER_FORMAT, imageKey, debug); HC_Set_Driver_Options (buffer); HC_Set_Camera (…); if (useOpenGLImageGeneration) HC_Set_Rendering_Options("hsra = hzb"); else HC_Set_Rendering_Options("hsra = szb"); HC_Include_Segment_By_Key (view->GetSceneKey()); HC_Close_Segment(); HC_Update_Display(); // Now use this in our printout. Notice that we do not // include any geometry into the scene since it is all // contained in the background image HC_Open_Segment (“/driver/msw/printer”); HC_Set_Color("windows= background"); HC_Set_Driver_Options((char *)allThePrinterDriverSettings); HC_Close_Segment ();

Note, the DPI of the image does not have to match the DPI of the output device since HOOPS will stretch the image so that it extends across the complete page, all we have to do is ensure that the aspect ratio of the image matches the aspect ratio of the print page. HOOPS uses some internal algorithms to eliminate white pixels from the image to ensure that we’re sending as little data as possible down to the printer.

In many cases scenes contain both lit and unlit geometry and users want the lit geometry to be printed quickly with minimal memory usage and also want the vector data (which typically consists of the edge, line and text data) to be printed with vector commands. Being able to get this kind of functionality is done by using a combination of the image generation method above and using hidden line algorithm to sort the vector data. What you do is create the image containing only the lit geometry, use that image as the background image for the print segment and then include the scene in the print segment which uses a “hidden line” hsra setting. The pseudo code for doing this is:

 

// At this point we have already created the image of // the appropriate size as is outlined above. We then // create the image however notice how we turn off the // visibility of the vector data and put an attribute // lock on it so that it overrides any of the settings // in the actual scene-graph HC_Open_Segment (imageDriver); sprintf (buffer, "use window id = %s%p, debug=%d", H_EXTRA_POINTER_FORMAT,
imageKey, debug); HC_Set_Driver_Options (buffer); HC_Set_Camera (); if (useOpenGLImageGeneration) HC_Set_Rendering_Options("hsra = hzb"); else HC_Set_Rendering_Options("hsra = szb"); HC_Set_Visibility(edges=off, lines=off, text=off, markers=off); HC_Set_Rendering_Options(attribute lock=(visibility)); HC_Include_Segment_By_Key (myScene); HC_Close_Segment(); HC_Update_Display(); // Now use the image we just generated as the background, // include the scene and use the hidden line sorting // algorithm to properly hidden surface remove the // non-visible vector data HC_Open_Segment (/driver/msw/printer); HC_Set_Color("windows=background"); HC_Set_Driver_Options((char *)allThePrinterDriverSettings); HC_Set_Rendering_Options(hsra=hidden line, hlro=(visibility=off));
HC_Include_Segment_By_Key (myScene); HC_Close_Segment ();

How do I get my HOOPS subwindows to be positioned correctly in my printouts

Many Developers have problems correctly positioning HOOPS subwindows on a printout. The problem is that HOOPS subwindows are defined in window space which means that a change in the aspect ratio of the drawing area results in a corresponding change in the shape of the subwindow. Thus each time we are putting subwindows into a drawing area which has a different aspect ratio we need to readjust the window settings. To do this we convert the coordinates of the subwindow in the original window into a coordinate system which is independent of aspect ratio and then use that position to re-calculate the location of the window on the drawing area with a different aspect ratio. Pseudo code for a function which does this is contained below:

 

// You would call this function for each windowed subsegment // in your scene as the aspect ratio changes. This function // only makes a difference if the aspect ratio between the // two drivers is different. Consequently this version of the // function will not work for repositioning subwindows in a // window as it is being resized void ResetWindows(HC_KEY currentDriver, HC_KEY newDriver, HC_KEY windowedSegment) { float left, right, top, bottom; HC_Open_Segment_By_Key (windowedSegment); HC_Show_Window(&left, &right, &top, &bottom); HC_Close_Segment(); HPoint bottomLeft, topRight; bottomLeft.Set(left, bottom, 0.0f); topRight.Set(right, top, 0.0f); HC_Open_Segment (currentDriver); HC_Compute_Coordinates(“.”, “local window”, bottomLeft, “world”, bottomLeft); HC_Compute_Coordinates(“.”, “local window”, topRight, “world”, topRight); HC_Close_Segment(); HC_Open_Segment (newDriver); HC_Compute_Coordinates(“.”, “world”, bottomLeft, “local window”, bottomLeft); HC_Compute_Coordinates(“.”, “world”, topRight, “local window”, topRight); HC_Close_Segment(); HC_Open_Segment (windowedSegment); HC_Set_Window(bottomLeft.x, bottomLeft.y, topRight.x, topRight.y); HC_Close_Segment(); }

 
 

 

 

 

 

©2004-06 Tech Soft 3D All Rights Reserved. Privacy | Legal