1365 lines
46 KiB
C++
1365 lines
46 KiB
C++
/******************************************************************************
|
||
* File : WhipFile.cpp (c) 2005-2011, SG|Facilitor
|
||
*
|
||
* Author : J. Groot Lipman
|
||
* Project : SLNKDWF
|
||
* Version : 2.xx
|
||
*
|
||
* Function : Implementeert class CWhipFile
|
||
* CWhipfile biedt functionaliteit om een bestaande DWF te
|
||
* manipuleren en het resultaat op te slaan als een nieuwe DWF
|
||
* - Contouren kunnen herkend worden (polygon op goede laag
|
||
* met een label erin op de goede laag)
|
||
* - Deze contouren kunnen gemanipuleerd worden (kleuren bijv)
|
||
* - Deze labels kunnen gemanipuleerd worden (text, positie)
|
||
* - Deze contouren worden bij het wegschrijven 'gewrapped' in
|
||
* een node objecten. Deze wordt opgeleverd door Whip2DC bij
|
||
* aanwijzen
|
||
* - Symbolen kunnen worden toegevoegd
|
||
*****************************************************************************/
|
||
|
||
#include "stdafx.h"
|
||
#include "myEPlotSection.h"
|
||
#include "WhipFile.h"
|
||
#include "SLNKContour.h"
|
||
|
||
//
|
||
// WHIPFILE.CPP
|
||
//
|
||
// This file defines class CWhipFile
|
||
// which is mostly concerned with detecting closed contours
|
||
// and merging a Contour file with a planfile. <<= jun 2007: al lang obsolete
|
||
//
|
||
|
||
// CWhipFile
|
||
|
||
const WT_Logical_Point CWhipFile::star[] =
|
||
{ WT_Logical_Point(-1000, 0),
|
||
WT_Logical_Point( -200, 200),
|
||
WT_Logical_Point( 0, 1000),
|
||
WT_Logical_Point( 200, 200),
|
||
WT_Logical_Point( 1000, 0),
|
||
WT_Logical_Point( 200, -200),
|
||
WT_Logical_Point( 0,-1000),
|
||
WT_Logical_Point( -200, -200),
|
||
WT_Logical_Point(-1000, 0)
|
||
};
|
||
|
||
const WT_Logical_Point CWhipFile::octa[] =
|
||
{ WT_Logical_Point( 1000, 414),
|
||
WT_Logical_Point( 414, 1000),
|
||
WT_Logical_Point( -414, 1000),
|
||
WT_Logical_Point(-1000, 414),
|
||
WT_Logical_Point(-1000, -414),
|
||
WT_Logical_Point( -414,-1000),
|
||
WT_Logical_Point( 414,-1000),
|
||
WT_Logical_Point( 1000, -414),
|
||
WT_Logical_Point( 1000, 414)
|
||
};
|
||
|
||
const WT_Logical_Point CWhipFile::square[] =
|
||
{ WT_Logical_Point( 0, 0),
|
||
WT_Logical_Point( 0, 1000),
|
||
WT_Logical_Point( 1000, 1000),
|
||
WT_Logical_Point( 1000, 0),
|
||
WT_Logical_Point( 0, 0)
|
||
};
|
||
|
||
const WT_Logical_Point CWhipFile::empty[] = // Lege contour
|
||
{ WT_Logical_Point( INT_MAX, INT_MAX)
|
||
};
|
||
|
||
CWhipFile::CWhipFile()
|
||
{
|
||
m_FontName.set("Arial");
|
||
m_FontHeight = 400.0;
|
||
m_FontHeightSymbols = 200.0;
|
||
|
||
m_reContouren.Parse(".*", FALSE);
|
||
m_reLabels.Parse(".*", FALSE);
|
||
m_reLayers.Parse(".*", FALSE);
|
||
m_hintScale = -1.0;
|
||
m_minContSize = 0.20e6; // Minimale opp om herkend te worden.
|
||
m_forFind = TRUE; // backward compatible
|
||
m_activeLayerName = "";
|
||
m_vdpi = 0;
|
||
|
||
// Predefine fixed symbols
|
||
// Merk op dat m_contunits hier nog gewoon de default identity matrix is
|
||
CSLNKSymbolDefinition * symb = new CSLNKSymbolDefinition(sizeof(star)/sizeof(star[0]), star, m_contunits);
|
||
m_SLNKSymbolDefinitions.SetAt("*STAR", symb);
|
||
|
||
symb = new CSLNKSymbolDefinition(sizeof(octa)/sizeof(octa[0]), octa, m_contunits);
|
||
m_SLNKSymbolDefinitions.SetAt("*OCTAGON", symb);
|
||
|
||
symb = new CSLNKSymbolDefinition(sizeof(square)/sizeof(square[0]), square, m_contunits);
|
||
m_SLNKSymbolDefinitions.SetAt("*SQUARE", symb);
|
||
|
||
symb = new CSLNKSymbolDefinition(sizeof(empty)/sizeof(empty[0]), empty, m_contunits);
|
||
m_SLNKSymbolDefinitions.SetAt("*EMPTY", symb);
|
||
}
|
||
|
||
int xxxx;
|
||
STDMETHODIMP CWhipFile::InterfaceSupportsErrorInfo(REFIID riid)
|
||
{
|
||
static const IID* arr[] =
|
||
{
|
||
&IID_IWhipFile
|
||
};
|
||
|
||
for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++)
|
||
{
|
||
if (InlineIsEqualGUID(*arr[i],riid))
|
||
return S_OK;
|
||
}
|
||
return S_FALSE;
|
||
}
|
||
|
||
// Open de contour file
|
||
STDMETHODIMP CWhipFile::Load(BSTR WhipPath)
|
||
{
|
||
myDoTRACE("\nCWhipFile::Open('%ls')", WhipPath);
|
||
|
||
m_W2DFile.set_filename(WhipPath);
|
||
|
||
return ProcessContouren();
|
||
}
|
||
|
||
|
||
// Set xc = CreateObject("SLNKDWF.DWFFile")
|
||
// xc.Open(dwfFile)
|
||
// Set y = CreateObject("SLNKDWF.WhipFile")
|
||
// y.LoadStream xc.EplotSections.Item(0)
|
||
STDMETHODIMP CWhipFile::LoadStream(VARIANT EPlotStream)
|
||
{
|
||
myDoTRACE("\nCCWhipFile::LoadStream()");
|
||
|
||
if (EPlotStream.vt!=VT_ERROR)
|
||
{
|
||
VARIANT *var2 = &EPlotStream;
|
||
if (var2->vt==(VT_VARIANT|VT_BYREF)) // ByRef
|
||
var2 = (VARIANT *)var2->pvarVal;
|
||
|
||
if (var2->vt==VT_DISPATCH)
|
||
{
|
||
CComQIPtr<IEPlotSection> EPlotSection;
|
||
EPlotSection = var2->pdispVal;
|
||
if (!EPlotSection)
|
||
return E_INVALIDARG;
|
||
else
|
||
{
|
||
m_iEPlotSection = EPlotSection;
|
||
CEPlotSectionImpl *epli;
|
||
m_iEPlotSection->get_EPlotSectionImpl((BYTE **)&epli);
|
||
m_W2DFile.set_eplotsection(epli);
|
||
}
|
||
}
|
||
else
|
||
return E_INVALIDARG;
|
||
}
|
||
|
||
return ProcessContouren();
|
||
}
|
||
|
||
void comment(myWT_File &my_file, const char *str)
|
||
{
|
||
if (!my_file.m_ascii)
|
||
return;
|
||
WT_Comments cmt;
|
||
cmt.set(str);
|
||
cmt.serialize(my_file);
|
||
}
|
||
|
||
HRESULT CWhipFile::ProcessContouren()
|
||
{
|
||
m_W2DFile.set_file_mode(WT_File::File_Read);
|
||
|
||
// Alle callback functies zijn static. Die kunnen de member-variabelen
|
||
// niet benaderen. Daarom maar via set_user_data onzelf doorgeven
|
||
// (voor 2.80 deden we dat complexer via een m_State)
|
||
m_W2DFile.heuristics().set_user_data((void *)this);
|
||
|
||
if (m_W2DFile.open() == WT_Result::Success)
|
||
{ xxxx=0;
|
||
CmyTimer xx("Contouren opzoeken");
|
||
m_contLayerActive = true;
|
||
m_labelLayerActive = true; // Kan bij de eerste laag anders blijken te zijn
|
||
|
||
read_for_contours(); // Zoek eerst alle contouren en labels
|
||
processLabels(); // En verwerk ze daarna
|
||
myDoTRACE("\nFound %d polylines, %d contours and %d labels.", xxxx, m_SLNKContouren.GetCount(), m_SLNKLabels.GetCount());
|
||
|
||
m_W2DFile.close(); // closing Input file.
|
||
|
||
double ClipWidth, ClipHeight;
|
||
m_iEPlotSection->get_PaperClipWidth(&ClipWidth);
|
||
m_iEPlotSection->get_PaperClipHeight(&ClipHeight);
|
||
if (ClipWidth > 0 && ClipHeight > 0)
|
||
{
|
||
double dwfDx = m_view.view().m_max.m_x - m_view.view().m_min.m_x;
|
||
double dwfDy = m_view.view().m_max.m_y - m_view.view().m_min.m_y;
|
||
m_vdpi = myRound(max(dwfDx / ClipWidth, dwfDy / ClipHeight));
|
||
myDoTRACE("\nGuessing vector dpi: %d", m_vdpi);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
return myAtlReportError (GetObjectCLSID(), "ERROR CWhipFile:: Unable to open file/stream:");
|
||
}
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP CWhipFile::SetLayers(BSTR reContouren, BSTR reLabels)
|
||
{
|
||
myTRACE("\nParsing met contouren %ls", reContouren);
|
||
myTRACE("\nParsing met labels %ls", (LPCTSTR)reLabels);
|
||
|
||
REParseError status = m_reContouren.Parse( CString(reContouren), false );
|
||
if (REPARSE_ERROR_OK != status)
|
||
return myAtlReportError (GetObjectCLSID(), "ERROR: Unable to parse Whipfile contour regLayers");
|
||
|
||
status = m_reLabels.Parse( CString(reLabels), false );
|
||
if (REPARSE_ERROR_OK != status)
|
||
return myAtlReportError (GetObjectCLSID(), "ERROR: Unable to parse Whipfile label regLayers");
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
// Lagen die over moeten blijven. De rest wordt er uit gestript.
|
||
STDMETHODIMP CWhipFile::SetFilterLayers(BSTR reLayers)
|
||
{
|
||
myTRACE("\nFilter met lagen %ls", reLayers);
|
||
|
||
REParseError status = m_reLayers.Parse( CString(reLayers), false );
|
||
if (REPARSE_ERROR_OK != status)
|
||
return myAtlReportError (GetObjectCLSID(), "ERROR: Unable to parse Whipfile SetFilterLayers");
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
// LUDE#30224
|
||
// Vectorworks tekeningen blijken wel eens een (negatieve) z-component in de units te hebben
|
||
// Met forse tegenzin corrigeer ik dat door hem hier op 1.0 te zetten
|
||
// Merk op: alle AutoCAD dwf's die ik ooit zag hebben hem al op 1.0 staan
|
||
WT_Units fixUnits(const WT_Units orgunits)
|
||
{
|
||
WT_Matrix matrix = orgunits.application_to_dwf_transform();
|
||
matrix(2, 2) = 1.0;
|
||
return WT_Units(matrix, orgunits.units());
|
||
}
|
||
|
||
void CWhipFile::read_for_contours()
|
||
{
|
||
WT_Result result;
|
||
|
||
m_W2DFile.set_text_action(my_process_text);
|
||
m_W2DFile.set_polyline_action(my_process_polyline);
|
||
|
||
// Shiften tijdens *inlezen* om overflow te voorkomen
|
||
// Problemen: hoe achterhaal je op een nette manier zo vroeg hoeveel je moet shiften
|
||
// (uit DWFGraphicResoure.transform() voelt niet goed)
|
||
// Bovendien werkt de transform niet op de Viewport/Units zodat dwf2dwg conversie niet klopt
|
||
// WT_Logical_Point lshift(m_W2DFile.lshift()[0] - 1, m_W2DFile.lshift()[1] - 1);
|
||
// m_W2DFile.heuristics().set_transform(WT_Transform(lshift, 1.0, 1.0, 0));
|
||
// y:\Library\Dwf770\develop\global\src\dwf\whiptk\heuristics.h
|
||
// This is only used when writing to a file. This method is not applicable in a read mode.
|
||
// anders zou ik het graag tijdens inlezen al doen om overflow problemen veel vroeger te voorkomen
|
||
// Toch lijkt het al te werken?
|
||
// m_W2DFile.heuristics().set_apply_transform(true);
|
||
|
||
// AutoCAD does not generate polygon's for closed polylines
|
||
// It only does for filled SOLID hatching
|
||
//m_W2DFile.set_polygon_action(my_process_polygon);
|
||
//m_W2DFile.set_polytriangle_action(my_process_polytriangle);
|
||
m_W2DFile.set_layer_action(my_process_layer);
|
||
// Do the actual reading.
|
||
do {
|
||
result = m_W2DFile.process_next_object();
|
||
} while (result == WT_Result::Success);
|
||
|
||
// Nu zijn ze wel een keer bekend, we hebben ze later weer nodig
|
||
// m_contunits=m_W2DFile.rendition().drawing_info().units();werkt niet goed met paperspace
|
||
// Deze doet het in de praktijk altijd wel?
|
||
m_contunits = fixUnits(m_W2DFile.rendition().viewport().viewport_units());
|
||
|
||
m_view=m_W2DFile.rendition().rendering_options().view();
|
||
|
||
// We gaan er later nog een keer door voor de plattegrond. Geen processing dan
|
||
m_W2DFile.set_text_action(WT_Text::default_process);
|
||
m_W2DFile.set_polyline_action(WT_Polyline::default_process);
|
||
}
|
||
|
||
// Result: Area in original drawing coordinates
|
||
// Veronderstel dat het laatste punt gelijk is aan het eerste
|
||
double PolygonArea(WT_Point_Set * ps, WT_Units units)
|
||
{
|
||
int i,j;
|
||
double area = 0;
|
||
|
||
for (i=0;i<ps->count();i++) {
|
||
j = (i + 1) % ps->count();
|
||
WT_Point3D dwfPtA = units.transform(ps->points()[i]);
|
||
WT_Point3D dwfPtB = units.transform(ps->points()[j]);
|
||
|
||
area += dwfPtA.m_x * dwfPtB.m_y;
|
||
area -= dwfPtA.m_y * dwfPtB.m_x;
|
||
}
|
||
|
||
area /= 2;
|
||
return(area < 0 ? -area : area);
|
||
}
|
||
|
||
// Iterate all labels and determine in which contour they fall
|
||
void CWhipFile::processLabels()
|
||
{
|
||
for (size_t lbl=0; lbl<m_SLNKLabels.GetCount(); lbl++)
|
||
{
|
||
WT_Text text = m_SLNKLabels[lbl];
|
||
|
||
// Find inside which Polygon it falls
|
||
// When multiple: choose smallest!
|
||
CSLNKContourImpl *prevContour = NULL;
|
||
for (size_t i=0; i<m_SLNKContouren.GetCount(); i++)
|
||
{
|
||
CSLNKContourImpl *contour= (m_SLNKContouren[i]);
|
||
if (CSLNKContourImpl::PointInPolygon(text.position(), *contour))
|
||
{
|
||
myTRACE("\n%s with area %8.2fm2", text.string().ascii(), contour->m_DWGArea/1e6);
|
||
if (contour->m_contLabel.length()==0)
|
||
{
|
||
if (prevContour != NULL)
|
||
{
|
||
myTRACE(" Hmm, we hadden al eerder succes");
|
||
if (prevContour->m_DWGArea > contour->m_DWGArea)
|
||
{
|
||
myTRACE(" en we hebben een kleinere. Reset prevContour");
|
||
prevContour->m_contLabel = "";
|
||
prevContour->m_ShowLabel = "";
|
||
prevContour->m_Key = "";
|
||
prevContour = contour;
|
||
}
|
||
else // Nieuwe contour is niet beter
|
||
{
|
||
contour = prevContour;
|
||
}
|
||
}
|
||
else
|
||
prevContour = contour;
|
||
prevContour->m_Key = text.string().ascii();
|
||
// Spaties voor of achteraan geven op de lange termijn
|
||
// problemen als we via XML communiceren
|
||
prevContour->m_Key.Trim();
|
||
prevContour->m_contLabel = prevContour->m_Key;
|
||
prevContour->m_ShowLabel = prevContour->m_Key;
|
||
#ifdef SHAKE_FOR_TEST
|
||
if (1||prevContour->m_Label.equals("x706"))
|
||
{
|
||
srand( (unsigned)time( NULL ) );
|
||
int i;
|
||
for (i=0;i<prevContour->count();i++) {
|
||
WT_Logical_Point *pt = &(prevContour->points()[i]);
|
||
int diff = (int)(400); // 0.1% afwijking
|
||
double dx = ((double)rand() / RAND_MAX - 0.5);
|
||
double dy = ((double)rand() / RAND_MAX - 0.5);
|
||
pt->m_x += diff * dx;
|
||
pt->m_y += diff * dy;
|
||
}
|
||
|
||
}
|
||
#endif
|
||
prevContour->m_ptLabel = text.position();
|
||
}
|
||
else
|
||
{
|
||
myTRACE("\nLabel %s with area %8.2fm2", text.string().ascii(), contour->m_DWGArea/1e6);
|
||
if (!strcmp(text.string().ascii(), contour->m_contLabel.ascii()))
|
||
myTRACE(" komt dubbel voor (maar wel dezelfde contour)!");
|
||
else
|
||
myTRACE(" was al bezet door %s", contour->m_contLabel.ascii());
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return;
|
||
}
|
||
|
||
WT_Result CWhipFile::my_process_layer (WT_Layer & layer, WT_File & file)
|
||
{
|
||
file.rendition().layer() = layer;
|
||
WT_Layer *ll;
|
||
|
||
CWhipFile *deze = (CWhipFile *)file.heuristics().user_data();
|
||
CString layer_name(layer.layer_name().ascii());
|
||
|
||
if (layer_name != "") // Anders zittie alleen maar in de weg
|
||
{ // Dat doet de default_process 'fout'
|
||
// Overbodige lagen negeren we:
|
||
if (layer_name == deze->m_activeLayerName)
|
||
return WT_Result::Success;
|
||
|
||
file.layer_list().add_layer(layer);
|
||
ll = &layer;
|
||
}
|
||
else
|
||
{
|
||
WT_Integer32 layer_num = layer.layer_num();
|
||
ll = file.layer_list().find_layer_from_index(layer_num);
|
||
if (ll)
|
||
layer_name = ll->layer_name().ascii();
|
||
else
|
||
myTRACE("Vreemd, laag %d niet teruggevonden", layer_num);
|
||
}
|
||
|
||
if (ll)
|
||
{
|
||
deze->m_activeLayerName = layer_name;
|
||
deze->m_labelLayerActive = deze->labelMatch(layer_name);
|
||
deze->m_contLayerActive = deze->contMatch(layer_name);
|
||
}
|
||
|
||
return WT_Result::Success;
|
||
}
|
||
|
||
// This is what AutoCAD seems to create for a normal closed polyline
|
||
// but also for the rendition of the character '0'
|
||
WT_Result CWhipFile::my_process_polyline(WT_Polyline & polyline, WT_File & file)
|
||
{
|
||
CWhipFile *deze = (CWhipFile *)file.heuristics().user_data();
|
||
if (!deze->m_contLayerActive)
|
||
return WT_Result::Success; // Wrong layer
|
||
|
||
bool frstIsLast = (polyline.points()[0].m_x == polyline.points()[polyline.count()-1].m_x &&
|
||
polyline.points()[0].m_y == polyline.points()[polyline.count()-1].m_y);
|
||
// (Vigor) DWF's uit ARKEY hebben de onhebbelijke eigenschap dat de contour begint
|
||
// met een aanhaallijntje. Dat ondersteunen we dan toch maar.
|
||
bool scndIsLast = false;
|
||
if (g_SLNKOptions.m_SkipContLeader && polyline.count()>1)
|
||
{
|
||
scndIsLast = (polyline.points()[1].m_x == polyline.points()[polyline.count()-1].m_x &&
|
||
polyline.points()[1].m_y == polyline.points()[polyline.count()-1].m_y);
|
||
}
|
||
// Houthoff tekening 1082ma50-F-B---04-Model.dwf had voor ruimte 04.44 dat
|
||
// de contour nog <20><>n lijntje doorliep na sluiten. Dat ondersteunen we hier maar.
|
||
bool xscndIsFirst = false; // een-na-laatste
|
||
if (polyline.count()>1)
|
||
{
|
||
xscndIsFirst = (polyline.points()[0].m_x == polyline.points()[polyline.count()-2].m_x &&
|
||
polyline.points()[0].m_y == polyline.points()[polyline.count()-2].m_y);
|
||
}
|
||
if (!frstIsLast && !scndIsLast && !xscndIsFirst)
|
||
return WT_Result::Success; // Not closed. Who cares
|
||
|
||
xxxx++;
|
||
|
||
//WT_Units units=file.rendition().drawing_info().units(); werkt niet goed met paperspace
|
||
// Waarom zetten we hier m_contunits eigenlijk nog niet gewoon direct?
|
||
WT_Units units = fixUnits(file.rendition().viewport().viewport_units());
|
||
|
||
// WD_True as we are going to mess
|
||
CSLNKContourImpl *myContour;
|
||
if (scndIsLast) // eerste lijntje droppen
|
||
myContour = new CSLNKContourImpl(polyline.count()-1,polyline.points()+1, WD_True, units);
|
||
else
|
||
myContour = new CSLNKContourImpl(polyline.count(),polyline.points(), WD_True, units);
|
||
|
||
// A major problem: Sometimes AutoCAD's DWFOUT merges two adjacent polylines
|
||
// into one WT_Polyline. We hate that so we start splitting them again here
|
||
// Note this also happens on rendering of some texts. We don't care about
|
||
// that but cannot detect the difference, so split them as well.
|
||
// TODO: Als een afgesplitste contour uiteindelijk binnen de start contour
|
||
// valt dan hebben we te maken met een eiland dat door een tekenaar
|
||
// gemaakt is. Dan moeten we niet splitsen. Zucht..
|
||
|
||
for (int i=1; i<myContour->count()-2; i++) // -2: Laat normale eindpunt ongemoeid
|
||
{
|
||
if ((myContour->points()[i]).m_x == (myContour->points()[0]).m_x &&
|
||
myContour->points()[i].m_y == myContour->points()[0].m_y
|
||
)
|
||
{ // Van 0..i is al een loop. Trek die er alvast uit
|
||
WT_Point3D dwgPt = units.transform(myContour->points()[0]);
|
||
myTRACE("\nSplit case %d-%d starting DWF(%d,%d) DWG(%.3f,%.3f)",i,myContour->count(),
|
||
myContour->points()[0].m_x, myContour->points()[0].m_y,
|
||
dwgPt.m_x, dwgPt.m_y);
|
||
// Create a copy of the looping section
|
||
// Sample: i=6, j=2, diff=4 pt
|
||
CSLNKContourImpl *myContour2 = new CSLNKContourImpl(i, myContour->points(), WD_True, units);
|
||
|
||
// Als alle volgende punten binnen myContour2 vallen hebben we met een (komend) eiland te maken.
|
||
// Dan hebben we spijt en gaan toch niet splitsen
|
||
bool allInside = true;
|
||
for (int i2=i+1; allInside && i2 < myContour->count(); i2++)
|
||
{
|
||
allInside = allInside && CSLNKContourImpl::PointInPolygon(myContour->points()[i2], *myContour2);
|
||
}
|
||
if(allInside)
|
||
{
|
||
delete myContour2; // toch maar niet
|
||
continue;
|
||
}
|
||
// Create a copy of the end section
|
||
CSLNKContourImpl *myContour3 = new CSLNKContourImpl(myContour->count()-i, myContour->points()+i, WD_True, units);
|
||
|
||
// Omgekeerd: Als alle myContour2 punten binnen myContour3 vallen
|
||
// is het *eerste* stuk het eiland.
|
||
// Dan hebben we ook spijt en gaan toch niet splitsen
|
||
allInside = true;
|
||
for (int i2=0; allInside && i2 < myContour2->count(); i2++)
|
||
{
|
||
allInside = allInside && CSLNKContourImpl::PointInPolygon(myContour2->points()[i2], *myContour3);
|
||
}
|
||
if(allInside)
|
||
{
|
||
delete myContour2; // toch maar niet
|
||
delete myContour3;
|
||
continue;
|
||
}
|
||
|
||
myContour2->m_DWGArea = PolygonArea(myContour2, units);
|
||
deze->m_SLNKContouren.Add(myContour2);
|
||
|
||
// Delete the old one (seem all together a little overkill)
|
||
delete myContour;
|
||
myContour = myContour3;
|
||
i=0; // vanaf daar verder kijken
|
||
}
|
||
}
|
||
|
||
// Bij akzo 4310 kwam (Alleen AutoCAD 2004) het volgende geval voor.
|
||
// Dat onderkennen we door te testen met het oude algoritme en een twee-punts overlap
|
||
// 0,8--->1
|
||
// | |
|
||
// | v
|
||
// 3,7<--2,6
|
||
// | ^
|
||
// v |
|
||
// 4----->5
|
||
|
||
for (int i=1; i<myContour->count()-1; i++)
|
||
{
|
||
for (int j=0; j<i; j++)
|
||
if (myContour->points()[i] == myContour->points()[j])
|
||
{
|
||
myTRACE("\nSplitsen?");
|
||
if (myContour->points()[i+1] == myContour->points()[j+1])
|
||
{
|
||
myTRACE(" YES");
|
||
// Van j..i is een loop. Trek die er uit
|
||
// myTRACE("\nSplit case %d-%d",i,myContour->count());
|
||
// Create a copy of the looping section
|
||
// Sample: i=6, j=2, diff=4 pt
|
||
CSLNKContourImpl *myContour2 = new CSLNKContourImpl(i-j+1, myContour->points()+j, WD_True, units);
|
||
myContour2->m_DWGArea = PolygonArea(myContour2, units);
|
||
deze->m_SLNKContouren.Add(myContour2);
|
||
|
||
// Close the hole in myContour
|
||
for (int k=j+1; k+i-j<myContour->count(); k++)
|
||
myContour->points()[k]=myContour->points()[k+i-j];
|
||
|
||
// Create a copy of the start section
|
||
CSLNKContourImpl *myContour3 = new CSLNKContourImpl(myContour->count()-(i-j), myContour->points(), WD_True, units);
|
||
// Delete the old one (seem all together a little overkill)
|
||
delete myContour;
|
||
myContour = myContour3;
|
||
i=j; // vanaf daar verder kijken
|
||
}
|
||
}
|
||
}
|
||
|
||
// Last (or only) section
|
||
myContour->m_DWGArea = PolygonArea(myContour, units);
|
||
WT_Point3D dwgPt = units.transform(myContour->points()[0]);
|
||
|
||
myTRACE("\nFound contour with area %8.0f (%8.2fm2) starting DWF(%d,%d) DWG(%.3f,%.3f)",
|
||
myContour->m_DWGArea, myContour->m_DWGArea/1e6,
|
||
myContour->points()[0].m_x, myContour->points()[0].m_y,
|
||
dwgPt.m_x, dwgPt.m_y);
|
||
if (myContour->m_DWGArea >= deze->m_minContSize)
|
||
deze->m_SLNKContouren.Add(myContour);// Doet uiteindelijk wel een delete op myContour
|
||
else
|
||
{
|
||
myTRACE(" te klein bevonden");
|
||
delete myContour;
|
||
}
|
||
|
||
return WT_Result::Success;
|
||
}
|
||
|
||
// Note: For SHX-fonts AutoCAD 2002+ creates an invisible (Text) object
|
||
// which will get used here
|
||
WT_Result CWhipFile::my_process_text (WT_Text & text, WT_File & file)
|
||
{
|
||
CWhipFile *deze = (CWhipFile *)file.heuristics().user_data();
|
||
if (!deze->m_labelLayerActive)
|
||
return WT_Result::Success; // Wrong layer
|
||
|
||
if (text.string().is_ascii() && strlen(text.string().ascii()) > 0)
|
||
deze->m_SLNKLabels.Add(text);
|
||
return WT_Result::Success;
|
||
}
|
||
|
||
// 'Herschrijf' de plan DWF naar de output
|
||
// Doe eerst de 'header' van de DWF (viewport en zo) en zodra
|
||
// we de eerste drawable tegenkomen doen we de contouren tussendoor
|
||
// zodat die (als ze ingekleurd worden) altijd onderaan liggen
|
||
HRESULT CWhipFile::SerializePlan(WT_File & my_plan_file, myWT_File & my_file, double scale)
|
||
{
|
||
CmyTimer tm("Serializing plan");
|
||
|
||
WT_Result result;
|
||
BOOL firstDrawable = true;
|
||
|
||
BOOL CurrentLayerOn = TRUE; // Skip contourlagen
|
||
// Deze drie waren niet geclear'd door de close na het lezen van de contouren
|
||
my_plan_file.layer_list().remove_all();
|
||
my_plan_file.object_node_list().remove_all();
|
||
my_plan_file.dash_pattern_list().remove_all();
|
||
|
||
// TODO Is dit 2.70 nog wel nodig? We doen verderop ook een en ander
|
||
// Zet wel m_activeLayerName dus nog laten zo
|
||
my_plan_file.set_layer_action(my_process_layer); // Override default processing
|
||
// Do the actual reading.
|
||
CString last_layer;
|
||
m_activeLayerName = ""; // reset
|
||
|
||
while ((result = my_plan_file.process_next_object()) == WT_Result::Success)
|
||
{
|
||
switch(my_plan_file.current_object()->object_type())
|
||
{
|
||
case WT_Object::Drawable:
|
||
if (firstDrawable)
|
||
{
|
||
comment(my_file, "== Contouren start (solid=true)");
|
||
GenerateContouren(my_plan_file, my_file, scale, true); // Alle 'solid' kleuren
|
||
comment(my_file, "== Contouren end (solid=true)");
|
||
firstDrawable = false;
|
||
}
|
||
if (my_plan_file.current_object()->object_id() == WT_Object::Origin_ID
|
||
&& !my_file.heuristics().allow_binary_data()
|
||
)
|
||
{ // I do not understand why but it will assert otherwise
|
||
break;
|
||
}
|
||
if (CurrentLayerOn)
|
||
my_plan_file.current_object()->serialize(my_file);
|
||
break;
|
||
case WT_Object::Attribute:
|
||
{ // TODO: Als !CurrentLayerOn dan zouden we ook nog fors kunnen schrappen in de WT_Attributes
|
||
// die vaak niet meer van toepassing zijn. Dan moeten we echter met desireded rendition gaan werken
|
||
// en dat is me nog even te veel werk.
|
||
// 2.80: WT_Color en WT_Font alvast wel via desired, scheelt best in de DWF-grootte
|
||
const WT_Attribute *obj = (WT_Attribute *)my_plan_file.current_object();
|
||
switch(obj->object_id())
|
||
{
|
||
case WT_Object::URL_ID: // Strippen omdat ze in de weg kunnen zitten met onze eigen URL's
|
||
case WT_Object::Object_Node_ID: // kunnen we ook niets mee. Had RWSN#20095 in 1101EM0108_01.dwf
|
||
break;
|
||
case WT_Object::Layer_ID:
|
||
{ // Sla de oorspronkelijke contour lagen over
|
||
// En ook de lagen die we niet willen
|
||
CurrentLayerOn = TRUE;
|
||
WT_Layer *layer = (WT_Layer *)obj;
|
||
WT_Integer32 layer_num = layer->layer_num();
|
||
if (layer_num==0)
|
||
{ // ARKEY heeft lagen met nummer 0. Dat mag niet volgens de
|
||
// Whip-spec en gaat ook mis (alleen) bij binaire DWF's
|
||
if (my_file.heuristics().allow_binary_data())
|
||
{
|
||
myDoTRACE("\nSkipping layer with invalid number 0");
|
||
break;
|
||
}
|
||
}
|
||
|
||
// Noot: gooi de originele contour-lagen er altijd uit
|
||
if ((labelMatch(m_activeLayerName) ||
|
||
contMatch(m_activeLayerName) ||
|
||
!layerMatch(m_activeLayerName))
|
||
)
|
||
CurrentLayerOn = FALSE; // Layer object hoeft ook niet meer geserialized
|
||
else
|
||
{
|
||
if (m_activeLayerName != last_layer) // cleaning, scheelt fors bij RIJSWIJKHB-02.dwf
|
||
{
|
||
layer->serialize(my_file);
|
||
last_layer = m_activeLayerName;
|
||
}
|
||
}
|
||
break;
|
||
}
|
||
case WT_Object::Color_ID:
|
||
{
|
||
my_file.desired_rendition().color() = *((WT_Color *)obj);
|
||
break;
|
||
}
|
||
case WT_Object::Font_ID:
|
||
{
|
||
my_file.desired_rendition().font() = *((WT_Font *)obj);
|
||
break;
|
||
}
|
||
default:
|
||
{
|
||
#ifdef _DEBUG
|
||
CString s(my_plan_file.file_stats()->descriptions());
|
||
// myTRACE("Attribute '%s'\n", s);
|
||
#endif
|
||
// Hoewel een Attibute gaat hij toch niet via desired_rendition
|
||
// Omdat we weten dat we net uit uit een DWF komen kunnen we best
|
||
// wel rechtstreeks serializen
|
||
// Let wel: desired_rendition is dan niet meer te vertrouwen. Zie @@@
|
||
obj->serialize(my_file);
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
default:
|
||
#ifdef _DEBUG
|
||
CString s(my_plan_file.file_stats()->descriptions());
|
||
//myTRACE("Skipping '%s'\n", s);
|
||
#endif
|
||
break;
|
||
}
|
||
}
|
||
|
||
myDoTRACE("\nWritten %d/%d layers", my_file.layer_list().count(), my_plan_file.layer_list().count());
|
||
|
||
// if (result == WT_Result::End_Of_DWF_Opcode_Found)
|
||
// dwfresult = DwfResult::Success;
|
||
|
||
// TODO: desired_rendition klopt nu niet meer met de daadwerkelijke rendition?
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
// Extra saveas wrapper om met __try een eventuele Win32 exception ook op te vangen
|
||
STDMETHODIMP CWhipFile::SaveAs(BSTR WhipPath, VARIANT_BOOL ascii)
|
||
{
|
||
myTRACE("\nAbout to save into %ls", (LPCTSTR)WhipPath);
|
||
|
||
__try {
|
||
return SaveAs2(WhipPath, ascii);
|
||
}
|
||
__except(EXCEPTION_EXECUTE_HANDLER)
|
||
{
|
||
DWORD exCode = GetExceptionCode();
|
||
myDoTRACE("\nUnhandled Win32 exception 0x%x in CWhipFile::SaveAs", exCode);
|
||
char err[128];
|
||
sprintf_s(err, "\nUnhandled Win32 exception 0x%x", exCode);
|
||
|
||
return myAtlReportError (GetObjectCLSID(), "\nCWhipFile::SaveAs('%ls')\n%s", (LPCSTR)WhipPath, err);
|
||
}
|
||
}
|
||
|
||
STDMETHODIMP CWhipFile::SaveAs2(BSTR WhipPath, VARIANT_BOOL ascii)
|
||
{
|
||
try {
|
||
myWT_File my_file;
|
||
my_file.set_filename(WhipPath);
|
||
my_file.m_ascii = ascii;
|
||
return Generate(my_file);
|
||
}
|
||
catch (WT_Result::Enum e)
|
||
{
|
||
CString err;
|
||
err.Format("\nInternal error WT_Result::Enum %d",e);
|
||
return myAtlReportError (GetObjectCLSID(), "\nCWhipFile::SaveAs('%ls')\n%s", (LPCSTR)WhipPath, err);
|
||
}
|
||
catch (CString &err)
|
||
{
|
||
return myAtlReportError (GetObjectCLSID(), err);
|
||
}
|
||
}
|
||
|
||
// Altijd hoogte 1000, echte fontheight gaf overflow bij SDU
|
||
class tempFontDC
|
||
{
|
||
public:
|
||
tempFontDC(WT_String m_FontName)
|
||
{
|
||
HDC tempDC = CreateDC("DISPLAY",NULL,NULL,NULL);
|
||
m_DC = CreateCompatibleDC ( tempDC );
|
||
DeleteDC(tempDC);
|
||
|
||
LOGFONT lf;
|
||
memset(&lf, 0, sizeof(LOGFONT)); // clear out structure.
|
||
strcpy_s(lf.lfFaceName, LF_FACESIZE, m_FontName.ascii());
|
||
lf.lfHeight = -FONT_SIZER;
|
||
fnt = CreateFontIndirect(&lf);
|
||
HGDIOBJ oldfont = SelectObject(m_DC, fnt);
|
||
}
|
||
|
||
~tempFontDC()
|
||
{
|
||
// Opruimen
|
||
DeleteObject(fnt);
|
||
DeleteDC(m_DC);
|
||
}
|
||
inline operator const HDC()
|
||
{ return m_DC; }
|
||
private:
|
||
HDC m_DC;
|
||
HFONT fnt;
|
||
};
|
||
|
||
bool CWhipFile::GenerateSymbols(myWT_File &my_file)
|
||
{
|
||
double scale = m_contunits.application_to_dwf_transform()(0,0);
|
||
// TODO: Echt uniek layernum (en URL num) bepalen
|
||
my_file.desired_rendition().layer() = WT_Layer(my_file, 65530, "SLNK Symbols");
|
||
|
||
for (size_t i=0; i<m_SLNKSymbols.GetCount(); i++)
|
||
{
|
||
CSLNKSymbolImpl *symbol= m_SLNKSymbols[i];
|
||
if (symbol->m_symbolName == "" || !m_SLNKSymbolDefinitions.Lookup(symbol->m_symbolName))
|
||
symbol->serialize(my_file, m_contunits, NULL,
|
||
m_next_node_num,
|
||
m_hintScale, m_forFind, scale);
|
||
else
|
||
{
|
||
CString s; s.Format("About to insert symbol %s", symbol->m_symbolName);
|
||
comment(my_file, s);
|
||
symbol->serialize(my_file, m_contunits, m_SLNKSymbolDefinitions[symbol->m_symbolName],
|
||
m_next_node_num,
|
||
m_hintScale, m_forFind, scale);
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
bool CWhipFile::GenerateSymbolLabels(myWT_File &my_file)
|
||
{
|
||
double scale = m_contunits.application_to_dwf_transform()(0,0);
|
||
// Zet een DC op om bij 'Center' de afmetingen van de tekst te kunnen bepalen
|
||
int fontheight= myRound(m_FontHeightSymbols * scale);
|
||
tempFontDC myDC(m_FontName);
|
||
|
||
WT_Font myfont;
|
||
myfont.font_name() = m_FontName;
|
||
myfont.height() = fontheight;
|
||
myfont.rotation() = 0;
|
||
myfont.width_scale() = 0;
|
||
my_file.desired_rendition().font() = my_file.rendition().font() = myfont;
|
||
myfont.serialize(my_file); // Vertrouw niets. Expliciete serialize. Zie @@@
|
||
|
||
WT_Color clr(255,255,255,0); //Teksten wit
|
||
my_file.desired_rendition().color() = my_file.rendition().color() = clr;
|
||
clr.serialize(my_file); // Vertrouw niets. Expliciete serialize. Zie @@@
|
||
|
||
// TODO: Echt uniek layernum (en URL num) bepalen
|
||
my_file.desired_rendition().layer() = WT_Layer(my_file, 65531, "SLNK Symbol Labels");
|
||
for (size_t i=0; i<m_SLNKSymbols.GetCount(); i++)
|
||
{
|
||
CSLNKSymbolImpl *symbol= m_SLNKSymbols[i];
|
||
|
||
WT_Transform wasTransform = my_file.heuristics().transform();
|
||
WT_Boolean wasApplyTransform = my_file.heuristics().apply_transform();
|
||
my_file.heuristics().set_apply_transform(WD_False); // Hebben we al rechtstreeks op de contour gedaan
|
||
symbol->m_SLNKContour.SerializeLabel(my_file, scale, myDC);
|
||
// En transform weer terug
|
||
my_file.heuristics().set_transform(wasTransform);
|
||
my_file.heuristics().set_apply_transform(wasApplyTransform);
|
||
}
|
||
return true;
|
||
}
|
||
|
||
// Schrijf alle uitgerekende contouren naar het DWF bestand
|
||
// Deze functie wordt twee keer aangeroepen
|
||
// Heel vroeg (voor de plattegrond) worden alle contouren met een solid kleur
|
||
// wegeschreven. Die komen dan helemaal onderop. Ze zouden anders afdekken
|
||
// In de tweede slag komen alle transparante contouren. Die komen na de
|
||
// plattegrond zodat de plattegrond doorschijnt.
|
||
// TODO: Sorteren op dunste contouren eerst, die dikke moeten bovenop?
|
||
bool CWhipFile::GenerateContouren(WT_File &my_planfile, myWT_File &my_file,
|
||
double scale, BOOL solidOnly)
|
||
{
|
||
// Zorg dat we zelf neutraal blijven
|
||
WT_Layer keepLayer = my_planfile.rendition().layer();
|
||
WT_Color keepColor = my_planfile.rendition().color();
|
||
WT_Line_Style keepStyle = my_planfile.rendition().line_style();
|
||
WT_Font keepFont = my_planfile.rendition().font();
|
||
|
||
// Vertrouw de huidige rendition niet!
|
||
WT_Color().serialize(my_file);
|
||
WT_Line_Style style;
|
||
style.line_join() = WT_Line_Style::Diamond_Join;
|
||
my_file.desired_rendition().line_weight() = myRound(10 * scale);
|
||
style.serialize(my_file);
|
||
|
||
//Store the current object node hoewel die echt null zal zijn....
|
||
WT_Object_Node current_node = my_file.desired_rendition().object_node();
|
||
|
||
// TODO: Echt uniek layernum (en URL num) bepalen
|
||
my_file.desired_rendition().layer() = WT_Layer(my_file, 65532, "SLNK Contours");
|
||
// Beide 'slagen' forceren (FSN#14349)
|
||
my_file.desired_rendition().layer().serialize(my_file);
|
||
|
||
// Sorteren: die met m_onTop zetten we achteraan/ bovenop
|
||
size_t last = m_SLNKContouren.GetCount() - 1; // alles na last heeft onTop
|
||
for (size_t i=0; i<last && i<m_SLNKContouren.GetCount(); i++)
|
||
{
|
||
CSLNKContourImpl *contour= m_SLNKContouren[i];
|
||
if (contour->m_onTop)
|
||
{
|
||
while (last > i && last > 0 && m_SLNKContouren[last]->m_onTop)
|
||
last --;
|
||
if (last > i && last > 0)
|
||
{
|
||
m_SLNKContouren[i] = m_SLNKContouren[last];
|
||
m_SLNKContouren[last] = contour;
|
||
last--;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
for (size_t i=0; i<m_SLNKContouren.GetCount(); i++)
|
||
{
|
||
CSLNKContourImpl *contour= m_SLNKContouren[i];
|
||
// i ook gebruiken als node_num, eigenlijk initialiseren op laatste van planfile
|
||
contour->serialize(my_file, m_next_node_num, solidOnly, m_forFind, scale);
|
||
}
|
||
my_file.desired_rendition().object_node() = current_node;
|
||
|
||
my_file.desired_rendition().line_weight() = 0; // Voor als er later bijvoorbeeld nog symbolen komen
|
||
|
||
my_file.desired_rendition().layer() = my_file.rendition().layer() = keepLayer;
|
||
if (keepLayer.layer_num()) keepLayer.serialize(my_file); // Zeker terugzetten
|
||
my_file.desired_rendition().color() = my_file.rendition().color() = keepColor;
|
||
keepColor.serialize(my_file); // Zeker terugzetten
|
||
my_file.desired_rendition().line_style() = my_file.rendition().line_style() = keepStyle;
|
||
keepStyle.serialize(my_file); //
|
||
my_file.desired_rendition().font() = my_file.rendition().font() = keepFont;
|
||
keepFont.serialize(my_file); //
|
||
|
||
return true;
|
||
}
|
||
|
||
bool CWhipFile::GenerateLabels(WT_File &my_planfile, myWT_File &my_file, double scale)
|
||
{
|
||
// Zorg dat we zelf neutraal blijven
|
||
WT_Layer keepLayer = my_planfile.rendition().layer();
|
||
WT_Color keepColor = my_planfile.rendition().color();
|
||
|
||
// TODO: Echt uniek layernum (en URL num) bepalen
|
||
my_file.desired_rendition().layer() = WT_Layer(my_file, 65533, "SLNK Labels");
|
||
WT_Font f;
|
||
f.width_scale() = 0; // Triggert FONT_WIDTH_SCALE_BIT bitje zetten
|
||
f.rotation() = 0;
|
||
f.serialize(my_file); // Op de default zetten.
|
||
my_file.desired_rendition().font() = my_file.rendition().font() = f;
|
||
|
||
// Zet een DC op om bij 'Center' de afmetingen van de tekst te kunnen bepalen
|
||
int fontheight= myRound(m_FontHeight * scale);
|
||
tempFontDC myDC(m_FontName);
|
||
|
||
WT_Font myfont;
|
||
myfont.font_name() = m_FontName;
|
||
myfont.height() = fontheight;
|
||
myfont.width_scale() = DEFAULT_WIDTH_SCALE; // Triggert FONT_WIDTH_SCALE_BIT bitje zetten
|
||
myfont.rotation() = 0;
|
||
my_file.desired_rendition().font() = my_file.rendition().font() = myfont;
|
||
myfont.serialize(my_file); // Vertrouw niets. Expliciete serialize. Zie @@@
|
||
|
||
// En nu nog een keer alle teksten
|
||
for (size_t i=0; i<m_SLNKContouren.GetCount(); i++)
|
||
{
|
||
CSLNKContourImpl *contour= m_SLNKContouren[i];
|
||
|
||
// Een polyline hebben we nu niet nodig
|
||
if (contour->m_ShowLabel != "")
|
||
{ // We have got a proper label/contour, origineel of gezet door de applicatie
|
||
contour->SerializeLabel(my_file, scale, myDC);
|
||
}
|
||
}
|
||
|
||
my_file.desired_rendition().layer() = my_file.rendition().layer() = keepLayer;
|
||
if (keepLayer.layer_num()) keepLayer.serialize(my_file); // Zeker terugzetten
|
||
my_file.desired_rendition().color() = my_file.rendition().color() = keepColor;
|
||
keepColor.serialize(my_file); // Zeker terugzetten
|
||
|
||
return true;
|
||
}
|
||
|
||
// We hebben de contouren bepaald. Genereer daarvoor nu nieuwe DWF-primitieven
|
||
// In het bijzonder kennen we er een kleurtje aan toe en plaatsen wel de labels (opnieuw)
|
||
STDMETHODIMP CWhipFile::Generate(myWT_File &my_file)
|
||
{
|
||
// Bepaal de te gebruiken hoogte in Logical Points
|
||
|
||
double scale = m_contunits.application_to_dwf_transform()(0,0);
|
||
myDoTRACE("\nSchaal: %.2f", scale);
|
||
|
||
m_next_node_num = 0;
|
||
|
||
WT_Result result;
|
||
|
||
my_file.set_file_mode(WT_File::File_Write);
|
||
|
||
WT_Boolean binary = !my_file.m_ascii;
|
||
my_file.heuristics().set_allow_binary_data(binary);
|
||
// Zal niet zo snel meer gebeuren maar we willen het zeker niet
|
||
my_file.heuristics().set_allow_drawable_merging(WD_False);
|
||
// Let op: De viewer kan 60-file niet zo maar lezen, dat moet naar packed-DWF
|
||
// Later: viewer 6.5 kan gewoon een W2D file tonen
|
||
// Let op: bij versie 55 worden Node's niet weggeschreven
|
||
// my_file.heuristics().set_target_version(55);
|
||
my_file.heuristics().set_target_version(600); // Zodat DWF Viewer 6.0 niet moeilijk doet
|
||
if (my_file.open() != WT_Result::Success)
|
||
{
|
||
return myAtlReportError (GetObjectCLSID(), "ERROR: Unable to open file for writing: %s", my_file.filename().ascii());
|
||
ATLASSERT(false);
|
||
}
|
||
|
||
// Symbolen worden mogelijk geplaatst net buiten onze coordinatenruimte (met name X)
|
||
// Dat gaf clipping problemen.
|
||
// Daarom verplaatsen we alles in onze coordinatenruimte naar links/onder (0,0)
|
||
// Merk op dat dit alleen helpt later in de de 'viewer', liefst zou ik het
|
||
// al tijdens het *inlezen* doen maar dat had haken en ogen (zie read_for_contours())
|
||
WT_Logical_Point lshift(-(max(0,this->m_view.view().m_min.m_x)),
|
||
-(max(0,this->m_view.view().m_min.m_y))); // Iets minder clipping van INT_MAX
|
||
// Contouren hebben we ondertussen al wel/
|
||
// Nu nog een keer door de DWF om de rest te kopieren naar de output
|
||
m_W2DFile.set_file_mode(WT_File::File_Read);
|
||
my_file.heuristics().set_apply_transform(WD_False);
|
||
myTRACE("\nAbout to open plan");
|
||
if (m_W2DFile.open() == WT_Result::Success)
|
||
{
|
||
comment(my_file, "== Original file start");
|
||
|
||
// TODO: Dit moet uit de originele PlanDWF z'n Manifest/Paper komen
|
||
|
||
int keep=my_file.heuristics().target_version();
|
||
// Even background ondersteunen
|
||
my_file.heuristics().set_target_version(55);
|
||
WT_Background bg(WT_Color(0,0,0));
|
||
bg.serialize(my_file);
|
||
my_file.heuristics().set_target_version(keep);
|
||
|
||
my_file.heuristics().set_transform(WT_Transform (lshift, 1.0, 1.0, 0));
|
||
my_file.heuristics().set_apply_transform(true);
|
||
|
||
SerializePlan(m_W2DFile, my_file, scale); // Heeft eventueel een GenerateContouren in zich!
|
||
comment(my_file, "== Original file end");
|
||
|
||
m_W2DFile.close();
|
||
}
|
||
else
|
||
{
|
||
myTRACE("\nKon plan niet openen");
|
||
return myAtlReportError (GetObjectCLSID(), "ERROR: Unable to open plan file");
|
||
}
|
||
|
||
comment(my_file, "== Contouren start (solid=false)");
|
||
// Twee loops. Eerst alle contouren (en vlakvullingen), daarna pas
|
||
// de teksten. Zodoende zijn de teksten altijd leesbaar
|
||
GenerateContouren(m_W2DFile, my_file, scale, false); // Alle transparante kleuren
|
||
comment(my_file, "== Contouren end (solid=false)");
|
||
//merging geeft vreemd effect op de contouren die we om symbolen tekenen in _DEBUG mode
|
||
// dan worden die contouren niet meer meegeschaald? TODO: Uitzoeken
|
||
//my_file.heuristics().set_allow_drawable_merging(WD_True); // Voor symbolen kan het (na verschalen) wel schelen
|
||
comment(my_file, "== Symbols start");
|
||
GenerateSymbols(my_file); // Ook alle contouren van symbolen
|
||
comment(my_file, "== Symbol labels start");
|
||
GenerateSymbolLabels(my_file);
|
||
comment(my_file, "== Contour labels start");
|
||
GenerateLabels(m_W2DFile, my_file, scale);
|
||
|
||
myTRACE("\nAbout to close");
|
||
//Restore the saved object node.
|
||
my_file.desired_rendition().fill() = WD_False;
|
||
my_file.close();
|
||
|
||
myTRACE("\nDone saving");
|
||
return S_OK;
|
||
}
|
||
|
||
// Highlight unrecognized contouren
|
||
STDMETHODIMP CWhipFile::HighlightUnrecognized()
|
||
{
|
||
try {
|
||
for (size_t i=0; i<m_SLNKContouren.GetCount(); i++)
|
||
{
|
||
CSLNKContourImpl *contour= m_SLNKContouren[i];
|
||
if (contour->m_contLabel.length()==0)
|
||
{
|
||
contour->m_Color.set(255, 0, 0);
|
||
}
|
||
}
|
||
return S_OK;
|
||
}
|
||
catch (WT_Result::Enum e)
|
||
{
|
||
CString err;
|
||
err.Format("\nInternal error WT_Result::Enum %d",e);
|
||
return myAtlReportError (GetObjectCLSID(), "\nCWhipFile::HighlightUnrecognized()\n%s", err);
|
||
}
|
||
|
||
}
|
||
|
||
STDMETHODIMP CWhipFile::SetLabelFont(BSTR FontName, DOUBLE FontHeight, DOUBLE FontHeightSymbols)
|
||
{
|
||
m_FontName.set(FontName);
|
||
m_FontHeight = FontHeight;
|
||
m_FontHeightSymbols = (FontHeightSymbols>0)?FontHeightSymbols:FontHeight;
|
||
|
||
for (size_t i=0; i<m_SLNKContouren.GetCount(); i++)
|
||
{
|
||
CSLNKContourImpl *contour= m_SLNKContouren[i];
|
||
contour->m_Fontheight = m_FontHeight;
|
||
}
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP CWhipFile::SetLabelPosition(BYTE p_LabelPos)
|
||
{
|
||
CSLNKContourImpl::LABELPOS LabelPos;
|
||
switch (p_LabelPos)
|
||
{
|
||
case 1: LabelPos = CSLNKContourImpl::LABEL_DEFAULT; break;
|
||
case 2: LabelPos = CSLNKContourImpl::LABEL_CENTROID; break;
|
||
case 3: LabelPos = CSLNKContourImpl::LABEL_TOPLEFT; break;
|
||
case 4: LabelPos = CSLNKContourImpl::LABEL_OUTSIDERIGHT; break;
|
||
case 5: LabelPos = CSLNKContourImpl::LABEL_OUTSIDEBOTTOM; break;
|
||
default: LabelPos = CSLNKContourImpl::LABEL_DEFAULT;
|
||
}
|
||
for (size_t i=0; i<m_SLNKContouren.GetCount(); i++)
|
||
{
|
||
CSLNKContourImpl *contour= m_SLNKContouren[i];
|
||
contour->m_Labelpos = LabelPos;
|
||
}
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP CWhipFile::get_AddSymbol(DOUBLE dwgX, DOUBLE dwgY, BSTR symbolName, ISLNKSymbol** pVal)
|
||
{
|
||
CString name(symbolName);
|
||
|
||
myTRACE("\nAdding symbol %s at %.2f,%.2f", name, dwgX, dwgY);
|
||
|
||
CSLNKSymbolImpl *mySymbol = new CSLNKSymbolImpl(dwgX, dwgY, m_contunits);
|
||
mySymbol->m_SLNKContour.m_Fontheight = m_FontHeightSymbols;
|
||
m_SLNKSymbols.Add(mySymbol);
|
||
|
||
// Als resultaat leveren we een COM object op waar je eventueel de rest van
|
||
// de properties op kunt zetten
|
||
CComObject<CSLNKSymbol> *theSymbol;
|
||
HRESULT hr = CComObject<CSLNKSymbol>::CreateInstance(&theSymbol);
|
||
if(FAILED(hr)) return hr;
|
||
|
||
theSymbol->AddRef();
|
||
hr = theSymbol->QueryInterface(IID_ISLNKSymbol, (void **)pVal);
|
||
theSymbol->SetParent(this); // Zodat scope blijft
|
||
theSymbol->Release();
|
||
if(FAILED(hr)) return hr;
|
||
theSymbol->SetImpl(mySymbol); // Heel belangrijk: zet de implementatie waar we een interface op bieden
|
||
|
||
if (!m_SLNKSymbolDefinitions.Lookup(name))
|
||
name = "*STAR"; // Die vinden we altijd ja
|
||
ATLASSERT(m_SLNKSymbolDefinitions.Lookup(name));
|
||
|
||
mySymbol->m_symbolName = name;
|
||
mySymbol->m_SLNKContour.set(m_SLNKSymbolDefinitions[name]->m_BoundingContour.count(),
|
||
m_SLNKSymbolDefinitions[name]->m_BoundingContour.points(), true); // TODO: Is copy wel nodig?==>Ja, we gaan ze later transformeren!
|
||
// De voorgedefinieerde symbolen hebben alleen maar een contour. Die activeren we hier
|
||
if (name[0] == '*')
|
||
{
|
||
// Default rood
|
||
mySymbol->m_SLNKContour.m_Color = WT_Color(255,0,0,255);
|
||
mySymbol->m_SLNKContour.m_outlineColor = WT_Color(255,0,0,255); // Anders wordtie helemaal niet getekend?
|
||
}
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP CWhipFile::DefineSymbol(BSTR symbolName, VARIANT EPlotStream, ISLNKContour** pContour)
|
||
{
|
||
myTRACE("\nDefining symbol %ls", symbolName);
|
||
if (EPlotStream.vt == VT_ERROR)
|
||
return E_INVALIDARG;
|
||
|
||
VARIANT *var2 = &EPlotStream;
|
||
if (var2->vt==(VT_VARIANT|VT_BYREF)) // ByRef
|
||
var2 = (VARIANT *)var2->pvarVal;
|
||
|
||
if (var2->vt!=VT_DISPATCH)
|
||
return E_INVALIDARG;
|
||
|
||
CComQIPtr<IEPlotSection> EPlotSection;
|
||
EPlotSection = var2->pdispVal;
|
||
if (!EPlotSection)
|
||
return E_INVALIDARG;
|
||
|
||
CSLNKSymbolDefinition * symb = new CSLNKSymbolDefinition(EPlotSection);
|
||
|
||
CString name(symbolName);
|
||
m_SLNKSymbolDefinitions.SetAt(name, symb);
|
||
|
||
return return_ContourItem(&symb->m_BoundingContour, pContour); // Geef de contour terug in pcontour
|
||
}
|
||
|
||
// Define symbol by W2D filename
|
||
STDMETHODIMP CWhipFile::DefineW2DSymbol(BSTR symbolName, BSTR WhipPath, ISLNKContour** pContour)
|
||
{
|
||
myTRACE("\nDefining symbol %ls by W2D file %ls", symbolName, WhipPath);
|
||
|
||
CSLNKSymbolDefinition * symb;
|
||
try
|
||
{
|
||
symb = new CSLNKSymbolDefinition(CString(WhipPath));
|
||
}
|
||
catch (CString &err)
|
||
{
|
||
return myAtlReportError (GetObjectCLSID(), "Error defining symbol %ls file %ls:%s\n", symbolName, WhipPath, err);
|
||
}
|
||
|
||
m_SLNKSymbolDefinitions.SetAt(CString(symbolName), symb);
|
||
|
||
return return_ContourItem(&symb->m_BoundingContour, pContour); // Geef de contour terug in pcontour
|
||
}
|
||
|
||
STDMETHODIMP CWhipFile::DefineBitmapSymbol(BSTR symbolName, BSTR symbolPath, double height)
|
||
{
|
||
myTRACE("\nDefining bitmap symbol %ls", symbolName);
|
||
CSLNKSymbolDefinition * symb = new CSLNKSymbolDefinition(CString(symbolPath), height, m_contunits);
|
||
CString name(symbolName);
|
||
m_SLNKSymbolDefinitions.SetAt(name, symb);
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
// Merk op: als iemand twee keer dezelfde contour opvraagt maken we twee onafhankelijke
|
||
// SLNKContour objecten aan die beide naar dezelfde CSLNKContourImpl wijzen
|
||
// Het maakt verder weinig uit en is wel gemakkelijker (toch?)
|
||
STDMETHODIMP CWhipFile::get_Contour(BSTR IdentLabel, ISLNKContour** pVal)
|
||
{
|
||
try {
|
||
for (size_t i=0; i<m_SLNKContouren.GetCount(); i++)
|
||
{
|
||
CSLNKContourImpl *contour = m_SLNKContouren[i];
|
||
if (contour->m_Key == CString(IdentLabel))
|
||
{
|
||
return get_ContourItem((ULONG) i, pVal);
|
||
}
|
||
}
|
||
return S_OK; // Niet gevonden. Automatisch NULL?
|
||
}
|
||
catch (WT_Result::Enum e)
|
||
{
|
||
CString err;
|
||
err.Format("\nInternal error WT_Result::Enum %d",e);
|
||
return myAtlReportError (GetObjectCLSID(), "\nCWhipFile::get_Contour('%ls')\n%s", (LPCSTR)IdentLabel, err);
|
||
}
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP CWhipFile::get_hintScale(DOUBLE* pVal)
|
||
{
|
||
(*pVal) = m_hintScale;
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP CWhipFile::put_hintScale(DOUBLE newVal)
|
||
{
|
||
m_hintScale = newVal;
|
||
myTRACE("\nhintScale set to %.6f", newVal);
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP CWhipFile::put_forFind(VARIANT_BOOL newVal)
|
||
{
|
||
m_forFind = newVal;
|
||
return S_OK;
|
||
}
|
||
|
||
// Levert aan de hand van een coordinaat op in welke ruimte deze valt
|
||
// Gebruikt door Facilitor Graphics om bijvoorbeeld te controleren of
|
||
// de XY van een symbool (nog) wel binnen een ruimte valt.
|
||
// mei 2010: Had dit niet ook opgelost kunnen worden met Whip2PNG.Find
|
||
// -->Neen, die hebben we daar in de code nog niet?
|
||
STDMETHODIMP CWhipFile::get_FindInContour(DOUBLE dwgX, DOUBLE dwgY, BSTR* pVal)
|
||
{
|
||
CString result;
|
||
WT_Point3D insertion(dwgX, dwgY);
|
||
WT_Logical_Point LPInsertion = m_contunits.transform(WT_Point3D(dwgX, dwgY));
|
||
|
||
for (size_t i=0; i<m_SLNKContouren.GetCount(); i++)
|
||
{
|
||
CSLNKContourImpl *contour= m_SLNKContouren[i];
|
||
if (contour->m_Key != "")
|
||
if (CSLNKContourImpl::PointInPolygon(LPInsertion, *contour))
|
||
{
|
||
result = contour->m_Key;
|
||
(*pVal) = result.AllocSysString();
|
||
}
|
||
}
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP CWhipFile::get_ContourCount(LONG* pVal)
|
||
{
|
||
*pVal = (LONG)m_SLNKContouren.GetCount();
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP CWhipFile::return_ContourItem(CSLNKContourImpl *pContour, ISLNKContour** pVal)
|
||
{
|
||
CComObject<CSLNKContour> *theContour;
|
||
HRESULT hr = CComObject<CSLNKContour>::CreateInstance(&theContour);
|
||
if(FAILED(hr)) return hr;
|
||
|
||
theContour->AddRef();
|
||
hr = theContour->QueryInterface(IID_ISLNKContour, (void **)pVal);
|
||
theContour->SetParent(this);
|
||
theContour->Release();
|
||
if(FAILED(hr)) return hr;
|
||
|
||
theContour->SetImpl(pContour); // Heel belangrijk: zet de implementatie waar we een interface op bieden
|
||
|
||
return S_OK; // Wel gevonden
|
||
}
|
||
|
||
STDMETHODIMP CWhipFile::get_ContourItem(ULONG i, ISLNKContour** pVal)
|
||
{
|
||
if (i < 0 || i >= m_SLNKContouren.GetCount())
|
||
return E_INVALIDARG;
|
||
|
||
return return_ContourItem(m_SLNKContouren[i], pVal);
|
||
}
|
||
|
||
STDMETHODIMP CWhipFile::get_minContSize(DOUBLE* pVal)
|
||
{
|
||
(*pVal) = m_minContSize;
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP CWhipFile::put_minContSize(DOUBLE newVal)
|
||
{
|
||
m_minContSize = newVal;
|
||
|
||
return S_OK;
|
||
}
|
||
|
||
STDMETHODIMP CWhipFile::get_AddContour(ISLNKContour** pVal)
|
||
{
|
||
// Je mag eigenlijk geen echt lege contour doorgeven, daar assert de pointset.cpp op?
|
||
CSLNKContourImpl *myContour = new CSLNKContourImpl(sizeof(empty)/sizeof(empty[0]), empty, WD_True, m_contunits);
|
||
|
||
myContour->m_contLabel = "Dynamic"; // Anders wordt hij niet getekend uiteindelijk
|
||
myContour->m_isDynamic = false; // Klinkt tegenstrijdig maar zorgt dat eerste AddPoint de boel reset
|
||
|
||
this->m_SLNKContouren.Add(myContour);
|
||
|
||
return get_ContourItem((ULONG)m_SLNKContouren.GetCount() - 1, pVal);
|
||
};
|
||
|
||
STDMETHODIMP CWhipFile::get_vectorDpi(LONG* pVal)
|
||
{
|
||
*pVal = m_vdpi;
|
||
|
||
return S_OK;
|
||
}
|