void CStartupView::DrawTitleText(Gdiplus::Graphics &graphics) { Gdiplus::Rect gdipRcLeftButtons; CalculateLeftButtonsRegion(gdipRcLeftButtons); Gdiplus::SolidBrush blackBrush(Gdiplus::Color(255, 0, 0, 0)); Gdiplus::Font titleFont(m_csFontFamily, m_iTitleFontSize, Gdiplus::FontStyleBold, Gdiplus::UnitPixel); Gdiplus::Font subTitleFont(m_csFontFamily, m_iNormalFontSize, Gdiplus::FontStyleBold, Gdiplus::UnitPixel); CString csRecord1; csRecord1.LoadString(IDS_RECORD); INT x = gdipRcLeftButtons.X; INT y = gdipRcLeftButtons.Y + 2*BUTTON_TITLE_HEIGHT; Gdiplus::PointF textOrigin(x/*gdipRcLeftButtons.X*/, y/*(gdipRcLeftButtons.Y + gdipRcLeftButtons.Height)*/ ); graphics.SetTextRenderingHint(Gdiplus::TextRenderingHintAntiAliasGridFit); graphics.DrawString(csRecord1, csRecord1.GetLength(), &titleFont, textOrigin, &blackBrush); x = gdipRcLeftButtons.X; y = gdipRcLeftButtons.Y + BUTTON_TITLE_HEIGHT + 2*BUTTON_SUBTITLE_HEIGHT + 2*(BUTTON_HEIGHT1 + 10) + SEPARATOR_HEIGHT + 5; //Gdiplus::PointF textOrigin(x/*gdipRcLeftButtons.X*/, y/*(gdipRcLeftButtons.Y + gdipRcLeftButtons.Height)*/ ); textOrigin.X = x; textOrigin.Y = y; CString csWelcome; //csWelcome.LoadStringW(IDS_WELCOME); csWelcome.LoadStringW(ID_MENU_NEW); graphics.DrawString(csWelcome, csWelcome.GetLength(), &titleFont, textOrigin, &blackBrush); textOrigin.Y += BUTTON_TITLE_HEIGHT; Gdiplus::Rect gdipRcRightButtons; CalculateRightButtonsRegion(gdipRcRightButtons); textOrigin.X = gdipRcRightButtons.X ; textOrigin.Y = gdipRcRightButtons.Y + BUTTON_TITLE_HEIGHT + BUTTON_HEIGHT;; CString csRecord; //csRecord.LoadStringW(IDS_RECORD); csRecord.LoadStringW(ID_MENU_OPEN); graphics.DrawString(csRecord, csRecord.GetLength(), &titleFont, textOrigin, &blackBrush); /*textOrigin.X = gdipRcRightButtons.X ; textOrigin.Y += 3*BUTTON_HEIGHT; CString csRecent; csRecent.LoadStringW(IDS_RECENTLY_OPENED_PROJECTS); graphics.DrawString(csRecent, csRecent.GetLength(), &titleFont, textOrigin, &blackBrush); */ }
void BpDocument::composeGraphBasics( Graph *g, bool isLineGraph, EqVar *xVar, EqVar *yVar, EqVar *zVar, int curves, GraphAxleParms *xParms, GraphAxleParms *yParms ) { //-------------------------------------------------------------------------- // Set the logical fonts and colors here //-------------------------------------------------------------------------- // Axis text fonts. QFont textFont( property()->string( "graphTextFontFamily" ), property()->integer( "graphTextFontSize" ) ); QPen textPen( property()->color( "graphTextFontColor" ) ); QFont axleFont( textFont ); QColor axleColor( property()->color( "graphAxleColor" ) ); QPen axlePen( axleColor, property()->integer( "graphAxleWidth" ), Qt::SolidLine ); QPen gridPen( property()->color( "graphGridColor" ), property()->integer( "graphGridWidth" ), Qt::SolidLine ); // Title fonts and colors. QFont subTitleFont( property()->string( "graphSubtitleFontFamily" ), property()->integer( "graphSubtitleFontSize" ) ); QColor subTitleColor( property()->color( "graphSubtitleFontColor" ) ); QFont titleFont( property()->string( "graphTitleFontFamily" ), property()->integer( "graphTitleFontSize" ) ); QColor titleColor( property()->color( "graphTitleFontColor" ) ); // Background and canvas colors. QBrush worldBg( property()->color( "graphBackgroundColor" ), Qt::SolidPattern ); QBrush canvasBg( "white", SolidPattern ); QPen canvasBox( "black", 1, NoPen ); //-------------------------------------------------------------------------- // Create the graph canvas, world, and decoration. //-------------------------------------------------------------------------- // Get the x- and y-axle parameters double xValMin = xParms->m_axleMin; double xValMax = xParms->m_axleMax; double xMajorStep = xParms->m_majorStep; int xDec = xParms->m_decimals; double yValMin = yParms->m_axleMin; double yValMax = yParms->m_axleMax; double yMajorStep = yParms->m_majorStep; int yDec = yParms->m_decimals; // Graph title and subtitle. QString qStr = m_eqTree->m_eqCalc->docDescriptionStore().stripWhiteSpace(); //if ( qStr.isNull() || qStr.isEmpty() ) //{ // translate( qStr, "BpDocument:NoRunDescription" ); //} g->setTitle( qStr, titleFont, titleColor ); if ( property()->boolean( "graphTitleActive" ) ) { QString text(""); translate( text, "BpDocument:Graphs:By" ); qStr = *(yVar->m_label) + "\n" + text + " " + *(xVar->m_label); if ( curves > 1 && isLineGraph && zVar ) { translate( text, "BpDocument:Graphs:And" ); qStr += "\n" + text + " " + *(zVar->m_label); } g->setSubTitle( qStr, subTitleFont, subTitleColor ); } // Use portrait orientation (assuming screen output, not printer). g->setCanvasRotation( 0.0 ); g->setCanvasScale( 1.0, 1.0 ); // NOTE: to change the graph location or size, // we must manipulate the m_composer->graph() args! g->setCanvas( m_screenSize->m_marginLeft, // upper left X pixel m_screenSize->m_marginTop, // upper left Y pixel m_screenSize->m_bodyWd, // graph canvas width in pixels m_screenSize->m_bodyHt, // graph canvas height in pixels 0 // graph border in pixels ); // Canvas background and box. g->setCanvasBg( canvasBg ); g->setCanvasBox( canvasBox ); // Make the world coordinate system 20% larger than the data range. g->setWorld( xValMin - 0.2 * (xValMax-xValMin), // canvas WORLD left coordinate yValMin - 0.2 * (yValMax-yValMin), // canvas WORLD bottom coordinate xValMax + 0.1 * (xValMax-xValMin), // canvas WORLD right coordinate yValMax + 0.1 * (yValMax-yValMin) // canvas WORLD top coordinate ); // Provide a colored background for the graph area. g->setWorldBg( xValMin, // colored bg WORLD left coordinate yValMin, // colored bg WORLD bottom coordinate xValMax, // colored bg WORLD right coordinate yValMax, // colored bg WORLD top coordinate worldBg // brush color and pattern ); //-------------------------------------------------------------------------- // Create a bottom axle with endpoints in WORLD coordinates (not AXLE). // This has all elements of an axle EXCEPT a minor grid and subtitle. //-------------------------------------------------------------------------- GraphAxle *b = g->addGraphAxle( xValMin, // axle's min scale (NOT WORLD) value xValMax, // axle's max scale (NOT WORLD) value axlePen // axle line pen (color, width, style) ); b->setWorld( xValMin, // axle's start WORLD x coordinate yValMin, // axle's start WORLD y coordinate xValMax, // axle's end WORLD x coordinate yValMin // axle's end WORLD y coordinate ); // Line graph bottom axles need labels and tic marks. if ( isLineGraph ) { b->setMajorLabels( axleFont, // label font axleColor, // font color xDec // decimal places (-1 mean no label) ); b->setMajorTics( GraphAxleBottom, // side of axle to draw tic marks xValMin, // first tic mark location in AXLE units xValMax, // last tic mark location in AXLE units xMajorStep, // tic spacing in AXLE units 0.05 * (yValMax-yValMin), // tic mark length in Y WORLD units axlePen // tic pen (color, width, style) ); b->setMinorTics( GraphAxleBottom, // side of axle to draw tic marks xValMin, // first tic mark location in AXLE units xValMax, // last tic mark location in AXLE units 0.50 * xMajorStep, // tic spacing in AXLE units 0.03 * (yValMax-yValMin), // tic mark length in Y WORLD units axlePen // tic pen (color, width, style) ); b->setMajorGrid( gridPen, // grid pen color, width, style (yValMax-yValMin) // length in Y WORLD units !! ); // Don't show the units for ratio variables. qStr = *(xVar->m_label) + " " + xVar->displayUnits(true); b->setTitle( qStr, // axle title string GraphAxleBottom, // axle side to write the string axleFont, // axle title font axleColor // axle title color ); } // Bar graphs just need the title. else { b->setTitle( *(xVar->m_label), // axle title string GraphAxleBottom, // axle side to write the string axleFont, // axle title font axleColor // axle title color ); } //-------------------------------------------------------------------------- // Create a top axle with endpoints in WORLD coordinates (not AXLE) // Same as bottom axle EXCEPT no tic labels or axle label //-------------------------------------------------------------------------- // Line graph top axles need tic marks. if ( isLineGraph ) { GraphAxle *t = g->addGraphAxle( xValMin, // axle's min scale (NOT WORLD) value xValMax, // axle's max scale (NOT WORLD) value axlePen // axle line pen (color, width, style) ); t->setWorld( xValMin, // axle's start WORLD x coordinate yValMax, // axle's start WORLD y coordinate xValMax, // axle's end WORLD x coordinate yValMax // axle's end WORLD y coordinate ); if ( false ) t->setMajorTics( GraphAxleTop, // side of axle to draw tic marks xValMin, // first tic mark location in AXLE units xValMax, // last tic mark location in AXLE units xMajorStep, // tic spacing in AXLE units 0.05 * (yValMax-yValMin), // tic mark length in WORLD units axlePen // tic pen (color, width, style) ); if ( false ) t->setMinorTics( GraphAxleTop, // side of axle to draw tic marks xValMin, // first tic mark location in AXLE units xValMax, // last tic mark location in AXLE units 0.50 * xMajorStep, // tic spacing in AXLE units 0.03 * (yValMax-yValMin), // tic mark length in WORLD units axlePen // tic pen (color, width, style) ); } //-------------------------------------------------------------------------- // Create a left axle with endpoints in WORLD coordinates (not AXLE) // This has all elements of an axle EXCEPT a minor grid and subtitle //-------------------------------------------------------------------------- GraphAxle *l = g->addGraphAxle( yValMin, // axle's min scale (NOT WORLD) value yValMax, // axle's max scale (NOT WORLD) value axlePen // axle line pen (color, width, style) ); l->setWorld( xValMin, // axle's start WORLD x coordinate yValMin, // axle's start WORLD y coordinate xValMin, // axle's end WORLD x coordinate yValMax // axle's end WORLD y coordinate ); l->setMajorLabels( axleFont, // label font axleColor, // font color yDec // decimal places (-1 mean no label) ); l->setMajorTics( GraphAxleLeft, // side of axle to draw tic marks yValMin, // first tic mark location in AXLE units yValMax, // last tic mark location in AXLE units yMajorStep, // tic spacing in AXLE units 0.04 * (xValMax-xValMin), // tic mark length in X WORLD units axlePen // tic pen (color, width, style) ); l->setMinorTics( GraphAxleLeft, // side of axle to draw tic marks yValMin, // first tic mark location in AXLE units yValMax, // last tic mark location in AXLE units 0.50 * yMajorStep, // tic spacing in AXLE units 0.02 * (xValMax-xValMin), // tic mark length in X WORLD units axlePen // tic pen (color, width, style) ); l->setMajorGrid( gridPen, // grid pen color, width, style (xValMax-xValMin) // length in X axis WORLD units !! ); // Don't show the units for fraction or ratio variables. qStr = *(yVar->m_label) + " " + yVar->displayUnits(true); l->setTitle( qStr, // axle title string GraphAxleLeft, // axle side to write the string axleFont, // axle title font axleColor // axle title font color ); //-------------------------------------------------------------------------- // Create a right axle with endpoints in WORLD coordinates (not AXLE) // Same as the left axle EXCEPT no tic labels or axle label. //-------------------------------------------------------------------------- GraphAxle *r = g->addGraphAxle( yValMin, // axle's min scale (NOT WORLD) value yValMax, // axle's max scale (NOT WORLD) value axlePen // axle line pen (color, width, style) ); r->setWorld( xValMax, // axle's start WORLD x coordinate yValMin, // axle's start WORLD y coordinate xValMax, // axle's end WORLD x coordinate yValMax // axle's end WORLD y coordinate ); if ( false ) r->setMajorTics( GraphAxleRight, // side of axle to draw tic marks yValMin, // first tic mark location in AXLE units yValMax, // last tic mark location in AXLE units yMajorStep, // tic spacing in AXLE units 0.04 * (xValMax-xValMin), // tic mark length in X WORLD units axlePen // tic pen (color, width, style) ); if ( false ) r->setMinorTics( GraphAxleLeft, // side of axle to draw tic marks yValMin, // first tic mark location in AXLE units yValMax, // last tic mark location in AXLE units 0.50 * yMajorStep, // tic spacing in AXLE units 0.02 * (xValMax-xValMin), // tic mark length in X WORLD units axlePen // tic pen (color, width, style) ); return; }
void BpDocument::composeTable3( int vid, EqVar *rowVar, EqVar *colVar ) { // START THE STANDARD PREAMBLE USED BY ALL TABLE COMPOSITION FUNCTIONS. // WIN98 requires that we actually create a font here and use it for // font metrics rather than using the widget's font. QFont subTitleFont( property()->string( "tableSubtitleFontFamily" ), property()->integer( "tableSubtitleFontSize" ) ); QPen subTitlePen( property()->color( "tableSubtitleFontColor" ) ); QFontMetrics subTitleMetrics( subTitleFont ); QFont textFont( property()->string( "tableTextFontFamily" ), property()->integer( "tableTextFontSize" ) ); QPen textPen( property()->color( "tableTextFontColor" ) ); QFontMetrics textMetrics( textFont ); QFont titleFont( property()->string( "tableTitleFontFamily" ), property()->integer( "tableTitleFontSize" ) ); QPen titlePen( property()->color( "tableTitleFontColor" ) ); QFontMetrics titleMetrics( titleFont ); QFont valueFont( property()->string( "tableValueFontFamily" ), property()->integer( "tableValueFontSize" ) ); QPen valuePen( property()->color( "tableValueFontColor" ) ); QFontMetrics valueMetrics( valueFont ); bool doRowBg = property()->boolean( "tableRowBackgroundColorActive" ); QBrush rowBrush( property()->color( "tableRowBackgroundColor" ), Qt::SolidPattern ); QString text(""); // Store pixel resolution into local variables. double yppi = m_screenSize->m_yppi; double xppi = m_screenSize->m_xppi; double m_padWd = m_pageSize->m_padWd; // Determine the height of the various display fonts. double textHt, titleHt, valueHt, rowHt, x0, x1; textHt = ( textMetrics.lineSpacing() + m_screenSize->m_padHt ) / yppi; titleHt = ( titleMetrics.lineSpacing() + m_screenSize->m_padHt ) / yppi; valueHt = ( valueMetrics.lineSpacing() + m_screenSize->m_padHt ) / yppi; rowHt = ( textHt > valueHt ) ? textHt : valueHt; // END THE STANDARD PREAMBLE USED BY ALL TABLE COMPOSITION FUNCTIONS. // Determine the number of rows we can display on a page. int rowsPerPage = (int) ( ( m_pageSize->m_bodyHt - 5. * titleHt - 4. * textHt ) / rowHt ); // Number of pages the table requires to accomodate all the rows. int pagesLong = 1 + (int) ( tableRows() / rowsPerPage ); // Arrays to hold the output values' column information. // Page on which the output value column appears. int *colPage = new int[ tableCols() ]; checkmem( __FILE__, __LINE__, colPage, "int colPage", tableCols() ); // Horizontal position of each output value column. double *colXPos = new double[ tableCols() ]; checkmem( __FILE__, __LINE__, colXPos, "double colXPos", tableCols() ); // Column header text. QString *colText = new QString[ tableCols() ]; checkmem( __FILE__, __LINE__, colText, "double colText", tableCols() ); // Prescription shading? bool doRx = property()->boolean( "tableShading" ); bool doBlank = property()->boolean( "tableShadingBlank" ); // Determine the row variable's (left-most) column width. int row, iid, cell; double len; QString qStr; // Start wide enough to hold the variable name and units. double rowWd = m_padWd + ( (double) headerWidth( rowVar, textMetrics ) / xppi ); // Enlarge it to hold the fattest row value. m_rowDecimals = 0; for ( row = 0; row < tableRows(); row++ ) { if ( rowVar->isDiscrete() ) { iid = (int) tableRow( row ); qStr = rowVar->m_itemList->itemName( iid ) + "MMM"; } else if ( rowVar->isContinuous() ) { // CDB DECIMALS MOD if ( false ) { qStr.sprintf( "%1.*fMMM", rowVar->m_displayDecimals, tableRow( row ) ); } else { // Start with 6 decimals for this row value int decimals = 6; qStr.sprintf( "%1.*f", decimals, tableRow( row ) ); // Remove all trailing zeros while ( qStr.endsWith( "0" ) ) { qStr = qStr.left( qStr.length()-1 ); decimals--; } // Update m_rowDecimals digits m_rowDecimals = ( decimals > m_rowDecimals ) ? decimals : m_rowDecimals; qStr.append( "MWM" ); } } len = (double) textMetrics.width( qStr ) / xppi; if ( len > rowWd ) { rowWd = len; } } // Find the fattest output value for this table variable. int col; int out = vid; EqVar *outVar = tableVar(vid); double colWd = 0; for ( row = 0; row < tableRows(); row++ ) { for ( col = 0; col < tableCols(); col++ ) { if ( outVar->isDiscrete() ) { iid = (int) tableVal( out ); qStr = outVar->m_itemList->itemName( iid ) + "WM"; } else if ( outVar->isContinuous() ) { qStr.sprintf( "%1.*fWM", outVar->m_displayDecimals, tableVal( out ) ); } len = (double) textMetrics.width( qStr ) / xppi; if ( len > colWd ) { colWd = len; } out += tableVars(); } // Next table column. } // Next table row. // Set the column header value text. m_colDecimals = 0; for ( col = 0; col < tableCols(); col++ ) { if ( colVar->isDiscrete() ) { iid = (int) tableCol( col ); colText[col] = colVar->m_itemList->itemName( iid ); } else if ( colVar->isContinuous() ) { // CDB DECIMALS MOD if ( false ) { colText[col].sprintf( " %1.*f", colVar->m_displayDecimals, tableCol( col ) ); } else { // Start with 6 decimals for this row value int decimals = 6; colText[col].sprintf( " %1.*f", decimals, tableCol( col ) ); // Remove all trailing zeros while ( colText[col].endsWith( "0" ) ) { colText[col] = colText[col].left( colText[col].length()-1 ); decimals--; } // Update Decimals digits m_colDecimals = ( decimals > m_colDecimals ) ? decimals : m_colDecimals; } } // Expand the column width to accomodate the header value text? len = (double) textMetrics.width( colText[col] ) / xppi; if ( len > colWd ) { colWd = len; } } // Next table column. // CDB DECIMALS MOD for ( col = 0; col < tableCols(); col++ ) { if ( colVar->isContinuous() ) { colText[col].sprintf( " %1.*f", m_colDecimals, tableCol( col ) ); } } // Add padding between each column. colWd += m_padWd; // Determine each column's position on each page. int pagesWide = 1; // Horizontal position of first column on the first page. double xpos = m_pageSize->m_bodyLeft + rowWd + 2. * m_padWd; for ( col = 0; col < tableCols(); col++ ) { // If past the right page edge, start a new page. if ( xpos + colWd > m_pageSize->m_bodyRight ) { // The table page width has just increased. pagesWide++; // This will be the first column on the new page. xpos = m_pageSize->m_bodyLeft + rowWd + 2. * m_padWd; } // Store the page and position of this output variable's column. colXPos[col] = xpos; colPage[col] = pagesWide; // Update the position pointer. xpos += ( 2. * m_padWd + colWd ); } // Determine the column title width (inches). double colTitleWd = textMetrics.width( *(colVar->m_label) ) / xppi; if ( ( textMetrics.width( colVar->m_displayUnits ) / xppi ) > colTitleWd ) { colTitleWd = textMetrics.width( colVar->m_displayUnits ) / xppi; } colTitleWd += ( 2. * m_padWd ); // Determine an offset shift to center each pageAcross. double *shift = new double[ pagesWide + 1 ]; checkmem( __FILE__, __LINE__, shift, "double shift", pagesWide + 1 ); for ( col = 0; col < tableCols(); col++ ) { // Table must be at least this wide. double minLeft = m_pageSize->m_bodyLeft + rowWd + 2. * m_padWd + colTitleWd; // Does it need to be wider to accomodate this column? if ( colXPos[col] + colWd > minLeft ) { minLeft = colXPos[col] + colWd; } // Just the last column of each page finally gets stored in shift[]. shift[colPage[col]] = 0.5 * ( m_pageSize->m_bodyRight - minLeft ); } // Start drawing the table. double yPos, s, bgLeft, bgRight, rightEdge, leftEdge; int i; // Loop for each page down. int thisPage = 1; for ( int pageDown = 1; pageDown <= pagesLong; pageDown++ ) { // Loop for each page across. for ( int pageAcross = 1; pageAcross <= pagesWide; pageAcross++, thisPage++ ) { // Table title indicates the table portion translate( text, "BpDocument:Table:PageOf", *(tableVar(vid)->m_label), QString( "%1" ).arg( thisPage ), QString( "%1" ).arg( pagesLong * pagesWide ) ); // Start a new page startNewPage( text, TocTable ); yPos = m_pageSize->m_marginTop + titleHt; // Draw a map of where we are. composePageMap( ( 2. * titleHt - 0.1 ), pagesLong, pagesWide, pagesLong, pagesWide, 1, 1, pageDown-1, pageAcross-1 ); // Display the table title::description m_composer->font( titleFont ); // use tableTitleFont m_composer->pen( titlePen ); // use tableTitleFontColor qStr = m_eqTree->m_eqCalc->docDescriptionStore().stripWhiteSpace(); m_composer->text( m_pageSize->m_marginLeft, yPos, // start at UL corner m_pageSize->m_bodyWd, titleHt,// width and height Qt::AlignVCenter|Qt::AlignHCenter, // center alignement qStr ); // display description yPos += titleHt; // Display the table title::variable m_composer->font( subTitleFont ); // use tableSubtitleFont m_composer->pen( subTitlePen ); // use tableSubtitleFontColor qStr = *(outVar->m_label); if ( outVar->isContinuous() ) { qStr = *(outVar->m_label) + " " + outVar->displayUnits(true); } m_composer->text( m_pageSize->m_marginLeft, yPos, // start at UL corner m_pageSize->m_bodyWd, titleHt,// width and height Qt::AlignVCenter|Qt::AlignHCenter, // center alignment qStr ); // table variable name yPos += titleHt; // Display the table title::portion //m_composer->text( // m_pageSize->m_marginLeft, yPos, // m_pageSize->m_bodyWd, titleHt, // Qt::AlignVCenter|Qt::AlignHCenter, // portion ); //yPos += titleHt; yPos += titleHt; // Everything else on this page is shifted s = shift[pageAcross]; // Determine left and right edges of the table. leftEdge = -1; for ( col = 0; col < tableCols(); col++ ) { if ( pageAcross == colPage[col] ) { rightEdge = colXPos[col] + colWd + s; if ( leftEdge < 0. ) { leftEdge = colXPos[col] + s; } } } // Must be at least wide enough to accomodate column header text. if ( rightEdge < leftEdge + colTitleWd ) { rightEdge = leftEdge + colTitleWd; } bgLeft = m_pageSize->m_marginLeft + s - m_padWd ; bgRight = rightEdge - leftEdge + rowWd + 4 * m_padWd ; // Display a colored row column header background? if ( doRowBg ) { m_composer->fill( bgLeft, yPos, bgRight, 3 * textHt, rowBrush ); } // Display the row column header0. m_composer->font( textFont ); // use tableTextFont m_composer->pen( textPen ); // use tableTextFontColor m_composer->text( m_pageSize->m_marginLeft + s, yPos, rowWd, textHt, Qt::AlignVCenter|Qt::AlignLeft, *(rowVar->m_hdr0) ); // Display the row column header1. m_composer->text( m_pageSize->m_marginLeft + s, yPos + textHt, rowWd, textHt, Qt::AlignVCenter|Qt::AlignLeft, *(rowVar->m_hdr1) ); // Display the row column units. m_composer->text( m_pageSize->m_marginLeft + s, yPos + 2. * textHt, rowWd, textHt, Qt::AlignVCenter|Qt::AlignLeft, rowVar->displayUnits() ); // Display the row column header underline // only if we are not coloring row backgrounds. int skipLines = 3; if ( ! doRowBg ) { m_composer->line( m_pageSize->m_marginLeft + s, yPos + 3.5 * textHt, m_pageSize->m_marginLeft + rowWd + s, yPos + 3.5 * textHt ); skipLines = 4; } // Display the output column headers. for ( col = 0; col < tableCols(); col++ ) { if ( pageAcross == colPage[col] ) { // Display the output column units. m_composer->text( colXPos[col] + s, yPos + 2. * textHt, colWd, textHt, Qt::AlignVCenter|Qt::AlignRight, colText[col] ); // Display the output column underline. if ( ! doRowBg ) { m_composer->line( colXPos[col] + s, yPos + 3.5 * textHt, colXPos[col] + colWd + s, yPos + 3.5 * textHt ); } } } // Display a centered column variable name and units header. m_composer->text( leftEdge, yPos, ( rightEdge - leftEdge ), textHt, Qt::AlignVCenter|Qt::AlignHCenter, *(colVar->m_label) ); if ( colVar->isContinuous() ) { m_composer->text( leftEdge, yPos + textHt, ( rightEdge - leftEdge ), textHt, Qt::AlignVCenter|Qt::AlignHCenter, colVar->displayUnits() ); } // If there are previous columns, display a visual cue. if ( pageAcross > 1 ) { for ( i = 0; i < 3; i++ ) { m_composer->text( 0, ( yPos + i * textHt ), ( m_pageSize->m_marginLeft + s - m_padWd ), textHt, Qt::AlignVCenter|Qt::AlignRight, "<" ); } } // If there are subsequent column pages, display a visual clue. if ( pageAcross < pagesWide ) { for ( i = 0; i < 3; i++ ) { m_composer->text( ( rightEdge + m_padWd ), ( yPos + i * textHt ), ( m_pageSize->m_pageWd - rightEdge ), textHt, Qt::AlignVCenter|Qt::AlignLeft, ">" ); } } // Set vertical start of rows. yPos += skipLines * textHt; // Determine the rows range to display on this page. int rowFrom = ( pageDown - 1 ) * rowsPerPage; int rowThru = pageDown * rowsPerPage - 1; if ( rowThru >= tableRows() ) { rowThru = tableRows() - 1; } // Determine the columns range to display on this page. int colFrom = -1; int colThru = 0; for ( col = 0; col < tableCols(); col++ ) { if ( colPage[col] == pageAcross ) { if ( colFrom == -1 ) { colFrom = col; } colThru = col; } } // Loop for each row on this page. bool doThisRowBg = false; for ( row = rowFrom; row <= rowThru; row++ ) { // Display a colored row background? if ( doRowBg && doThisRowBg ) { m_composer->fill( bgLeft, yPos, bgRight, textHt, rowBrush ); } doThisRowBg = ! doThisRowBg; // Left-most (row variable) column value. if ( rowVar->isDiscrete() ) { iid = (int) tableRow( row ); qStr = rowVar->m_itemList->itemName( iid ); } else if ( rowVar->isContinuous() ) { // CDB DECIMALS MOD if ( false ) { qStr.sprintf( "%1.*f", rowVar->m_displayDecimals, tableRow( row ) ); } else { qStr.sprintf( "%1.*f", m_rowDecimals, tableRow( row ) ); } } m_composer->font( textFont ); // use tableTextFont m_composer->pen( textPen ); // use tableTextFontColor m_composer->text( m_pageSize->m_marginLeft + s, yPos, rowWd, textHt, Qt::AlignVCenter|Qt::AlignLeft, qStr ); // Loop for each column value on this page. m_composer->font( valueFont ); // use tableValueFont m_composer->pen( valuePen ); // use tableValueFontColor out = vid + colFrom * tableVars() + row * tableCols() * tableVars(); for ( col = colFrom; col <= colThru; col++ ) { // Determine whether to hatch this cell cell = col + row * tableCols(); bool hatch = doRx && ! tableInRx( cell ); // Discrete variables use their item name. if ( outVar->isDiscrete() ) { iid = (int) tableVal( out ); qStr = outVar->m_itemList->itemName( iid ); } // Continuous variables use the current display units format. else if ( outVar->isContinuous() ) { qStr.sprintf( " %1.*f", outVar->m_displayDecimals, tableVal( out ) ); } // Display the output value. if ( hatch && doBlank ) { // draw nothing } else { m_composer->text( colXPos[col] + s, yPos, colWd, textHt, Qt::AlignVCenter|Qt::AlignRight, qStr ); } out += tableVars(); // RX hatching if ( hatch && ! doBlank && ! outVar->isDiagram() ) { x0 = colXPos[col] + s - m_padWd; x1 = colXPos[col] + s + m_padWd + colWd; m_composer->line( x0, yPos, x1, ( yPos + textHt ) ); m_composer->line( x0, ( yPos + textHt ), x1, yPos ); } } // Next table output variable. yPos += rowHt; } // Next table row. } // Next pageAcross. } // Next pageDown. // Be polite and stop the composer. m_composer->end(); // Clean up and return. delete[] colPage; delete[] colXPos; delete[] colText; delete[] shift; return; }
void BpDocument::composeFireCharacteristicsDiagram( void ) { // Surface Module must be active and using fuel model inputs PropertyDict *prop = m_eqTree->m_propDict; if ( ! prop->boolean( "surfaceModuleActive" ) || ! prop->boolean( "surfaceCalcFireCharacteristicsDiagram" ) ) { return; } // Graph fonts. QFont textFont( property()->string( "graphTextFontFamily" ), property()->integer( "graphTextFontSize" ) ); QColor textColor( property()->color( "graphTextFontColor" ) ); QPen textPen( textColor ); QFont subTitleFont( property()->string( "graphSubtitleFontFamily" ), property()->integer( "graphSubtitleFontSize" ) ); QColor subTitleColor( property()->color( "graphSubtitleFontColor" ) ); // Open the result file QString resultFile = m_eqTree->m_resultFile; FILE *fptr = 0; if ( ! ( fptr = fopen( resultFile.latin1(), "r" ) ) ) // This code block should never be executed! { QString text(""); translate( text, "BpDocument:FireCharacteristicsDiagram:NoLogOpen", resultFile ); error( text ); return; } // Allocate ros and hpua data arrays int rows = tableRows(); int cols = tableCols(); int cells = rows * cols; double *hpua = new double[ cells ]; checkmem( __FILE__, __LINE__, hpua, "double hpua", cells ); double *ros = new double[ cells ]; checkmem( __FILE__, __LINE__, ros, "double ros", cells ); // Set the variable names we're looking for const char* hpuaName = "vSurfaceFireHeatPerUnitArea"; const char* rosName = "vSurfaceFireSpreadAtHead"; if ( prop->boolean( "surfaceConfSpreadDirInput" ) ) { rosName = "vSurfaceFireSpreadAtVector"; } // Read and store the ros and hpua values char buffer[1024], varName[128], varUnits[128]; int row, col, cell; double value; double rosMax = 0.0; double hpuaMax = 0.0; while ( fgets( buffer, sizeof(buffer), fptr ) ) { if ( strncmp( buffer, "CELL", 4 ) == 0 ) { if ( strstr( buffer, hpuaName ) ) { sscanf( buffer, "CELL %d %d %s cont %lf %s", &row, &col, varName, &value, varUnits ); cell = ( col - 1 ) + ( cols * ( row - 1) ); if ( ( hpua[ cell ] = value ) > hpuaMax ) { hpuaMax = value; } } else if ( strstr( buffer, rosName ) ) { sscanf( buffer, "CELL %d %d %s cont %lf %s", &row, &col, varName, &value, varUnits ); cell = ( col - 1 ) + ( cols * ( row - 1) ); if ( ( ros[ cell ] = value ) > rosMax ) { rosMax = value; } } } } fclose( fptr ); // Get variable pointers EqVar *hpuaVar = m_eqTree->m_varDict->find( "vSurfaceFireHeatPerUnitArea" ); EqVar *rosVar = m_eqTree->m_varDict->find( "vSurfaceFireSpreadAtHead" ); EqVar *fliVar = m_eqTree->m_varDict->find( "vSurfaceFireLineIntAtHead" ); EqVar *flVar = m_eqTree->m_varDict->find( "vSurfaceFireFlameLengAtHead" ); // Conversion factor double flFactor, fliFactor, rosFactor, hpuaFactor, offset; appSiUnits()->conversionFactorOffset( flVar->m_nativeUnits, flVar->m_displayUnits, &flFactor, &offset ); appSiUnits()->conversionFactorOffset( fliVar->m_nativeUnits, fliVar->m_displayUnits, &fliFactor, &offset ); appSiUnits()->conversionFactorOffset( hpuaVar->m_nativeUnits, hpuaVar->m_displayUnits, &hpuaFactor, &offset ); appSiUnits()->conversionFactorOffset( rosVar->m_nativeUnits, rosVar->m_displayUnits, &rosFactor, &offset ); // Determine which of four different chart scales to use static const int Scales = 4; static double RosScale[Scales] = { 100., 200., 400., 800. }; // ft/min static double HpuaScale[Scales] = { 2000., 4000., 8000., 16000. }; // Btu/ft2 double rosScale = 0.; // Max y-axis ros double hpuaScale = 0.; // Max x-axis hpua int scale; for ( scale=0; scale<Scales; scale++ ) { if ( rosMax < ( rosScale = RosScale[ scale ] ) ) { break; } } for ( scale=0; scale<Scales; scale++ ) { if ( hpuaMax < ( hpuaScale = HpuaScale[scale] ) ) { break; } } // Set axis maximums to appropriate predefined scale in display units rosMax = rosFactor * rosScale; hpuaMax = hpuaFactor * hpuaScale; double ratio = rosMax / hpuaMax; // Create the graph Graph graph; GraphLine *graphLine; GraphMarker *graphMarker; static const int Points = 100; double l_x[Points]; double l_y[Points]; // Draw the four standard hauling chart fli-fl levels static const int Lines = 4; static const double Fli[Lines] = { 100., 500., 1000., 2000. }; // Btu/ft/s static const double Fl[Lines] = { 4., 8., 11., 15. }; // ft // Create the hauling chart lines // Put Fireline Int label 65% of the way along the HPUA axis (display units) double xPosFli = 0.65 * hpuaMax; // Put Flame Length label 85% of the way along the HPUA axis (display units) double xPosFl = 0.85 * hpuaMax; // Fireline Int and Flame Length label Y positions (display units) double yPosFl[Lines], yPosFli[Lines]; // Icon locations (in display units) double xIcon[Lines+1], yIcon[Lines+1]; double diff, minDiff; QString label; QPen redPen( "red", 1 ); QColor blackColor( "black" ); int alignCenter = Qt::AlignHCenter | Qt::AlignVCenter; // Fireline intensity - flame length curves int line, point; for ( line = 0; line < Lines; line++ ) { minDiff = 999999999.; for ( point = 0; point < Points; point++ ) { // Hpua value in native units (Btu/ft2) l_x[point] = ( (point+1) * hpuaScale ) / (double) Points; // Ros value in native units (ft/min) l_y[point] = 60. * Fli[line] / l_x[point]; // Convert to display units l_x[point] *= hpuaFactor; l_y[point] *= rosFactor; // Check for curve inflection point (for icon placement) if ( ( diff = fabs( l_y[point]/l_x[point] - ratio ) ) < minDiff ) { minDiff = diff; xIcon[line+1] = l_x[point]; yIcon[line+1] = l_y[point]; } } // Create a graph line (with its own copy of the data). graphLine = graph.addGraphLine( Points, l_x, l_y, redPen ); // Fireline intensity label label = QString( "%1" ).arg( ( Fli[line] * fliFactor ), 0, 'f', 0 ); yPosFli[line] = rosFactor * ( 60. * Fli[line] / ( xPosFli / hpuaFactor ) ); graph.addGraphMarker( xPosFli, yPosFli[line], label, textFont, blackColor, alignCenter ); // Flame length label label = QString( "%1" ).arg( ( Fl[line] * flFactor ), 0, 'f', 0 ); yPosFl[line] = rosFactor * ( 60. * Fli[line] / ( xPosFl / hpuaFactor ) ); graph.addGraphMarker( xPosFl, yPosFl[line], label, textFont, blackColor, alignCenter ); } // Next line // Fireline intensity label and units translate( label, "BpDocument:FireCharacteristicsDiagram:FLI" ); graph.addGraphMarker( xPosFli, ( yPosFli[Lines-1] + 0.10 * rosMax ), label, textFont, blackColor, alignCenter ); graph.addGraphMarker( xPosFli, ( yPosFli[Lines-1] + 0.05 * rosMax ), fliVar->m_displayUnits, textFont, blackColor, alignCenter ); // Flame length label and units translate( label, "BpDocument:FireCharacteristicsDiagram:FL" ); graph.addGraphMarker( xPosFl, ( yPosFl[Lines-1] + 0.10 * rosMax ), label, textFont, blackColor, alignCenter ); graph.addGraphMarker( xPosFl, ( yPosFl[Lines-1] + 0.05 * rosMax ), flVar->m_displayUnits, textFont, blackColor, alignCenter ); // Add icons QPixmap pixmap[Lines]; pixmap[0] = QPixmap( fireman_xpm ); pixmap[1] = QPixmap( dozer_xpm ); pixmap[2] = QPixmap( torchtree_xpm ); pixmap[3] = QPixmap( mtnfire_xpm ); xIcon[0] = yIcon[0] = 0.0; for ( line=0; line<Lines; line++ ) { graphMarker = graph.addGraphMarker( xIcon[line] + ( 0.5 * ( xIcon[line+1] - xIcon[line] ) ), yIcon[line] + ( 0.5 * ( yIcon[line+1] - yIcon[line] ) ), "", textFont, blackColor, alignCenter ); graphMarker->setGraphMarkerPixmap( pixmap[line] ); } // Finally, add a marker for each output result QColor bluePen( "blue" ); for ( cell=0; cell<cells; cell++ ) { //fprintf( stderr, "%02d: %3.2f %3.2f\n", i, hpua[i], ros[i] ); graph.addGraphMarker( hpua[cell], ros[cell], QString( "%1" ).arg( cell + 1 ), textFont, bluePen, alignCenter ); } // Compose the graph EqVar *zVar = 0; GraphAxleParms xParms( 0.0, hpuaMax, 11 ); GraphAxleParms yParms( 0.0, rosMax, 11 ); composeGraphBasics( &graph, true, hpuaVar, rosVar, zVar, Lines, &xParms, &yParms ); // Create a separate page for this graph. translate( label, "BpDocument:FireCharacteristicsDiagram:Caption" ); graph.setSubTitle( label, subTitleFont, subTitleColor ); startNewPage( label, TocHaulChart ); // This is how we save the graph and its composer. m_composer->graph( graph, m_pageSize->m_marginLeft + m_pageSize->m_bodyWd * property()->real( "graphXOffset" ), m_pageSize->m_marginTop + m_pageSize->m_bodyHt * property()->real( "graphYOffset" ), m_pageSize->m_bodyWd * property()->real( "graphScaleWidth" ), m_pageSize->m_bodyHt * property()->real( "graphScaleHeight" ) ); // Be polite and stop the composer. m_composer->end(); delete[] ros; ros = 0; delete[] hpua; hpua = 0; return; }