775 lines
25 KiB
C++
775 lines
25 KiB
C++
#include "StdAfx.h"
|
|
#include "Whip2dcState.h"
|
|
#include "SLNKContourImpl.h"
|
|
#include <math.h>
|
|
|
|
#ifndef PI
|
|
#define PI 3.141592653589793f
|
|
#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;
|
|
}
|
|
|
|
CWhip2DCState::~CWhip2DCState()
|
|
{
|
|
myTRACE("\nVertextlist eindigde op: %d", m_vertexList_size);
|
|
delete [] m_vertexList;
|
|
}
|
|
|
|
void CWhip2DCState::erasePaper (WT_File & file)
|
|
{
|
|
HBRUSH tempBrush = CreateSolidBrush(m_paperColor);
|
|
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)
|
|
{
|
|
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);
|
|
|
|
Polygon(hMemDC, lpPoints, nCount);
|
|
|
|
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]));
|
|
}
|