SLNKDWF 2.00

svn path=/Slnkdwf/trunk/; revision=12481
This commit is contained in:
Jos Groot Lipman
2007-08-01 13:42:28 +00:00
parent d622b95c4d
commit 80d0142c23
822 changed files with 256928 additions and 0 deletions

View File

@@ -0,0 +1,505 @@
#include "StdAfx.h"
#include "slnkcontourImpl.h"
#include <math.h>
#define PALETTE_RED 1 // Color in the default colormap is red.
/*static*/ WT_Integer32 CSLNKContourImpl::m_next_node_num = 0; // Eigenlijk initialiseren op laatste van planfile
CSLNKContourImpl::CSLNKContourImpl(void)
: m_DWGArea(-1), m_outlineAlpha(255)
{
m_Color = WT_RGBA32(0,0,0,0); // alpha==0, 100% transparant
}
CSLNKContourImpl::~CSLNKContourImpl(void)
{
}
// Algoritm: search google for Randolph Franklin polygon
BOOL CSLNKContourImpl::PointInPolygon(const WT_Logical_Point pt, const WT_Point_Set &ps)
{
double ptx = pt.m_x;
double pty = pt.m_y;
int i, j, c = 0;
for (i = 0, j = ps.count()-1; i < ps.count(); j = i++) {
WT_Logical_Point pti = ps.points()[i];
if (pti.m_x==ptx&&pti.m_y==pty) // Op een hoekpunt is altijd goed!
{
return TRUE;
}
WT_Logical_Point ptj = ps.points()[j];
if ((((pti.m_y <= pty) && (pty < ptj.m_y)) ||
((ptj.m_y <= pty) && (pty < pti.m_y))) &&
(ptx < (ptj.m_x - pti.m_x) * (pty - pti.m_y) / (ptj.m_y - pti.m_y) + pti.m_x))
c = !c;
}
return c;
}
BOOL CSLNKContourImpl::PointInPolygon(const CPoint pt, const CPoint *ps, int size)
{
double ptx = pt.x;
double pty = pt.y;
int i, j, c = 0;
for (i = 0, j = size-1; i < size; j = i++) {
CPoint pti = ps[i];
if (pti.x==ptx&&pti.y==pty) // Op een hoekpunt is altijd goed!
{
return TRUE;
}
CPoint ptj = ps[j];
if ((((pti.y <= pty) && (pty < ptj.y)) ||
((ptj.y <= pty) && (pty < pti.y))) &&
(ptx < (ptj.x - pti.x) * (pty - pti.y) / (ptj.y - pti.y) + pti.x))
c = !c;
}
return c;
}
// Signed Area needed for centroid!
// Negative is clockwise, Positve counterclockwise
/*static*/double CSLNKContourImpl::DWFArea(const WT_Polygon &pg)
{
int i;
double area = 0;
for (i=0;i<pg.count();i++) {
const WT_Logical_Point &dwfPtA = pg.points()[i];
const WT_Logical_Point &dwfPtB = pg.points()[(i + 1) % pg.count()];
area += (double)dwfPtA.m_x * dwfPtB.m_y;
area -= (double)dwfPtA.m_y * dwfPtB.m_x;
}
area /= 2;
return area;
}
/* Bepaal label positie
Default is natuurlijk de plaats waar hij oorspronkelijk gevonden
Alternatief 1 is de Centroide (gewogen gemiddelde van de coordinaten)
Let wel: deze kan er buiten vallen. Aanroeper moet maar bepalen
of hij dat acceptabel vind
Alternatief 2 is 'linksbovenin'
Alternatief 3 is 'rechts aan de buitenkant' (handig voor symbolen)
Alternatief 4 is 'onder aan de buitenkant' (handig voor symbolen)
*/
WT_Logical_Point CSLNKContourImpl::LabelPosition(LABELPOS pos /*= LABEL_DEFAULT*/)
{
switch (pos)
{
case LABEL_DEFAULT:
return WT_Logical_Point(m_ptLabel.m_x, m_ptLabel.m_y);
case LABEL_CENTROID:
return Centroid(*this);
case LABEL_TOPLEFT:
{ // Zoek het meest 'linksboven' hoekpunt
WT_Logical_Point pt = points()[0]; // Eerste gok
for (int i = 1; i < count(); i++) {
if (points()[i].m_y - pt.m_y > points()[i].m_x - pt.m_x)
pt = points()[i];
}
return pt;
}
case LABEL_OUTSIDERIGHT:
{
WT_Logical_Box bx = bounds();
return WT_Logical_Point(bx.maxpt().m_x, bx.minpt().m_y/2+bx.maxpt().m_y/2); // Pas op voor overflow
}
case LABEL_OUTSIDEBOTTOM:
{
WT_Logical_Box bx = bounds();
return WT_Logical_Point(bx.minpt().m_x/2+bx.maxpt().m_x/2, bx.minpt().m_y); // Pas op voor overflow
}
default:
return WT_Logical_Point(m_ptLabel.m_x, m_ptLabel.m_y);
}
}
/*static*/WT_Logical_Point CSLNKContourImpl::Centroid(const WT_Polygon &pg)
{
double ptx = 0;
double pty = 0;
int i, j;
for (i = 0; i < pg.count(); i++) {
j = (i + 1) % pg.count();
double Xi=pg.points()[i].m_x, // Alles naar double anders krijgen wel overflows
Yi=pg.points()[i].m_y,
Xj=pg.points()[j].m_x,
Yj=pg.points()[j].m_y;
double dArea = Xi*Yj - Xj*Yi;
ptx += (Xi+Xj) * dArea;
pty += (Yi+Yj) * dArea;
}
double dDWFArea6 = 6*DWFArea(pg);
return WT_Logical_Point((WT_Integer32)(ptx / dDWFArea6), (WT_Integer32)(pty / dDWFArea6));
}
void CSLNKContourImpl::SerializeLabel(WT_File &my_file, LABELPOS pos, int fontheight, HDC myDC)
{
if (m_Color.rgba().m_rgb.a==255)
{ // Volle achtergrond kleur
COLORREF DCclr = RGB(m_Color.rgba().m_rgb.r,
m_Color.rgba().m_rgb.g,
m_Color.rgba().m_rgb.b);
// Net niet 100% kleuren om te zorgen dat bij achtergrond
// zwart/wit toggle deze kleuren niet mee togglen
if (isDarkRGB(DCclr))
my_file.desired_rendition().color() = WT_Color(254,254,254,0);
else
my_file.desired_rendition().color() = WT_Color(1,1,1,0);
}
else
my_file.desired_rendition().color() = WT_Color(255,255,255,0); //Teksten wit
CString tok(m_ExtraLabel); // strtok seems to modify
tok.Replace("~", "\n"); // We ondersteunen ook ~ als newline
tok.Replace("[br]", "\n"); // We ondersteunen ook [br] als newline
tok.Replace("[BR]", "\n"); // We ondersteunen ook [BR] als newline
WT_Logical_Point ptTxt = LabelPosition(pos);
// De wiskundige label-positie is bepaald. Nu iets corrigeren om
// (afhankelijk van het font) mooier te zijn
// Ook eventueel hori/vert centreren
int width = -1; // Voor UBB code [c] van centreren
switch (pos)
{
case CSLNKContourImpl::LABEL_DEFAULT:
break;
case CSLNKContourImpl::LABEL_TOPLEFT: // Iets naar rechtstonder moven
ptTxt.m_x += fontheight/4;
ptTxt.m_y -= fontheight;
break;
case CSLNKContourImpl::LABEL_OUTSIDERIGHT: // Iets naar rechts en verticaal centreren
{
// Eerst een keer simuleren om grootte te bepalen
ATLASSERT(myDC!=NULL);
WT_Logical_Point ptBR = DrawOneLabel(my_file, pos, ptTxt, tok, fontheight, myDC);
width = (ptBR.m_x - ptTxt.m_x);
ptTxt.m_y -= (ptBR.m_y - ptTxt.m_y)/2 + fontheight*9/10;
ptTxt.m_x += fontheight/4;
break;
}
case CSLNKContourImpl::LABEL_OUTSIDEBOTTOM: // Iets naar beneden en horizontaal centreren
{
// Eerst een keer simuleren om grootte te bepalen
ATLASSERT(myDC!=NULL);
WT_Logical_Point ptBR = DrawOneLabel(my_file, pos, ptTxt, tok, fontheight, myDC);
width = (ptBR.m_x - ptTxt.m_x);
ptTxt.m_y -= fontheight;
ptTxt.m_x -= (ptBR.m_x - ptTxt.m_x)/2;
break;
}
case CSLNKContourImpl::LABEL_CENTROID:
{ ATLASSERT(myDC!=NULL);
// Als niet binnen contour dan terugvallen op DEFAULT
if (!CSLNKContourImpl::PointInPolygon(ptTxt, *this))
ptTxt = LabelPosition(CSLNKContourImpl::LABEL_DEFAULT);
// Eerst een keer simuleren om grootte te bepalen
WT_Logical_Point ptBR = DrawOneLabel(my_file, pos, ptTxt, tok, fontheight, myDC);
width = (ptBR.m_x - ptTxt.m_x);
ptTxt.m_x -= (ptBR.m_x - ptTxt.m_x)/2;
ptTxt.m_y -= (ptBR.m_y - ptTxt.m_y)/2 + fontheight*9/10;
// Nooit verder naar links/boven dan TOPLEFT zou doen
// JGL: jul 2007: Waarom niet? Bij heel kleine ruimtes mag bij centreren de boel er best wel iets buiten
// WT_Logical_Point ptTL = LabelPosition(CSLNKContourImpl::LABEL_TOPLEFT);
//ptTxt.m_x = max(ptTxt.m_x, ptTL.m_x+fontheight/4);
//ptTxt.m_y = min(ptTxt.m_y, ptTL.m_y-fontheight);
#ifdef _DEBUG
WT_Polymarker pm(1, &ptTxt, true);
pm.serialize(my_file);
#endif
}
}
// Nu echt tekenen met width<>-2
DrawOneLabel(my_file, pos, ptTxt, tok, fontheight, myDC, width);
}
// Draw one (possibly multline) label
// When width==-2 the drawing is simulated and the result
// is the calculated bottomright of the full text
// Als width==-1 is centreren niet mogelijk/nodig
// Als width>0 is centreren mogelijk via [c]
WT_Logical_Point CSLNKContourImpl::DrawOneLabel(WT_File &my_file,
LABELPOS pos,
WT_Logical_Point ptTxt,
CString tok,
int fontheight,
HDC myDC,
int width/*=-2*/)// Voor centreren. Moet aanroeper al een keer bepaald hebben
{
long max_width=0; // Bepaal hiermee 'rechtsonder' van de tekst als myDC
//TODO: UBB sluitcodes ondersteunen
int curpos = 0;
CString token = tok.Tokenize("\n", curpos);
int line = 0;
bool centering=false;
while( token != "" )
{
//CString f(token);
int skipextra = 0; // Extra skip bij underline
long size=100;
// Supported UBB-like codes:
// [[This is literal text in square brackets]
// [i]This text is italic
// [b]This text is bold
// [u]This text is underline
// [cFF00FF]This text is colored
// [s50]This text is 50% sized
// Bovenstaand alleen voor de huidige regel
// [c] Centreer alle regels binnen bounding box (anders links gealigned)
while (token[0] == '[')
{
token.Delete(0);
if (token[0]=='[') break; // [[ALF-TB] to escape parsing
switch (tolower(token[0]))
{
case 'i': // Italic
if (width != -2)
my_file.desired_rendition().font().style().set_italic(true);
token.Delete(0);
break;
case 'b': // Bold
if (width != -2)
my_file.desired_rendition().font().style().set_bold(true);
token.Delete(0);
break;
case 'u': // Underline
if (width != -2)
my_file.desired_rendition().font().style().set_underlined(true);
token.Delete(0);
skipextra = fontheight / 5;
break;
case 'c': // Color or Center
{
int end = token.Find(']');
if (end==1)
{
token.Delete(0);
if (width>0) centering = true;
break;
}
if (end >= 0)
{
long clr;
if (sscanf(token, "c%lx]", &clr))
{
WT_Color x(clr>>16,(clr&0xff00)>>8,clr&0xff);
if (width != -2)
my_file.desired_rendition().color() = x;
}
token.Delete(0, end);
}
break;
}
case 's': // Size
{
int end = token.Find(']');
if (end >= 0)
{
if (sscanf(token, "s%d]", &size))
{
int fh = myRound(double(size)*fontheight/100);
ptTxt.m_y += (fontheight - fh);
if (width != -2)
my_file.desired_rendition().font().height() = fh;
}
token.Delete(0, end);
}
break;
}
}
if (token[0]==']') token.Delete(0); // Skip closing ]
}
if (width != -2) // Echt tekenen (lees: wegschrijven naar DWF)
{
int horoffset=0;
if (centering)
{
RECT rc = { 0, 0, 0, 0};
DrawText(myDC, token, token.GetLength(), &rc, DT_CALCRECT); // Grootte bepalen
// Tekst horizontaal centreren
horoffset = width/2 - MulDiv(rc.right*size/100,fontheight,FONT_SIZER)/2;
}
WT_String txt;
if (WT_String::is_ascii(token.GetLength(), token))
// txt.set(f.GetLength(), f);
txt.set(token.GetLength(), token);
else
{ // Use UNICODE for example for Micha<68>l
CStringW s(token);
txt.set(s.GetLength(), s);
}
WT_Text my_text(WT_Logical_Point(ptTxt.m_x+horoffset, ptTxt.m_y), txt);
my_text.serialize(my_file);
// Altijd terug voor volgende regel
my_file.desired_rendition().font().style().set_italic(false);
my_file.desired_rendition().font().style().set_bold(false);
my_file.desired_rendition().font().style().set_underlined(false);
my_file.desired_rendition().color() = WT_Color(255,255,255,0); //Teksten wit TODO: (contrasteren met background)
my_file.desired_rendition().font().height() = fontheight;
}
else
{
// We willen de breedte en hoogte weten van de volledige tekst
RECT rc = { 0, 0, 0, 0};
// Volgens de documentatie werkt DT_CALCRECT niet voor de breedte bij
// multiline teksten maar in de praktijk wel?
// ==>JGL: Onze token is toch maar <20><>n regel
DrawText(myDC, token, token.GetLength(), &rc, DT_CALCRECT); // Grootte bepalen
// Tekst horizontaal en verticaal centreren
// ptRes.m_y += rc.bottom; halen we wel uit ptY
max_width = max(max_width, MulDiv(rc.right,size,100));
}
line ++;
/* Get next token: */
token = tok.Tokenize("\n", curpos);
ptTxt.m_y -= fontheight + skipextra;
}
return WT_Logical_Point(ptTxt.m_x+MulDiv(max_width,fontheight,FONT_SIZER), ptTxt.m_y);
}
/****************************************************************************
Serialize een contour.
Varianten:
- (!fromSymbol)Gesloten polyline op contourlaag
Hiermee komen we twee keer langs, met en zonder solidOnly
- waar uiteindelijk geen label in gevonden (m_contLabel is leeg)
- waar uiteindelijk wel label in gevonden (m_Key zal waarschijnlijk contourlabel zijn maar kan zijn veranderd)
- Geen kleur gezet
- Met solid kleur gezet
- Met transparante kleur gezet
- (m_fromSymbol) Symbool (al dan niet met m_Key gedefinieerd)
- Ingebouwd (star)
- Gedefinieerd (bounding octagon)
Als solidOnly dan alleen als alpha==255 en een label (wel herkend)
****************************************************************************/
WT_Result CSLNKContourImpl::serialize(WT_File & file, BOOL solidOnly)
{
if (!m_fromSymbol && m_contLabel == "" && !solidOnly) // Alleen bij tweede slag
{ // May very well be a textobject itself, just emit it
file.desired_rendition().color() =
WT_Color(PALETTE_RED, file.desired_rendition().color_map());
file.desired_rendition().line_weight() = 0;
WT_Polyline my_line( count(), points(), WD_False);
my_line.serialize(file);
}
else
{ // We have got a proper label/contour
if (m_fromSymbol ||
(m_Color.rgba().m_rgb.a==255 && solidOnly) ||
(m_Color.rgba().m_rgb.a<255 && !solidOnly))
{
// Start a node for 'everything'. Dit is wat we concreet teruggeven bij klikken in de tekening
WT_Object_Node my_node(file,m_next_node_num++,m_Key);
file.desired_rendition().object_node() = my_node;
//char s[256];
//sprintf(s, "Ruimte %s (%.2fm2)", m_Label.ascii(), m_DWGArea/1e6);
// Van de URL gebruiken we met name de friendlyName voor de poly2Map
if (m_Url.index() !=0 )
{
file.desired_rendition().url().add_url_optimized(m_Url, file);
}
//
// Add the filled polygon for the room
//
// Ook als geheel doorzichtig
// - poly2Map heeft namelijk een poly nodig
// - voor als we ruimte willen aanwijzen want de point-in werkt later op polygons
file.desired_rendition().color() = m_Color; // Set the color for the polygon
WT_Polygon my_poly( count(), points(), WD_False);
my_poly.serialize(file);
#if 0
WT_RGBA32 rgba[3];
WT_RGBA32 clr(this.m_Color.rgba());
rgba[0] = clr;
rgba[1] = WT_RGBA32 (clr.m_rgb.r+64>255?255:clr.m_rgb.r+64,
clr.m_rgb.g+64>255?255:clr.m_rgb.g+64,
clr.m_rgb.b+64>255?255:clr.m_rgb.b+64, clr.m_rgb.a);
rgba[1] = WT_RGBA32 (clr.m_rgb.r-64<0?0:clr.m_rgb.r-64,
clr.m_rgb.g-64<0?0:clr.m_rgb.g-64,
clr.m_rgb.b-64<0?0:clr.m_rgb.b-64, clr.m_rgb.a);
rgba[2] = rgba[1];
WT_Logical_Point vP[3];
vP[0] = this.LabelPosition(CSLNKContourImpl::LABEL_CENTROID);
if (!CSLNKContourImpl::PointInPolygon(vP[0], *contour))
vP[0] = this.LabelPosition(CSLNKContourImpl::LABEL_DEFAULT);
for (int i = 0; i < count()-1; i++)
{
vP[1] = points()[i];
vP[2] = points()[i+1];
WT_Gouraud_Polytriangle gpt (3, vP, rgba, WD_True);
gpt.serialize (my_file);
}
#endif
if (m_Pattern.pattern_id() != WT_Fill_Pattern::Solid)
{ // Nog een keer gearceerd
WT_Fill_Pattern pOld = file.desired_rendition().fill_pattern();
file.desired_rendition().fill_pattern() = m_Pattern;
WT_RGBA32 clr(m_Color.rgba());
//WT_Color xor((128+clr.m_rgb.r)%256, (128+clr.m_rgb.g)%256,(128+clr.m_rgb.b)%256);
WT_Color xor(255, (128+clr.m_rgb.g)%256,(128+clr.m_rgb.b)%256);
file.desired_rendition().color() = xor; // Inverse
WT_Polygon my_poly2( count(), points(), WD_False);
my_poly2.serialize(file);
file.desired_rendition().fill_pattern() = pOld;
}
//
// Nu nogmaals om de rand van de ruimte te tekenen
// Dikte is door de aanroeper al gezet
//
// TODO: Altijd contrasteren met achtergrond
if (m_outlineAlpha>0) // Voor symbolen niet nodig
{
file.desired_rendition().color() = WT_Color(128,128,128, m_outlineAlpha); // Set the color for the polyline
//my_file.desired_rendition().color() = WT_Color(0,0,0); // Zwart
WT_Polyline my_line( count(), points(), WD_False);
my_line.serialize(file);
}
file.desired_rendition().url().clear();
}
}
return WT_Result::Success;
};
#ifndef DWFTK_READ_ONLY
void CSLNKContourImpl::serializeXML( DWFToolkit::DWFXMLSerializer& rSerializer, unsigned int nFlags )
throw( DWFException )
{
rSerializer.startElement( L"Contour ", L"SLNKDWF" );
rSerializer.addAttribute( L"Label", DWFString(m_contLabel) );
wchar_t zTempBuffer[32];
_DWFCORE_SWPRINTF( zTempBuffer, 32, L"%.2f", m_DWGArea );
rSerializer.addAttribute( "Area", zTempBuffer );
//rSerializer.addAttribute( DWFXML::kzAttribute_Category, _zCategory );
//rSerializer.addAttribute( DWFXML::kzAttribute_Type, _zType );
//rSerializer.addAttribute( DWFXML::kzAttribute_Units, _zUnits );
rSerializer.endElement();
}
#endif