726 lines
23 KiB
C++
726 lines
23 KiB
C++
#include "StdAfx.h"
|
||
#include "slnkcontourImpl.h"
|
||
#include <math.h>
|
||
|
||
#ifndef PI
|
||
#define PI 3.14159265358979323846
|
||
#endif
|
||
|
||
#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_outlineColor(WT_RGBA32(128,128,128,255))
|
||
{
|
||
m_Color = WT_RGBA32(0,0,0,0); // alpha==0, onzichtbaar
|
||
m_Lineweight = 10.0; // 10mm default
|
||
m_Fontheight = 200.0;
|
||
m_Labelpos = LABEL_DEFAULT;
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
// http://www.codeguru.com/forum/printthread.php?t=194400
|
||
void DistanceFromLine(double cx, double cy, double ax, double ay ,
|
||
double bx, double by, double &distanceSegment,
|
||
double &distanceLine)
|
||
{
|
||
|
||
//
|
||
// find the distance from the point (cx,cy) to the line
|
||
// determined by the points (ax,ay) and (bx,by)
|
||
//
|
||
// distanceSegment = distance from the point to the line segment
|
||
// distanceLine = distance from the point to the line (assuming
|
||
// infinite extent in both directions
|
||
//
|
||
|
||
/*
|
||
|
||
Subject 1.02: How do I find the distance from a point to a line?
|
||
|
||
|
||
Let the point be C (Cx,Cy) and the line be AB (Ax,Ay) to (Bx,By).
|
||
Let P be the point of perpendicular projection of C on AB. The parameter
|
||
r, which indicates P's position along AB, is computed by the dot product
|
||
of AC and AB divided by the square of the length of AB:
|
||
|
||
(1) AC dot AB
|
||
r = ---------
|
||
||AB||^2
|
||
|
||
r has the following meaning:
|
||
|
||
r=0 P = A
|
||
r=1 P = B
|
||
r<0 P is on the backward extension of AB
|
||
r>1 P is on the forward extension of AB
|
||
0<r<1 P is interior to AB
|
||
|
||
The length of a line segment in d dimensions, AB is computed by:
|
||
|
||
L = sqrt( (Bx-Ax)^2 + (By-Ay)^2 + ... + (Bd-Ad)^2)
|
||
|
||
so in 2D:
|
||
|
||
L = sqrt( (Bx-Ax)^2 + (By-Ay)^2 )
|
||
|
||
and the dot product of two vectors in d dimensions, U dot V is computed:
|
||
|
||
D = (Ux * Vx) + (Uy * Vy) + ... + (Ud * Vd)
|
||
|
||
so in 2D:
|
||
|
||
D = (Ux * Vx) + (Uy * Vy)
|
||
|
||
So (1) expands to:
|
||
|
||
(Cx-Ax)(Bx-Ax) + (Cy-Ay)(By-Ay)
|
||
r = -------------------------------
|
||
L^2
|
||
|
||
The point P can then be found:
|
||
|
||
Px = Ax + r(Bx-Ax)
|
||
Py = Ay + r(By-Ay)
|
||
|
||
And the distance from A to P = r*L.
|
||
|
||
Use another parameter s to indicate the location along PC, with the
|
||
following meaning:
|
||
s<0 C is left of AB
|
||
s>0 C is right of AB
|
||
s=0 C is on AB
|
||
|
||
Compute s as follows:
|
||
|
||
(Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay)
|
||
s = -----------------------------
|
||
L^2
|
||
|
||
|
||
Then the distance from C to P = |s|*L.
|
||
|
||
*/
|
||
|
||
|
||
double r_numerator = (cx-ax)*(bx-ax) + (cy-ay)*(by-ay);
|
||
double r_denomenator = (bx-ax)*(bx-ax) + (by-ay)*(by-ay);
|
||
double r = r_numerator / r_denomenator;
|
||
//
|
||
double px = ax + r*(bx-ax);
|
||
double py = ay + r*(by-ay);
|
||
//
|
||
double s = ((ay-cy)*(bx-ax)-(ax-cx)*(by-ay) ) / r_denomenator;
|
||
|
||
distanceLine = fabs(s)*sqrt(r_denomenator);
|
||
|
||
//
|
||
// (xx,yy) is the point on the lineSegment closest to (cx,cy)
|
||
//
|
||
double xx = px;
|
||
double yy = py;
|
||
|
||
if ( (r >= 0) && (r <= 1) )
|
||
{
|
||
distanceSegment = distanceLine;
|
||
}
|
||
else
|
||
{
|
||
|
||
double dist1 = (cx-ax)*(cx-ax) + (cy-ay)*(cy-ay);
|
||
double dist2 = (cx-bx)*(cx-bx) + (cy-by)*(cy-by);
|
||
if (dist1 < dist2)
|
||
{
|
||
xx = ax;
|
||
yy = ay;
|
||
distanceSegment = sqrt(dist1);
|
||
}
|
||
else
|
||
{
|
||
xx = bx ;
|
||
yy = by;
|
||
distanceSegment = sqrt(dist2);
|
||
}
|
||
|
||
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
// Vind de hoek van de edge van ps die het dichtst bij pt ligt
|
||
// (het maakt ons niet uit of pt er binnen of buiten ligt)
|
||
// A = P2Y - P1Y
|
||
// B = P1X - P2X
|
||
// C = P2X * P1Y - P2Y * P1X
|
||
// DistToLine = Abs((A * PX + B * PY + C) / Sqr(A * A + B * B))
|
||
/*static*/ void CSLNKContourImpl::EdgeAngle(const WT_Logical_Point pt, const WT_Point_Set &ps, double &EdgeAngle, double &EdgeDistance)
|
||
{
|
||
double ptx = pt.m_x;
|
||
double pty = pt.m_y;
|
||
int i, j, c = 0;
|
||
double minDistSeg = 0x7FFFFFFF; // Max WT_Integer32
|
||
double minDistLine;
|
||
double angle = 0.0;
|
||
myTRACE("\npt = %d,%d", pt.m_x, pt.m_y);
|
||
for (i = 0, j = ps.count()-1; i < ps.count(); j = i++) {
|
||
WT_Logical_Point pt1 = ps.points()[i];
|
||
WT_Logical_Point pt2 = ps.points()[j];
|
||
double DistSeg, DistLine;
|
||
DistanceFromLine(pt.m_x, pt.m_y,
|
||
pt1.m_x, pt1.m_y,
|
||
pt2.m_x, pt2.m_y,
|
||
DistSeg, DistLine);
|
||
|
||
// Bij een 'ingedeukte' ruimte kan DistSeg == minDistSeg zijn. Dan wil
|
||
// je juist een zo'n groot mogelijke afstand tot de virtuele projectie
|
||
if (DistSeg < minDistSeg || (DistSeg == minDistSeg && DistLine > minDistLine))
|
||
{
|
||
long dy = pt2.m_y - pt1.m_y;
|
||
long dx = pt2.m_x - pt1.m_x;
|
||
|
||
//ASSERT(!(dx == 0 && dy == 0));
|
||
|
||
angle = atan2((double)dy, (double)dx) * (180 / PI); // Tussen -180 en +180
|
||
if (dy==0) if (dx<0) angle=-180; else angle=0;
|
||
|
||
myTRACE("\nDist %.1f angle set to: %.3f", DistSeg, angle);
|
||
minDistSeg = DistSeg;
|
||
minDistLine = DistLine;
|
||
}
|
||
}
|
||
if (DWFArea(ps) < 0)
|
||
EdgeAngle = angle;
|
||
else
|
||
EdgeAngle = 180+angle;
|
||
if (EdgeAngle < 0) EdgeAngle += 360;
|
||
EdgeDistance = minDistLine; //We rekenen met Seg maar projecteren uiteindelijk op Line
|
||
}
|
||
|
||
// Signed Area needed for centroid!
|
||
// Negative is clockwise, Positive counterclockwise
|
||
/*static*/double CSLNKContourImpl::DWFArea(const WT_Point_Set &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_Point_Set &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,
|
||
double scale,
|
||
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_ShowLabel); // 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(m_Labelpos);
|
||
int l_fontheight = myRound(m_Fontheight * scale);
|
||
|
||
// 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 (m_Labelpos)
|
||
{
|
||
case CSLNKContourImpl::LABEL_DEFAULT:
|
||
break;
|
||
case CSLNKContourImpl::LABEL_TOPLEFT: // Iets naar rechtstonder moven
|
||
ptTxt.m_x += l_fontheight/4;
|
||
ptTxt.m_y -= l_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, ptTxt, tok, l_fontheight, scale, myDC);
|
||
width = (ptBR.m_x - ptTxt.m_x);
|
||
ptTxt.m_y -= (ptBR.m_y - ptTxt.m_y)/2 + l_fontheight*9/10;
|
||
ptTxt.m_x += l_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, ptTxt, tok, l_fontheight, scale, myDC);
|
||
width = (ptBR.m_x - ptTxt.m_x);
|
||
ptTxt.m_y -= l_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, ptTxt, tok, l_fontheight, scale, 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 + l_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 + l_fontheight/4);
|
||
//ptTxt.m_y = min(ptTxt.m_y, ptTL.m_y - l_fontheight);
|
||
#ifdef _DEBUG
|
||
WT_Polymarker pm(1, &ptTxt, true);
|
||
pm.serialize(my_file);
|
||
#endif
|
||
}
|
||
}
|
||
|
||
// Nu echt tekenen met width<>-2
|
||
DrawOneLabel(my_file, ptTxt, tok, l_fontheight, scale, 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,
|
||
WT_Logical_Point ptTxt,
|
||
CString tok,
|
||
int l_fontheight,
|
||
double scale,
|
||
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
|
||
my_file.desired_rendition().font().height() = l_fontheight;
|
||
|
||
//TODO: UBB sluitcodes ondersteunen
|
||
int curpos = 0;
|
||
CString token = tok.Tokenize("\n", curpos);
|
||
int line = 0;
|
||
bool centering=false;
|
||
while( token != "" )
|
||
{
|
||
// invariant (ook bij binnenkomst): ptTxt.m_y bevat het linksonderpunt van de huidige regel
|
||
// uitgaande van l_fontheight. Bij [s] gebruik moeten we dus corrigeren
|
||
//CString f(token);
|
||
int skipextra = 0; // Extra skip bij underline
|
||
long size=100;
|
||
int thisLineHeight = l_fontheight; // mooie default
|
||
|
||
// 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 van standaard labelfont
|
||
// [S800]This text is 800 height sized
|
||
// Bovenstaand alleen voor de huidige regel
|
||
// [c] Centreer alle(!) volgende 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 = l_fontheight / 5;
|
||
break;
|
||
case 'c': // Color or Center
|
||
{
|
||
int end = token.Find(']');
|
||
if (end==1)
|
||
{
|
||
token.Delete(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
|
||
{
|
||
BOOL bigS = (token[0]=='S');
|
||
int end = token.Find(']');
|
||
if (end >= 0)
|
||
{
|
||
token.Delete(0);
|
||
if (sscanf(token, "%d]", &size))
|
||
{
|
||
if (bigS)
|
||
thisLineHeight = myRound(size * scale);
|
||
else
|
||
thisLineHeight = myRound(double(size)*l_fontheight/100);
|
||
|
||
ptTxt.m_y -= (thisLineHeight - l_fontheight); // Correctie op de invariant voor huidige regel
|
||
if (width != -2)
|
||
my_file.desired_rendition().font().height() = thisLineHeight;
|
||
}
|
||
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,thisLineHeight,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() = l_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,thisLineHeight,l_fontheight));
|
||
}
|
||
|
||
line ++;
|
||
/* Get next token: */
|
||
token = tok.Tokenize("\n", curpos);
|
||
|
||
ptTxt.m_y -= l_fontheight + skipextra;
|
||
}
|
||
return WT_Logical_Point(ptTxt.m_x+MulDiv(max_width,l_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, BOOL forFind, double scale)
|
||
{
|
||
if (!m_fromSymbol && m_contLabel == "" && !solidOnly) // Alleen bij tweede slag
|
||
{ // May very well be a textobject itself, just emit it
|
||
#ifdef _DEBUG
|
||
// niet meer in release-mode
|
||
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);
|
||
#endif
|
||
}
|
||
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;
|
||
}
|
||
|
||
file.desired_rendition().url().clear();
|
||
}
|
||
|
||
//
|
||
// Nu nogmaals om de zichtbare rand van de ruimte te tekenen
|
||
//
|
||
if (!solidOnly // Randje altijd alleen in de tweede slag zodat bij voorkeur bovenop
|
||
&& m_outlineColor.rgba().m_rgb.a>0) // Voor symbolen niet nodig
|
||
{
|
||
file.desired_rendition().color() = m_outlineColor; // Set the color for the polyline
|
||
file.desired_rendition().line_weight() = myRound(m_Lineweight * scale);
|
||
// Fraaier bij lijndikte aan begin/eind
|
||
file.desired_rendition().line_style().line_end_cap() = WT_Line_Style::Round_Cap;
|
||
|
||
// Als eerste punt ongelijk aan laatste punt dan points() eentje uitbreiden
|
||
// De polygon sluit vanzelf wel maar deze polyline niet
|
||
if (count() > 2 && (points()[0].m_x != points()[count()-1].m_x || points()[0].m_y != points()[count()-1].m_y))
|
||
AddPoint(points()[0]);
|
||
|
||
WT_Polyline my_line( count(), points(), WD_False);
|
||
my_line.serialize(file);
|
||
}
|
||
}
|
||
return WT_Result::Success;
|
||
};
|
||
|
||
void CSLNKContourImpl::AddPoint(double pValX, double pValY, WT_Units units)
|
||
{
|
||
AddPoint(units.transform(WT_Point3D(pValX, pValY)));
|
||
}
|
||
|
||
void CSLNKContourImpl::AddPoint(WT_Logical_Point pt)
|
||
{
|
||
bool wasEmpty = (points()[0].m_x == INT_MAX &&
|
||
points()[0].m_y == INT_MAX);
|
||
|
||
// TODO: Overflow controle?
|
||
WT_Logical_Point *pts = new WT_Logical_Point[count()+1];
|
||
int i;
|
||
for (i = 0; i < count(); i++)
|
||
{
|
||
pts[i] = points()[i];
|
||
}
|
||
// Het nieuwe punt
|
||
pts[i] = pt;
|
||
|
||
// Bij wasEmpty het eerste dummy punt overslaan
|
||
set(wasEmpty?1:(count() + 1), &pts[wasEmpty?1:0], true);
|
||
|
||
// Na elk punt voor de zekerheid area opnieuw?
|
||
if (wasEmpty)
|
||
m_ptLabel = points()[0];
|
||
|
||
delete[] pts;
|
||
} |