Files
Slnkdwf/SlnkDWFImpl/Whip2DCState.cpp
Jos Groot Lipman def569d005 Extra check
svn path=/Slnkdwf/trunk/; revision=12517
2011-09-14 20:11:00 +00:00

787 lines
25 KiB
C++

#include "StdAfx.h"
#include "Whip2dcState.h"
#include "SLNKContourImpl.h"
#include <math.h>
#ifndef PI
#define PI 3.14159265358979323846
#endif
CWhip2DCState::CWhip2DCState()
{
Reset();
}
void CWhip2DCState::Reset()
{
m_vertexList_size=100; // Aardig begin
m_vertexList = new CPoint[m_vertexList_size];
bLayerVisible = TRUE; // When no layers at all
bIsSymbolLayer = FALSE;
findIt = FALSE;
m_ClipWidth = -1;
m_ClipHeight = -1;
m_mul = 0; // Signal invalid
m_MinMax = WT_Logical_Box(INT_MAX, INT_MAX, INT_MIN, INT_MIN); // Signal invalid
memset(&m_logfont, 0, sizeof(LOGFONT)); // clear out structure.
m_spacing = 1024;
m_height = 1024;
m_hrgn = NULL;
m_font = NULL;
m_forcePaper = false;
m_Maximize = false;
m_lRotation = 0;
}
CWhip2DCState::~CWhip2DCState()
{
myTRACE("\nVertextlist eindigde op: %d", m_vertexList_size);
delete [] m_vertexList;
}
void CWhip2DCState::erasePaper (WT_File & file)
{
// m_paperColor is 0x00rrggbb
// COLORREF is net andersom
COLORREF crf = RGB(((BYTE)((m_paperColor)>>16)),
((BYTE)(((WORD)(m_paperColor)) >> 8)),
((BYTE)(m_paperColor)));
HBRUSH tempBrush = CreateSolidBrush(crf);
HBRUSH oldbrush = (HBRUSH) SelectObject(myDC,tempBrush);
CRect rc;
GetClipBox(myDC,&rc);
FillRect(myDC,rc,tempBrush);
SelectObject(myDC,oldbrush);
DeleteObject(tempBrush);
SetBkColor(myDC, m_paperColor);
ColorPenAndBrush(file); // Eventuele toggle wit<-->zwart
}
CPoint *CWhip2DCState::new_DWFToLP(WT_Point_Set const &pts)
{
if (m_vertexList_size<pts.count()) // To small. Enlarge
{
delete [] m_vertexList;
m_vertexList_size = max(m_vertexList_size*2, pts.count());
m_vertexList = new CPoint[m_vertexList_size];
}
for (int i = 0; i < pts.count(); i++)
{
m_vertexList[i] = DWFToLP(pts.points()[i]);
}
return m_vertexList;
}
// Schaal de Whip-coordinatenruimte terug naar een GDI geschikte ruimte
CPoint CWhip2DCState::DWFToLP(WT_Logical_Point const &pt)
{
return CPoint(myRound((pt.m_x - m_MinMax.minpt().m_x)*m_mul),
myRound((m_MinMax.maxpt().m_y - pt.m_y)*m_mul));
}
// Used for 'finding' a clicked point LPtoDP
WT_Logical_Point CWhip2DCState::LPToDWF(CPoint pt)
{
int intx = m_MinMax.minpt().m_x + myRound(pt.x/m_mul);
int inty = m_MinMax.maxpt().m_y - myRound(pt.y/m_mul);
return WT_Logical_Point(intx, inty);
}
void CWhip2DCState::DWGExtents(double &resminX, double &resminY,
double &resmaxX, double &resmaxY)
{
WT_Point3D dwgPtmin = m_Units.transform(m_orgMinMax.m_min);
WT_Point3D dwgPtmax = m_Units.transform(m_orgMinMax.m_max);
resminX = dwgPtmin.m_x;
resminY = dwgPtmin.m_y;
resmaxX = dwgPtmax.m_x;
resmaxY = dwgPtmax.m_y;
}
// Volgende 3 regels werkt slecht als iemand net een fractie buiten
// de tekening klikt: dan treed er een overflow DWFfindXY op
// Bij het zoeken is dat niet zo'n ramp, er wordt toch niets gevonden
// WT_Point3D dwgPt = my_input_file.rendition().viewport().viewport_units().transform(m_State.DWFfindXY);
// (*resX) = dwgPt.m_x;
// (*resY) = dwgPt.m_y;
void CWhip2DCState::LPToDWG(CPoint pt, double &resX, double &resY)
{
WT_Point3D dwgPtmin = m_Units.transform(m_MinMax.m_min);
WT_Point3D dwgPtmax = m_Units.transform(m_MinMax.m_max);
// CWhip2DCState::LPToDWF maar dan met een double resultaat
double DWFx = (pt.x/m_mul + m_MinMax.minpt().m_x);
double DWFy = (m_MinMax.maxpt().m_y - pt.y/m_mul);
double xScale = (dwgPtmax.m_x-dwgPtmin.m_x)/
(m_MinMax.maxpt().m_x-m_MinMax.minpt().m_x);
double yScale = (dwgPtmax.m_y-dwgPtmin.m_y)/
(m_MinMax.maxpt().m_y-m_MinMax.minpt().m_y);
double DWGx = dwgPtmin.m_x + (DWFx-m_MinMax.minpt().m_x)*xScale;
double DWGy = dwgPtmin.m_y + (DWFy-m_MinMax.minpt().m_y)*yScale;
resX = DWGx;
resY = DWGy;
}
#define PATH_TEXT 0x2000 // Whip and GDI font engine only
WT_Result CWhip2DCState::my_process_font (WT_Font & font)
{
int charset = font.charset().charset();
int pitch_and_family = font.pitch().pitch() | font.family().family();
BOOL italic = font.style().italic();
BOOL underline = font.style().underlined();
BOOL bold = font.style().bold();
WT_Unsigned_Integer16 fd = font.fields_defined();
if (fd & WT_Font::FONT_HEIGHT_BIT)
{
m_height = font.height();
m_logfont.lfHeight = -myRound(m_height*m_mul);
}
if (fd & WT_Font::FONT_SPACING_BIT)
{
m_spacing = font.spacing().spacing(); // Lossen we met TextFormatter op
}
if (fd & WT_Font::FONT_WIDTH_SCALE_BIT)
{
m_logfont.lfWidth = 0;
WT_Integer32 m_wscale = font.width_scale(); // Met TextFormatter extra nauwkeurig
if (m_wscale != 1024)
{
// In ieder geval huidige font eerst nog zetten voor de goede hoogte
// Niet echt fijn maar wel nodig voor locatie.dwg/Voetgangersingang
HFONT oldfont1 = m_font;
m_font = CreateFontIndirect(&m_logfont);
ATLASSERT(m_font);
HFONT oldfont = (HFONT) SelectObject(myDC, m_font);
ATLASSERT(oldfont);
DeleteObject(oldfont);
DeleteObject(oldfont1);
// Bounds is veel sterker dan widthscale. Ze komen wel vaak in combinatie
// voor (locatie.dwf)
// Daar lossen we het eventueel 'extra' op mbv. Textformatter
TEXTMETRIC tm;
// TODO: GetTextMetrics heeft hier geen correctie voor zoom-onnauwkeurigheid
if ( GetTextMetrics(myDC, &tm) !=0 )
{
// TODO en hier wordt ook mogelijk nog een onnauwkeurigheid
// geintroduceerd
//
m_logfont.lfWidth = MulDiv(tm.tmAveCharWidth, m_wscale, 1024);
//m_logfont.lfWidth = (tm.tmAveCharWidth);
}
}
}
if (fd & WT_Font::FONT_OBLIQUE_BIT)
{
//Oblique betekent karakters schuin gooien. Kennen we nog niet echt
//int oblique = MulDiv(3600, font.oblique(), 65536);
//m_logfont.lfEscapement = oblique;
}
if ((fd & WT_Font::FONT_FLAGS_BIT) && (font.flags() & PATH_TEXT))
{
// Voor zover komt er altijd een bounds en wordt de rotatie opgelost
// in CWhip2DCState::drawBoundText
m_logfont.lfOrientation = 0;
m_logfont.lfEscapement = 0; // Moet bijna altijd gelijk zijn
}
else // Ignore the rotation setting when PATH_TEXT. DWF Viewer does that too
// (note: becomes important for the next text, not this one)
if (fd & WT_Font::FONT_ROTATION_BIT)
{
int rotation = MulDiv(3600, font.rotation(), 65536) % 3600;
// Voor heel kleine fonts ronden we de rotatie af op 30 graden cirkel.
// Dat kan bij veel variatie in rotatie fors schelen (Locatie.dwf bemating)
#if 0
if (m_height*m_mul < geekFontSize)
rotation = myRound((floor((double)rotation/300.0+0.5))*300);
else // eventueel op 10 graden circel, scheelt ook flink
if (m_height*m_mul < geekFontSize*2)
rotation = myRound((floor((double)rotation/100.0+0.5))*100);
//else heel ver ingezoomd: Volle resolutie
#endif
m_logfont.lfOrientation = rotation;
m_logfont.lfEscapement = rotation; // Moet bijna altijd gelijk zijn
}
// else
// myTRACE("Geen rotatie?");
m_logfont.lfWeight = bold ? FW_BOLD : FW_DONTCARE;
m_logfont.lfItalic = italic;
m_logfont.lfUnderline = underline;
m_logfont.lfStrikeOut = FALSE;
if (fd & WT_Font::FONT_CHARSET_BIT)
{
m_logfont.lfCharSet = ANSI_CHARSET; //charset;
m_logfont.lfCharSet = charset; // Geeft problement op DIT03: SansSerif-->Dingbats
}
m_logfont.lfOutPrecision = OUT_DEFAULT_PRECIS;
m_logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
m_logfont.lfQuality = NONANTIALIASED_QUALITY; // Nooit cleartype o.i.d.
//m_logfont.lfQuality = DEFAULT_QUALITY;
if (fd & (WT_Font::FONT_PITCH_BIT || WT_Font::FONT_FAMILY_BIT))
m_logfont.lfPitchAndFamily = pitch_and_family;
m_logfont.lfPitchAndFamily |= TMPF_TRUETYPE;
if (fd & WT_Font::FONT_NAME_BIT)
{
char* facename = new char[font.font_name().name().length()+1];
strcpy(facename, font.font_name().name().ascii());
memset(m_logfont.lfFaceName,0,LF_FACESIZE*sizeof(char));
strncpy(m_logfont.lfFaceName,facename,LF_FACESIZE);
delete [] facename;
}
int keep=m_logfont.lfOrientation;
if (findIt || m_height*m_mul < geekFontSize
) // Dan doen we hier toch niets met de rotatie. Hoogte/breedte moeten we wel hebben
{
m_logfont.lfOrientation = 0;
m_logfont.lfEscapement = 0; // Moet bijna altijd gelijk zijn
}
HFONT oldfont1 = m_font;
m_font = CreateFontIndirect(&m_logfont);
ATLASSERT(m_font);
HFONT oldfont = (HFONT) SelectObject(myDC, m_font);
ATLASSERT(oldfont);
DeleteObject(oldfont);
DeleteObject(oldfont1);
// Alleen TrueType texten reageren op Orientation
// Voor heel kleine fontgroottes wordt wel een 'Ms Sans Serif' of 'Small fonts' gekozen
// door CreateFontIndirect
// Daarom hier vooralsnog TrueType forceren door Arial te benoemen.
// TODO: Alleen als orientation <> 0
// TODO: TextFormatter ook voor niet TrueType teksten laten werken
#ifdef _DEBUG
OUTLINETEXTMETRIC otm[3]; // big enough for the strings
if ( GetOutlineTextMetrics(myDC, sizeof(otm), otm)==0 )
{
// ATLASSERT(FALSE); // Waarschijnlijk klein font dat geen TrueType is
}
#endif
if (GetDeviceCaps(myDC, TECHNOLOGY) != DT_METAFILE) // Daar werkt dit niet voor
{
TEXTMETRIC tm;
BOOL x = GetTextMetrics(myDC, &tm);
ATLASSERT(x);
char szFaceName[LF_FULLFACESIZE];
GetTextFace (myDC, LF_FULLFACESIZE, szFaceName) ;
if (!(TMPF_TRUETYPE & tm.tmPitchAndFamily))
{
HFONT oldfont1 = m_font;
strcpy(m_logfont.lfFaceName, "Arial"); // Probeer het nog eens met een echte TrueType
m_font = CreateFontIndirect(&m_logfont);
ATLASSERT(m_font);
HFONT oldfont = (HFONT) SelectObject(myDC, m_font);
ATLASSERT(oldfont);
DeleteObject(oldfont);
DeleteObject(oldfont1);
}
}
m_logfont.lfOrientation = keep; // Wel terugzetten voor findIt want er wordt nog wel mee gerekend
m_logfont.lfEscapement = keep;
//if (!hfont || hfont == INVALID_HANDLE_VALUE)
if (!m_kfm.Setup(myDC, m_font, m_height*m_mul))
{ // Waarschijnlijk rasterfont? Zo ver mag het hier niet meer komen?
myTRACE("\nGetOutlineTextMetrics faalde: !!!");
}
return WT_Result::Success;
}
// Soms worden de bounds meegegeven. Die gelden heel sterk
// Ze forceren de rotatie en afmetingen
// De hoogte doen we door een goede fontgrootte te kiezen
// De breedte doen we door de spacing te varieren
WT_Result CWhip2DCState::drawBoundText (WT_Text & text, WT_File & file)
{
// Vervang heel kleine teksten door een simpel gekleurd vlakje als het kan.
// Is een stuk sneller
// Helaas lijkt schuine true-type tekst (bemating) niet altijd bounds te hebben?
// ==>Maar vertikale wel
if (file.rendition().font().height()*m_mul < geekFontSize)
{
CPoint *vertexList = new_DWFToLP(WT_Polygon(4, text.bounds().bounds(), FALSE));
DrawGeekBox(vertexList, 4);
return WT_Result::Success;
}
#ifdef _DEBUG
if (m_mul > 0.1)
Marker(DWFToLP(text.bounds().bounds()[0]));
#endif
#ifdef xxxxDEBUG
SetPolyFillMode(myDC, ALTERNATE);
CPoint *vertexList = new_DWFToLP(WT_Polygon(4, text.bounds().bounds(), FALSE));
Polyline(myDC, vertexList, 4);
//return WT_Result::Success;
#endif
CPoint p0(DWFToLP(text.bounds().bounds()[0]));
CPoint p1(DWFToLP(text.bounds().bounds()[1]));
CPoint p2(DWFToLP(text.bounds().bounds()[2]));
CPoint p3(DWFToLP(text.bounds().bounds()[3]));
// Is de tekst uberhaubt zichtbaar? Laat anders maar
if (GetDeviceCaps(myDC, TECHNOLOGY) != DT_METAFILE &&
GetObjectType(myDC) != OBJ_ENHMETADC)
{
CRect textRect(p0, p2); // Tikkie grof voor diagonale teksten. Better safe than sorry
if (!RectVisible(myDC, textRect))
return WT_Result::Success;
}
// dx, dy van de onderlijn bepaalt rotatie
int dx=(p1.x-p0.x), dy=(p0.y-p1.y);
double angle;
if (dx==0)
angle = (dy>0?TWO_PI:-TWO_PI)/4.0;
else
angle = atan((double)dy/dx);
int rotation = myRound(3600*angle/TWO_PI);
int keep_rotation = m_logfont.lfOrientation;
int keep_height = m_logfont.lfHeight;
int keep_width = m_logfont.lfWidth;
double w = _hypot(dx,dy); // sqrt((double)dx*dx+dy*dy);
dx=(p3.x-p0.x), dy=(p0.y-p3.y);
double h = _hypot(dx,dy); // sqrt((double)dx*dx+dy*dy);
// Hoe groot wordt hij als ik niets bijzonders doe?
SIZE sz;
GetTextExtentPoint32(myDC,text.string().ascii(), text.string().length(), &sz);
// grootte correctie
double wScale = w/sz.cx;
double hScale = h/sz.cy;
//myTRACE("\nlfh=%d, hscl=%.3f,wscl=%.3f h=%.1f w=%.1f cy=%d cx=%d %s", m_logfont.lfHeight, hScale, wScale, h, w, sz.cy, sz.cx, text.string().ascii());
// Nauwkeuriger fontbepalen
m_logfont.lfHeight = myRound(m_logfont.lfHeight * hScale);
// TODO: Indien mogelijk nauwkeuriger benaderen met lfWidth?
// Is nodig voor SPCA tekst rechtsboven. Widthscale 1.5 en ook bounds
TEXTMETRIC tm;
if (m_logfont.lfWidth == 0)
{
if ( GetTextMetrics(myDC, &tm) !=0 )
{ // Rationale: Hierboven is lfHeight nog vergroot met hScale
// Anderzijds moeten we corrigeren voor wScale/hScale
// tm.tmAveCharWidth * hScale * (wScale/hScale) reduceert tot:
m_logfont.lfWidth = myRound(tm.tmAveCharWidth * wScale);
}
}
else
m_logfont.lfWidth = myRound(m_logfont.lfWidth * wScale);
// Ook nu corrigeren voor rotatie
m_logfont.lfOrientation = rotation;
m_logfont.lfEscapement = rotation; // Moet bijna altijd gelijk zijn
HFONT temp_font = CreateFontIndirect(&m_logfont); // Voor de rotatie en nieuwe hoogte
HFONT old_font = (HFONT) SelectObject(myDC, temp_font);
// Hoe groot wordt hij nu?
GetTextExtentPoint32(myDC,text.string().ascii(), text.string().length(), &sz);
// grootte correctie
wScale = w/sz.cx;
hScale = h/sz.cy;
SetTextAlign(myDC,TA_LEFT|TA_BOTTOM);
//myTRACE("\nlfh=%d, hscl=%.3f,wscl=%.3f h=%.1f w=%.1f cy=%d cx=%d %s", m_logfont.lfHeight, hScale, wScale, h, w, sz.cy, sz.cx, text.string().ascii());
int errH = myRound(h-sz.cy);
int errW = myRound(w-sz.cx);
//myTRACE("\nAfwijking: h=%d w=%d", errH, errW);
if (abs(errW) <= 1) // Goedkoopste variant (errH doen we toch niets meer mee)
{
TextOut(myDC, p0.x, p0.y,
text.string().ascii(), text.string().length()); // Efficienter en fraaier
// myTRACE("->Normal");
}
else
{ // Spacing aanpassen
// if (!strcmp(text.string().ascii(), "02-06-1L18"))
// DebugBreak();
m_kfm.Setup(myDC, temp_font, abs(m_logfont.lfHeight)); // Voor als height gewijzigd
// myTRACE("->Spacing");
double dw, dh;
m_kfm.GetTextExtent(myDC, text.string().ascii(), text.string().length(), dw, dh);
m_kfm.TextOutSpacing(myDC, p0.x, myRound(p0.y-(h-sz.cy)/2.0),
text.string().ascii(), text.string().length(), w / dw); // acceptabel
}
// Font wel weer terugzetten, tijdelijk boundsrotatie goldt puur voor de huidige tekst
(HFONT) SelectObject(myDC, old_font);
m_logfont.lfOrientation = keep_rotation;
m_logfont.lfEscapement = keep_rotation;
m_logfont.lfHeight = keep_height;
m_logfont.lfWidth = keep_width;
DeleteObject(temp_font);
SetTextAlign(myDC,TA_LEFT|TA_BASELINE);
return WT_Result::Success;
}
// SetExtents is a very important functions as m_mul is
// calculated here
#define SWAP32(a, b) { WT_Integer32 h=b;b=a;a=h; }
void CWhip2DCState::SetExtents(WT_Logical_Box MinMax)
{
ATLASSERT(m_Size.cx > 0 && m_Size.cy); // weird?
WT_Logical_Point dwfPtmin = MinMax.m_min;
WT_Logical_Point dwfPtmax = MinMax.m_max;
// better_markups_large.dwf pagina 'Untitled sheet 2' had een ongenormaliseerde Contour
if (dwfPtmin.m_x > dwfPtmax.m_x)
SWAP32(dwfPtmin.m_x, dwfPtmax.m_x);
if (dwfPtmin.m_y > dwfPtmax.m_y)
SWAP32(dwfPtmin.m_y, dwfPtmax.m_y);
WT_Integer32 dwfDx = dwfPtmax.m_x - dwfPtmin.m_x;
WT_Integer32 dwfDy = dwfPtmax.m_y - dwfPtmin.m_y;
m_MinMax = WT_Logical_Box(dwfPtmin, dwfPtmax);
m_orgMinMax = m_MinMax;
if (m_ClipWidth > 0)
{
double dpi= max(dwfDx / m_ClipWidth, dwfDy / m_ClipHeight);
myDoTRACE("\nGuessing vector dpi: %d", myRound(dpi));
}
//CSize ss;
//GetViewportExtEx(myDC,&ss);
double mulY = (double)m_Size.cy / dwfDy;
double mulX = (double)m_Size.cx / dwfDx;
if (mulY<mulX)
{
m_mul = mulY;
if (m_centerImage)
m_MinMax.minpt().m_x += myRound((dwfDx - m_Size.cx/mulY ) / 2); // Centreren
}
else
{
m_mul = mulX;
if (m_centerImage)
m_MinMax.maxpt().m_y += myRound((m_Size.cy/mulX - dwfDy) / 2); // Centreren
}
myDoTRACE("\nm_mul=%.6f", m_mul);
}
/*****************************************************************************\
* Name CWhip2DCState::AlphaPolygon()
* Input LPPOINT lpPoints
* int nCount
* Action Teken een (gevulde) polygon met behulp van AlphaBlending (doorzichtig)
* Return void
*
* Called
*****************************************************************************/
void CWhip2DCState::AlphaPolygon(LPPOINT lpPoints, int nCount ) const
{
// Alphablend is vrij traag. Daarom extents bepalen om niet meer
// te doen dan strikt noodzakelijk. Scheelt ongeveer een factor 3
CRect minmax(INT_MAX, INT_MAX, INT_MIN, INT_MIN);
for (int i=0; i<nCount; i++)
{
minmax.left = min(minmax.left, lpPoints[i].x);
minmax.top = min(minmax.top, lpPoints[i].y);
minmax.right = max(minmax.right, lpPoints[i].x);
minmax.bottom = max(minmax.bottom, lpPoints[i].y);
}
if (RectVisible(myDC, minmax)) // Niet geheel erbuiten
{
CRect clip;
GetClipBox(myDC,&clip);
CRect res;
res.IntersectRect(clip, minmax);
minmax = res;
HDC hMemDC = CreateCompatibleDC(myDC);
SetMapMode(hMemDC, GetMapMode(myDC));
int maxw = minmax.Width();
int maxh = minmax.Height();
// Neem een zo klein mogelijke bitmap
HBITMAP memBM = CreateCompatibleBitmap ( myDC, maxw, maxh);
HGDIOBJ hOld = SelectObject(hMemDC, memBM);
CPoint pp = -minmax.TopLeft(); // Omdat onze bitmap minmaal van grootte is
SetViewportOrgEx(hMemDC, pp.x, pp.y, NULL);
// Kopieer eerst de bitmap zodat de AlphaBlend het niet
// bedekte origineel ongemoeid laat
BOOL bltRes = BitBlt(hMemDC, minmax.left, minmax.top, maxw, maxh,
myDC, minmax.left, minmax.top, SRCCOPY);
if (!bltRes)
myTRACE("\nHmmm, BitBlt failed?");
HBRUSH oldbrush = (HBRUSH) SelectObject(hMemDC,m_brush);
HPEN pen = CreatePen(PS_NULL, 0, RGB(0,0,0)); // Geen outline tekenen
HPEN pOld = (HPEN)SelectObject(hMemDC, pen);
Polygon(hMemDC, lpPoints, nCount);
SelectObject(hMemDC, pOld);
DeleteObject(pen);
SelectObject(hMemDC,oldbrush);
BLENDFUNCTION blend50 = { AC_SRC_OVER, 0, m_alpha, 0 };
{
//CmyTimer Timer("AlphaPolygon:AlphaBlend");
BOOL res =
AlphaBlend(myDC, minmax.left, minmax.top, maxw, maxh,
hMemDC, minmax.left, minmax.top, maxw, maxh,
blend50); // 50% blending
// The source rectangle must lie completely within the source surface,
// otherwise an error occurs and the function returns FALSE.
#ifdef _DEBUG
if (!res)
{
myTRACE("\nHmmm, AlphaBlend failed?");
_CrtDbgBreak();
}
#endif
}
SelectObject(hMemDC, hOld);
DeleteObject(memBM);
DeleteDC(hMemDC);
}
else
{
//myTRACE("\nAlphaPolygon skipped: outside visible area");
}
}
void CWhip2DCState::Marker( CPoint pt)
{
// LOGPEN p;
// GetObject(m_pen, sizeof(LOGPEN), &p);
HPEN p2 = CreatePen (PS_DOT, 0, RGB(128,128,128));
HPEN oldpen = (HPEN) SelectObject(myDC, p2);
//int sz=(int)(15*m_mul);
int sz=(int)(10);
MoveToEx(myDC, pt.x - sz, pt.y - sz, (LPPOINT) NULL);
LineTo (myDC, pt.x + sz, pt.y + sz);
MoveToEx(myDC, pt.x - sz, pt.y + sz, (LPPOINT) NULL);
LineTo (myDC, pt.x + sz, pt.y - sz);
SelectObject(myDC, oldpen);
DeleteObject(p2);
}
// Creeer een PEN object
// Houd rekening met kleur, width, fill, endcap etc.
void CWhip2DCState::ColorPenAndBrush (WT_File & file)
{
const WT_Color &color = file.rendition().color();
const WT_Fill_Pattern &fillPattern = file.rendition().fill_pattern();
const WT_Line_Style &style = file.rendition().line_style();
const WT_Line_Pattern &linePattern = file.rendition().line_pattern();
WT_RGBA32 clr;
if (color.index() == WD_NO_COLOR_INDEX)
clr = color.rgba();
else
clr = file.rendition().color_map().map(color.index());
if (m_forceBW) // Forceer alles zwart/(wit)
clr = WT_RGBA32(0,0,0,255);
m_DCclr = RGB(clr.m_rgb.r, clr.m_rgb.g, clr.m_rgb.b);
// if ( m_forcePaper ) Toch maar altijd
// Normaal gesproken zal het zonder m_forcePaper wel goed zitten
// maar het kan anders mis gaan bij symbolen die wit zijn
// gedefinieerd en op een zwarte DWF worden geplaatst
// ==> Bij "S-HuntngtnCllg-10YR - MP-Model.dwf" gaat het fout, veel zwart wat wit had moeten blijven
// Daar moeten we dan maar mee leven
// ==> Ook bij intelligent_design_data_large.dwf waar een witte rechthoek
// achter tekst is getekend. Die wordt zwart
if (1)
{
if (!isDarkRGB(m_paperColor) // licht papier
&& clr == WT_RGBA32(255,255,255,clr.m_rgb.a)) // Wit naar zwart
m_DCclr = RGB(0, 0, 0);
if (isDarkRGB(m_paperColor) // donker papier
&& clr == WT_RGBA32(0,0,0,clr.m_rgb.a)) // Zwart naar wit
m_DCclr = RGB(255, 255, 255);
}
CFromTo replace;
if (m_replaceColors.Lookup(m_paperColor, replace))
{
if (m_DCclr == replace.from)
m_DCclr = replace.to;
}
m_alpha = clr.m_rgb.a; // Misschien later nodig voor AlphaPolygon
SetTextColor(myDC, m_DCclr); // Deze in ieder geval zetten
int w = myRound(file.rendition().line_weight().weight_value()*m_mul);
#if 0
m_pen = CreatePen (PS_INSIDEFRAME , w, DCclr);
HPEN oldpenn = (HPEN) SelectObject(myDC, m_pen);
DeleteObject(oldpenn);
return;
#endif
//
// fillpattern
//
int hatchCode = -1; // invalid becomes solid
switch (fillPattern.pattern_id())
{
case WT_Fill_Pattern::Illegal: // Not a pattern (the enum default.)
case WT_Fill_Pattern::Solid: // Solid filled.
break; // No hatch
case WT_Fill_Pattern::Checkerboard: //Checkerboard pattern.
hatchCode = HS_CROSS; break;
case WT_Fill_Pattern::Square_Dots: //Pattern with square dots.
case WT_Fill_Pattern::Diamonds: //Diamond pattern.
case WT_Fill_Pattern::Crosshatch: //Crosshatched pattern.
hatchCode = HS_DIAGCROSS; break;
case WT_Fill_Pattern::Horizontal_Bars: //Pattern with horizontal bars.
hatchCode = HS_HORIZONTAL; break;
case WT_Fill_Pattern::Slant_Left: // Pattern with lines slanting left.
hatchCode = HS_FDIAGONAL; break;
case WT_Fill_Pattern::Slant_Right: //Pattern with lines slanting right.
hatchCode = HS_BDIAGONAL; break;
case WT_Fill_Pattern::Vertical_Bars: //Pattern with vertical bars.
hatchCode = HS_VERTICAL; break;
case WT_Fill_Pattern::User_Defined: //RESERVED, currently no way to describe a user defined fill pattern.
case WT_Fill_Pattern::Undefined: //Not a pattern.
break; // No hatch
default:
break;
}
if (hatchCode == -1)
m_brush = ::CreateSolidBrush(m_DCclr);
else
m_brush = ::CreateHatchBrush(hatchCode, m_DCclr);
HBRUSH oldbrush = (HBRUSH) SelectObject(myDC, m_brush);
DeleteObject(oldbrush);
if (w==0)
m_pen = CreatePen(PS_SOLID, w, GetTextColor(myDC)); // Die is veel sneller
else
{
//
// pen style
//
DWORD penStyle = PS_GEOMETRIC;//|PS_INSIDEFRAME;
switch (style.line_end_cap()) // We negeren line_start_cap
{
case WT_Line_Style::Square_Cap:
case WT_Line_Style::Diamond_Cap: { penStyle |= PS_ENDCAP_SQUARE; break; };
case WT_Line_Style::Butt_Cap: { penStyle |= PS_ENDCAP_FLAT; break; };
case WT_Line_Style::Round_Cap: {penStyle |= PS_ENDCAP_ROUND; break; };
default: {penStyle |= PS_ENDCAP_SQUARE; break; };
}
switch (style.line_join())
{
case WT_Line_Style::Bevel_Join: { penStyle |= PS_JOIN_BEVEL; break; };
case WT_Line_Style::Miter_Join: { penStyle |= PS_JOIN_MITER; break; };
case WT_Line_Style::Round_Join: { penStyle |= PS_JOIN_ROUND; break; };
case WT_Line_Style::Diamond_Join: { penStyle |= PS_JOIN_ROUND; break; };
default: { penStyle |= PS_JOIN_ROUND; break; };
}
// TODO: Goed interpreteren. SetMiterLimit(myDC, style.miter_length(), NULL);
LOGBRUSH b;
b.lbColor = m_DCclr;
b.lbHatch = hatchCode;
b.lbStyle = BS_SOLID;
m_pen = ExtCreatePen(penStyle, w, &b, 0, NULL);
}
if (m_pen == 0)
{
myTRACE("\n(Ext)CreatePen failed (%d): %s", GetLastError(), myGetLastErrorMsg());
};
HPEN oldpen = (HPEN) SelectObject(myDC, m_pen);
DeleteObject(oldpen);
}
// Altijd rond 0,0
CPoint rotate(double radian, double ptx, double pty)
{
return CPoint(myRound(ptx * cos(radian) + pty * sin(radian)),
myRound(pty * cos(radian) - ptx * sin(radian)));
}
void CWhip2DCState::DrawGeekBox(CPoint *pts, int nCount)
{
// Pendikte tijdelijk op 0
myTempPEN tempPen(myDC, 0, GetTextColor(myDC));
//HBRUSH hbrushNew = CreateSolidBrush(GetTextColor(myDC));
HBRUSH hbrushNew = CreateHatchBrush(HS_DIAGCROSS, GetTextColor(myDC)); // Minder 'eng'
HBRUSH hbrushOld = (HBRUSH)SelectObject(myDC, hbrushNew);
Polygon(myDC, pts, nCount);
// Opruimen
SelectObject(myDC, hbrushOld);
DeleteObject(hbrushNew);
}
void CWhip2DCState::DrawGeekText(WT_Text &text)
{
CPoint acPt = DWFToLP(text.position());
double w,h;
if (text.string().is_ascii())
{
m_kfm.GetTextExtent(myDC, text.string().ascii(), text.string().length(), w, h);
}
else
{
CSize s;
GetTextExtentPoint32W(myDC, text.string().unicode(), text.string().length(), &s);
w = s.cx; h = s.cy;
}
// TODO: De .5 snap ik nog niet maar anders is de box te groot
h *= 0.5;
if (h < 1.0) h = 1.0;
double radian = m_logfont.lfOrientation * 2 * PI / 3600;
CPoint pts[]=
{
acPt,
acPt + rotate(radian, w, 0),
acPt + rotate(radian, w, -h),
acPt + rotate(radian, 0, -h),
acPt
};
DrawGeekBox(pts, sizeof(pts)/sizeof(pts[0]));
}