// 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 int 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*/) { 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_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); 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 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; } int CWhip2DCImpl::Paint(VARIANT_BOOL forceBW, VARIANT_BOOL markers /* = VARIANT_FALSE */) { #ifdef _DEBUG /// CneutralGDI neutralGDI("CWhip2DCImpl::Paint"); #endif //#define EXPERIMENT // Helaas: bij sterk inzoomen (lijkt: m_mul > 1) komen er af en toe zwarte // randen in de viewer te voorschijn #ifdef EXPERIMENT SetMapMode(m_State.myDC, MM_ANISOTROPIC); SIZE wsz, vsz; if (m_State.m_mul < 1.0) { SetWindowExtEx(m_State.myDC, myRound(m_State.m_Size.cx / m_State.m_mul), myRound(m_State.m_Size.cy / m_State.m_mul), &wsz); SetViewportExtEx(m_State.myDC, m_State.m_Size.cx, m_State.m_Size.cy, &vsz); } else { SetWindowExtEx(m_State.myDC, m_State.m_Size.cx, m_State.m_Size.cy, &wsz); SetViewportExtEx(m_State.myDC, myRound(m_State.m_Size.cx * m_State.m_mul), myRound(m_State.m_Size.cy * m_State.m_mul), &vsz); } m_State.m_mul = 1.0; int mm = GetMapMode(m_State.myDC); #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 // Voortschrijdend inzicht: doorgeven van (void *)this was eigenlijk // veel praktischer geweest. Bij whipfile.cpp doen we dat al sinds // 2.80 maar hier is me dat nog even te veel werk. 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) { 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 markers = VARIANT_TRUE; #endif if (markers) { // 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 } return S_OK; } // Zoek alle teksten in de tekening op en lever ze op als array int 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 *****************************************************************************/ int CWhip2DCImpl::Find(LONG findX, LONG findY, BYTE AsMap, CString & pContourKey, 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) pContourKey = m_State.MapBuilder; else { if (m_State.foundTextLabel != "") { pTextLabel = m_State.foundTextLabel; pTextLayer = m_State.foundTextLayer; } if (m_State.foundNode.object_node_name()) { pContourKey = 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!! int 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!! int 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(); CString layer_name(layer.layer_name().ascii()); file.rendition().layer() = layer; WT_Layer *ll; if (layer_name != "") // Anders zittie alleen maar in de weg { // Dat doet de default_process 'fout' // Overbodige lagen negeren we: if (layer_name == m_State->m_activeLayerName) return WT_Result::Success; file.layer_list().add_layer(layer); ll = &layer; if (m_State->m_Layernames.Find(layer.layer_name().ascii()) < 0) m_State->m_Layernames.Add(layer.layer_name().ascii()); } else { WT_Integer32 layer_num = layer.layer_num(); ll = file.layer_list().find_layer_from_index(layer_num); } if (ll) { // Overbodige lagen negeren we: if (ll->layer_name().ascii() == m_State->m_activeLayerName) return WT_Result::Success; m_State->m_activeLayerName = 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(m_State->m_activeLayerName, &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 = (m_State->m_activeLayerName == "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 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 (objKey != "") { // SLNKSymbolKey voor FACILITOR 5.3.1 backward compatible if (m_State->bIsSymbolLayer) smbl.Format(" SLNKSymbolKey=\"%s\" SLNKKey=\"%s\"", objKey, objKey); else smbl.Format(" SLNKKey=\"%s\"", objKey); } CString Builder; Builder.Format("\n", smbl, Title, shape, Coords, Href); 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; // Die is veel sneller en dunner en heeft geen last van Miter/overshooting spikes HPEN ThinPen = CreatePen(PS_SOLID, 0, GetTextColor(m_State->myDC)); HPEN pOld = (HPEN)SelectObject(m_State->myDC, ThinPen); //Het volgende is een alternatief voor ThinPen //FLOAT oldMiter; //SetMiterLimit(m_State->myDC, 1.0, &oldMiter); for (int i = 0; i < polytriangle.count()-2; i++) { Polygon(m_State->myDC, vertexList+i, 3); } //SetMiterLimit(m_State->myDC, oldMiter, NULL); SelectObject(m_State->myDC, pOld); DeleteObject(ThinPen); 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 éé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; } int CWhip2DCImpl::get_LayerCount(LONG* pVal) { (*pVal) = (LONG)m_State.m_Layernames.GetSize(); return S_OK; } int CWhip2DCImpl::get_TextCount(LONG* pVal) { (*pVal) = (LONG)m_State.m_FoundTexts.GetCount(); return S_OK; } int 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; } int CWhip2DCImpl::get_LayerItem(LONG i, CString* pVal) { if (i<0 || i>=(LONG)m_State.m_Layernames.GetSize()) return E_INVALIDARG; (*pVal) = m_State.m_Layernames[i]; return S_OK; } int CWhip2DCImpl::get_paperColor(LONG* pVal) { (*pVal) = m_State.m_paperColor; return S_OK; } int CWhip2DCImpl::put_paperColor(LONG newVal) { m_State.m_forcePaper = true; m_State.m_paperColor = newVal; return S_OK; } int CWhip2DCImpl::ReplaceColor(LONG paperColor, LONG oldColor, LONG newColor) { m_State.m_replaceColors[paperColor] = CFromTo(oldColor, newColor); return S_OK; }