Printing a view

My goal is to print modeled objects under Open CASACED with a scale factor on a paper with different size (A0, A1, A2, A3, A4). I need the print to keep a good precision. For ex with a scale factor 1:10e object should be the real size divided by 10. This print has to keep a good precision to be able to mesure some distance on the printed paper with a ruler. I also want to print object at scale 1:1.

Does anyone has experiment printing in Open CASCADE either through a bitmap or through a vectorial file (hpgl for ex). It seems that Open CASCADE can output a viewer in a gif file. But the limitation is the size of the printing area. First the precision is bad while it rely on screen pixel size. Second this size is limited to the screen size.

Is there any other way ?

Thanks to all people who are printing CASCADE results.

Philippe.

Sven Jungnickel's picture

Hi Philippe,

yes I solved my problem. In principle it functions like this:

- Dump your view to a PixMap with a call to the function ToPixMap() of class V3d_View
(Parameters are size in x, y and color depth)

- Then dump the content of the pixmap to a file (XWD,GIF or BMP file) with a call to Dump() of the
the class Aspect_PixMap. The name of the file extension selects the format:

Handle(Aspect_PixMap) aBitmap = view->ToPixMap (ansicht->GetSize().cx, ansicht->GetSize().cy, 24);

aBitmap->Dump((Standard_CString)(LPCTSTR)filename);

- To draw the bitmap I made use of an existing class CPicture found at www.codeguru.com which is able to load a bitmap
from a file and display it in a device context

As you I have to print out in A0 format with a good quality. Therefore I decided to set the resolution to 300 dpi. If you calculate the necessary amount of bytes to store the information you'll see that it is really huge with a color depth of 24 bits. With growing picture size the performance of the function ToPixMap() decreases very much. So don't try to render the information for a A0 plot at once. You'll have to break up a view into multiple tiles. Seems to be difficult but isn't. Below is the function who does this for me. The number of tiles has been calculated before.

The function simply calculates a new projection reference point and modifies the window limits to the tile size and updates the view before it is dumped to a file

