ProjectionAlgos: Make the style of the lines in the SVG file configurable.

* getSVG provides new style parameters for every kind of line:
  V, V0, V1, H, H0, H1.
* Old line width parameters are removed. The style parameters
  can be used instead.
* A style is a map container for svg attribute keys and values
  (string, string).
* The Python interface is updated to offer the new style parameters
  accordingly as a dict.
* Because there are many parameters on the function call now,
  the Python interface supports keyword parameters.
* Update ArchSectionPlane to take advantage of the new style parameters.
  This simplifies the code. String replacements could be removed
  (done in a later commit).
* FeatureViewPy.cpp is – to my knowledge – the only function that used the
  old line width parameters. I rewrote it to use the new style parameters.
This commit is contained in:
Simon
2017-04-13 17:49:36 +02:00
committed by Yorik van Havre
parent 2bda3a3207
commit 9633c94515
5 changed files with 223 additions and 151 deletions

View File

@@ -196,21 +196,21 @@ def getSVG(section,allOn=False,renderMode="Wireframe",showHidden=False,showFill=
shapes,hshapes,sshapes,cutface,cutvolume,invcutvolume = getCutShapes(objs,section,showHidden)
if shapes:
baseshape = Part.makeCompound(shapes)
svgf = Drawing.projectToSVG(baseshape,direction)
if svgf:
svgf = svgf.replace('stroke-width="0.35"','stroke-width="LWPlaceholder"')
svgf = svgf.replace('stroke-width="1"','stroke-width="LWPlaceholder"')
svgf = svgf.replace('stroke-width:0.01','stroke-width:LWPlaceholder')
svg += svgf
style = {'stroke-width': 'LWPlaceholder'}
svgf = Drawing.projectToSVG(
baseshape, direction,
hStyle=style, h0Style=style, h1Style=style,
vStyle=style, v0Style=style, v1Style=style)
svg += svgf
if hshapes:
hshapes = Part.makeCompound(hshapes)
svgh = Drawing.projectToSVG(hshapes,direction)
if svgh:
svgh = svgh.replace('stroke-width="0.35"','stroke-width="LWPlaceholder"')
svgh = svgh.replace('stroke-width="1"','stroke-width="LWPlaceholder"')
svgh = svgh.replace('stroke-width:0.01','stroke-width:LWPlaceholder')
svgh = svgh.replace('fill="none"','fill="none"\nstroke-dasharray="DAPlaceholder"')
svg += svgh
style = {'stroke-width': 'LWPlaceholder',
'stroke-dasharray': 'DAPlaceholder'}
svgh = Drawing.projectToSVG(
hshapes, direction,
hStyle=style, h0Style=style, h1Style=style,
vStyle=style, v0Style=style, v1Style=style)
svg += svgh
if sshapes:
svgs = ""
if showFill:
@@ -224,14 +224,12 @@ def getSVG(section,allOn=False,renderMode="Wireframe",showHidden=False,showFill=
svgs += f
svgs += "</g>\n"
sshapes = Part.makeCompound(sshapes)
svgs += Drawing.projectToSVG(sshapes,direction)
if svgs:
svgs = svgs.replace('stroke-width="0.35"','stroke-width="SWPlaceholder"')
svgs = svgs.replace('stroke-width="1"','stroke-width="SWPlaceholder"')
svgs = svgs.replace('stroke-width:0.01','stroke-width:SWPlaceholder')
svgs = svgs.replace('stroke-width="0.35 px"','stroke-width="SWPlaceholder"')
svgs = svgs.replace('stroke-width:0.35','stroke-width:SWPlaceholder')
svg += svgs
style = {'stroke-width': 'SWPlaceholder'}
svgs += Drawing.projectToSVG(
sshapes, direction,
hStyle=style, h0Style=style, h1Style=style,
vStyle=style, v0Style=style, v1Style=style)
svg += svgs
scaledlinewidth = linewidth/scale
st = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetFloat("CutLineThickness",2)
yt = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetFloat("SymbolLineThickness",0.6)

View File

@@ -37,10 +37,39 @@
#include <Mod/Part/App/OCCError.h>
using namespace std;
using Part::TopoShapePy;
using Part::TopoShape;
namespace Drawing {
/** Copies a Python dictionary of Python strings to a C++ container.
*
* After the function call, the key-value pairs of the Python
* dictionary are copied into the target buffer as C++ pairs
* (pair<string, string>).
*
* @param sourceRange is a Python dictionary (Py::Dict). Both, the
* keys and the values must be Python strings.
*
* @param targetIt refers to where the data should be inserted. Must
* be of concept output iterator.
*/
template<typename OutputIt>
void copy(Py::Dict sourceRange, OutputIt targetIt)
{
string key;
string value;
for (auto keyPy : sourceRange.keys()) {
key = Py::String(keyPy);
value = Py::String(sourceRange[keyPy]);
*targetIt = {key, value};
++targetIt;
}
}
class Module : public Py::ExtensionModule<Module>
{
public:
@@ -54,8 +83,8 @@ public:
"[V,V1,VN,VO,VI,H,H1,HN,HO,HI] = projectEx(TopoShape[,App.Vector Direction, string type])\n"
" -- Project a shape and return the all parts of it."
);
add_varargs_method("projectToSVG",&Module::projectToSVG,
"string = projectToSVG(TopoShape[,App.Vector Direction, string type])\n"
add_keyword_method("projectToSVG",&Module::projectToSVG,
"string = projectToSVG(TopoShape[, App.Vector direction, string type, float tolerance, dict vStyle, dict v0Style, dict v1Style, dict hStyle, dict h0Style, dict h1Style])\n"
" -- Project a shape and return the SVG representation as string."
);
add_varargs_method("projectToDXF",&Module::projectToDXF,
@@ -160,32 +189,76 @@ private:
return list;
}
Py::Object projectToSVG(const Py::Tuple& args)
{
PyObject *pcObjShape;
PyObject *pcObjDir=0;
const char *type=0;
float scale=1.0f;
float tol=0.1f;
if (!PyArg_ParseTuple(args.ptr(), "O!|O!sff",
&(TopoShapePy::Type), &pcObjShape,
&(Base::VectorPy::Type), &pcObjDir, &type, &scale, &tol))
throw Py::Exception();
Py::Object projectToSVG(const Py::Tuple& args, const Py::Dict& keys)
{
static char* argNames[] = {"topoShape", "direction", "type", "tolerance", "vStyle", "v0Style", "v1Style", "hStyle", "h0Style", "h1Style", NULL};
PyObject *pcObjShape = 0;
PyObject *pcObjDir = 0;
const char *extractionTypePy = 0;
ProjectionAlgos::ExtractionType extractionType = ProjectionAlgos::Plain;
const float tol = 0.1f;
PyObject* vStylePy = 0;
ProjectionAlgos::XmlAttributes vStyle;
PyObject* v0StylePy = 0;
ProjectionAlgos::XmlAttributes v0Style;
PyObject* v1StylePy = 0;
ProjectionAlgos::XmlAttributes v1Style;
PyObject* hStylePy = 0;
ProjectionAlgos::XmlAttributes hStyle;
PyObject* h0StylePy = 0;
ProjectionAlgos::XmlAttributes h0Style;
PyObject* h1StylePy = 0;
ProjectionAlgos::XmlAttributes h1Style;
// Get the arguments
TopoShapePy* pShape = static_cast<TopoShapePy*>(pcObjShape);
Base::Vector3d Vector(0,0,1);
if (pcObjDir)
Vector = static_cast<Base::VectorPy*>(pcObjDir)->value();
ProjectionAlgos Alg(pShape->getTopoShapePtr()->getShape(),Vector);
if (!PyArg_ParseTupleAndKeywords(
args.ptr(), keys.ptr(),
"O!|O!sfOOOOOO",
argNames,
&(TopoShapePy::Type), &pcObjShape,
&(Base::VectorPy::Type), &pcObjDir,
&extractionTypePy, &tol,
&vStylePy, &v0StylePy, &v1StylePy,
&hStylePy, &h0StylePy, &h1StylePy))
throw Py::Exception();
bool hidden = false;
if (type && std::string(type) == "ShowHiddenLines")
hidden = true;
// Convert all arguments into the right format
TopoShapePy* pShape = static_cast<TopoShapePy*>(pcObjShape);
Base::Vector3d directionVector(0,0,1);
if (pcObjDir)
directionVector = static_cast<Base::VectorPy*>(pcObjDir)->value();
if (extractionTypePy && string(extractionTypePy) == "ShowHiddenLines")
extractionType = ProjectionAlgos::WithHidden;
if (vStylePy)
copy(Py::Dict(vStylePy), inserter(vStyle, vStyle.begin()));
if (v0StylePy)
copy(Py::Dict(v0StylePy), inserter(v0Style, v0Style.begin()));
if (v1StylePy)
copy(Py::Dict(v1StylePy), inserter(v1Style, v1Style.begin()));
if (hStylePy)
copy(Py::Dict(hStylePy), inserter(hStyle, hStyle.begin()));
if (h0StylePy)
copy(Py::Dict(h0StylePy), inserter(h0Style, h0Style.begin()));
if (h1StylePy)
copy(Py::Dict(h1StylePy), inserter(h1Style, h1Style.begin()));
// Execute the SVG generation
ProjectionAlgos Alg(pShape->getTopoShapePtr()->getShape(),
directionVector);
Py::String result(Alg.getSVG(extractionType, tol,
vStyle, v0Style, v1Style,
hStyle, h0Style, h1Style));
return result;
}
Py::String result(Alg.getSVG(hidden?ProjectionAlgos::WithHidden:ProjectionAlgos::Plain, scale, tol));
return result;
}
Py::Object projectToDXF(const Py::Tuple& args)
{
PyObject *pcObjShape;

View File

@@ -120,7 +120,13 @@ App::DocumentObjectExecReturn *FeatureViewPart::execute(void)
ProjectionAlgos::ExtractionType type = ProjectionAlgos::Plain;
if (hidden) type = (ProjectionAlgos::ExtractionType)(type|ProjectionAlgos::WithHidden);
if (smooth) type = (ProjectionAlgos::ExtractionType)(type|ProjectionAlgos::WithSmooth);
result << Alg.getSVG(type, this->LineWidth.getValue() / this->Scale.getValue(), this->Tolerance.getValue(), this->HiddenWidth.getValue() / this->Scale.getValue());
ProjectionAlgos::XmlAttributes visible_style = {
{"stroke_width", to_string(this->LineWidth.getValue() / this->Scale.getValue())}
};
ProjectionAlgos::XmlAttributes hidden_style = {
{"stroke_width", to_string(this->HiddenWidth.getValue() / this->Scale.getValue()) }
};
result << Alg.getSVG(type, this->Tolerance.getValue(), visible_style, visible_style, visible_style, hidden_style, hidden_style, hidden_style);
result << "</g>" << endl;

View File

@@ -37,7 +37,6 @@
#include <HLRBRep_Algo.hxx>
#include <TopoDS_Shape.hxx>
#include <HLRTopoBRep_OutLiner.hxx>
//#include <BRepAPI_MakeOutLine.hxx>
#include <HLRAlgo_Projector.hxx>
#include <HLRBRep_ShapeBounds.hxx>
#include <HLRBRep_HLRToShape.hxx>
@@ -99,29 +98,6 @@ ProjectionAlgos::~ProjectionAlgos()
{
}
/*
// no longer used, replaced invertY by adding
// << " transform=\"scale(1,-1)\"" << endl
// to getSVG(...) below.
// invertY, as here, wasn't right for intended purpose - always reflected in model Y direction rather
// than SVG projection Y direction. Also better to reflect about (0,0,0) rather than bbox centre
TopoDS_Shape ProjectionAlgos::invertY(const TopoDS_Shape& shape)
{
// make sure to have the y coordinates inverted
gp_Trsf mat;
Bnd_Box bounds;
BRepBndLib::Add(shape, bounds);
bounds.SetGap(0.0);
Standard_Real xMin, yMin, zMin, xMax, yMax, zMax;
bounds.Get(xMin, yMin, zMin, xMax, yMax, zMax);
mat.SetMirror(gp_Ax2(gp_Pnt((xMin+xMax)/2,(yMin+yMax)/2,(zMin+zMax)/2), gp_Dir(0,1,0)));
BRepBuilderAPI_Transform mkTrf(shape, mat);
return mkTrf.Shape();
}
*/
//added by tanderson. aka blobfish.
//projection algorithms build a 2d curve(pcurve) but no 3d curve.
//this causes problems with meshing algorithms after save and load.
@@ -159,112 +135,125 @@ void ProjectionAlgos::execute(void)
HI = build3dCurves(shapes.IsoLineHCompound());// isoparamtriques invisibly
}
std::string ProjectionAlgos::getSVG(ExtractionType type, double scale, double tolerance, double hiddenscale)
string ProjectionAlgos::getSVG(ExtractionType type,
double tolerance,
XmlAttributes V_style,
XmlAttributes V0_style,
XmlAttributes V1_style,
XmlAttributes H_style,
XmlAttributes H0_style,
XmlAttributes H1_style)
{
std::stringstream result;
stringstream result;
SVGOutput output;
if (!H.IsNull() && (type & WithHidden)) {
double width = hiddenscale;
H_style.insert({"stroke", "rgb(0, 0, 0)"});
H_style.insert({"stroke-width", "0.15"});
H_style.insert({"stroke-linecap", "butt"});
H_style.insert({"stroke-linejoin", "miter"});
H_style.insert({"stroke-dasharray", "0.2,0.1)"});
H_style.insert({"fill", "none"});
H_style.insert({"transform", "scale(1,-1)"});
BRepMesh_IncrementalMesh(H,tolerance);
result << "<g"
//<< " id=\"" << ViewName << "\"" << endl
<< " stroke=\"rgb(0, 0, 0)\"" << endl
<< " stroke-width=\"" << width << "\"" << endl
<< " stroke-linecap=\"butt\"" << endl
<< " stroke-linejoin=\"miter\"" << endl
<< " stroke-dasharray=\"0.2,0.1\"" << endl
<< " fill=\"none\"" << endl
<< " transform=\"scale(1,-1)\"" << endl
<< " >" << endl
<< output.exportEdges(H)
<< "</g>" << endl;
result << "<g";
for (const auto& attribute : H_style)
result << " " << attribute.first << "=\""
<< attribute.second << "\"\n";
result << " >" << endl
<< output.exportEdges(H)
<< "</g>" << endl;
}
if (!HO.IsNull() && (type & WithHidden)) {
double width = hiddenscale;
H0_style.insert({"stroke", "rgb(0, 0, 0)"});
H0_style.insert({"stroke-width", "0.15"});
H0_style.insert({"stroke-linecap", "butt"});
H0_style.insert({"stroke-linejoin", "miter"});
H0_style.insert({"stroke-dasharray", "0.02,0.1)"});
H0_style.insert({"fill", "none"});
H0_style.insert({"transform", "scale(1,-1)"});
BRepMesh_IncrementalMesh(HO,tolerance);
result << "<g"
//<< " id=\"" << ViewName << "\"" << endl
<< " stroke=\"rgb(0, 0, 0)\"" << endl
<< " stroke-width=\"" << width << "\"" << endl
<< " stroke-linecap=\"butt\"" << endl
<< " stroke-linejoin=\"miter\"" << endl
<< " stroke-dasharray=\"0.02,0.1\"" << endl
<< " fill=\"none\"" << endl
<< " transform=\"scale(1,-1)\"" << endl
<< " >" << endl
<< output.exportEdges(HO)
<< "</g>" << endl;
result << "<g";
for (const auto& attribute : H0_style)
result << " " << attribute.first << "=\""
<< attribute.second << "\"\n";
result << " >" << endl
<< output.exportEdges(HO)
<< "</g>" << endl;
}
if (!VO.IsNull()) {
double width = scale;
V0_style.insert({"stroke", "rgb(0, 0, 0)"});
V0_style.insert({"stroke-width", "1.0"});
V0_style.insert({"stroke-linecap", "butt"});
V0_style.insert({"stroke-linejoin", "miter"});
V0_style.insert({"fill", "none"});
V0_style.insert({"transform", "scale(1,-1)"});
BRepMesh_IncrementalMesh(VO,tolerance);
result << "<g"
//<< " id=\"" << ViewName << "\"" << endl
<< " stroke=\"rgb(0, 0, 0)\"" << endl
<< " stroke-width=\"" << width << "\"" << endl
<< " stroke-linecap=\"butt\"" << endl
<< " stroke-linejoin=\"miter\"" << endl
<< " fill=\"none\"" << endl
<< " transform=\"scale(1,-1)\"" << endl
<< " >" << endl
<< output.exportEdges(VO)
<< "</g>" << endl;
result << "<g";
for (const auto& attribute : V0_style)
result << " " << attribute.first << "=\""
<< attribute.second << "\"\n";
result << " >" << endl
<< output.exportEdges(VO)
<< "</g>" << endl;
}
if (!V.IsNull()) {
double width = scale;
V_style.insert({"stroke", "rgb(0, 0, 0)"});
V_style.insert({"stroke-width", "1.0"});
V_style.insert({"stroke-linecap", "butt"});
V_style.insert({"stroke-linejoin", "miter"});
V_style.insert({"fill", "none"});
V_style.insert({"transform", "scale(1,-1)"});
BRepMesh_IncrementalMesh(V,tolerance);
result << "<g"
//<< " id=\"" << ViewName << "\"" << endl
<< " stroke=\"rgb(0, 0, 0)\"" << endl
<< " stroke-width=\"" << width << "\"" << endl
<< " stroke-linecap=\"butt\"" << endl
<< " stroke-linejoin=\"miter\"" << endl
<< " fill=\"none\"" << endl
<< " transform=\"scale(1,-1)\"" << endl
<< " >" << endl
<< output.exportEdges(V)
<< "</g>" << endl;
result << "<g";
for (const auto& attribute : V_style)
result << " " << attribute.first << "=\""
<< attribute.second << "\"\n";
result << " >" << endl
<< output.exportEdges(V)
<< "</g>" << endl;
}
if (!V1.IsNull() && (type & WithSmooth)) {
double width = scale;
V1_style.insert({"stroke", "rgb(0, 0, 0)"});
V1_style.insert({"stroke-width", "1.0"});
V1_style.insert({"stroke-linecap", "butt"});
V1_style.insert({"stroke-linejoin", "miter"});
V1_style.insert({"fill", "none"});
V1_style.insert({"transform", "scale(1,-1)"});
BRepMesh_IncrementalMesh(V1,tolerance);
result << "<g"
//<< " id=\"" << ViewName << "\"" << endl
<< " stroke=\"rgb(0, 0, 0)\"" << endl
<< " stroke-width=\"" << width << "\"" << endl
<< " stroke-linecap=\"butt\"" << endl
<< " stroke-linejoin=\"miter\"" << endl
<< " fill=\"none\"" << endl
<< " transform=\"scale(1,-1)\"" << endl
<< " >" << endl
<< output.exportEdges(V1)
<< "</g>" << endl;
result << "<g";
for (const auto& attribute : V1_style)
result << " " << attribute.first << "=\""
<< attribute.second << "\"\n";
result << " >" << endl
<< output.exportEdges(V1)
<< "</g>" << endl;
}
if (!H1.IsNull() && (type & WithSmooth) && (type & WithHidden)) {
double width = hiddenscale;
H1_style.insert({"stroke", "rgb(0, 0, 0)"});
H1_style.insert({"stroke-width", "0.15"});
H1_style.insert({"stroke-linecap", "butt"});
H1_style.insert({"stroke-linejoin", "miter"});
H1_style.insert({"stroke-dasharray", "0.09,0.05)"});
H1_style.insert({"fill", "none"});
H1_style.insert({"transform", "scale(1,-1)"});
BRepMesh_IncrementalMesh(H1,tolerance);
result << "<g"
//<< " id=\"" << ViewName << "\"" << endl
<< " stroke=\"rgb(0, 0, 0)\"" << endl
<< " stroke-width=\"" << width << "\"" << endl
<< " stroke-linecap=\"butt\"" << endl
<< " stroke-linejoin=\"miter\"" << endl
<< " stroke-dasharray=\"0.09,0.05\"" << endl
<< " fill=\"none\"" << endl
<< " transform=\"scale(1,-1)\"" << endl
<< " >" << endl
<< output.exportEdges(H1)
<< "</g>" << endl;
result << "<g";
for (const auto& attribute : H1_style)
result << " " << attribute.first << "=\""
<< attribute.second << "\"\n";
result << " >" << endl
<< output.exportEdges(H1)
<< "</g>" << endl;
}
return result.str();
}
/* dxf output section - Dan Falck 2011/09/25 */
std::string ProjectionAlgos::getDXF(ExtractionType type, double /*scale*/, double tolerance)
string ProjectionAlgos::getDXF(ExtractionType type, double /*scale*/, double tolerance)
{
std::stringstream result;
stringstream result;
DXFOutput output;
if (!H.IsNull() && (type & WithHidden)) {

View File

@@ -43,15 +43,21 @@ public:
virtual ~ProjectionAlgos();
void execute(void);
// static TopoDS_Shape invertY(const TopoDS_Shape&);
enum ExtractionType {
Plain = 0,
WithHidden = 1,
WithSmooth = 2
};
typedef std::map<std::string,std::string> XmlAttributes;
std::string getSVG(ExtractionType type, double scale=0.35, double tolerance=0.05, double hiddenscale=0.15);
std::string getSVG(ExtractionType type, double tolerance=0.05,
XmlAttributes V_style=XmlAttributes(),
XmlAttributes V0_style=XmlAttributes(),
XmlAttributes V1_style=XmlAttributes(),
XmlAttributes H_style=XmlAttributes(),
XmlAttributes H0_style=XmlAttributes(),
XmlAttributes H1_style=XmlAttributes());
std::string getDXF(ExtractionType type, double scale, double tolerance);//added by Dan Falck 2011/09/25