Files
Slnkdwf/SlnkDWFImpl/Whip2DCImpl.cpp
Jos Groot Lipman 0b9083fc17 SLNKDWF 2.11
svn path=/Slnkdwf/trunk/; revision=12487
2008-02-12 07:07:56 +00:00

1807 lines
59 KiB
C++
Raw Blame History

// Whip2DCImpl.cpp : Implementation of CWhip2DCImpl
#include "stdafx.h"
#undef USE_CIMAGE
#include "Whip2DCImpl.h"
#ifndef USE_CIMAGE
#include "CxImage\CxImage\ximage.h"
#else
#include "atlimage.h"
#endif
#include "SLNKContourImpl.h"
// CWhip2DC
STDMETHODIMP CWhip2DCImpl::Load(HDC hDC, CEPlotSectionImpl *EPlotStream,
const CString &WhipPath,
const CString & RegExp, long sizeX, long sizeY,
VARIANT_BOOL centerImage, VARIANT_BOOL maximize,/*=FALSE*/
double dwgScale/*=0.0*/, long lRotation /*=0*/)
{
m_State.Reset();
m_WhipPath = WhipPath;
m_State.myDC = hDC;
m_State.m_Layernames.RemoveAll();
m_State.m_centerImage = centerImage;
m_State.m_Maximize = maximize;
m_State.m_lRotation = lRotation;
m_iEPlotSection = EPlotStream;
REParseError status = m_State.reLayers.Parse( CString(RegExp), false );
if (REPARSE_ERROR_OK != status)
{
myTRACE("\nSorry, kan reguliere expressie layersOn niet parsen");
// return E_FAIL;
}
m_State.m_Size = CSize(sizeX, sizeY);
// Om iets zinvols te kunnen doen moeten we altijd wel schaalinformatie hebben
// In het eenvoudigste geval komen we al heel rap een view of viewport tegen
// Die 'geloven' en gebruiken we. Daarmee kunnen we o.a. m_mul bepalen, de verhouding
// tussen DWF units en device units
// maximize: Voor (draggable) symbolen moeten we de exacte extents/bounds weten
// van de drawable entiteiten en doorzoeken we gegarandeerd de hele tekening
// TODO: Om helemaal bij client-side aan te sluiten moeten we de
// de extents van ((de extents van de boudingbox rechtop) geroteerd) gebruiken
myWT_File my_input_file; // input file.
if (m_iEPlotSection)
{
my_input_file.set_eplotsection(m_iEPlotSection);
m_State.m_ClipWidth = m_iEPlotSection->get_PaperClipWidth();
m_State.m_ClipHeight = m_iEPlotSection->get_PaperClipHeight();
}
else
my_input_file.set_filename(m_WhipPath.ascii());
m_State.m_mul=0;
my_input_file.set_file_mode(WT_File::File_Read);
if (0) { // altijd 'gewoon' recht rekenen
if (m_State.m_lRotation != 0)
{
WT_Logical_Point lCenter(0,0);
m_State.m_Trans = WT_Transform(lCenter, 1.0, 1.0, m_State.m_lRotation);
my_input_file.heuristics().set_transform(m_State.m_Trans);
my_input_file.heuristics().set_apply_transform(true);
my_input_file.rendition().font().rotation() = MulDiv(m_State.m_lRotation,16384,90);
}
}
WT_Result result;
if (my_input_file.open() != WT_Result::Success)
throw myCString("\nCWhip2DCImpl::Load: unable to open file '%s'", m_WhipPath.ascii());
BOOL ViewportDone = FALSE;
double dScale = 1.0;
// Doorloop de DWF totdat alles gelezen is
// Stop als we een view/viewport hebben (dan wordt m_mul gezet) tenzij maximize, dan lezen we alles
while ((result = my_input_file.process_next_object()) == WT_Result::Success
&& (m_State.m_mul == 0 || maximize))
{
switch(my_input_file.current_object()->object_type())
{
case WT_Object::Attribute:
{
const WT_Attribute *obj = (WT_Attribute *)my_input_file.current_object();
if (obj->object_id() == WT_Object::View_ID)
{
WT_View *view = (WT_View *)my_input_file.current_object();
if (!maximize)
m_State.SetExtents(view->view()); // m_mul wordt gezet en de loop eindigt
else
{
// 'Move' alles naar het midden van het eerste kwadrant
// Anders kunnen we later bij bounds bepaling overflow krijgen
// Waar roteren we eigenlijk omheen?
WT_Logical_Point lCenter;
if (m_State.m_lRotation==0||m_State.m_lRotation==90||m_State.m_lRotation==180||m_State.m_lRotation==270)
lCenter = WT_Logical_Point(INT_MAX/2,INT_MAX/2);
else
lCenter = WT_Logical_Point(0, 0);
m_State.m_Trans = WT_Transform (lCenter, 1.0, 1.0, m_State.m_lRotation);
my_input_file.heuristics().set_transform(m_State.m_Trans);
}
break;
}
if (obj->object_id() == WT_Object::Viewport_ID)
{
if (m_State.m_mul == 0)
{
WT_Viewport *viewport = (WT_Viewport *)my_input_file.current_object();
dScale = viewport->viewport_units().application_to_dwf_transform()(0,0); // Symbol's dScale
if (!maximize)
{
WT_Logical_Point dwfPtmin = viewport->contour()->points()[0];
WT_Logical_Point dwfPtmax = viewport->contour()->points()[2];
m_State.SetExtents(WT_Logical_Box(dwfPtmin, dwfPtmax)); // m_mul wordt gezet en de loop eindigt
}
}
break;
}
break;
}
case WT_Object::Drawable:
{
if (!my_input_file.rendition().visibility().visible())
break;
WT_Drawable *obj = (WT_Drawable *)my_input_file.current_object();
if (obj->object_id() != WT_Object::Origin_ID // Belachelijk dat die Drawable is?
// && obj->object_id() != WT_Object::Text_ID // Text roteert nog niet goed
)
{
WT_Logical_Box bx = obj->bounds(&my_input_file);
ATLASSERT(bx.minpt().m_x<=bx.maxpt().m_x);
ATLASSERT(bx.minpt().m_y<=bx.maxpt().m_y);
m_State.m_MinMax.minpt().m_x = min(m_State.m_MinMax.minpt().m_x, bx.minpt().m_x);
m_State.m_MinMax.minpt().m_y = min(m_State.m_MinMax.minpt().m_y, bx.minpt().m_y);
m_State.m_MinMax.maxpt().m_x = max(m_State.m_MinMax.maxpt().m_x, bx.minpt().m_x);
m_State.m_MinMax.maxpt().m_y = max(m_State.m_MinMax.maxpt().m_y, bx.minpt().m_y);
m_State.m_MinMax.minpt().m_x = min(m_State.m_MinMax.minpt().m_x, bx.maxpt().m_x);
m_State.m_MinMax.minpt().m_y = min(m_State.m_MinMax.minpt().m_y, bx.maxpt().m_y);
m_State.m_MinMax.maxpt().m_x = max(m_State.m_MinMax.maxpt().m_x, bx.maxpt().m_x);
m_State.m_MinMax.maxpt().m_y = max(m_State.m_MinMax.maxpt().m_y, bx.maxpt().m_y);
}
break;
}
default:
//myTRACE("Skipping '%s'\n", wtFile->file_stats()->descriptions());
break;
}
}
result = my_input_file.close(); // closing Input file.
if (m_State.m_mul==0 && result == WT_Result::Success)
{ // Blijkbaar geen view en/of viewport gevonden
m_State.SetExtents(m_State.m_MinMax); // Die hebben we dan in de vorige slag wel bepaald
}
result = my_input_file.close(); // closing Input file.
if (dwgScale > 0.0) // dwgSchaal geforceerd!
{ // Vooralsnog alleen getest met m_Maximize aan
double old_mul = m_State.m_mul;
CSize old_size = m_State.m_Size;
m_State.m_mul = 1.0/dwgScale/dScale;
if (m_State.m_Maximize) // Eventueel centreren ongedaan maken
m_State.m_MinMax = m_State.m_orgMinMax;
WT_Integer32 dwfDx = m_State.m_MinMax.maxpt().m_x - m_State.m_MinMax.minpt().m_x;
WT_Integer32 dwfDy = m_State.m_MinMax.maxpt().m_y - m_State.m_MinMax.minpt().m_y;
m_State.m_Size = CPoint(myRound(m_State.m_mul*dwfDx)+1, myRound(m_State.m_mul*dwfDy+1)+1);
m_State.m_Size.cx = max(m_State.m_Size.cx, 1);
m_State.m_Size.cy = max(m_State.m_Size.cy, 1);
myDoTRACE("\nm_mul forced from %.8f to %.8f and size from (%d, %d) to (%d, %d)",
old_mul, m_State.m_mul, old_size.cx,old_size.cy,m_State.m_Size.cx,m_State.m_Size.cy);
}
ATLASSERT(m_State.m_mul!=0);
return S_OK;
}
// Om onze definitieve bitmap grootte te kunnen bepalen
CSize &CWhip2DCImpl::get_Size()
{
return m_State.m_Size;
}
STDMETHODIMP CWhip2DCImpl::Paint(VARIANT_BOOL forceBW)
{
#ifdef _DEBUG
/// CneutralGDI neutralGDI("CWhip2DCImpl::Paint");
#endif
CmyTimer Timer("CWhip2DCImpl::Paint");
m_State.m_forceBW = forceBW;
m_State.findIt = FALSE;
SetBkMode(m_State.myDC, TRANSPARENT);
m_State.geekFontSize = 4; // 4pt en lager is toch niet leesbaar
// Overigens tikt dit vooral hard aan omdat we de
// rotatie van die kleine teksten niet meer zetten
myWT_File my_input_file; // input file.
if (m_iEPlotSection)
{
my_input_file.set_eplotsection(m_iEPlotSection);
if (!m_State.m_forcePaper)
{
m_State.m_paperColor = m_iEPlotSection->get_PaperColor();
}
}
else
{
if (!m_State.m_forcePaper)
{
m_State.m_paperColor = RGB(255,255,255); // Gok maar op wit. Echte kleur komt misschien wel
}
my_input_file.set_filename(m_WhipPath.ascii());
}
// Setup our default font
WT_Font myFont;
myFont.font_name().set("Arial");
myFont.height() = 100;
my_input_file.rendition().font() = myFont;
// Alle callback functies zijn static. Die kunnen de variabele
// m_State niet benaderen. Daarom maar via set_user_data
my_input_file.heuristics().set_user_data((void *)&m_State);
if (m_State.m_lRotation != 0) // Tijdens het laden roteren
{
my_input_file.heuristics().set_transform(m_State.m_Trans);
my_input_file.heuristics().set_apply_transform(true);
}
my_input_file.set_file_mode(WT_File::File_Read);
if (my_input_file.open() == WT_Result::Success)
{
SetTextAlign(m_State.myDC,TA_LEFT|TA_BASELINE);
// Setup our default pen and brush
if (isDarkRGB(m_State.m_paperColor))
SetTextColor(m_State.myDC, RGB(255,255,255));
else
SetTextColor(m_State.myDC, RGB(0, 0, 0));
// Standaard zit onze m_pen in de DC
m_State.m_pen = CreatePen(PS_INSIDEFRAME, 0, GetTextColor(m_State.myDC));
m_State.m_brush = CreateSolidBrush(GetTextColor(m_State.myDC));
LOGBRUSH b;
b.lbColor = GetTextColor(m_State.myDC);
//b.lbHatch = hatchCode;
b.lbStyle = BS_SOLID;
HBRUSH oldbrush=(HBRUSH) SelectObject(m_State.myDC, m_State.m_pen);
HPEN oldpen=(HPEN)SelectObject(m_State.myDC, m_State.m_brush);
// Wis myDC met wit. Wordt mogelijk overruled in WT_Background
m_State.erasePaper(my_input_file);
WT_Result result = read_dwf_for_extracting_Objects(my_input_file, FALSE);
my_input_file.close(); // closing Input file.
// Alles opruimen
if (m_State.m_hrgn)
DeleteObject(m_State.m_hrgn);
if (m_State.m_font)
DeleteObject(m_State.m_font);
SelectObject(m_State.myDC, oldbrush);
SelectObject(m_State.myDC, oldpen);
DeleteObject(m_State.m_brush);
DeleteObject(m_State.m_pen);
if (result != WT_Result::Success)
throw myCString("\nCWhip2DCImpl::Paint: unable to read file '%s'", m_WhipPath.ascii());
}
else // TODO: Fatsoenlijke error terug
{
throw myCString("\nCWhip2DCImpl::Paint: unable to open file '%s'", m_WhipPath.ascii());
}
// For when user wants to use DPtoDWF
m_State.m_Units = my_input_file.rendition().viewport().viewport_units();
#if 0
{
// Raster er overheen
CRect clip;
GetClipBox(m_State.myDC,&clip); // Zichtbaar deel op scherm
SetBkMode(m_State.myDC, TRANSPARENT);
HBRUSH tempBrush = ::CreateHatchBrush(HS_DIAGCROSS, RGB(32,0,0));
HBRUSH tempBrush2 = ::CreateHatchBrush(HS_CROSS, RGB(0,64,0));
HBRUSH oldbrush = (HBRUSH) SelectObject(m_State.myDC,tempBrush);
CRect rc;
GetClipBox(m_State.myDC,&rc);
SetBrushOrgEx(m_State.myDC, 0, 0, NULL);
//Rectangle(m_State.myDC, clip.left,clip.top,clip.right,clip.bottom);
HBRUSH oldbrush2 = (HBRUSH) SelectObject(m_State.myDC,tempBrush2);
Rectangle(m_State.myDC, clip.left,clip.top,clip.right,clip.bottom);
SetBrushOrgEx(m_State.myDC, 2, 2, NULL);
Rectangle(m_State.myDC, clip.left,clip.top,clip.right,clip.bottom);
SetBrushOrgEx(m_State.myDC, 4, 4, NULL);
Rectangle(m_State.myDC, clip.left,clip.top,clip.right,clip.bottom);
SetBrushOrgEx(m_State.myDC, 6, 6, NULL);
Rectangle(m_State.myDC, clip.left,clip.top,clip.right,clip.bottom);
SelectObject(m_State.myDC,oldbrush2);
SelectObject(m_State.myDC,oldbrush);
DeleteObject(tempBrush);
DeleteObject(tempBrush2);
}
#endif
#ifdef _DEBUG
// Toon bij sterk inzoomen een raster van DWF-punten ter referentie
LOGFONT lf;
memset(&lf, 0, sizeof(LOGFONT)); // clear out structure.
strncpy(lf.lfFaceName, "Tahoma", LF_FACESIZE);
lf.lfHeight = -10;
HFONT fnt = CreateFontIndirect(&lf);
HGDIOBJ oldfont = SelectObject(m_State.myDC, fnt);
if (m_State.m_mul > 10.0)
{
CRect clip;
GetClipBox(m_State.myDC,&clip); // Zichtbaar deel op scherm
WT_Logical_Point topleft(m_State.LPToDWF(clip.TopLeft()));
WT_Logical_Point botright(m_State.LPToDWF(clip.BottomRight()));
for (int x = topleft.m_x; x <= botright.m_x; x++)
for (int y = topleft.m_y; y >= botright.m_y; y--)
{
CPoint pt = m_State.DWFToLP(WT_Logical_Point(x, y));
SetPixel(m_State.myDC, pt.x, pt.y, RGB(128,128,128));
// Bij nog sterker inzoomen tonen we DWF-coordinaten
if (m_State.m_mul > 80.0)
{
CString txt;
txt.Format("%d", x);
TextOut(m_State.myDC, pt.x+5, pt.y, txt, txt.GetLength());
txt.Format("%d", y);
TextOut(m_State.myDC, pt.x+5, pt.y+10, txt, txt.GetLength());
}
}
}
SelectObject(m_State.myDC, oldfont);
DeleteObject(fnt);
// Pas op: geeft ASSERT's op te grote myRound binnen DWFToLP bij ver inzoomen
#if 0
//CPoint pt0 = m_State.DWFToLP(WT_Logical_Point(INT_MAX, 100000000));
//CPoint pt1 = m_State.DWFToLP(WT_Logical_Point(INT_MAX, -100000000));
HPEN m_pen = CreatePen(PS_SOLID, 3, RGB(255,255,0));
HPEN oldpen = (HPEN) SelectObject(m_State.myDC, m_pen);
MoveToEx(m_State.myDC, pt0.x, pt0.y, NULL);
LineTo(m_State.myDC, pt1.x, pt1.y);
#endif
#endif
return S_OK;
}
// Zoek alle teksten in de tekening op en lever ze op als array
STDMETHODIMP CWhip2DCImpl::FindTexts(const CString &findText)
{
CmyTimer Timer("CWhip2DCImpl::FindText");
m_State.bLayerVisible = TRUE; // When no layers at all
m_State.findIt = TRUE;
m_State.m_FoundTexts.RemoveAll();
m_State.foundTextLabel = "";
myWT_File my_input_file; // input file.
if (m_iEPlotSection)
my_input_file.set_eplotsection(m_iEPlotSection);
else
my_input_file.set_filename(m_WhipPath.ascii());
my_input_file.heuristics().set_user_data((void *)&m_State);
my_input_file.set_file_mode(WT_File::File_Read);
if (my_input_file.open() == WT_Result::Success)
{
WT_Result result;
my_input_file.set_polygon_action(my_process_polygon_find); // Requires polyline and fill too!
my_input_file.set_text_action(my_process_text_scan);
my_input_file.set_layer_action(my_process_layer);
// Do the actual reading.
do {
result = my_input_file.process_next_object();
} while (result == WT_Result::Success);
if (result == WT_Result::End_Of_DWF_Opcode_Found || result == WT_Result::User_Requested_Abort)
return WT_Result::Success;
else
return result;
}
else
myTRACE("\nSorry, kan file niet openen: %s", m_WhipPath);
// For when user wants to use DPtoDWF
m_State.m_Units = my_input_file.rendition().viewport().viewport_units();
my_input_file.close(); // closing Input file.
return S_OK;
}
/*****************************************************************************\
* Name CWhip2DCImpl::Find()
* Input HDC dc
* LONG sizeX,
* LONG sizeY,
* LONG offsetX,
* LONG offsetY,
* DOUBLE dScale
* ....
* Action Zoek een in de tekening aangeklikt punt op
* of bepaal de clientside imagemap (voor tooltips)
* Deze laatste heeft als neveneffect dat SLNKEvent clientside
* gezet wordt waar we een heleboel info uit halen
* Return S_OK
*
* Called
* TODO: AsMap wordt voor steeds meer doeleinden gebruikt. Oppassen dat
* bijvoorbeeld extents wel correct worden bepaald
*****************************************************************************/
STDMETHODIMP CWhip2DCImpl::Find(LONG findX, LONG findY,
BYTE AsMap,
CString & pContourLabel,CString & pContourLayer,
CString & pTextLabel, CString & pTextLayer,
double &pEdgeAngle, double &pEdgeDistance)
{
CmyTimer Timer("CWhip2DCImpl::Find (includes AsMap)");
m_State.bLayerVisible = TRUE; // When no layers at all
m_State.findIt = TRUE;
m_State.foundTextLabel = "";
// Note: At the first View we find we will fill
// DWFfindXY with the actual WT_logical coordinates
m_State.LPfindXY = CPoint(findX, findY);
DPtoLP(m_State.myDC, &m_State.LPfindXY, 1);
// Extents zijn in Load al bepaald, we kunnen ons zoekpunt in DWF-coordinaten bepalen
m_State.DWFfindXY = m_State.LPToDWF(m_State.LPfindXY);
myTRACE("\nZoeken naar : (%d, %d)-->(%d, %d)", m_State.LPfindXY.x, m_State.LPfindXY.y, m_State.DWFfindXY.m_x, m_State.DWFfindXY.m_y);
#ifdef _DEBUG
CPoint ptback = m_State.DWFToLP(m_State.DWFfindXY);
myTRACE("\nTerugvertaling: (%d, %d)\n", ptback.x, ptback.y);
#endif
myWT_File my_input_file; // input file.
// For TextExtent32
SetTextAlign(m_State.myDC,TA_LEFT|TA_BASELINE);
WT_Font myFont;
myFont.font_name().set("Arial"); // Real font will follow later
myFont.height() = 100;
my_input_file.rendition().font() = myFont;
// Papierkleur zetten voor Find lijkt onzinnig maar we willen
// de kleur na afloop kunnen opvragen als oMap.paperColor
if (m_iEPlotSection)
{
my_input_file.set_eplotsection(m_iEPlotSection);
if (!m_State.m_forcePaper)
{
m_State.m_paperColor = m_iEPlotSection->get_PaperColor();
}
}
else
{
my_input_file.set_filename(m_WhipPath.ascii());
if (!m_State.m_forcePaper)
{
m_State.m_paperColor = RGB(255,255,255); // Gok maar op wit. Echte kleur komt misschien wel
}
}
// Alle callback functies zijn static. Die kunnen de variabele
// m_State niet benaderen. Daarom maar via set_user_data
my_input_file.heuristics().set_user_data((void *)&m_State);
my_input_file.set_file_mode(WT_File::File_Read);
if (my_input_file.open() == WT_Result::Success)
{
WT_Result result = read_dwf_for_extracting_Objects(my_input_file, TRUE);
}
else
myTRACE("\nSorry, kan file niet openen: %s", m_WhipPath);
// For when user wants to use DPtoDWF
m_State.m_Units = my_input_file.rendition().viewport().viewport_units();
my_input_file.close(); // closing Input file.
if (AsMap)
pContourLabel = m_State.MapBuilder;
else
{
if (m_State.foundTextLabel != "")
{
pTextLabel = m_State.foundTextLabel;
pTextLayer = m_State.foundTextLayer;
}
if (m_State.foundNode.object_node_name())
{
pContourLabel = CString(m_State.foundNode.object_node_name().ascii());
pContourLayer = m_State.foundNodeLayer;
pEdgeAngle = m_State.foundEdgeAngle;
pEdgeDistance = m_State.foundEdgeDistance;
}
}
// Alles opruimen
if (m_State.m_hrgn)
DeleteObject(m_State.m_hrgn);
if (m_State.m_font)
DeleteObject(m_State.m_font);
return S_OK;
}
// Call Find() or Paint() first!!
STDMETHODIMP CWhip2DCImpl::DPtoDWG(LONG findX, LONG findY,
DOUBLE* resX, DOUBLE* resY)
{
m_State.LPfindXY = CPoint(findX, findY);
DPtoLP(m_State.myDC, &m_State.LPfindXY, 1);
if ((resX != NULL) && (resY != NULL))
{
if (m_State.m_mul==0) // Geen extents, vast ook geen transform
{
(*resX) = 0; // Zoek het maar lekker zelf uit
(*resY) = 0;
}
else
{
// Zoek de DWG coordinaten op
m_State.LPToDWG(m_State.LPfindXY, *resX, *resY);
}
}
return S_OK;
}
// Call Find() or Paint() first!!
STDMETHODIMP CWhip2DCImpl::DWGExtents(DOUBLE* resminX, DOUBLE* resminY,
DOUBLE* resmaxX, DOUBLE* resmaxY)
{
if (resminX && resminY && resmaxX && resmaxY)
{
if (m_State.m_mul==0) // Geen extents, vast ook geen transform
{
(*resminX) = (*resminY) = 0; // Zoek het maar lekker zelf uit
(*resmaxX) = (*resmaxY) = 0;
}
else
{
// Zoek de DWG coordinaten op
m_State.DWGExtents(*resminX, *resminY, *resmaxX, *resmaxY);
}
}
return S_OK;
}
WT_Result CWhip2DCImpl::read_dwf_for_extracting_Objects(myWT_File &my_input_file, BOOL findIt)
{
WT_Result result;
// Defined actions.
if (!findIt) // When finding we don't need most handlers in the first place
{
my_input_file.set_color_action(my_process_color);
my_input_file.set_fill_pattern_action(my_process_fillPattern);
my_input_file.set_line_weight_action(my_process_lineWeight);
my_input_file.set_line_style_action(my_process_lineStyle);
my_input_file.set_line_pattern_action(my_process_linePattern);
my_input_file.set_filled_ellipse_action(my_process_filledEllipse);
my_input_file.set_outline_ellipse_action(my_process_outlineEllipse);
my_input_file.set_polytriangle_action(my_process_polytriangle);
my_input_file.set_polymarker_action(my_process_polymarker);
my_input_file.set_contour_set_action(my_process_contourSet);
my_input_file.set_png_group4_image_action(my_process_pngGroup4Image);
my_input_file.set_image_action(my_process_image);
my_input_file.set_gouraud_polyline_action(my_process_gouraudPolyline);
my_input_file.set_gouraud_polytriangle_action(my_process_gouraudPolytriangle);
my_input_file.set_polygon_action(my_process_polygon); // Requires polyline and fill too!
my_input_file.set_text_action(my_process_text);
my_input_file.set_polyline_action(my_process_polyline);
}
else // Use find-version
{
my_input_file.set_polygon_action(my_process_polygon_find); // Requires polyline and fill too!
my_input_file.set_text_action(my_process_text_find);
}
// The following are also necessary when finding
my_input_file.set_background_action(my_process_background); // setting m_paperColor
my_input_file.set_font_extension_action(my_process_font_extension);
my_input_file.set_font_action(my_process_font);
my_input_file.set_layer_action(my_process_layer);
my_input_file.set_viewport_action(my_process_viewport);
my_input_file.set_view_action(my_process_view);
// Do the actual reading.
do {
//CneutralGDI neutralGDI("read_dwf_for_extracting_Objects");
#ifdef _DEBUG
CString s(my_input_file.file_stats()->descriptions());
//myTRACE("Attribute '%s'\n", s);
#endif
if (m_progress_action)
{
int pos = my_input_file.file_pos();
size_t sz = my_input_file.size();
if (!m_progress_action(m_progress_param, sz==0?0:double(pos)/sz))
return WT_Result::User_Requested_Abort;
}
result = my_input_file.process_next_object();
} while (result == WT_Result::Success);
if (result == WT_Result::End_Of_DWF_Opcode_Found || result == WT_Result::User_Requested_Abort)
return WT_Result::Success;
else
return result;
}
// We gebruiken deze view als initial display
// Sinds we het scannen al in de load doen is deze obsolete
WT_Result CWhip2DCImpl::my_process_view (WT_View & view, WT_File & file)
{
return WT_Result::Success;
}
// (Alleen) als we nog geen View hebben gehad gebruiken we de 1e Viewport
// als alternatief. Je moet toch wat. DWFPrinter doet dat
WT_Result CWhip2DCImpl::my_process_viewport (WT_Viewport & viewport, WT_File & file)
{
CWhip2DCState *m_State = (CWhip2DCState *)file.heuristics().user_data();
BOOL firstTime = (!file.rendition().viewport().contour());
file.rendition().viewport() = viewport;
// Voor de zekerheid opnieuw. ADT3_MTextFormattingCodesinScheduleTags.dwf had
// (waarschijnlijk door de DWFPrinter) de eerste (Font) voor de eerste (Viewport)
// en dan was de hoogte niet goed gezet
m_State->my_process_font(file.rendition().font());
double dScale = viewport.viewport_units().application_to_dwf_transform()(0,0);
myDoTRACE("\nThis viewport: 1 pixel = %.8f drawing units.", 1.0/(dScale*m_State->m_mul));
if (m_State->findIt) // When finding no need (or actually: support) for clipping
return WT_Result::Success;
if (!viewport.contour()) // dwftest_bc.dwf
{
SelectClipRgn(m_State->myDC, NULL);
return WT_Result::Success;
}
// Viewports-ANSI A.dwf heeft diverse viewports
myTRACE("\nViewport met %d punten", viewport.contour()->total_points());
// TODO: Door afronding kan het gebeuren dat de clipregion ene pixel
// te ver naar binnen valt waardoor meest rechtse lijntjes wegvallen
// Daarom viewport ter grootte van minmax niet aanzetten
// NOOT: Ook riskant als later symbolen net buiten de extents geplaatst zijn?
if (firstTime)
{
myTRACE("\nSkipping 'region-all'");
SelectClipRgn(m_State->myDC, NULL); // Eventueel uitzetten
return WT_Result::Success;
}
CPoint *vertexList =
m_State->new_DWFToLP(WT_Point_Set(viewport.contour()->total_points(),
viewport.contour()->points(), false));
// LET OP: CreatePolyPolygonRgn verwacht Device Units!
LPtoDP(m_State->myDC, vertexList, viewport.contour()->total_points());
if (m_State->m_hrgn)
DeleteObject(m_State->m_hrgn);
m_State->m_hrgn = CreatePolyPolygonRgn(vertexList, (int *)viewport.contour()->counts(),
viewport.contour()->contours(),
ALTERNATE);
ATLASSERT(m_State->m_hrgn);
int res = SelectClipRgn(m_State->myDC, m_State->m_hrgn);
ATLASSERT(res != ERROR);
#ifdef _DEBUG
{
CString s;
switch(res) {
case NULLREGION : s = "NULLREGION Region is empty."; break;
case SIMPLEREGION: s = "SIMPLEREGION Region is a single rectangle."; break;
case COMPLEXREGION: s = "COMPLEXREGION Region is more than one rectangle."; break;
case ERROR: s.Format("SelectClipRgn failed (%d): %s", GetLastError(), myGetLastErrorMsg()); break;
}
myTRACE("\nRegion aangemaakt: %s", s);
}
#endif
return WT_Result::Success;
}
WT_Result CWhip2DCImpl::my_process_color (WT_Color & color, WT_File & file)
{
WT_Color::default_process(color, file);
CWhip2DCState *m_State = (CWhip2DCState *)file.heuristics().user_data();
m_State->ColorPenAndBrush(file);
return WT_Result::Success;
}
WT_Result CWhip2DCImpl::my_process_lineWeight (WT_Line_Weight & lineWeight, WT_File & file)
{
WT_Line_Weight::default_process(lineWeight, file);
my_process_color(file.rendition().color(),file);
return WT_Result::Success;
}
WT_Result CWhip2DCImpl::my_process_lineStyle (WT_Line_Style & lineStyle, WT_File & file)
{
WT_Line_Style::default_process(lineStyle, file);
my_process_color(file.rendition().color(),file);
return WT_Result::Success;
}
WT_Result CWhip2DCImpl::my_process_linePattern (WT_Line_Pattern & linePattern, WT_File & file)
{
WT_Line_Pattern::default_process(linePattern, file);
my_process_color(file.rendition().color(),file);
return WT_Result::Success;
}
WT_Result CWhip2DCImpl::my_process_layer (WT_Layer & layer, WT_File & file)
{
CWhip2DCState *m_State = (CWhip2DCState *)file.heuristics().user_data();
file.rendition().layer() = layer;
if (layer.layer_name().length()>0) // Anders zittie alleen maar in de weg
{ // Dat doet de default_process 'fout'
file.layer_list().add_layer(layer);
m_State->m_Layernames.Add(layer.layer_name().ascii());
}
WT_Integer32 layer_num = layer.layer_num();
WT_Layer *ll = file.layer_list().find_layer_from_index(layer_num);
if (ll&&ll->layer_name().ascii())
{
//myTRACE("\n my_output_file.desired_rendition().layer() = layer %s;", layer.layer_name().ascii());
CAtlREMatchContext<> mcUrl;
if ( m_State->reLayers.Match(ll->layer_name().ascii(), &mcUrl))
{
//myTRACE(".. does match!");
m_State->bLayerVisible = TRUE;
}
else
{
m_State->bLayerVisible = FALSE;
// myTRACE("\nLayer %s .. does not match", ll->layer_name().ascii());
}
// myTRACE("\nLayer %s .. does not match", ll->layer_name().ascii());
m_State->bIsSymbolLayer = (ll->layer_name() == "SLNK Symbols");
//myDoTRACE("\nLayer %s %d", ll->layer_name().ascii(), m_State->bIsSymbolLayer);
}
else
{
myTRACE("\nNo layer name for contour. Assuming match");
m_State->bLayerVisible = TRUE;
m_State->bIsSymbolLayer = FALSE;
}
return WT_Result::Success;
}
WT_Result CWhip2DCImpl::my_process_font_extension (WT_Font_Extension & font_extension, WT_File & file)
{
// myTRACE("\n !! Don't know how to handle font_extension yet!! (%s/%s)",
// font_extension.logfont_name().ascii(), font_extension.cannonical_name().ascii());
return WT_Result::Success;
}
WT_Result CWhip2DCImpl::my_process_font (WT_Font & font, WT_File & file)
{
WT_Font::default_process ( font, file);
CWhip2DCState *m_State = (CWhip2DCState *)file.heuristics().user_data();
m_State->my_process_font(file.rendition().font());
return WT_Result::Success;
}
// Merk op: gewone cirkels komen ook hier binnen met Ellipse.start()+65536==Ellipse.end()
WT_Result CWhip2DCImpl::my_process_Ellipse (WT_Ellipse & Ellipse, WT_File & file, WT_Boolean fill)
{
CWhip2DCState *m_State = (CWhip2DCState *)file.heuristics().user_data();
if (!m_State->bLayerVisible)
return WT_Result::Success;
//TODO: De tilt correct meenemen als hij niet orthogonaal is
// Overigens nog nooit gezien
WT_Integer32 minor=Ellipse.minor();
WT_Integer32 major=Ellipse.major();
WT_Logical_Point pos = Ellipse.position();
if (minor<0||major<0)
{ // Gebeurde bij "Inventor_Engine _2D.dwf".
return WT_Result::Success; // Negeren
}
switch (Ellipse.tilt())
{
case 0: break;
case 32768: break;
case 16384:
case 49152:
{
int tmp=major;major=minor;minor=tmp;
break;
}
default:
if (major != minor)
myTRACE("\nNiet-ortho tilt (%d) nog niet ondersteund (%d,%d)", Ellipse.tilt(), pos.m_x, pos.m_y);
}
double start = Ellipse.start_radian();
double end = Ellipse.end_radian();
double tilt = Ellipse.tilt_radian();
#define SC 5
// Bij GDI hoeven de referentiepunten niet op de ellipse te liggen
// En door SC hebben we betere resolutie
WT_Logical_Point ls(pos.m_x+myRound(cos(start+tilt)*SC*major),
pos.m_y+myRound(sin(start+tilt)*SC*minor));
WT_Logical_Point le(pos.m_x+myRound(cos(end +tilt)*SC*major),
pos.m_y+myRound(sin(end +tilt)*SC*minor));
CPoint s = m_State->DWFToLP(ls);
CPoint e = m_State->DWFToLP(le);
#ifdef _DEBUG
// Toon aanhaallijnen
if (m_State->m_mul>10)
{
HPEN p2 = CreatePen (PS_DOT, 0, RGB(128,128,128));
HPEN oldpen = (HPEN) SelectObject(m_State->myDC, p2);
CPoint acPt = m_State->DWFToLP(pos);
m_State->Marker(acPt);
MoveToEx(m_State->myDC, s.x, s.y, (LPPOINT) NULL);
LineTo (m_State->myDC, acPt.x, acPt.y);
LineTo (m_State->myDC, e.x, e.y);
SelectObject(m_State->myDC, oldpen);
DeleteObject(p2);
}
#endif
if ( Ellipse.start()+65536!=Ellipse.end()
&& _hypot(e.x-s.x, e.y-s.y)<2.0)
{ // Voorkom onbedoelde volledige cirkels als s==e door afronding
// Wel de niet-uitvergrootte versies
WT_Logical_Point ls(pos.m_x+myRound(cos(start+tilt)*major),
pos.m_y+myRound(sin(start+tilt)*minor));
WT_Logical_Point le(pos.m_x+myRound(cos(end +tilt)*major),
pos.m_y+myRound(sin(end +tilt)*minor));
CPoint s = m_State->DWFToLP(ls);
CPoint e = m_State->DWFToLP(le);
MoveToEx(m_State->myDC, s.x, s.y, NULL);
LineTo(m_State->myDC, e.x, e.y);
return WT_Result::Success;
}
CPoint topleft = m_State->DWFToLP(WT_Logical_Point(pos.m_x-major, pos.m_y-minor));
CPoint bottomright = m_State->DWFToLP(WT_Logical_Point(pos.m_x+major, pos.m_y+minor));
if (fill)
{
SetPolyFillMode(m_State->myDC, ALTERNATE);
::Ellipse(m_State->myDC, topleft.x, topleft.y,
bottomright.x, bottomright.y);
}
else
{
if (Ellipse.start() + 65536 == Ellipse.end())
{
// Voorkom afrondfouten. ::Ellipse zou gaan vullen
e=s;
}
SetArcDirection(m_State->myDC, AD_COUNTERCLOCKWISE);
Arc(m_State->myDC, topleft.x, topleft.y,
bottomright.x, bottomright.y,
s.x, s.y, e.x, e.y);
}
return WT_Result::Success;
}
WT_Result CWhip2DCImpl::my_process_filledEllipse (WT_Filled_Ellipse & filledEllipse, WT_File & file)
{
return my_process_Ellipse(filledEllipse, file, TRUE);
}
WT_Result CWhip2DCImpl::my_process_outlineEllipse (WT_Outline_Ellipse & outlineEllipse, WT_File & file)
{
return my_process_Ellipse(outlineEllipse, file, FALSE);
}
// Genereer een een html <area> fragment
CString CWhip2DCImpl::PolyToMap(WT_Polygon & polygon,
WT_Object_Node node, WT_URL URL,
CWhip2DCState *m_State)
{
CString objKey = node.object_node_name().ascii(); // Zo doen wij dat namelijk
CString ptList;
double opp = CSLNKContourImpl::DWFArea(polygon)*m_State->m_mul*m_State->m_mul;
if (abs(opp) < 10) // Clientside minder dan 10 pixels
{
myTRACE("\nSkipping oppervlakte %.6f", opp);
return "";
}
#if 0
// het werkt niet:PtVisible levert altijd false op (omdat we geen bitmap selecteren in CWhip2PNG::GetAsMap?
BOOL anyVisible = false; // als de boundingcontour geheel buiten beeld valt is hij niet nodig
// Uit priaktische overwegingen implementeren we dat als: een
// hoekpunt van de bounding contour moet in beeld zijn
#endif
CString shape;
if (polygon.count() == 5 && // Linksom of rechtsom rechthoekig
((polygon.points()[0].m_x == polygon.points()[1].m_x &&
polygon.points()[1].m_y == polygon.points()[2].m_y &&
polygon.points()[2].m_x == polygon.points()[3].m_x &&
polygon.points()[3].m_y == polygon.points()[4].m_y
) ||
(polygon.points()[0].m_y == polygon.points()[1].m_y &&
polygon.points()[1].m_x == polygon.points()[2].m_x &&
polygon.points()[2].m_y == polygon.points()[3].m_y &&
polygon.points()[3].m_x == polygon.points()[4].m_x
)
)
)
{
shape = "rect";
CPoint pt1 = m_State->DWFToLP(polygon.points()[0]);
CPoint pt2 = m_State->DWFToLP(polygon.points()[2]);
#if 0
anyVisible|=PtVisible(m_State->myDC, pt1.x,pt1.y);
anyVisible|=PtVisible(m_State->myDC, pt2.x,pt1.y);
anyVisible|=PtVisible(m_State->myDC, pt2.x,pt2.y);
anyVisible|=PtVisible(m_State->myDC, pt1.x,pt2.y);
#endif
LPtoDP(m_State->myDC, &pt1, 1);
LPtoDP(m_State->myDC, &pt2, 1);
ptList.Format("%d,%d,%d,%d", min(pt1.x, pt2.x), min(pt1.y, pt2.y),
max(pt1.x, pt2.x), max(pt1.y, pt2.y));
}
else
{
shape = "poly";
for (int i = 0; i < polygon.count(); i++)
{
CPoint pt = m_State->DWFToLP(polygon.points()[i]);
#if 0
anyVisible|=PtVisible(m_State->myDC, pt.x,pt.y);
#endif
LPtoDP(m_State->myDC, &pt, 1);
CString s;
s.Format("%s,%d,%d", ptList, pt.x, pt.y);
ptList = s;
}
ptList = ptList.Mid(1); // Eerste komma er af
}
#if 0
if (!anyVisible)
return ""; // Toch niet in beeld
#endif
CString Coords, Title, Href;
Coords.Format("coords=\"%s\"", ptList);
WT_URL_List lUrl = URL.url();
CString ttl;
if (lUrl.count()>0)
{
WT_URL_Item *firstURL = (WT_URL_Item *)lUrl.get_head();
if (firstURL->address().length() == 0)
Href = "";
else
Href.Format("href=\"%s\"", CString(firstURL->address().ascii()));
if (firstURL->friendly_name().is_ascii())
ttl = firstURL->friendly_name().ascii();
else
ttl = CStringW(firstURL->friendly_name().unicode());
}
else
ttl = objKey; // Is dit wel zo logisch/wenselijk?
ttl.Replace("\\n", "\n");
Title.Format("title=\"%s\"", ttl);
CString smbl = "";
if (m_State->bIsSymbolLayer && objKey != "")
smbl.Format("\nSLNKSymbolKey=\"%s\"", objKey);
CString Builder;
Builder.Format("\n<area shape=\"%s\"\n%s\n%s\n%s%s>",
shape, Coords, Title, Href, smbl);
return Builder;
};
// Binnen DWF is een polygon altijd 'gevuld'
WT_Result CWhip2DCImpl::my_process_polygon (WT_Polygon & polygon, WT_File & file)
{
CWhip2DCState *m_State = (CWhip2DCState *)file.heuristics().user_data();
if (!m_State->bLayerVisible)
return WT_Result::Success;
if (m_State->m_alpha>0) // Niet geheel doorzichtig
{
// Zo weinig mogelijk onze penExt gebruiken want die is trager.
// Voor de arcering is hij mogelijk wel nodig
CPoint *vertexList = m_State->new_DWFToLP(polygon);
if (m_State->m_forceBW) // Dan nooit vullen, wel outline
{
HPEN pen = CreatePen(PS_SOLID, 0, RGB(0,0,0)); // Alleen outline tekenen
HPEN pOld = (HPEN)SelectObject(m_State->myDC, pen);
Polyline(m_State->myDC, vertexList, polygon.count());
SelectObject(m_State->myDC, pOld);
DeleteObject(pen);
}
else if (m_State->m_alpha==255) // Normal polygon
{
HPEN pen = CreatePen(PS_NULL, 0, RGB(0,0,0)); // Geen outline tekenen
HPEN pOld = (HPEN)SelectObject(m_State->myDC, pen);
Polygon(m_State->myDC, vertexList, polygon.count());
SelectObject(m_State->myDC, pOld);
DeleteObject(pen);
}
else
m_State->AlphaPolygon(vertexList, polygon.count());
}
return WT_Result::Success;
}
WT_Result CWhip2DCImpl::my_process_polygon_find (WT_Polygon & polygon, WT_File & file)
{
CWhip2DCState *m_State = (CWhip2DCState *)file.heuristics().user_data();
if (!m_State->bLayerVisible)
return WT_Result::Success;
// Kijk of we het punt gevonden hebben
if (CSLNKContourImpl::PointInPolygon(m_State->DWFfindXY, polygon))
{
m_State->foundNode = file.rendition().object_node();
CSLNKContourImpl::EdgeAngle(m_State->DWFfindXY, polygon, m_State->foundEdgeAngle, m_State->foundEdgeDistance);
double scale = file.rendition().viewport().viewport_units().application_to_dwf_transform()(0,0);
m_State->foundEdgeDistance /= scale;
WT_Integer32 layer_num = file.rendition().layer().layer_num();
WT_Layer *ll = file.layer_list().find_layer_from_index(layer_num);
if (ll&&ll->layer_name().ascii())
{
myTRACE("op laag '%s'", ll->layer_name().ascii());
m_State->foundNodeLayer = ll->layer_name().ascii();
}
}
#if 0
Werkt niet goed: het (b)lijkt dat bij clipbox altijd leeg is (omdat we geen bitmap in de DC hebben?)
// Imagemap opbouwen. Alleen voor die entiteiten die (deels) in beeld zijn
WT_Logical_Box bx = polygon.bounds(&file);
CRect rc(m_State->DWFToLP(bx.minpt()), m_State->DWFToLP(bx.maxpt()));
CRect clip;
GetClipBox(m_State->myDC,&clip);
CRect res;
if (!res.IntersectRect(clip, rc)) // Niet geheel erbuiten
return WT_Result::Success; // Toch niet zichtbaar
#endif
// Achterwaarts opbouwen. Laatste getekende staat dan vooraan de Map
// en wordt als eerste gevonden
m_State->MapBuilder = PolyToMap(polygon,
file.rendition().object_node(),
file.rendition().url(),
m_State ) + m_State->MapBuilder;
return WT_Result::Success;
}
WT_Result CWhip2DCImpl::my_process_polymarker (WT_Polymarker & polymarker, WT_File & file)
{
CWhip2DCState *m_State = (CWhip2DCState *)file.heuristics().user_data();
if (!m_State->bLayerVisible)
return WT_Result::Success;
// TODO: Dit moet nog beter. Kleur en zo en de goede markers
//if (file.rendition().m_marker_symbol()
for (int i = 0; i < polymarker.count(); i++)
{
CPoint acPt = m_State->DWFToLP(polymarker.points()[i]);
SetPixel(m_State->myDC, acPt.x, acPt.y, RGB(128,128,128));
#ifdef _DEBUG
m_State->Marker(acPt);
#endif
}
return WT_Result::Success;
}
// Wordt bijvoorbeeld gegenereerd voor ScalaSans truetype teksten die gerenderd worden
WT_Result CWhip2DCImpl::my_process_contourSet (WT_Contour_Set & contourSet, WT_File & file)
{
CWhip2DCState *m_State = (CWhip2DCState *)file.heuristics().user_data();
if (!m_State->bLayerVisible)
return WT_Result::Success;
CPoint *vertexList = m_State->new_DWFToLP(WT_Point_Set(contourSet.total_points(), contourSet.points(), false));
PolyPolygon(m_State->myDC, vertexList, (int *)contourSet.counts(), contourSet.contours()); // No Alpha support
return WT_Result::Success;
}
// Gesignaleerd: locatie.dwf kleine roze solid cirkels
// en H_BRNDMLDR.dwf (overshoots na verkleining?)
WT_Result CWhip2DCImpl::my_process_polytriangle (WT_Polytriangle & polytriangle, WT_File & file)
{
CWhip2DCState *m_State = (CWhip2DCState *)file.heuristics().user_data();
if (!m_State->bLayerVisible)
return WT_Result::Success;
SetPolyFillMode(m_State->myDC, ALTERNATE);
CPoint *vertexList = m_State->new_DWFToLP(WT_Point_Set(polytriangle.count(), polytriangle.points(), false));
// Het volgende is wel iets efficienter maar werkt niet goed omdat
// de volgorde van de punten van de triangles niet netjes een polygon vormt
// Eigenlijk moet het echter wel: wij krijgen nu een outline om iedere triangle
// wat niet de boeling is
// Polygon(m_State->myDC, vertexList, polytriangle.count());
// return WT_Result::Success;
//HPEN pOld = (HPEN)SelectObject(m_State->myDC, m_State->m_penExt);
for (int i = 0; i < polytriangle.count()-2; i++)
{
Polygon(m_State->myDC, vertexList+i, 3);
}
//SelectObject(m_State->myDC, pOld);
return WT_Result::Success;
}
WT_Result CWhip2DCImpl::my_process_pngGroup4Image (WT_PNG_Group4_Image & pngGroup4Image, WT_File & file)
{
CWhip2DCState *m_State = (CWhip2DCState *)file.heuristics().user_data();
if (!m_State->bLayerVisible)
return WT_Result::Success;
CPoint Pt1 = m_State->DWFToLP(pngGroup4Image.min_corner());
CPoint Pt2 = m_State->DWFToLP(pngGroup4Image.max_corner());
int dx = Pt2.x - Pt1.x;
int dy = Pt1.y - Pt2.y;
if (dx==0 || dy==0)
return WT_Result::Success;
// Is de tekst uberhaubt zichtbaar? Laat anders maar
if (GetDeviceCaps(m_State->myDC, TECHNOLOGY) != DT_METAFILE &&
GetObjectType(m_State->myDC) != OBJ_ENHMETADC)
{
CRect textRect(Pt1, Pt2); // Tikkie grof voor diagonale teksten. Better safe than sorry
if (!RectVisible(m_State->myDC, textRect))
return WT_Result::Success;
}
//CString s;
//s.Format("CWhip2DCImpl::my_process_pngGroup4Image sz=%d dx=%d dy=%d",
// pngGroup4Image.data_size(), dx, dy);
//CmyTimer p(s);
#ifdef USE_CIMAGE
HGLOBAL m_hBuffer = ::GlobalAlloc(GMEM_MOVEABLE, pngGroup4Image.data_size());
if (m_hBuffer)
{
void* pBuffer = ::GlobalLock(m_hBuffer);
if (pBuffer)
{
CopyMemory(pBuffer, pngGroup4Image.data(), pngGroup4Image.data_size());
IStream* pStream = NULL;
if (::CreateStreamOnHGlobal(m_hBuffer, FALSE, &pStream) == S_OK)
{
CImage m_pBitmap;
HRESULT res = m_pBitmap.Load(pStream);
pStream->Release();
if (SUCCEEDED(res))
{
::SetStretchBltMode(m_State->myDC, HALFTONE) ;
m_pBitmap.Draw(m_State->myDC, Pt1.x, Pt2.y, dx, dy);
}
}
::GlobalUnlock(m_hBuffer);
}
::GlobalFree(m_hBuffer);
m_hBuffer = NULL;
}
#else
CxImage img;
DWORD fmt = CXIMAGE_FORMAT_UNKNOWN;
switch (pngGroup4Image.format())
{
case WD_IMAGE_GROUP4X_MAPPED_EXT_OPCODE:
{
fmt = CXIMAGE_FORMAT_UNKNOWN;
break;
}
case WD_IMAGE_GROUP4_BITONAL_EXT_OPCODE:
{
fmt = CXIMAGE_FORMAT_TIF;
break;
}
case WD_IMAGE_PNG_EXT_OPCODE:
{
fmt = CXIMAGE_FORMAT_PNG;
break;
}
}
if (img.Decode((BYTE *) pngGroup4Image.data(),
pngGroup4Image.data_size(),
fmt))
{
if (m_State->m_ClipWidth > 0)
{
double inchWidth = m_State->m_ClipWidth
*(pngGroup4Image.max_corner().m_x - pngGroup4Image.min_corner().m_x)
/(m_State->m_MinMax.maxpt().m_x-m_State->m_MinMax.minpt().m_x);
double dpi=double(img.GetWidth()) / inchWidth;
myDoTRACE("\nGuessing raster dpi: %d", myRound(dpi));
}
// Forceert *niet* transparant
// Telecommunications.dwf heeft iets van transparante PNG's wat niet niets toonde
// (GDI+ deed dat wel goed)
//img.SetTransIndex(-1);
//Draw2 (b)lijkt transparantie (op zwarte achtergrond) alleen goed te doen al we achtergrond/voorgrond zetten
COLORREF keepBk = SetBkColor(m_State->myDC, RGB(255, 255, 255));
COLORREF keepText = SetTextColor(m_State->myDC, RGB(0, 0, 0));
img.Draw2(m_State->myDC, Pt1.x, Pt2.y, dx, dy);
SetBkColor(m_State->myDC, keepBk);
SetTextColor(m_State->myDC, keepText);
}
else
myDoTRACE("\nimg.Decode failed: %s", img.GetLastError());
#endif
return WT_Result::Success;
}
// Wordt gebruikt voor JPG's
WT_Result CWhip2DCImpl::my_process_image (WT_Image & image, WT_File & file)
{
CWhip2DCState *m_State = (CWhip2DCState *)file.heuristics().user_data();
if (!m_State->bLayerVisible)
return WT_Result::Success;
DWORD fmt = CXIMAGE_FORMAT_UNKNOWN;
switch (image.format())
{
case WD_IMAGE_JPEG_EXT_OPCODE:
{
fmt = CXIMAGE_FORMAT_JPG;
break;
}
}
if (image.format() != WD_IMAGE_JPEG_EXT_OPCODE)
{
myTRACE("\nWT_Image format %d not supported", image.format());
return WT_Result::Success;
}
CPoint Pt1 = m_State->DWFToLP(image.min_corner());
CPoint Pt2 = m_State->DWFToLP(image.max_corner());
#ifdef USE_CIMAGE
HGLOBAL m_hBuffer = ::GlobalAlloc(GMEM_MOVEABLE, image.data_size());
if (m_hBuffer)
{
void* pBuffer = ::GlobalLock(m_hBuffer);
if (pBuffer)
{
CopyMemory(pBuffer, image.data(), image.data_size());
IStream* pStream = NULL;
if (::CreateStreamOnHGlobal(m_hBuffer, FALSE, &pStream) == S_OK)
{
CImage m_pBitmap;
HRESULT res = m_pBitmap.Load(pStream);
pStream->Release();
if (SUCCEEDED(res))
{
::SetStretchBltMode(m_State->myDC, HALFTONE) ;
m_pBitmap.Draw(m_State->myDC, Pt1.x, Pt2.y, Pt2.x - Pt1.x, Pt1.y - Pt2.y);
}
}
//m_pBitmap = NULL;
::GlobalUnlock(m_hBuffer);
}
::GlobalFree(m_hBuffer);
m_hBuffer = NULL;
}
#else
CxImage img;
if (img.Decode((BYTE *) image.data(),
image.data_size(),
fmt))
{
if (m_State->m_ClipWidth > 0)
{
double inchWidth = m_State->m_ClipWidth
*(image.max_corner().m_x - image.min_corner().m_x)
/(m_State->m_MinMax.maxpt().m_x-m_State->m_MinMax.minpt().m_x);
double dpi=double(img.GetWidth()) / inchWidth;
myDoTRACE("\nGuessing raster dpi: %d", myRound(dpi));
}
img.Draw2(m_State->myDC, Pt1.x, Pt2.y, Pt2.x - Pt1.x, Pt1.y - Pt2.y);
}
else
myTRACE("\nimg.Decode failed: %s", img.GetLastError());
#endif
return WT_Result::Success;
}
WT_Result CWhip2DCImpl::my_process_polyline (WT_Polyline & polyline, WT_File & file)
{
CWhip2DCState *m_State = (CWhip2DCState *)file.heuristics().user_data();
if (!m_State->bLayerVisible)
return WT_Result::Success;
CPoint *vertexList = m_State->new_DWFToLP(polyline);
Polyline(m_State->myDC, vertexList, polyline.count());
return WT_Result::Success;
}
// Merk op dat alleen TrueType teksten hier getekend worden.
// De SHX fonts worden als losse lijnstukjes gedaan
WT_Result CWhip2DCImpl::my_process_text (WT_Text & text, WT_File & file)
{
CWhip2DCState *m_State = (CWhip2DCState *)file.heuristics().user_data();
if (!m_State->bLayerVisible)
return WT_Result::Success;
// Van Pseudo-teksten weten we de hoogte niet. Zoeken kunnen we er ook niet mee
if (!file.rendition().visibility().visible())
return WT_Result::Success;
CPoint acPt = m_State->DWFToLP(text.position());
if (m_State->m_mul==0)
{ // Heel grof hoogte bepalen voor extents
WT_Logical_Point pt(text.position());
CPoint dummy = m_State->DWFToLP(pt);
pt.m_x += file.rendition().font().height(); // Gok op <20><>n vierkante letter
pt.m_y += file.rendition().font().height();
dummy = m_State->DWFToLP(pt);
}
if (text.string().is_ascii())
{
// myTRACE("\nTekst: %s", text.string().ascii());
#ifdef _DEBUG
//if (!strcmp(text.string().ascii(),"Width scale=1024 (1x)"))
if (!strcmp(text.string().ascii(),"TP036"))
{
int x = 1;
}
#endif
CString txt(text.string().ascii());
if (txt.Trim().GetLength() == 0) // Komt voor bij outlets van AC_C2_0
return WT_Result::Success; // voorkom geeking
if (text.bounds().bounds() != NULL)
{
return m_State->drawBoundText(text, 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_State->m_mul < m_State->geekFontSize)
{
m_State->DrawGeekText(text);
return WT_Result::Success;
}
else
m_State->m_kfm.TextOutSpacing(m_State->myDC, acPt.x, acPt.y,
text.string().ascii(), text.string().length(),
(m_State->m_spacing/1024.0));
//TextOut(m_State->myDC, acPt.x, acPt.y, text.string().ascii(), text.string().length());
}
else
{
if (file.rendition().font().height()*m_State->m_mul >= 0.5)
TextOutW(m_State->myDC, acPt.x, acPt.y, text.string().unicode(), text.string().length());
}
#ifdef _DEBUG
if (m_State->m_mul > 0.1)
m_State->Marker(acPt);
#endif
return WT_Result::Success;
}
WT_Result CWhip2DCImpl::my_process_text_scan (WT_Text & text, WT_File & file)
{
CWhip2DCState *m_State = (CWhip2DCState *)file.heuristics().user_data();
if (!m_State->bLayerVisible)
return WT_Result::Success;
CString txt(text.string().ascii());
if (txt.Trim().GetLength() == 0) // Komt voor bij outlets van AC_C2_0
return WT_Result::Success;
CFoundText tFound;
tFound.m_FoundText = text;
WT_Integer32 layer_num = file.rendition().layer().layer_num();
WT_Layer *ll = file.layer_list().find_layer_from_index(layer_num);
if (ll&&ll->layer_name().ascii())
tFound.m_FoundLayer = ll->layer_name().ascii();
tFound.m_FoundAt = text.position();
m_State->m_FoundTexts.Add(tFound);
return WT_Result::Success;
}
#pragma optimize( "p", on )
WT_Result CWhip2DCImpl::my_process_text_find (WT_Text & text, WT_File & file)
{
CWhip2DCState *m_State = (CWhip2DCState *)file.heuristics().user_data();
if (!m_State->bLayerVisible)
return WT_Result::Success;
if (!file.rendition().visibility().visible())
return WT_Result::Success;
CPoint acPt = m_State->DWFToLP(text.position());
if (!text.string().is_ascii()) // Die kunnen we nog niet aan
return WT_Result::Success;
BOOL found = FALSE;
CPoint LPbounds[4]; // Het echte testen gaan we in LP-coordinaten doen
// (Mooie tussenweg tussen DP en DWF)
double radian = 0.0; // Graden rotatie
// Echte boundingbox heeft voorkeur
if (text.bounds().bounds() != NULL)
{
CPoint pts[]=
{
m_State->DWFToLP(text.bounds().bounds()[0]),
m_State->DWFToLP(text.bounds().bounds()[1]),
m_State->DWFToLP(text.bounds().bounds()[2]),
m_State->DWFToLP(text.bounds().bounds()[3])
};
memcpy(LPbounds, pts, 4*sizeof(CPoint));
//myTRACE("\nZoeken met behulp van text bounds %s", text.string().ascii());
}
else
{
CSize LPSize(0,0);
if (text.string().is_ascii())
{
double w,h;
m_State->m_kfm.GetTextExtent(m_State->myDC, text.string().ascii(), text.string().length(), w, h);
// TODO: De .6 snap ik nog niet maar anders is de box te groot
LPSize = CPoint((int)w, (int)(h*0.6));
//GetTextExtentPoint32(m_State->myDC, text.string().ascii(), text.string().length(), &LPSize);
}
// else
// GetTextExtentPoint32W(m_State->myDC, text.string().unicode(), text.string().length(), &Size);
CPoint pts[]=
{
acPt,
CPoint(acPt.x+LPSize.cx, acPt.y),
CPoint(acPt.x+LPSize.cx, acPt.y-LPSize.cy),
CPoint(acPt.x , acPt.y-LPSize.cy)
};
radian = m_State->m_logfont.lfOrientation * TWO_PI / 3600;
memcpy(LPbounds, pts, 4*sizeof(CPoint));
}
// In plaats van onze box 'goed' draaien gaan we ons testpunt 'fout' draaien. Is simpeler
CPoint dist(m_State->LPfindXY - acPt);
CPoint fnd(acPt);
// Compiler bug? De volgende regels deden het niet goed in release mode:
// fnd.y werd gewoon niet aangepast
// Opgelost door voor deze functie #pragma optimize( "p", on ) te zetten
fnd.x += int(cos(radian) * dist.x - sin(radian) * dist.y);
fnd.y += int(sin(radian) * dist.x + cos(radian) * dist.y);
if (CSLNKContourImpl::PointInPolygon(fnd, LPbounds, 4))
{
m_State->foundTextLabel = text.string().ascii();
// myTRACE("\nVolgens mij geklikt binnen (%d-%d,%d-%d) op '%s'", acPt.x, acPt.y, acPt.x+Size.cx, acPt.y+Size.cy, text.string().ascii());
WT_Integer32 layer_num = file.rendition().layer().layer_num();
WT_Layer *ll = file.layer_list().find_layer_from_index(layer_num);
if (ll&&ll->layer_name().ascii())
{
myTRACE("op laag '%s'", ll->layer_name().ascii());
m_State->foundTextLayer = ll->layer_name().ascii();
}
}
return WT_Result::Success;
}
WT_Result CWhip2DCImpl::my_process_background (WT_Background & background, WT_File & file)
{
CWhip2DCState *m_State = (CWhip2DCState *)file.heuristics().user_data();
if (m_State->m_forcePaper) // Wissen is al wel gedaan
return WT_Result::Success;
WT_RGBA32 clr;
if (background.color().index() == WD_NO_COLOR_INDEX)
clr = background.color().rgba();
else
clr = file.rendition().color_map().map(background.color().index());
COLORREF DCclr = RGB(clr.m_rgb.r, clr.m_rgb.g, clr.m_rgb.b);
m_State->m_paperColor = DCclr; // Wordt later misschien opgevraagd.
if (m_State->findIt) // When finding no need for actuel painting
return WT_Result::Success;
m_State->erasePaper(file);
return WT_Result::Success;
}
// poor mans Gouraud shading
#if 0
COLORREF avgColor (WT_Gouraud_Point_Set & gouraudPointSet)
{
int r=0,g=0,b=0;
for (int i = 0; i < gouraudPointSet.count(); i++)
{
WT_RGBA32 clr = gouraudPointSet.colors()[i];
r+=clr.m_rgb.r;
g+=clr.m_rgb.g;
b+=clr.m_rgb.b;
}
COLORREF DCclr;
DCclr = RGB(r/gouraudPointSet.count(),
g/gouraudPointSet.count(),
b/gouraudPointSet.count());
return DCclr;
}
void shadedline (int x1, int firstcolor, int x2, int lastcolor, int y)
{
int length;
int numcolors;
int colorvalue;
int step;
int x;
length = x2 - x1 + 1;
if (length > 0)
{
numcolors = lastcolor - firstcolor + 1;
colorvalue = firstcolor << 8;
step = ((long)numcolors << 8) / (long)length;
for (x = x1; x <= x2; x++)
{
drawpixel (x, y, colorvalue >> 8);
colorvalue += step;
}
}
}
#endif
WT_Result CWhip2DCImpl::my_process_gouraudPolyline (WT_Gouraud_Polyline & gouraudPolyline, WT_File & file)
{
CWhip2DCState *m_State = (CWhip2DCState *)file.heuristics().user_data();
if (!m_State->bLayerVisible)
return WT_Result::Success;
//myTRACE("\n !! Don't know how to handle gouraudPolyline very well yet!! (%d points)", gouraudPolyline.count());
#if 1
int w=myRound(file.rendition().line_weight().weight_value()*m_State->m_mul);
WT_RGBA32 prev_clr;
CPoint prev_pt;
for (int i = 0; i < gouraudPolyline.count(); i++)
{
WT_RGBA32 clr = gouraudPolyline.colors()[i];
CPoint pt = m_State->DWFToLP(gouraudPolyline.points()[i]);
if (i > 0)
{
//int dv = myRound(_hypot(pt.x-prev_pt.x,pt.y-prev_pt.y) / 10); // Om de 10 pixels is goed zat
int dv = 10; // Toch maar altijd 10 stuks
int j;
for (j = 0; j < dv; j++)
{
COLORREF DCclr = RGB((clr.m_rgb.r*j + prev_clr.m_rgb.r*(dv-j))/dv,
(clr.m_rgb.g*j + prev_clr.m_rgb.g*(dv-j))/dv,
(clr.m_rgb.b*j + prev_clr.m_rgb.b*(dv-j))/dv);
m_State->m_pen = CreatePen (PS_SOLID, w, DCclr);
HPEN oldpen = (HPEN) SelectObject(m_State->myDC, m_State->m_pen);
DeleteObject(oldpen);
LineTo(m_State->myDC, myRound(((double)pt.x*j+prev_pt.x*(dv-j))/dv),
myRound(((double)pt.y*j+prev_pt.y*(dv-j))/dv));
}
}
else
MoveToEx(m_State->myDC, pt.x, pt.y, NULL);
prev_pt = pt;
prev_clr = clr;
}
return WT_Result::Success;
#endif
#if 0
COLORREF DCclr = RGB(0,0,0);
DCclr = avgColor(gouraudPolyline);
int w=myRound(file.rendition().line_weight().weight_value()*m_State->m_mul);
m_State->m_pen = CreatePen (PS_SOLID, w, DCclr);
HPEN oldpen = (HPEN) SelectObject(m_State->myDC, m_State->m_pen);
DeleteObject(oldpen);
CPoint *vertexList = m_State->new_DWFToLP(gouraudPolyline);
Polyline(m_State->myDC, vertexList, gouraudPolyline.count());
return WT_Result::Success;
#endif
#if 0
// TODO: Dit is natuurlijk gewoon een gedegenereerde gouraudPolytriangle!
// maar die lijkt GradientFill niet te tekenen?
// Waarschijnlijk: "Triangle drawing is lower-right exclusive"
TRIVERTEX *vert = new TRIVERTEX[2*gouraudPolyline.count()];
GRADIENT_TRIANGLE *gTri = new GRADIENT_TRIANGLE[gouraudPolyline.count()];
for (int i = 0; i < gouraudPolyline.count(); i++)
{
WT_RGBA32 clr = gouraudPolyline.colors()[i];
vert[2*i].x = m_State->DWFToLP(gouraudPolyline.points()[i]).x;
vert[2*i].y = m_State->DWFToLP(gouraudPolyline.points()[i]).y;
// Pas op: TRIVERTEX verwacht 16 bit RGB!
vert[2*i].Red = clr.m_rgb.r<<8;
vert[2*i].Green = clr.m_rgb.g<<8;
vert[2*i].Blue = clr.m_rgb.b<<8;
vert[2*i+1].x = m_State->DWFToLP(gouraudPolyline.points()[i]).x;
vert[2*i+1].y = m_State->DWFToLP(gouraudPolyline.points()[i]).y+1;
// Pas op: TRIVERTEX verwacht 16 bit RGB!
vert[2*i+1].Red = clr.m_rgb.r<<8;
vert[2*i+1].Green = clr.m_rgb.g<<8;
vert[2*i+1].Blue = clr.m_rgb.b<<8;
vert[i].Alpha = clr.m_rgb.a<<8;
gTri[i].Vertex1 = 2*i;
gTri[i].Vertex2 = 2*(i+1);
gTri[i].Vertex3 = 2*(i+1)+1;
}
GradientFill(m_State->myDC,vert,2*gouraudPolyline.count(),
gTri,gouraudPolyline.count()-2,GRADIENT_FILL_TRIANGLE);
delete [] vert;
delete [] gTri;
#endif
return WT_Result::Success;
}
WT_Result CWhip2DCImpl::my_process_gouraudPolytriangle (WT_Gouraud_Polytriangle & gouraudPolytriangle, WT_File & file)
{
CWhip2DCState *m_State = (CWhip2DCState *)file.heuristics().user_data();
if (!m_State->bLayerVisible)
return WT_Result::Success;
TRIVERTEX *vert = new TRIVERTEX[gouraudPolytriangle.count()];
GRADIENT_TRIANGLE *gTri = new GRADIENT_TRIANGLE[gouraudPolytriangle.count()];
for (int i = 0; i < gouraudPolytriangle.count(); i++)
{
WT_RGBA32 clr = gouraudPolytriangle.colors()[i];
vert[i].x = m_State->DWFToLP(gouraudPolytriangle.points()[i]).x;
vert[i].y = m_State->DWFToLP(gouraudPolytriangle.points()[i]).y;
// Pas op: TRIVERTEX verwacht 16 bit RGB!
vert[i].Red = clr.m_rgb.r<<8;
vert[i].Green = clr.m_rgb.g<<8;
vert[i].Blue = clr.m_rgb.b<<8;
vert[i].Alpha = clr.m_rgb.a<<8;
gTri[i].Vertex1 = i;
gTri[i].Vertex2 = i+1;
gTri[i].Vertex3 = i+2;
}
// Zal geloof ik niet werken op Windows 95...
GradientFill(m_State->myDC,vert,gouraudPolytriangle.count(),
gTri,gouraudPolytriangle.count()-2,GRADIENT_FILL_TRIANGLE);
delete [] vert;
delete [] gTri;
return WT_Result::Success;
}
WT_Result CWhip2DCImpl::my_process_fillPattern (WT_Fill_Pattern & fillPattern, WT_File & file)
{
WT_Fill_Pattern::default_process(fillPattern, file);
file.rendition().fill_pattern() = fillPattern; // Dit doet de default niet (goed)!!
CWhip2DCState *m_State = (CWhip2DCState *)file.heuristics().user_data();
m_State->ColorPenAndBrush(file);
return WT_Result::Success;
}
STDMETHODIMP CWhip2DCImpl::get_LayerCount(LONG* pVal)
{
(*pVal) = (LONG)m_State.m_Layernames.GetCount();
return S_OK;
}
STDMETHODIMP CWhip2DCImpl::get_TextCount(LONG* pVal)
{
(*pVal) = (LONG)m_State.m_FoundTexts.GetCount();
return S_OK;
}
STDMETHODIMP CWhip2DCImpl::get_TextItem(LONG i, CFoundText &pVal)
{
if (i<0 || i>=(LONG)m_State.m_FoundTexts.GetCount())
return E_INVALIDARG;
pVal = m_State.m_FoundTexts.GetAt(i);
return S_OK;
}
STDMETHODIMP CWhip2DCImpl::get_LayerItem(LONG i, CString* pVal)
{
if (i<0 || i>=(LONG)m_State.m_Layernames.GetCount())
return E_INVALIDARG;
(*pVal) = m_State.m_Layernames.GetAt(i);
return S_OK;
}
STDMETHODIMP CWhip2DCImpl::get_paperColor(LONG* pVal)
{
(*pVal) = m_State.m_paperColor;
return S_OK;
}
STDMETHODIMP CWhip2DCImpl::put_paperColor(LONG newVal)
{
m_State.m_forcePaper = true;
m_State.m_paperColor = newVal;
return S_OK;
}
STDMETHODIMP CWhip2DCImpl::ReplaceColor(LONG paperColor, LONG oldColor, LONG newColor)
{
m_State.m_replaceColors[paperColor] = CFromTo(oldColor, newColor);
return S_OK;
}