void CAuswertung::SaveTilesToFile(Handle(V3d_View) view, CEinzelteilansicht *ansicht, int rows, int columns)
{
CString filename;

//////////////////////////////////////////////////////////////////////////
// Anzahl der Bildkacheln setzen

ansicht->m_tiles = rows * columns;
ansicht->m_tiles_rows = rows;
ansicht->m_tiles_columns = columns;
ansicht->m_picture_array.SetSize(rows * columns);

//////////////////////////////////////////////////////////////////////////
// Nur eine Bildkachel ?
//////////////////////////////////////////////////////////////////////////

if ( (rows * columns) == 1 )
{
// Dateinamen zusammensetzen
filename = ansicht->GetName() + ".gif";

// Aktuelle View in Bitmap ausgeben
Handle(Aspect_PixMap) aBitmap = view->ToPixMap (ansicht->GetSize().cx, ansicht->GetSize().cy, 24);

// Bitmap in Datei speichern
aBitmap->Dump((Standard_CString)(LPCTSTR)filename);
}
else
{
Standard_Real origUmin, origVmin, origUmax, origVmax;
Standard_Real newUmin, newVmin, newUmax, newVmax;
Graphic3d_Vertex origProjectionReferencePoint;
Graphic3d_Vertex newProjectionReferencePoint;
double tile_width_calc, tile_height_calc;
int tile_width, tile_height;
Standard_Real x_rp, y_rp;
Standard_Real x_delta, y_delta;
tPicture myPicture;

myPicture.tiles = rows * columns;
myPicture.rows = rows;
myPicture.columns = columns;
myPicture.pixel = ansicht->GetSize();

//////////////////////////////////////////////////////////////////////
// Originalkonfiguration des Ansichtsfensters speichern
//////////////////////////////////////////////////////////////////////

Visual3d_ViewMapping myMapping = view->View()->ViewMapping();
Visual3d_ViewOrientation myOrientation = view->View()->ViewOrientation();
myMapping.WindowLimit(origUmin, origVmin, origUmax, origVmax);
origProjectionReferencePoint = myMapping.ProjectionReferencePoint();
newProjectionReferencePoint = myMapping.ProjectionReferencePoint();

//////////////////////////////////////////////////////////////////////
// Länge und Breite des Ansichtsfensters berechnen
//////////////////////////////////////////////////////////////////////

Standard_Real window_width_orig = origUmax - origUmin;
Standard_Real window_height_orig = origVmax - origVmin;

//////////////////////////////////////////////////////////////////////
// Kachelgrösse berechnen
//////////////////////////////////////////////////////////////////////

tile_width_calc = (double)ansicht->GetSize().cx / (double)columns;
tile_height_calc = (double)ansicht->GetSize().cy / (double)rows;

//////////////////////////////////////////////////////////////////////
// Kacheln erzeugen
//////////////////////////////////////////////////////////////////////

for (int i = 0, column = 1, row = 1; i < myPicture.tiles; i++)
{
// Dateiname: ".gif"
filename.Format(_T("%s%d.gif"), (LPCTSTR)ansicht->GetName(), i + 1);

//////////////////////////////////////////////////////////////////
// Koordinatenkreuz ein-/ausblenden
//////////////////////////////////////////////////////////////////

if ( row == rows && column == 1)
{
// Für Kachel links unten Koordinatenkreuz einblenden
view->TriedronDisplay(Aspect_TOTP_LEFT_LOWER, Quantity_NOC_SKYBLUE, 0.1);
}
else
{
// Alle anderen Kacheln ohne Koordinatenkreuz
view->TriedronErase();
}

//////////////////////////////////////////////////////////////////
// Tatsächliche Breite der Kachel berechnen -Rundungsfehler
// ausgleichen!
//////////////////////////////////////////////////////////////////

if ( column == columns)
{
// Letzte Spalte erhält die Pixel die durch den Rundungsfehler entstanden sind
tile_width = myPicture.pixel.cx - (column - 1) * (int)floor(tile_width_calc);
}
else
{
// Kachelgrösse abrunden - Rundungsfehler wird zur letzten Kachel
// der Reihe addiert
tile_width = (int)floor(tile_width_calc);
}

//////////////////////////////////////////////////////////////////
// Tatsächliche Höhe der Kachel berechnen -Rundungsfehler
// ausgleichen!
//////////////////////////////////////////////////////////////////

if ( row == rows)
{
// Kachelbreite = Differenz Fenstergrösse - Höhe der bisherigen Kacheln
tile_height = myPicture.pixel.cy - (row - 1) * (int)floor(tile_height_calc);
}
else
{
// Kachelgrösse abrunden - Rundungsfehler wird zur letzten Kachel
// der Spalte addiert
tile_height = (int)floor(tile_height_calc);
}

myPicture.width_px.Add(tile_width);
myPicture.height_px.Add(tile_height);
myPicture.width.Add((double)tile_width / (double)myPicture.pixel.cx * window_width_orig);
myPicture.height.Add((double)tile_height / (double)myPicture.pixel.cy * window_height_orig);

//////////////////////////////////////////////////////////////////
// Neuen Referenzpunkt berechnen
//////////////////////////////////////////////////////////////////

// Referenzpunkt in linken obere Ecke des Ansichtsfensters verschieben
x_rp = origProjectionReferencePoint.X() - window_width_orig / 2;
y_rp = origProjectionReferencePoint.Y() + window_height_orig / 2;

// Vorherige Kachelbreiten aufsummieren
double sum_width = 0;
for (int i = 1; i < column; i++ )
{
sum_width += myPicture.width.GetAt(i-1);
}

// Vorherige Kachelhöhen aufsummieren
double sum_height = 0;
for (int i = 1; i < row; i++ )
{
sum_height += myPicture.height.GetAt(i-1);
}

x_delta = myPicture.width.GetAt(column - 1) / 2 + sum_width;
y_delta = myPicture.height.GetAt(row - 1) / 2 + sum_height;

newProjectionReferencePoint.SetXCoord(x_rp + x_delta);
newProjectionReferencePoint.SetYCoord(y_rp - y_delta);

//////////////////////////////////////////////////////////////////
// Neue Window Limits des Ansichtsfensters berechnen
//////////////////////////////////////////////////////////////////

newUmin = origUmin + sum_width;
newUmax = origUmin + sum_width + myPicture.width.GetAt(column - 1);
newVmin = origVmax - sum_height - myPicture.height.GetAt(row - 1);
newVmax = origVmax - sum_height;

//////////////////////////////////////////////////////////////////
// View aktualisieren
//////////////////////////////////////////////////////////////////

// View Mapping aktualisieren
myMapping.SetWindowLimit(newUmin, newVmin, newUmax, newVmax);
myMapping.SetProjectionReferencePoint(newProjectionReferencePoint);

// Neues View Mapping setzen
view->View()->SetViewMapping(myMapping);

// View neu zeichnen
view->Redraw();
view->Update();

//////////////////////////////////////////////////////////////////
// Gif-Datei rendern und ausgeben
//////////////////////////////////////////////////////////////////

// Aktuelle View in Bitmap ausgeben
Handle(Aspect_PixMap) aBitmap = view->ToPixMap (10, 10, 8);

// Aktuelle View in Bitmap ausgeben
aBitmap = view->ToPixMap (tile_width, tile_height, 24);

// Bitmap in Datei speichern
aBitmap->Dump((Standard_CString)(LPCTSTR)filename);

//////////////////////////////////////////////////////////////////
// Zeilen- und Spaltenindex inkrementieren
//////////////////////////////////////////////////////////////////

if ( column == columns )
{
row++;
column = 1;
}
else
{
column++;
}
}

//////////////////////////////////////////////////////////////////////
// Koordinatenkreuz wieder anzeigen

view->TriedronDisplay(Aspect_TOTP_LEFT_LOWER, Quantity_NOC_SKYBLUE, 0.1);

}

return;
}