mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-07-11 22:03:01 -06:00
Bazaar/DXF : provide a GetBoundingBox() function and zoom to drawing extents upon saving
git-svn-id: svn://ultimatepp.org/upp/trunk@5276 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
parent
2539ab8e37
commit
ebcd401c53
15 changed files with 198 additions and 120 deletions
|
|
@ -74,3 +74,36 @@ DXFBlockRef &DXFBlockRef::Set(String const &n, Pointf const &p, double s, double
|
|||
angle = R(a);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// gets bounding box of element
|
||||
Rectf DXFBlockRef::GetBoundingBox(void) const
|
||||
{
|
||||
Rectf res;
|
||||
|
||||
// get dxf object
|
||||
DXF const &dxf = GetDXF();
|
||||
|
||||
// get block data by name; if none, returns
|
||||
if(!dxf.HasBlock(name))
|
||||
return Rectf(1e99, -1e99, -1e99, 1e99);
|
||||
DXFBlock const &blk = dxf.GetBlock(name);
|
||||
|
||||
// get the bounding box of included entities
|
||||
Rectf bbe = blk.entities.GetBoundingBox();
|
||||
|
||||
// now we need to apply transformation to bbox points
|
||||
TransMatrix M;
|
||||
M.Translate(insertPoint).Rotate(angle).Scale(scale);
|
||||
Pointf bl = M(bbe.BottomLeft());
|
||||
Pointf tl = M(bbe.TopLeft());
|
||||
Pointf br = M(bbe.BottomRight());
|
||||
Pointf tr = M(bbe.TopRight());
|
||||
|
||||
// and now get the minimum and maximum coordinate values
|
||||
res.left = min(min(bl.x, tl.x), min(br.x, tr.x));
|
||||
res.right = max(max(bl.x, tl.x), max(br.x, tr.x));
|
||||
res.bottom = min(min(bl.y, tl.y), min(br.y, tr.y));
|
||||
res.top = max(max(bl.y, tl.y), max(br.y, tr.y));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,9 @@ class DXFBlockRef : public DXFEntity
|
|||
DXFBlockRef &SetAngle(double a);
|
||||
DXFBlockRef &Set(Pointf const &p, double s, double a);
|
||||
DXFBlockRef &Set(String const &n, Pointf const &p, double s, double a);
|
||||
|
||||
// gets bounding box of element
|
||||
virtual Rectf GetBoundingBox(void) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -40,3 +40,9 @@ DXFCircle &DXFCircle::Set(Pointf c, double d)
|
|||
radius = S(d);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// gets bounding box of element
|
||||
Rectf DXFCircle::GetBoundingBox(void) const
|
||||
{
|
||||
return Rectf(center.x - radius, center.y + radius, center.x + radius, center.y - radius);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,9 @@ class DXFCircle : public DXFEntity
|
|||
DXFCircle &Set(Pointf const &c);
|
||||
DXFCircle &Set(double d);
|
||||
DXFCircle &Set(Pointf c, double d);
|
||||
|
||||
// gets bounding box of element
|
||||
virtual Rectf GetBoundingBox(void) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -20,11 +20,26 @@ DXF::DXF() : nextHandle(0x1000), blocks(this), objects(this), tables(this)
|
|||
|
||||
// do NOT scale insertions by default
|
||||
scaleInsertions = false;
|
||||
|
||||
// initialize view center and height
|
||||
viewCenter = Pointf(100, 100);
|
||||
viewHeight = 50;
|
||||
}
|
||||
|
||||
// write drawing to file
|
||||
bool DXF::Write(Stream &s)
|
||||
{
|
||||
// if we've got some entities, calculate drawing bounding box
|
||||
// and zoom to fit it before saving
|
||||
if(entities.entities.GetCount())
|
||||
{
|
||||
Rectf bb = entities.GetBoundingBox();
|
||||
viewCenter = Pointf( (bb.left + bb.right) / 2, (bb.top + bb.bottom) / 2);
|
||||
viewHeight = bb.top - bb.bottom;
|
||||
double viewWidth = bb.right - bb.left;
|
||||
if(viewHeight * 2.128571428571428 < viewWidth)
|
||||
viewHeight = viewWidth / 2.128571428571428;
|
||||
}
|
||||
header.Write(s);
|
||||
tables.Write(s);
|
||||
blocks.Write(s);
|
||||
|
|
@ -69,3 +84,11 @@ DXFBlock &DXF::GetBlock(String const &name)
|
|||
return blocks.blocks[idx];
|
||||
return *(DXFBlock *)NULL;
|
||||
}
|
||||
|
||||
DXFBlock const &DXF::GetBlock(String const &name) const
|
||||
{
|
||||
int idx = blocks.blocks.Find(name);
|
||||
if(idx >= 0)
|
||||
return blocks.blocks[idx];
|
||||
return *(DXFBlock *)NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,6 +50,11 @@ class DXF : public DXFBlock
|
|||
|
||||
// flag for scaling insertions with transform matrix
|
||||
bool scaleInsertions;
|
||||
|
||||
// view center point and height
|
||||
// calculated from GetBoundingBox functions
|
||||
Pointf viewCenter;
|
||||
double viewHeight;
|
||||
|
||||
protected:
|
||||
|
||||
|
|
@ -77,6 +82,7 @@ class DXF : public DXFBlock
|
|||
|
||||
// gets a block by name
|
||||
DXFBlock &GetBlock(String const &name);
|
||||
DXFBlock const &GetBlock(String const &name) const;
|
||||
|
||||
// sets insertion scale option
|
||||
DXF &SetScaleInsertions(bool i = true) { scaleInsertions = i; return *this; }
|
||||
|
|
|
|||
|
|
@ -133,3 +133,18 @@ DXFBlockRef &DXFEntities::InsertBlock(String const &name, Pointf const &insp, do
|
|||
entities.Add(blk);
|
||||
return *blk;
|
||||
}
|
||||
|
||||
// get bounding box of entities
|
||||
Rectf DXFEntities::GetBoundingBox(void) const
|
||||
{
|
||||
Rectf bb(1e99, -1e99, -1e99, 1e99);
|
||||
for(int i = 0; i < entities.GetCount(); i++)
|
||||
{
|
||||
Rectf r = entities[i].GetBoundingBox();
|
||||
bb.left = min(bb.left, r.left);
|
||||
bb.top = max(bb.top, r.top);
|
||||
bb.right = max(bb.right, r.right);
|
||||
bb.bottom = min(bb.bottom, r.bottom);
|
||||
}
|
||||
return bb;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,6 +73,9 @@ class DXFEntities : public Pte<DXFEntities>
|
|||
DXFBlockRef &InsertBlock(String const &name, Pointf const &insp, double scale, double angle);
|
||||
DXFBlockRef &InsertBlock(String const &name, Pointf const &insp, double scale) { return InsertBlock(name, insp, scale, 0.0); }
|
||||
DXFBlockRef &InsertBlock(String const &name, Pointf const &insp) { return InsertBlock(name, insp, 1.0, 0.0); }
|
||||
|
||||
// get bounding box of entities
|
||||
Rectf GetBoundingBox(void) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -71,6 +71,9 @@ class DXFEntity
|
|||
// gets/sets linetype
|
||||
DXFEntity *SetLineType(String const &l);
|
||||
String const &GetLineType(void) const { return lineType; }
|
||||
|
||||
// gets bounding box of element
|
||||
virtual Rectf GetBoundingBox(void) const { return Rectf(1e99, -1e99, -1e99, 1e99); }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -30,3 +30,9 @@ bool DXFLine::Write(Stream &s)
|
|||
s << "11\n" << p2.x << "\n21\n" << p2.y << "\n31\n" << 0.0 << "\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
// gets bounding box of element
|
||||
Rectf DXFLine::GetBoundingBox(void) const
|
||||
{
|
||||
return Rectf(min(p1.x, p2.x), max(p1.y, p2.y), max(p1.x, p2.x), min(p1.y, p2.y));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@ class DXFLine : public DXFEntity
|
|||
Pointf const &GetP2(void) const { return p2; }
|
||||
Vector<Pointf> GetPoints(void) const;
|
||||
DXFLine &SetPoints(Pointf const &p1, Pointf const &p2);
|
||||
|
||||
// gets bounding box of element
|
||||
virtual Rectf GetBoundingBox(void) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -320,3 +320,77 @@ DXFLwPolyline &DXFLwPolyline::SetWidth(double w)
|
|||
width = w;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// normalizes an angle in range 0..2 * M_PI
|
||||
static double norm(double a)
|
||||
{
|
||||
a = fmod(a, 2 * M_PI);
|
||||
if(a < 0)
|
||||
a = 2 * M_PI + a;
|
||||
return a;
|
||||
}
|
||||
|
||||
// gets bounding box of element
|
||||
Rectf DXFLwPolyline::GetBoundingBox(void) const
|
||||
{
|
||||
Rectf r(1e99, -1e99, -1e99, 1e99);
|
||||
for(int i = 0; i < vertices.GetCount(); i++)
|
||||
{
|
||||
Pointf const &p = vertices[i];
|
||||
|
||||
// first, check the vertex
|
||||
r.left = min(r.left, p.x);
|
||||
r.top = max(r.top, p.y);
|
||||
r.right = max(r.right, p.x);
|
||||
r.bottom = min(r.bottom, p.y);
|
||||
|
||||
// get the bulge at vertex; if not zero, we need to check
|
||||
// the arc for extents
|
||||
if(bulges[i] != 0)
|
||||
{
|
||||
Pointf const &p2 = (i < vertices.GetCount() - 1 ? vertices[i + 1] : vertices[0]);
|
||||
|
||||
// skip me if points are the same OR second point is first one and pline
|
||||
// is not closed
|
||||
if(&p != &p2 && (closed || &p2 != &vertices[0]))
|
||||
{
|
||||
// first, we need radius and center
|
||||
// here quite complicated, but it should be a simpler way...
|
||||
double chord = sqrt(sqr(p2.x - p.x) + sqr(p2.y - p.y));
|
||||
double sagitta = fabs(chord / 2 * bulges[i]);
|
||||
double radius = (sqr(chord / 2) + sqr(sagitta)) / 2 / sagitta;
|
||||
double a12 = atan2(p2.y - p.y, p2.x - p.x);
|
||||
double xm = (p2.x + p.x) / 2;
|
||||
double ym = (p2.y - p.y) / 2;
|
||||
double apot = radius - sagitta;
|
||||
double ac = bulges[i] > 0 ? a12 + M_PI / 2 : a12 - M_PI / 2;
|
||||
double xc = xm + apot * cos(ac);
|
||||
double yc = ym + apot * sin(ac);
|
||||
|
||||
// now we check how many quadrants does the arc span
|
||||
// first, we take the angle of arc endpoints and adjust it
|
||||
// depending on arc direction
|
||||
double a1 = atan2(p.y - yc, p.x - xc);
|
||||
double a2 = atan2(p2.y - yc, p2.x - xc);
|
||||
if(bulges[i] < 0)
|
||||
{
|
||||
double t = a1;
|
||||
a1 = a2;
|
||||
a2 = t;
|
||||
}
|
||||
|
||||
// check if crossing quadrants
|
||||
bool cross0 = norm(a1) > norm(a2);
|
||||
bool cross90 = norm(a1 - M_PI / 2) > norm(a2 - M_PI / 2);
|
||||
bool cross180 = norm(a1 - M_PI) > norm(a2 - M_PI);
|
||||
bool cross270 = norm(a1 - 3 * M_PI / 2) > norm(a2 - 3 * M_PI / 2);
|
||||
|
||||
if(cross0) r.right = xc + radius;
|
||||
if(cross90) r.top = yc + radius;
|
||||
if(cross180) r.left = xc - radius;
|
||||
if(cross270) r.bottom = yc - radius;
|
||||
}
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,6 +71,9 @@ class DXFLwPolyline : public DXFEntity
|
|||
// get/set global width
|
||||
double GetWidth(void) { return width; }
|
||||
DXFLwPolyline &SetWidth(double w);
|
||||
|
||||
// gets bounding box of element
|
||||
virtual Rectf GetBoundingBox(void) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -153,6 +153,23 @@ bool DXFTables::Write(Stream &s)
|
|||
{
|
||||
s << "0\nSECTION\n2\nTABLES\n";
|
||||
|
||||
// active viweport -- partially hardwired, we just need to set
|
||||
// zoom factor and view center point to fit created drawing
|
||||
s << "0\nTABLE\n2\nVPORT\n";
|
||||
s << "5\n8\n330\n0\n100\nAcDbSymbolTable\n70\n2\n";
|
||||
s << "0\nVPORT\n5\n676\n330\n8\n100\nAcDbSymbolTableRecord\n100\nAcDbViewportTableRecord\n";
|
||||
s << "2\n*Active\n70\n0\n";
|
||||
s << "10\n0.0\n20\n0.0\n11\n1.0\n21\n1.0\n";
|
||||
s << "12\n" << dxf->viewCenter.x << "\n22\n" << dxf->viewCenter.y << "\n";
|
||||
s << "13\n0.0\n23\n0.0\n14\n10.0\n24\n10.0\n15\n10.0\n25\n10.0\n16\n0.0\n26\n0.0\n36\n1.0\n";
|
||||
s << "17\n0.0\n27\n0.0\n37\n0.0\n";
|
||||
s << "40\n" << dxf->viewHeight << "\n41\n2.128571428571428\n";
|
||||
s << "42\n50.0\n43\n0.0\n44\n0.0\n50\n0.0\n51\n0.0\n";
|
||||
s << "71\n0\n72\n1000\n73\n1\n74\n1\n75\n0\n76\n0\n77\n0\n78\n0\n";
|
||||
s << "281\n0\n65\n1\n110\n0.0\n120\n0.0\n130\n0.0\n111\n1.0\n121\n0.0\n131\n0.0\n";
|
||||
s << "112\n0.0\n122\n1.0\n132\n0.0\n79\n0\n146\n0.0\n";
|
||||
s << "0\nENDTAB\n";
|
||||
|
||||
// hardwired tables from template
|
||||
s << (const char *)dxf_tbl;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,126 +1,6 @@
|
|||
0
|
||||
TABLE
|
||||
2
|
||||
VPORT
|
||||
5
|
||||
8
|
||||
330
|
||||
0
|
||||
100
|
||||
AcDbSymbolTable
|
||||
70
|
||||
2
|
||||
0
|
||||
VPORT
|
||||
5
|
||||
676
|
||||
330
|
||||
8
|
||||
100
|
||||
AcDbSymbolTableRecord
|
||||
100
|
||||
AcDbViewportTableRecord
|
||||
2
|
||||
*Active
|
||||
70
|
||||
0
|
||||
10
|
||||
0.0
|
||||
20
|
||||
0.0
|
||||
11
|
||||
1.0
|
||||
21
|
||||
1.0
|
||||
12
|
||||
1267.482156174376
|
||||
22
|
||||
595.4614156523915
|
||||
13
|
||||
0.0
|
||||
23
|
||||
0.0
|
||||
14
|
||||
10.0
|
||||
24
|
||||
10.0
|
||||
15
|
||||
10.0
|
||||
25
|
||||
10.0
|
||||
16
|
||||
0.0
|
||||
26
|
||||
0.0
|
||||
36
|
||||
1.0
|
||||
17
|
||||
0.0
|
||||
27
|
||||
0.0
|
||||
37
|
||||
0.0
|
||||
40
|
||||
1190.922831304783
|
||||
41
|
||||
2.128571428571428
|
||||
42
|
||||
50.0
|
||||
43
|
||||
0.0
|
||||
44
|
||||
0.0
|
||||
50
|
||||
0.0
|
||||
51
|
||||
0.0
|
||||
71
|
||||
0
|
||||
72
|
||||
1000
|
||||
73
|
||||
1
|
||||
74
|
||||
1
|
||||
75
|
||||
0
|
||||
76
|
||||
0
|
||||
77
|
||||
0
|
||||
78
|
||||
0
|
||||
281
|
||||
0
|
||||
65
|
||||
1
|
||||
110
|
||||
0.0
|
||||
120
|
||||
0.0
|
||||
130
|
||||
0.0
|
||||
111
|
||||
1.0
|
||||
121
|
||||
0.0
|
||||
131
|
||||
0.0
|
||||
112
|
||||
0.0
|
||||
122
|
||||
1.0
|
||||
132
|
||||
0.0
|
||||
79
|
||||
0
|
||||
146
|
||||
0.0
|
||||
0
|
||||
ENDTAB
|
||||
0
|
||||
TABLE
|
||||
2
|
||||
STYLE
|
||||
5
|
||||
3
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue