"Professional CMake" book suggest the following: "Targets should build successfully with or without compiler support for precompiled headers. It should be considered an optimization, not a requirement. In particular, do not explicitly include a precompile header (e.g. stdafx.h) in the source code, let CMake force-include an automatically generated precompile header on the compiler command line instead. This is more portable across the major compilers and is likely to be easier to maintain. It will also avoid warnings being generated from certain code checking tools like iwyu (include what you use)." Therefore, removed the "#include <PreCompiled.h>" from sources, also there is no need for the "#ifdef _PreComp_" anymore
742 lines
26 KiB
C++
742 lines
26 KiB
C++
/***************************************************************************
|
|
* Copyright (c) 2011 Werner Mayer <wmayer[at]users.sourceforge.net> *
|
|
* *
|
|
* This file is part of the FreeCAD CAx development system. *
|
|
* *
|
|
* This library is free software; you can redistribute it and/or *
|
|
* modify it under the terms of the GNU Library General Public *
|
|
* License as published by the Free Software Foundation; either *
|
|
* version 2 of the License, or (at your option) any later version. *
|
|
* *
|
|
* This library is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU Library General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU Library General Public *
|
|
* License along with this library; see the file COPYING.LIB. If not, *
|
|
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
|
* Suite 330, Boston, MA 02111-1307, USA *
|
|
* *
|
|
***************************************************************************/
|
|
//this file originally part of TechDraw workbench
|
|
//migrated to TechDraw workbench 2022-01-26 by Wandererfan
|
|
|
|
|
|
# include <cmath>
|
|
# include <sstream>
|
|
# include <Approx_Curve3d.hxx>
|
|
# include <BRep_Tool.hxx>
|
|
# include <BRepAdaptor_Curve.hxx>
|
|
# include <BRepBuilderAPI_MakeEdge.hxx>
|
|
# include <BRepLProp_CLProps.hxx>
|
|
# include <Geom_BezierCurve.hxx>
|
|
# include <Geom_BSplineCurve.hxx>
|
|
# include <GeomConvert_BSplineCurveKnotSplitting.hxx>
|
|
# include <GeomConvert_BSplineCurveToBezierCurve.hxx>
|
|
# include <gp_Ax2.hxx>
|
|
# include <gp_Dir.hxx>
|
|
# include <gp_Circ.hxx>
|
|
# include <gp_Elips.hxx>
|
|
# include <gp_Pnt.hxx>
|
|
# include <gp_Vec.hxx>
|
|
# include <Poly_Polygon3D.hxx>
|
|
# include <Standard_Failure.hxx>
|
|
# include <Standard_Version.hxx>
|
|
# include <TColStd_Array1OfReal.hxx>
|
|
# include <TopExp_Explorer.hxx>
|
|
# include <TopoDS.hxx>
|
|
# include <TopoDS_Edge.hxx>
|
|
# include <TopoDS_Shape.hxx>
|
|
# if OCC_VERSION_HEX < 0x070600
|
|
# include <BRepAdaptor_HCurve.hxx>
|
|
# endif
|
|
|
|
#include <Base/Tools.h>
|
|
|
|
#include "TechDrawExport.h"
|
|
|
|
|
|
#if OCC_VERSION_HEX >= 0x070600
|
|
using BRepAdaptor_HCurve = BRepAdaptor_Curve;
|
|
#endif
|
|
|
|
using namespace TechDraw;
|
|
using namespace std;
|
|
|
|
TopoDS_Edge TechDrawOutput::asCircle(const BRepAdaptor_Curve& c) const
|
|
{
|
|
double curv=0;
|
|
gp_Pnt pnt, center;
|
|
|
|
try {
|
|
// approximate the circle center from three positions
|
|
BRepLProp_CLProps prop(c, c.FirstParameter(), 2,Precision::Confusion());
|
|
curv += prop.Curvature();
|
|
prop.CentreOfCurvature(pnt);
|
|
center.ChangeCoord().Add(pnt.Coord());
|
|
|
|
prop.SetParameter(0.5*(c.FirstParameter()+c.LastParameter()));
|
|
curv += prop.Curvature();
|
|
prop.CentreOfCurvature(pnt);
|
|
center.ChangeCoord().Add(pnt.Coord());
|
|
|
|
prop.SetParameter(c.LastParameter());
|
|
curv += prop.Curvature();
|
|
prop.CentreOfCurvature(pnt);
|
|
center.ChangeCoord().Add(pnt.Coord());
|
|
|
|
center.ChangeCoord().Divide(3);
|
|
curv /= 3;
|
|
}
|
|
catch (Standard_Failure&) {
|
|
// if getting center of curvature fails, e.g.
|
|
// for straight lines it raises LProp_NotDefined
|
|
return TopoDS_Edge();
|
|
}
|
|
|
|
// get circle from curvature information
|
|
double radius = 1 / curv;
|
|
|
|
TopLoc_Location location;
|
|
Handle(Poly_Polygon3D) polygon = BRep_Tool::Polygon3D(c.Edge(), location);
|
|
if (!polygon.IsNull()) {
|
|
const TColgp_Array1OfPnt& nodes = polygon->Nodes();
|
|
for (int i = nodes.Lower(); i <= nodes.Upper(); i++) {
|
|
gp_Pnt p = nodes(i);
|
|
double dist = p.Distance(center);
|
|
if (std::abs(dist - radius) > 0.001)
|
|
return TopoDS_Edge();
|
|
}
|
|
|
|
gp_Circ circ;
|
|
circ.SetLocation(center);
|
|
circ.SetRadius(radius);
|
|
gp_Pnt p1 = nodes(nodes.Lower());
|
|
gp_Pnt p2 = nodes(nodes.Upper());
|
|
double dist = p1.Distance(p2);
|
|
|
|
if (dist < Precision::Confusion()) {
|
|
BRepBuilderAPI_MakeEdge mkEdge(circ);
|
|
return mkEdge.Edge();
|
|
}
|
|
else {
|
|
gp_Vec dir1(center, p1);
|
|
dir1.Normalize();
|
|
gp_Vec dir2(center, p2);
|
|
dir2.Normalize();
|
|
p1 = gp_Pnt(center.XYZ() + radius * dir1.XYZ());
|
|
p2 = gp_Pnt(center.XYZ() + radius * dir2.XYZ());
|
|
BRepBuilderAPI_MakeEdge mkEdge(circ, p1, p2);
|
|
return mkEdge.Edge();
|
|
}
|
|
}
|
|
|
|
return TopoDS_Edge();
|
|
}
|
|
|
|
TopoDS_Edge TechDrawOutput::asBSpline(const BRepAdaptor_Curve& c, int maxDegree) const
|
|
{
|
|
Standard_Real tol3D = 0.001;
|
|
Standard_Integer maxSegment = 50;
|
|
Handle(BRepAdaptor_HCurve) hCurve = new BRepAdaptor_HCurve(c);
|
|
// approximate the curve using a tolerance
|
|
Approx_Curve3d approx(hCurve, tol3D, GeomAbs_C0, maxSegment, maxDegree);
|
|
if (approx.IsDone() && approx.HasResult()) {
|
|
// have the result
|
|
Handle(Geom_BSplineCurve) spline = approx.Curve();
|
|
BRepBuilderAPI_MakeEdge mkEdge(spline, spline->FirstParameter(), spline->LastParameter());
|
|
return mkEdge.Edge();
|
|
}
|
|
|
|
return TopoDS_Edge();
|
|
}
|
|
|
|
SVGOutput::SVGOutput()
|
|
{
|
|
}
|
|
|
|
std::string SVGOutput::exportEdges(const TopoDS_Shape& input)
|
|
{
|
|
std::stringstream result;
|
|
|
|
TopExp_Explorer edges(input, TopAbs_EDGE);
|
|
for (int i = 1 ; edges.More(); edges.Next(), i++) {
|
|
const TopoDS_Edge& edge = TopoDS::Edge(edges.Current());
|
|
BRepAdaptor_Curve adapt(edge);
|
|
if (adapt.GetType() == GeomAbs_Circle) {
|
|
printCircle(adapt, result);
|
|
}
|
|
else if (adapt.GetType() == GeomAbs_Ellipse) {
|
|
printEllipse(adapt, i, result);
|
|
}
|
|
else if (adapt.GetType() == GeomAbs_BSplineCurve) {
|
|
// TopoDS_Edge circle = asCircle(adapt);
|
|
// if (circle.IsNull()) {
|
|
printBSpline(adapt, i, result);
|
|
// }
|
|
// else {
|
|
// BRepAdaptor_Curve adapt_circle(circle);
|
|
// printCircle(adapt_circle, result);
|
|
// }
|
|
}
|
|
else if (adapt.GetType() == GeomAbs_BezierCurve) {
|
|
printBezier(adapt, i, result);
|
|
}
|
|
// fallback
|
|
else {
|
|
printGeneric(adapt, i, result);
|
|
}
|
|
}
|
|
|
|
return result.str();
|
|
}
|
|
|
|
void SVGOutput::printCircle(const BRepAdaptor_Curve& c, std::ostream& out)
|
|
{
|
|
gp_Circ circ = c.Circle();
|
|
const gp_Pnt& p= circ.Location();
|
|
double r = circ.Radius();
|
|
double f = c.FirstParameter();
|
|
double l = c.LastParameter();
|
|
gp_Pnt s = c.Value(f);
|
|
gp_Pnt m = c.Value((l+f)/2.0);
|
|
gp_Pnt e = c.Value(l);
|
|
|
|
gp_Vec v1(m, s);
|
|
gp_Vec v2(m, e);
|
|
gp_Vec v3(0, 0,1);
|
|
double a = v3.DotCross(v1, v2);
|
|
|
|
// a full circle
|
|
if (fabs(l-f) > 1.0 && s.SquareDistance(e) < 0.001) {
|
|
out << "<circle cx =\"" << p.X() << "\" cy =\""
|
|
<< p.Y() << "\" r =\"" << r << "\" />";
|
|
}
|
|
// arc of circle
|
|
else {
|
|
// See also https://developer.mozilla.org/en/SVG/Tutorial/Paths
|
|
char xar = '0'; // x-axis-rotation
|
|
char las = (l-f > std::numbers::pi) ? '1' : '0'; // large-arc-flag
|
|
char swp = (a < 0) ? '1' : '0'; // sweep-flag, i.e. clockwise (0) or counter-clockwise (1)
|
|
out << "<path d=\"M" << s.X() << " " << s.Y()
|
|
<< " A" << r << " " << r << " "
|
|
<< xar << " " << las << " " << swp << " "
|
|
<< e.X() << " " << e.Y() << "\" />";
|
|
}
|
|
}
|
|
|
|
void SVGOutput::printEllipse(const BRepAdaptor_Curve& c, int id, std::ostream& out)
|
|
{
|
|
gp_Elips ellp = c.Ellipse();
|
|
const gp_Pnt& p= ellp.Location();
|
|
double r1 = ellp.MajorRadius();
|
|
double r2 = ellp.MinorRadius();
|
|
double f = c.FirstParameter();
|
|
double l = c.LastParameter();
|
|
gp_Pnt s = c.Value(f);
|
|
gp_Pnt m = c.Value((l+f)/2.0);
|
|
gp_Pnt e = c.Value(l);
|
|
|
|
// If the minor radius is very small compared to the major radius
|
|
// the geometry actually degenerates to a line
|
|
double ratio = std::min(r1, r2)/std::max(r1, r2);
|
|
if (ratio < 0.001) {
|
|
printGeneric(c, id, out);
|
|
return;
|
|
}
|
|
|
|
gp_Vec v1(m, s);
|
|
gp_Vec v2(m, e);
|
|
gp_Vec v3(0, 0,1);
|
|
double a = v3.DotCross(v1, v2);
|
|
|
|
// a full ellipse
|
|
// See also https://developer.mozilla.org/en/SVG/Tutorial/Paths
|
|
gp_Dir xaxis = ellp.XAxis().Direction();
|
|
Standard_Real angle = xaxis.AngleWithRef(gp_Dir(1, 0,0), gp_Dir(0, 0,-1));
|
|
angle = Base::toDegrees<double>(angle);
|
|
if (fabs(l-f) > 1.0 && s.SquareDistance(e) < 0.001) {
|
|
out << "<g transform = \"rotate(" << angle << ", " << p.X() << ", " << p.Y() << ")\">" << std::endl;
|
|
out << "<ellipse cx =\"" << p.X() << "\" cy =\""
|
|
<< p.Y() << "\" rx =\"" << r1 << "\" ry =\"" << r2 << "\"/>" << std::endl;
|
|
out << "</g>" << std::endl;
|
|
}
|
|
// arc of ellipse
|
|
else {
|
|
char las = (l-f > std::numbers::pi) ? '1' : '0'; // large-arc-flag
|
|
char swp = (a < 0) ? '1' : '0'; // sweep-flag, i.e. clockwise (0) or counter-clockwise (1)
|
|
out << "<path d=\"M" << s.X() << " " << s.Y()
|
|
<< " A" << r1 << " " << r2 << " "
|
|
<< angle << " " << las << " " << swp << " "
|
|
<< e.X() << " " << e.Y() << "\" />" << std::endl;
|
|
}
|
|
}
|
|
|
|
void SVGOutput::printBezier(const BRepAdaptor_Curve& c, int id, std::ostream& out)
|
|
{
|
|
try {
|
|
std::stringstream str;
|
|
str << "<path d=\"M";
|
|
|
|
Handle(Geom_BezierCurve) bezier = c.Bezier();
|
|
Standard_Integer poles = bezier->NbPoles();
|
|
|
|
// if its a bezier with degree higher than 3 convert it into a B-spline
|
|
if (bezier->Degree() > 3 || bezier->IsRational()) {
|
|
TopoDS_Edge edge = asBSpline(c, 3);
|
|
if (!edge.IsNull()) {
|
|
BRepAdaptor_Curve spline(edge);
|
|
printBSpline(spline, id, out);
|
|
}
|
|
else {
|
|
Standard_Failure::Raise("do it the generic way");
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
gp_Pnt p1 = bezier->Pole(1);
|
|
str << p1.X() << ", " << p1.Y();
|
|
if (bezier->Degree() == 3) {
|
|
if (poles != 4)
|
|
Standard_Failure::Raise("do it the generic way");
|
|
gp_Pnt p2 = bezier->Pole(2);
|
|
gp_Pnt p3 = bezier->Pole(3);
|
|
gp_Pnt p4 = bezier->Pole(4);
|
|
str << " C"
|
|
<< p2.X() << ", " << p2.Y() << " "
|
|
<< p3.X() << ", " << p3.Y() << " "
|
|
<< p4.X() << ", " << p4.Y() << " ";
|
|
}
|
|
else if (bezier->Degree() == 2) {
|
|
if (poles != 3)
|
|
Standard_Failure::Raise("do it the generic way");
|
|
gp_Pnt p2 = bezier->Pole(2);
|
|
gp_Pnt p3 = bezier->Pole(3);
|
|
str << " Q"
|
|
<< p2.X() << ", " << p2.Y() << " "
|
|
<< p3.X() << ", " << p3.Y() << " ";
|
|
}
|
|
else if (bezier->Degree() == 1) {
|
|
if (poles != 2)
|
|
Standard_Failure::Raise("do it the generic way");
|
|
gp_Pnt p2 = bezier->Pole(2);
|
|
str << " L" << p2.X() << ", " << p2.Y() << " ";
|
|
}
|
|
else {
|
|
Standard_Failure::Raise("do it the generic way");
|
|
}
|
|
|
|
str << "\" />";
|
|
out << str.str();
|
|
}
|
|
catch (Standard_Failure&) {
|
|
printGeneric(c, id, out);
|
|
}
|
|
}
|
|
|
|
void SVGOutput::printBSpline(const BRepAdaptor_Curve& c, int id, std::ostream& out)
|
|
{
|
|
try {
|
|
std::stringstream str;
|
|
Handle(Geom_BSplineCurve) spline;
|
|
Standard_Real tol3D = 0.001;
|
|
Standard_Integer maxDegree = 3, maxSegment = 100;
|
|
Handle(BRepAdaptor_HCurve) hCurve = new BRepAdaptor_HCurve(c);
|
|
// approximate the curve using a tolerance
|
|
Approx_Curve3d approx(hCurve, tol3D, GeomAbs_C0, maxSegment, maxDegree);
|
|
if (approx.IsDone() && approx.HasResult()) {
|
|
// have the result
|
|
spline = approx.Curve();
|
|
} else {
|
|
printGeneric(c, id, out);
|
|
return;
|
|
}
|
|
|
|
GeomConvert_BSplineCurveToBezierCurve crt(spline);
|
|
Standard_Integer arcs = crt.NbArcs();
|
|
str << "<path d=\"M";
|
|
for (Standard_Integer i=1; i<=arcs; i++) {
|
|
Handle(Geom_BezierCurve) bezier = crt.Arc(i);
|
|
Standard_Integer poles = bezier->NbPoles();
|
|
if (i == 1) {
|
|
gp_Pnt p1 = bezier->Pole(1);
|
|
str << p1.X() << ", " << p1.Y();
|
|
}
|
|
if (bezier->Degree() == 3) {
|
|
if (poles != 4)
|
|
Standard_Failure::Raise("do it the generic way");
|
|
gp_Pnt p2 = bezier->Pole(2);
|
|
gp_Pnt p3 = bezier->Pole(3);
|
|
gp_Pnt p4 = bezier->Pole(4);
|
|
str << " C"
|
|
<< p2.X() << ", " << p2.Y() << " "
|
|
<< p3.X() << ", " << p3.Y() << " "
|
|
<< p4.X() << ", " << p4.Y() << " ";
|
|
}
|
|
else if (bezier->Degree() == 2) {
|
|
if (poles != 3)
|
|
Standard_Failure::Raise("do it the generic way");
|
|
gp_Pnt p2 = bezier->Pole(2);
|
|
gp_Pnt p3 = bezier->Pole(3);
|
|
str << " Q"
|
|
<< p2.X() << ", " << p2.Y() << " "
|
|
<< p3.X() << ", " << p3.Y() << " ";
|
|
}
|
|
else if (bezier->Degree() == 1) {
|
|
if (poles != 2)
|
|
Standard_Failure::Raise("do it the generic way");
|
|
gp_Pnt p2 = bezier->Pole(2);
|
|
str << " L" << p2.X() << ", " << p2.Y() << " ";
|
|
}
|
|
else {
|
|
Standard_Failure::Raise("do it the generic way");
|
|
}
|
|
}
|
|
|
|
str << "\" />";
|
|
out << str.str();
|
|
}
|
|
catch (Standard_Failure&) {
|
|
printGeneric(c, id, out);
|
|
}
|
|
}
|
|
|
|
void SVGOutput::printGeneric(const BRepAdaptor_Curve& bac, int id, std::ostream& out)
|
|
{
|
|
TopLoc_Location location;
|
|
Handle(Poly_Polygon3D) polygon = BRep_Tool::Polygon3D(bac.Edge(), location);
|
|
if (!polygon.IsNull()) {
|
|
const TColgp_Array1OfPnt& nodes = polygon->Nodes();
|
|
char c = 'M';
|
|
out << "<path id= \"" /*<< ViewName*/ << id << "\" d=\" ";
|
|
for (int i = nodes.Lower(); i <= nodes.Upper(); i++){
|
|
out << c << " " << nodes(i).X() << " " << nodes(i).Y()<< " " ;
|
|
c = 'L';
|
|
}
|
|
out << "\" />" << endl;
|
|
} else if (bac.GetType() == GeomAbs_Line) {
|
|
//BRep_Tool::Polygon3D assumes the edge has polygon representation - ie already been "tessellated"
|
|
//this is not true for all edges, especially "floating edges"
|
|
double f = bac.FirstParameter();
|
|
double l = bac.LastParameter();
|
|
gp_Pnt s = bac.Value(f);
|
|
gp_Pnt e = bac.Value(l);
|
|
char c = 'M';
|
|
out << "<path id= \"" /*<< ViewName*/ << id << "\" d=\" ";
|
|
out << c << " " << s.X() << " " << s.Y()<< " " ;
|
|
c = 'L';
|
|
out << c << " " << e.X() << " " << e.Y()<< " " ;
|
|
out << "\" />" << endl;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
DXFOutput::DXFOutput()
|
|
{
|
|
}
|
|
|
|
std::string DXFOutput::exportEdges(const TopoDS_Shape& input)
|
|
{
|
|
std::stringstream result;
|
|
|
|
TopExp_Explorer edges(input, TopAbs_EDGE);
|
|
for (int i = 1 ; edges.More(); edges.Next(), i++) {
|
|
const TopoDS_Edge& edge = TopoDS::Edge(edges.Current());
|
|
BRepAdaptor_Curve adapt(edge);
|
|
if (adapt.GetType() == GeomAbs_Circle) {
|
|
printCircle(adapt, result);
|
|
}
|
|
else if (adapt.GetType() == GeomAbs_Ellipse) {
|
|
printEllipse(adapt, i, result);
|
|
}
|
|
else if (adapt.GetType() == GeomAbs_BSplineCurve) {
|
|
printBSpline(adapt, i, result);
|
|
}
|
|
// fallback
|
|
else {
|
|
printGeneric(adapt, i, result);
|
|
}
|
|
}
|
|
|
|
return result.str();
|
|
}
|
|
|
|
void DXFOutput::printHeader( std::ostream& out)
|
|
{
|
|
out << 0 << endl;
|
|
out << "SECTION" << endl;
|
|
out << 2 << endl;
|
|
out << "ENTITIES" << endl;
|
|
}
|
|
|
|
void DXFOutput::printCircle(const BRepAdaptor_Curve& c, std::ostream& out)
|
|
{
|
|
gp_Circ circ = c.Circle();
|
|
//const gp_Ax1& axis = c->Axis();
|
|
const gp_Pnt& p= circ.Location();
|
|
double r = circ.Radius();
|
|
double f = c.FirstParameter();
|
|
double l = c.LastParameter();
|
|
gp_Pnt s = c.Value(f);
|
|
gp_Pnt m = c.Value((l+f)/2.0);
|
|
gp_Pnt e = c.Value(l);
|
|
|
|
gp_Vec v1(m, s);
|
|
gp_Vec v2(m, e);
|
|
gp_Vec v3(0, 0,1);
|
|
double a = v3.DotCross(v1, v2);
|
|
|
|
// a full circle
|
|
if (s.SquareDistance(e) < 0.001) {
|
|
//out << "<circle cx =\"" << p.X() << "\" cy =\""
|
|
//<< p.Y() << "\" r =\"" << r << "\" />";
|
|
out << 0 << endl;
|
|
out << "CIRCLE" << endl;
|
|
out << 8 << endl; // Group code for layer name
|
|
out << "sheet_layer" << endl; // Layer number
|
|
out << "100" << endl;
|
|
out << "AcDbEntity" << endl;
|
|
out << "100" << endl;
|
|
out << "AcDbCircle" << endl;
|
|
out << 10 << endl; // Centre X
|
|
out << p.X() << endl; // X in WCS coordinates
|
|
out << 20 << endl;
|
|
out << p.Y() << endl; // Y in WCS coordinates
|
|
out << 30 << endl;
|
|
out << 0 << endl; // Z in WCS coordinates-leaving flat
|
|
out << 40 << endl; //
|
|
out << r << endl; // Radius
|
|
}
|
|
|
|
|
|
|
|
// arc of circle
|
|
else {
|
|
// See also https://developer.mozilla.org/en/SVG/Tutorial/Paths
|
|
/*char xar = '0'; // x-axis-rotation
|
|
char las = (l-f > std::numbers::pi) ? '1' : '0'; // large-arc-flag
|
|
char swp = (a < 0) ? '1' : '0'; // sweep-flag, i.e. clockwise (0) or counter-clockwise (1)
|
|
out << "<path d=\"M" << s.X() << " " << s.Y()
|
|
<< " A" << r << " " << r << " "
|
|
<< xar << " " << las << " " << swp << " "
|
|
<< e.X() << " " << e.Y() << "\" />";*/
|
|
double ax = s.X() - p.X();
|
|
double ay = s.Y() - p.Y();
|
|
double bx = e.X() - p.X();
|
|
double by = e.Y() - p.Y();
|
|
|
|
double start_angle = Base::toDegrees(atan2(ay, ax));
|
|
double end_angle = Base::toDegrees(atan2(by, bx));
|
|
|
|
if (a > 0) {
|
|
double temp = start_angle;
|
|
start_angle = end_angle;
|
|
end_angle = temp;}
|
|
out << 0 << endl;
|
|
out << "ARC" << endl;
|
|
out << 8 << endl; // Group code for layer name
|
|
out << "sheet_layer" << endl; // Layer number
|
|
out << "100" << endl;
|
|
out << "AcDbEntity" << endl;
|
|
out << "100" << endl;
|
|
out << "AcDbCircle" << endl;
|
|
out << 10 << endl; // Centre X
|
|
out << p.X() << endl; // X in WCS coordinates
|
|
out << 20 << endl;
|
|
out << p.Y() << endl; // Y in WCS coordinates
|
|
out << 30 << endl;
|
|
out << 0 << endl; // Z in WCS coordinates
|
|
out << 40 << endl; //
|
|
out << r << endl; // Radius
|
|
out << "100" << endl;
|
|
out << "AcDbArc" << endl;
|
|
out << 50 << endl;
|
|
out << start_angle << endl; // Start angle
|
|
out << 51 << endl;
|
|
out << end_angle << endl; // End angle
|
|
}
|
|
}
|
|
|
|
void DXFOutput::printEllipse(const BRepAdaptor_Curve& c, int /*id*/, std::ostream& out)
|
|
{
|
|
gp_Elips ellp = c.Ellipse();
|
|
const gp_Pnt& p= ellp.Location();
|
|
double r1 = ellp.MajorRadius();
|
|
double r2 = ellp.MinorRadius();
|
|
double dp = ellp.Axis().Direction().Dot(gp_Vec(0, 0,1));
|
|
|
|
// a full ellipse
|
|
/* if (s.SquareDistance(e) < 0.001) {
|
|
out << "<ellipse cx =\"" << p.X() << "\" cy =\""
|
|
<< p.Y() << "\" rx =\"" << r1 << "\" ry =\"" << r2 << "\"/>";
|
|
}
|
|
// arc of ellipse
|
|
else {
|
|
// See also https://developer.mozilla.org/en/SVG/Tutorial/Paths
|
|
gp_Dir xaxis = ellp.XAxis().Direction();
|
|
Standard_Real angle = xaxis.Angle(gp_Dir(1, 0,0));
|
|
angle = Base::toDegrees<double>(angle);
|
|
char las = (l-f > std::numbers::pi) ? '1' : '0'; // large-arc-flag
|
|
char swp = (a < 0) ? '1' : '0'; // sweep-flag, i.e. clockwise (0) or counter-clockwise (1)
|
|
out << "<path d=\"M" << s.X() << " " << s.Y()
|
|
<< " A" << r1 << " " << r2 << " "
|
|
<< angle << " " << las << " " << swp << " "
|
|
<< e.X() << " " << e.Y() << "\" />";
|
|
}*/
|
|
gp_Dir xaxis = ellp.XAxis().Direction();
|
|
double angle = xaxis.AngleWithRef(gp_Dir(1, 0,0), gp_Dir(0, 0,-1));
|
|
//double rotation = Base::toDegrees<double>(angle);
|
|
|
|
double start_angle = c.FirstParameter();
|
|
double end_angle = c.LastParameter();
|
|
|
|
double major_x;double major_y;
|
|
|
|
major_x = r1 * cos(angle);
|
|
major_y = r1 * sin(angle);
|
|
|
|
double ratio = r2/r1;
|
|
|
|
if(dp < 0){
|
|
double temp = start_angle;
|
|
start_angle = end_angle;
|
|
end_angle = temp;
|
|
}
|
|
out << 0 << endl;
|
|
out << "ELLIPSE" << endl;
|
|
out << 8 << endl; // Group code for layer name
|
|
out << "sheet_layer" << endl; // Layer number
|
|
out << "100" << endl;
|
|
out << "AcDbEntity" << endl;
|
|
out << "100" << endl;
|
|
out << "AcDbEllipse" << endl;
|
|
out << 10 << endl; // Centre X
|
|
out << p.X() << endl; // X in WCS coordinates
|
|
out << 20 << endl;
|
|
out << p.Y() << endl; // Y in WCS coordinates
|
|
out << 30 << endl;
|
|
out << 0 << endl; // Z in WCS coordinates
|
|
out << 11 << endl; //
|
|
out << major_x << endl; // Major X
|
|
out << 21 << endl;
|
|
out << major_y << endl; // Major Y
|
|
out << 31 << endl;
|
|
out << 0 << endl; // Major Z
|
|
out << 40 << endl; //
|
|
out << ratio << endl; // Ratio
|
|
out << 41 << endl;
|
|
out << start_angle << endl; // Start angle
|
|
out << 42 << endl;
|
|
out << end_angle << endl; // End angle
|
|
}
|
|
|
|
void DXFOutput::printBSpline(const BRepAdaptor_Curve& c, int id, std::ostream& out) //Not even close yet- DF
|
|
{
|
|
try {
|
|
std::stringstream str;
|
|
Handle(Geom_BSplineCurve) spline;
|
|
Standard_Real tol3D = 0.001;
|
|
Standard_Integer maxDegree = 3, maxSegment = 50;
|
|
Handle(BRepAdaptor_HCurve) hCurve = new BRepAdaptor_HCurve(c);
|
|
// approximate the curve using a tolerance
|
|
Approx_Curve3d approx(hCurve, tol3D, GeomAbs_C0, maxSegment, maxDegree);
|
|
if (approx.IsDone() && approx.HasResult()) {
|
|
// have the result
|
|
spline = approx.Curve();
|
|
} else {
|
|
printGeneric(c, id, out);
|
|
return;
|
|
}
|
|
|
|
//GeomConvert_BSplineCurveToBezierCurve crt(spline);
|
|
//GeomConvert_BSplineCurveKnotSplitting crt(spline, 0);
|
|
//Standard_Integer arcs = crt.NbArcs();
|
|
//Standard_Integer arcs = crt.NbSplits()-1;
|
|
Standard_Integer m = 0;
|
|
if (spline->IsPeriodic()) {
|
|
m = spline->NbPoles() + 2*spline->Degree() - spline->Multiplicity(1) + 2;
|
|
}
|
|
else {
|
|
for (int i=1; i<= spline->NbKnots(); i++)
|
|
m += spline->Multiplicity(i);
|
|
}
|
|
TColStd_Array1OfReal knotsequence(1, m);
|
|
spline->KnotSequence(knotsequence);
|
|
TColgp_Array1OfPnt poles(1, spline->NbPoles());
|
|
spline->Poles(poles);
|
|
|
|
|
|
str << 0 << endl
|
|
<< "SPLINE" << endl
|
|
<< 8 << endl // Group code for layer name
|
|
<< "sheet_layer" << endl // Layer name
|
|
<< "100" << endl
|
|
<< "AcDbEntity" << endl
|
|
<< "100" << endl
|
|
<< "AcDbSpline" << endl
|
|
<< 70 << endl
|
|
<< spline->IsRational()*4 << endl //flags
|
|
<< 71 << endl << spline->Degree() << endl
|
|
<< 72 << endl << knotsequence.Length() << endl
|
|
<< 73 << endl << poles.Length() << endl
|
|
<< 74 << endl << 0 << endl; //fitpoints
|
|
|
|
for (int i = knotsequence.Lower() ; i <= knotsequence.Upper(); i++) {
|
|
str << 40 << endl << knotsequence(i) << endl;
|
|
}
|
|
for (int i = poles.Lower(); i <= poles.Upper(); i++) {
|
|
gp_Pnt pole = poles(i);
|
|
str << 10 << endl << pole.X() << endl
|
|
<< 20 << endl << pole.Y() << endl
|
|
<< 30 << endl << pole.Z() << endl;
|
|
if (spline->IsRational()) {
|
|
str << 41 << endl << spline->Weight(i) << endl;
|
|
}
|
|
}
|
|
|
|
//str << "\" />";
|
|
out << str.str();
|
|
}
|
|
catch (Standard_Failure&) {
|
|
printGeneric(c, id, out);
|
|
}
|
|
}
|
|
|
|
void DXFOutput::printGeneric(const BRepAdaptor_Curve& c, int /*id*/, std::ostream& out)
|
|
{
|
|
double uStart = c.FirstParameter();
|
|
gp_Pnt PS;
|
|
gp_Vec VS;
|
|
c.D1(uStart, PS, VS);
|
|
|
|
double uEnd = c.LastParameter();
|
|
gp_Pnt PE;
|
|
gp_Vec VE;
|
|
c.D1(uEnd, PE, VE);
|
|
|
|
out << "0" << endl;
|
|
out << "LINE" << endl;
|
|
out << "8" << endl; // Group code for layer name
|
|
out << "sheet_layer" << endl; // Layer name
|
|
out << "100" << endl;
|
|
out << "AcDbEntity" << endl;
|
|
out << "100" << endl;
|
|
out << "AcDbLine" << endl;
|
|
out << "10" << endl; // Start point of line
|
|
out << PS.X() << endl; // X in WCS coordinates
|
|
out << "20" << endl;
|
|
out << PS.Y() << endl; // Y in WCS coordinates
|
|
out << "30" << endl;
|
|
out << "0" << endl; // Z in WCS coordinates
|
|
out << "11" << endl; // End point of line
|
|
out << PE.X() << endl; // X in WCS coordinates
|
|
out << "21" << endl;
|
|
out << PE.Y() << endl; // Y in WCS coordinates
|
|
out << "31" << endl;
|
|
out << "0" << endl; // Z in WCS coordinates
|
|
}
|