diff --git a/src/Mod/TechDraw/App/DrawGeomHatch.cpp b/src/Mod/TechDraw/App/DrawGeomHatch.cpp index 20e6e9c665..4b05873783 100644 --- a/src/Mod/TechDraw/App/DrawGeomHatch.cpp +++ b/src/Mod/TechDraw/App/DrawGeomHatch.cpp @@ -68,6 +68,7 @@ #include "HatchLine.h" #include "DrawUtil.h" #include "Geometry.h" +#include "DrawPage.h" #include "DrawViewPart.h" #include "DrawViewSection.h" #include "DrawGeomHatch.h" @@ -94,6 +95,9 @@ DrawGeomHatch::DrawGeomHatch(void) ADD_PROPERTY_TYPE(NamePattern,(""),vgroup,App::Prop_None,"The name of the pattern"); ADD_PROPERTY_TYPE(ScalePattern,(1.0),vgroup,App::Prop_None,"GeomHatch pattern size adjustment"); ScalePattern.setConstraints(&scaleRange); + + m_saveFile = ""; + m_saveName = ""; getParameters(); @@ -105,28 +109,18 @@ DrawGeomHatch::~DrawGeomHatch() void DrawGeomHatch::onChanged(const App::Property* prop) { - if (prop == &Source ) { + if (prop == &Source ) { if (!isRestoring()) { - DrawGeomHatch::execute(); + DrawGeomHatch::execute(); + } + } + if (isRestoring()) { + if ((prop == &FilePattern) || //make sure right pattern gets loaded at start up + (prop == &NamePattern)) { + DrawGeomHatch::execute(); } } - if (prop == &FilePattern || - prop == &NamePattern ) { - if ((!FilePattern.isEmpty()) && - (!NamePattern.isEmpty())) { - std::vector specs = getDecodedSpecsFromFile(); - m_lineSets.clear(); - for (auto& hl: specs) { - //hl.dump("hl from file"); - LineSet ls; - ls.setHatchLine(hl); - m_lineSets.push_back(ls); - } - - } - } - App::DocumentObject::onChanged(prop); } @@ -148,7 +142,23 @@ short DrawGeomHatch::mustExecute() const App::DocumentObjectExecReturn *DrawGeomHatch::execute(void) { - + //save names & check if different + if ((!FilePattern.isEmpty()) && + (!NamePattern.isEmpty())) { + if ((m_saveFile != FilePattern.getValue()) || + (m_saveName != NamePattern.getValue())) { + m_saveFile = FilePattern.getValue(); + m_saveName = NamePattern.getValue(); + std::vector specs = getDecodedSpecsFromFile(); + m_lineSets.clear(); + for (auto& hl: specs) { + //hl.dump("hl from file"); + LineSet ls; + ls.setPATLineSpec(hl); + m_lineSets.push_back(ls); + } + } + } return App::DocumentObject::StdReturn; } @@ -159,7 +169,7 @@ DrawViewPart* DrawGeomHatch::getSourceView(void) const return result; } -std::vector DrawGeomHatch::getDecodedSpecsFromFile() +std::vector DrawGeomHatch::getDecodedSpecsFromFile() { std::string fileSpec = FilePattern.getValue(); std::string myPattern = NamePattern.getValue(); @@ -167,49 +177,265 @@ std::vector DrawGeomHatch::getDecodedSpecsFromFile() } -//!get all the specification lines and decode them into HatchLine structures +//!get all the specification lines and decode them into PATLineSpec structures /*static*/ -std::vector DrawGeomHatch::getDecodedSpecsFromFile(std::string fileSpec, std::string myPattern) +std::vector DrawGeomHatch::getDecodedSpecsFromFile(std::string fileSpec, std::string myPattern) { - std::vector result; + std::vector result; Base::FileInfo fi(fileSpec); if (!fi.isReadable()) { Base::Console().Error("DrawGeomHatch::getDecodedSpecsFromFile not able to open %s!\n",fileSpec.c_str()); return result; } - result = HatchLine::getSpecsForPattern(fileSpec,myPattern); + result = PATLineSpec::getSpecsForPattern(fileSpec,myPattern); return result; } -std::vector DrawGeomHatch::getDrawableLines(int i) //get the drawable lines for face i +std::vector DrawGeomHatch::getTrimmedLines(int i) //get the trimmed hatch lines for face i { std::vector result; DrawViewPart* source = getSourceView(); if (!source || !source->hasGeometry()) { - Base::Console().Message("TRACE - DC::getDrawableLines - no source geometry\n"); + Base::Console().Message("TRACE - DGH::getTrimmedLines - no source geometry\n"); return result; } - return getDrawableLines(source, m_lineSets,i, ScalePattern.getValue()); + return getTrimmedLines(source, m_lineSets,i, ScalePattern.getValue()); } /* static */ -std::vector DrawGeomHatch::getDrawableLines(DrawViewPart* source, std::vector lineSets, int iface, double scale ) +//! get hatch lines trimmed to face outline +std::vector DrawGeomHatch::getTrimmedLines(DrawViewPart* source, std::vector lineSets, int iface, double scale ) { std::vector result; - //is source is a section? + if (lineSets.empty()) { + Base::Console().Log("INFO - DGH::getTrimmedLines - no LineSets!\n"); + return result; + } + + TopoDS_Face face = extractFace(source,iface); + + + Bnd_Box bBox; + BRepBndLib::Add(face, bBox); + bBox.SetGap(0.0); + + for (auto& ls: lineSets) { + PATLineSpec hl = ls.getPATLineSpec(); + std::vector candidates = DrawGeomHatch::makeEdgeOverlay(hl, bBox, scale); //completely cover face bbox with lines + + //make Compound for this linespec + BRep_Builder builder; + TopoDS_Compound Comp; + builder.MakeCompound(Comp); + for (auto& c: candidates) { + builder.Add(Comp, c); + } + + //Common(Compound,Face) + BRepAlgoAPI_Common mkCommon(face, Comp); + if ((!mkCommon.IsDone()) || + (mkCommon.Shape().IsNull()) ) { + Base::Console().Log("INFO - DGH::getTrimmedLines - Common creation failed\n"); + return result; + } + TopoDS_Shape common = mkCommon.Shape(); + Bnd_Box overlayBox; + overlayBox.SetGap(0.0); + BRepBndLib::Add(common, overlayBox); + ls.setBBox(overlayBox); + + + //get resulting edges + std::vector resultEdges; + TopTools_IndexedMapOfShape mapOfEdges; + TopExp::MapShapes(common, TopAbs_EDGE, mapOfEdges); + for ( int i = 1 ; i <= mapOfEdges.Extent() ; i++ ) { //remember, TopExp makes no promises about the order it finds edges + const TopoDS_Edge& edge = TopoDS::Edge(mapOfEdges(i)); + if (edge.IsNull()) { + Base::Console().Log("INFO - DGH::getTrimmedLines - edge: %d is NULL\n",i); + continue; + } + resultEdges.push_back(edge); + } + + std::vector resultGeoms; + int i = 0; + for (auto& e: resultEdges) { + TechDrawGeometry::BaseGeom* base = BaseGeom::baseFactory(e); + if (base == nullptr) { + Base::Console().Log("FAIL - DGH::getTrimmedLines - baseFactory failed for edge: %d\n",i); + throw Base::Exception("DGH::getTrimmedLines - baseFactory failed"); + } + resultGeoms.push_back(base); + i++; + } + ls.setEdges(resultEdges); + ls.setGeoms(resultGeoms); + result.push_back(ls); + } + return result; +} +/* static */ +std::vector DrawGeomHatch::makeEdgeOverlay(PATLineSpec hl, Bnd_Box b, double scale) +{ + std::vector result; + + double minX,maxX,minY,maxY,minZ,maxZ; + b.Get(minX,minY,minZ,maxX,maxY,maxZ); + + Base::Vector3d start; + Base::Vector3d end; + Base::Vector3d origin = hl.getOrigin(); + double interval = hl.getInterval() * scale; + double angle = hl.getAngle(); + + //only dealing with angles -180:180 for now + if (angle > 90.0) { + angle = -(180.0 - angle); + } else if (angle < -90.0) { + angle = (180 + angle); + } + double slope = hl.getSlope(); + + if (angle == 0.0) { //odd case 1: horizontal lines + double y = origin.y; + int repeatUp = (int) ceil(((maxY - y)/interval) + 1); + int repeatDown = (int) ceil(((y - minY)/interval) + 1); + int repeatTotal = repeatUp + repeatDown; + + // make repeats + for (int i = 0; i < repeatTotal; i++) { + Base::Vector3d newStart(minX,minY + float(i)*interval,0); + Base::Vector3d newEnd(maxX,minY + float(i)*interval,0); + TopoDS_Edge newLine = makeLine(newStart,newEnd); + result.push_back(newLine); + } + } else if ((angle == 90.0) || + (angle == -90.0)) { //odd case 2: vertical lines + double x = origin.x; + int repeatRight = (int) ceil(((maxX - x)/interval) + 1); + int repeatLeft = (int) ceil(((x - minX)/interval) + 1); + int repeatTotal = repeatRight + repeatLeft; + + // make repeats + for (int i = 0; i < repeatTotal; i++) { + Base::Vector3d newStart(minX + float(i)*interval,minY,0); + Base::Vector3d newEnd(minX + float(i)*interval,maxY,0); + TopoDS_Edge newLine = makeLine(newStart,newEnd); + result.push_back(newLine); + } +//TODO: check if this makes 2-3 extra lines. might be some "left" lines on "right" side of vv + } else if (angle > 0) { //oblique (bottom left -> top right) + //ex: 60,0,0,0,4.0,25,-25 +// Base::Console().Message("TRACE - DGH-makeEdgeOverlay - making angle > 0\n"); + double xLeftAtom = origin.x + (minY - origin.y)/slope; //the "atom" is the fill line that passes through the + //pattern-origin (not necc. R2 origin) + double xRightAtom = origin.x + (maxY - origin.y)/slope; + int repeatRight = (int) ceil(((maxX - xLeftAtom)/interval) + 1); + int repeatLeft = (int) ceil(((xRightAtom - minX)/interval) + 1); + + double leftStartX = xLeftAtom - (repeatLeft * interval); + double leftEndX = xRightAtom - (repeatLeft * interval); + int repeatTotal = repeatRight + repeatLeft; + + //make repeats + for (int i = 0; i < repeatTotal; i++) { + Base::Vector3d newStart(leftStartX + (float(i) * interval),minY,0); + Base::Vector3d newEnd (leftEndX + (float(i) * interval),maxY,0); + TopoDS_Edge newLine = makeLine(newStart,newEnd); + result.push_back(newLine); + } + } else { //oblique (bottom right -> top left) + // ex: -60,0,0,0,4.0,25.0,-12.5,12.5,-6 +// Base::Console().Message("TRACE - DGH-makeEdgeOverlay - making angle < 0\n"); + double xRightAtom = origin.x + ((minY - origin.y)/slope); //x-coord of left end of Atom line + double xLeftAtom = origin.x + ((maxY - origin.y)/slope); //x-coord of right end of Atom line + int repeatRight = (int) ceil(((maxX - xLeftAtom)/interval) + 1); //number of lines to Right of Atom + int repeatLeft = (int) ceil(((xRightAtom - minX)/interval) + 1);//number of lines to Left of Atom + double leftEndX = xLeftAtom - (repeatLeft * interval); + double leftStartX = xRightAtom - (repeatLeft * interval); + int repeatTotal = repeatRight + repeatLeft; + + // make repeats + for (int i = 0; i < repeatTotal; i++) { + Base::Vector3d newStart(leftStartX + float(i)*interval,minY,0); + Base::Vector3d newEnd(leftEndX + float(i)*interval,maxY,0); + TopoDS_Edge newLine = makeLine(newStart,newEnd); + result.push_back(newLine); + } + } + + return result; +} + +TopoDS_Edge DrawGeomHatch::makeLine(Base::Vector3d s, Base::Vector3d e) +{ + TopoDS_Edge result; + gp_Pnt start(s.x,s.y,0.0); + gp_Pnt end(e.x,e.y,0.0); + TopoDS_Vertex v1 = BRepBuilderAPI_MakeVertex(start); + TopoDS_Vertex v2 = BRepBuilderAPI_MakeVertex(end); + BRepBuilderAPI_MakeEdge makeEdge1(v1,v2); + result = makeEdge1.Edge(); + return result; +} + +//! get all the untrimed hatchlines for a face +//! these will be clipped to shape on the gui side +std::vector DrawGeomHatch::getFaceOverlay(int fdx) +{ +// Base::Console().Message("TRACE - DGH::getFaceOverlay(%d)\n",fdx); + std::vector result; + DrawViewPart* source = getSourceView(); + if (!source || + !source->hasGeometry()) { + Base::Console().Message("TRACE - DGH::getFaceOverlay - no source geometry\n"); + return result; + } + + TopoDS_Face face = extractFace(source,fdx); + + Bnd_Box bBox; + BRepBndLib::Add(face, bBox); + bBox.SetGap(0.0); + + for (auto& ls: m_lineSets) { + PATLineSpec hl = ls.getPATLineSpec(); + std::vector candidates = DrawGeomHatch::makeEdgeOverlay(hl, bBox, ScalePattern.getValue()); + std::vector resultGeoms; + int i = 0; + for (auto& e: candidates) { + TechDrawGeometry::BaseGeom* base = BaseGeom::baseFactory(e); + if (base == nullptr) { + Base::Console().Log("FAIL - DGH::getFaceOverlay - baseFactory failed for edge: %d\n",i); + throw Base::Exception("DGH::getFaceOverlay - baseFactory failed"); + } + resultGeoms.push_back(base); + i++; + } + ls.setEdges(candidates); + ls.setGeoms(resultGeoms); + result.push_back(ls); + } + + return result; +} + +/* static */ +//! get TopoDS_Face(iface) from DVP +TopoDS_Face DrawGeomHatch::extractFace(DrawViewPart* source, int iface ) +{ + TopoDS_Face result; + + //is source a section? DrawViewSection* section = dynamic_cast(source); bool usingSection = false; if (section != nullptr) { usingSection = true; } - - if (lineSets.empty()) { - Base::Console().Log("INFO - DC::getDrawableLines - no LineSets!\n"); - return result; - } std::vector faceWires; if (usingSection) { @@ -229,176 +455,14 @@ std::vector DrawGeomHatch::getDrawableLines(DrawViewPart* source, std:: mkFace.Add(*itWire); } if (!mkFace.IsDone()) { - Base::Console().Log("INFO - DC::getDrawableLines - face creation failed\n"); + Base::Console().Log("INFO - DGH::extractFace - face creation failed\n"); return result; } - TopoDS_Face face = mkFace.Face(); - - Bnd_Box bBox; - BRepBndLib::Add(face, bBox); - bBox.SetGap(0.0); - - for (auto& ls: lineSets) { - HatchLine hl = ls.getHatchLine(); - std::vector candidates = DrawGeomHatch::makeEdgeOverlay(hl, bBox, scale); - - //make Compound for this linespec - BRep_Builder builder; - TopoDS_Compound Comp; - builder.MakeCompound(Comp); - for (auto& c: candidates) { - builder.Add(Comp, c); - } - - //Common Compound with Face - BRepAlgoAPI_Common mkCommon(face, Comp); - if ((!mkCommon.IsDone()) || - (mkCommon.Shape().IsNull()) ) { - Base::Console().Log("INFO - DC::getDrawableLines - Common creation failed\n"); - return result; - } - TopoDS_Shape common = mkCommon.Shape(); - - //Save edges from Common - std::vector resultEdges; - std::vector resultGeoms; - TopTools_IndexedMapOfShape mapOfEdges; - TopExp::MapShapes(common, TopAbs_EDGE, mapOfEdges); - for ( int i = 1 ; i <= mapOfEdges.Extent() ; i++ ) { - const TopoDS_Edge& edge = TopoDS::Edge(mapOfEdges(i)); - if (edge.IsNull()) { - Base::Console().Log("INFO - DC::getDrawableLines - edge: %d is NULL\n",i); - continue; - } - TechDrawGeometry::BaseGeom* base = BaseGeom::baseFactory(edge); - if (base == nullptr) { - Base::Console().Log("FAIL - DC::getDrawableLines - baseFactory failed for edge: %d\n",i); - throw Base::Exception("GeometryObject::addGeomFromCompound - baseFactory failed"); - } - resultGeoms.push_back(base); - resultEdges.push_back(edge); - } - ls.setEdges(resultEdges); - ls.setGeoms(resultGeoms); - result.push_back(ls); - } + result = mkFace.Face(); return result; } -/* static */ -std::vector DrawGeomHatch::makeEdgeOverlay(HatchLine hl, Bnd_Box b, double scale) -{ - std::vector result; - - double minX,maxX,minY,maxY,minZ,maxZ; - b.Get(minX,minY,minZ,maxX,maxY,maxZ); - - Base::Vector3d start; - Base::Vector3d end; - Base::Vector3d origin = hl.getOrigin(); -// double interval = hl.getInterval() * ScalePattern.getValue(); - double interval = hl.getInterval() * scale; - double angle = hl.getAngle(); - - //only dealing with angles -180:180 for now - if (angle > 90.0) { - angle = -(180.0 - angle); - } else if (angle < -90.0) { - angle = (180 + angle); - } - angle = -angle; //not sure why this is required? inverted Y? - double slope = tan(angle * M_PI/180.0); - - if (angle == 0.0) { //odd case 1: horizontal lines - double y = origin.y; - double x1 = minX; - double x2 = maxX; - start = Base::Vector3d(x1,y,0); - end = Base::Vector3d(x2,y,0); - int repeatUp = (int) ceil(((maxY - y)/interval) + 1); - int repeatDown = (int) ceil(((y - minY)/interval) + 1); - // make up repeats - int i; - for (i = 1; i < repeatUp; i++) { - Base::Vector3d newStart(minX,y + float(i)*interval,0); - Base::Vector3d newEnd(maxX,y + float(i)*interval,0); - TopoDS_Edge newLine = makeLine(newStart,newEnd); - result.push_back(newLine); - } - // make down repeats - for (i = 1; i < repeatDown; i++) { - Base::Vector3d newStart(minX, y - float(i)*interval,0); - Base::Vector3d newEnd(maxX, y - float(i)*interval,0); - TopoDS_Edge newLine = makeLine(newStart,newEnd); - result.push_back(newLine); - } - } else if (angle > 0) { //bottomleft - topright - double xRightAtom = origin.x + ((maxY - origin.y)/slope); - double xLeftAtom = origin.x + ((minY - origin.y)/slope); - start = Base::Vector3d(xLeftAtom,minY,0); - end = Base::Vector3d(xRightAtom,maxY,0); - int repeatRight = (int) ceil(((maxX - xLeftAtom)/interval) + 1); - int repeatLeft = (int) ceil(((xRightAtom - minX)/interval) + 1); - - // make right repeats - int i; - for (i = 1; i < repeatRight; i++) { - Base::Vector3d newStart(start.x + float(i)*interval,minY,0); - Base::Vector3d newEnd(end.x + float(i)*interval,maxY,0); - TopoDS_Edge newLine = makeLine(newStart,newEnd); - result.push_back(newLine); - } - // make left repeats - for (i = 1; i < repeatLeft; i++) { - Base::Vector3d newStart(start.x - float(i)*interval,minY,0); - Base::Vector3d newEnd(end.x - float(i)*interval,maxY,0); - TopoDS_Edge newLine = makeLine(newStart,newEnd); - result.push_back(newLine); - } - } else { //topleft - bottomright - double x2 = origin.x + (maxY - origin.y)/slope; - double x1 = origin.x + (minY - origin.y)/slope; - start = Base::Vector3d(x2,maxY,0); - end = Base::Vector3d(x1,minY,0); - int repeatRight = (int) ceil(((maxX - start.x)/interval) + 1); - int repeatLeft = (int) ceil(((end.x - minX)/interval) + 1); - - // make right repeats - int i; - for (i = 1; i < repeatRight; i++) { - Base::Vector3d newStart(start.x + float(i)*interval,maxY,0); - Base::Vector3d newEnd(end.x + float(i)*interval,minY,0); - TopoDS_Edge newLine = makeLine(newStart,newEnd); - result.push_back(newLine); - } - // make left repeats - for (i = 1; i < repeatLeft; i++) { - Base::Vector3d newStart(start.x - float(i)*interval,maxY,0); - Base::Vector3d newEnd(end.x - float(i)*interval,minY,0); - TopoDS_Edge newLine = makeLine(newStart,newEnd); - result.push_back(newLine); - } - } - //atom is centre line in a set of pattern lines. - TopoDS_Edge atom = makeLine(start,end); - result.push_back(atom); - return result; -} - -TopoDS_Edge DrawGeomHatch::makeLine(Base::Vector3d s, Base::Vector3d e) -{ - TopoDS_Edge result; - gp_Pnt start(s.x,s.y,0.0); - gp_Pnt end(e.x,e.y,0.0); - TopoDS_Vertex v1 = BRepBuilderAPI_MakeVertex(start); - TopoDS_Vertex v2 = BRepBuilderAPI_MakeVertex(end); - BRepBuilderAPI_MakeEdge makeEdge1(v1,v2); - result = makeEdge1.Edge(); - return result; -} - void DrawGeomHatch::getParameters(void) { -//this is probably "/build/data/Mod/TechDraw/PAT" Base::Reference hGrp = App::GetApplication().GetUserParameter() .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/PAT"); diff --git a/src/Mod/TechDraw/App/DrawGeomHatch.h b/src/Mod/TechDraw/App/DrawGeomHatch.h index d9885b16d6..7540b9d09f 100644 --- a/src/Mod/TechDraw/App/DrawGeomHatch.h +++ b/src/Mod/TechDraw/App/DrawGeomHatch.h @@ -29,6 +29,7 @@ #include class TopoDS_Edge; +class TopoDS_Face; class Bnd_Box; namespace TechDrawGeometry @@ -39,7 +40,7 @@ class BaseGeom; namespace TechDraw { class DrawViewPart; -class HatchLine; +class PATLineSpec; class LineSet; class DashSet; @@ -66,17 +67,21 @@ public: DrawViewPart* getSourceView(void) const; - std::vector getDrawableLines(int i = 0); - static std::vector getDrawableLines(DrawViewPart* dvp, std::vector lineSets, int iface, double scale); + std::vector getFaceOverlay(int i = 0); + std::vector getTrimmedLines(int i = 0); + static std::vector getTrimmedLines(DrawViewPart* dvp, std::vector lineSets, int iface, double scale); - static std::vector makeEdgeOverlay(HatchLine hl, Bnd_Box bBox, double scale); + static std::vector makeEdgeOverlay(PATLineSpec hl, Bnd_Box bBox, double scale); static TopoDS_Edge makeLine(Base::Vector3d s, Base::Vector3d e); - static std::vector getDecodedSpecsFromFile(std::string fileSpec, std::string myPattern); + static std::vector getDecodedSpecsFromFile(std::string fileSpec, std::string myPattern); + static TopoDS_Face extractFace(DrawViewPart* source, int iface ); protected: void getParameters(void); - std::vector getDecodedSpecsFromFile(); + std::vector getDecodedSpecsFromFile(); std::vector m_lineSets; + std::string m_saveFile; + std::string m_saveName; private: static App::PropertyFloatConstraint::Constraints scaleRange; diff --git a/src/Mod/TechDraw/App/DrawViewSection.cpp b/src/Mod/TechDraw/App/DrawViewSection.cpp index eb232361e0..4062ea452c 100644 --- a/src/Mod/TechDraw/App/DrawViewSection.cpp +++ b/src/Mod/TechDraw/App/DrawViewSection.cpp @@ -539,7 +539,7 @@ Base::Vector3d DrawViewSection::getSectionVector (const std::string sectionName) std::vector DrawViewSection::getDrawableLines(int i) { std::vector result; - result = DrawGeomHatch::getDrawableLines(this,m_lineSets,i,HatchScale.getValue()); + result = DrawGeomHatch::getTrimmedLines(this,m_lineSets,i,HatchScale.getValue()); return result; } diff --git a/src/Mod/TechDraw/App/HatchLine.cpp b/src/Mod/TechDraw/App/HatchLine.cpp index 3f36c9b2ae..6ebe3738af 100644 --- a/src/Mod/TechDraw/App/HatchLine.cpp +++ b/src/Mod/TechDraw/App/HatchLine.cpp @@ -30,7 +30,9 @@ #include #endif +#include #include +#include #include #include @@ -42,23 +44,80 @@ using namespace TechDraw; -HatchLine::HatchLine() +double LineSet::getMinX(void) +{ + double xMin,yMin,zMin,xMax,yMax,zMax; + m_box.Get(xMin,yMin,zMin,xMax,yMax,zMax); + return xMin; +} + +double LineSet::getMinY(void) +{ + double xMin,yMin,zMin,xMax,yMax,zMax; + m_box.Get(xMin,yMin,zMin,xMax,yMax,zMax); + return yMin; +} + +double LineSet::getMaxX(void) +{ + double xMin,yMin,zMin,xMax,yMax,zMax; + m_box.Get(xMin,yMin,zMin,xMax,yMax,zMax); + return xMax; +} + +double LineSet::getMaxY(void) +{ + double xMin,yMin,zMin,xMax,yMax,zMax; + m_box.Get(xMin,yMin,zMin,xMax,yMax,zMax); + return yMax; +} + +bool LineSet::isDashed(void) +{ + bool result = m_hatchLine.isDashed(); + return result; +} + +//TODO: needs to incorporate deltaX parameter +//! calculates the apparent start point for dashed lines +Base::Vector3d LineSet::calcApparentStart(TechDrawGeometry::BaseGeom* g) +{ + Base::Vector3d result; + Base::Vector3d start(g->getStartPoint().x,g->getStartPoint().y,0.0); + double angle = getPATLineSpec().getAngle(); + if (angle == 0.0) { //horizontal + result = Base::Vector3d(getMinX(),start.y,0.0); + } else if ((angle == 90.0) || + (angle == -90.0)) { //vertical + result = Base::Vector3d(start.x,getMinY(),0.0); + } else { + double slope = getPATLineSpec().getSlope(); + double y = getMinY(); + double x = ((y - start.y) / slope) + start.x; + result = Base::Vector3d(x,y,0); + } + return result; +} + + +//******************************************* +PATLineSpec::PATLineSpec() { init(); } -HatchLine::HatchLine(std::string& lineSpec) +PATLineSpec::PATLineSpec(std::string& lineSpec) { init(); load(lineSpec); } -HatchLine::~HatchLine() +PATLineSpec::~PATLineSpec() { } -void HatchLine::init(void) +void PATLineSpec::init(void) { m_angle = 0.0; m_origin = Base::Vector3d(0.0,0.0,0.0); @@ -66,11 +125,11 @@ void HatchLine::init(void) m_offset = 0.0; } -void HatchLine::load(std::string& lineSpec) +void PATLineSpec::load(std::string& lineSpec) { std::vector values = split(lineSpec); if (values.size() < 5) { - Base::Console().Message( "HatchLine::load(%s) invalid entry in pattern\n",lineSpec.c_str() ); + Base::Console().Message( "PATLineSpec::load(%s) invalid entry in pattern\n",lineSpec.c_str() ); return; } m_angle = values[0]; @@ -78,11 +137,13 @@ void HatchLine::load(std::string& lineSpec) m_offset = values[3]; m_interval = values[4]; if (values.size() > 5) { - m_dashParms.insert(std::end(m_dashParms), std::begin(values) + 5, std::end(values)); + std::vector dash; + dash.insert(std::end(dash), std::begin(values) + 5, std::end(values)); + m_dashParms = DashSpec(dash); } } -std::vector HatchLine::split(std::string line) +std::vector PATLineSpec::split(std::string line) { std::vector result; std::stringstream lineStream(line); @@ -101,25 +162,26 @@ std::vector HatchLine::split(std::string line) return result; } -void HatchLine::dump(char* title) +void PATLineSpec::dump(char* title) { Base::Console().Message( "DUMP: %s\n",title); Base::Console().Message( "Angle: %.3f\n", m_angle); Base::Console().Message( "Origin: %s\n",DrawUtil::formatVector(m_origin).c_str()); Base::Console().Message( "Offset: %.3f\n",m_offset); Base::Console().Message( "Interval: %.3f\n",m_interval); - std::stringstream ss; - for (auto& d: m_dashParms) { - ss << d << ", "; - } - ss << "end"; - Base::Console().Message( "DashSpec: %s\n",ss.str().c_str()); +// std::stringstream ss; +// for (auto& d: m_dashParms) { +// ss << d << ", "; +// } +// ss << "end"; +// Base::Console().Message( "DashSpec: %s\n",ss.str().c_str()); + m_dashParms.dump("dashspec"); } //static class methods -std::vector HatchLine::getSpecsForPattern(std::string& parmFile, std::string& parmName) +std::vector PATLineSpec::getSpecsForPattern(std::string& parmFile, std::string& parmName) { - std::vector result; + std::vector result; std::vector lineSpecs; std::ifstream inFile; inFile.open (parmFile, std::ifstream::in); @@ -137,15 +199,15 @@ std::vector HatchLine::getSpecsForPattern(std::string& parmFile, std: return result; } - //decode definition lines into HatchLine objects + //decode definition lines into PATLineSpec objects for (auto& l: lineSpecs) { - HatchLine hl(l); + PATLineSpec hl(l); result.push_back(hl); } return result; } -bool HatchLine::findPatternStart(std::ifstream& inFile, std::string& parmName) +bool PATLineSpec::findPatternStart(std::ifstream& inFile, std::string& parmName) { bool result = false; while ( inFile.good() ){ @@ -176,7 +238,7 @@ bool HatchLine::findPatternStart(std::ifstream& inFile, std::string& parmName) } //get the definition lines for this pattern -std::vector HatchLine::loadPatternDef(std::ifstream& inFile) +std::vector PATLineSpec::loadPatternDef(std::ifstream& inFile) { std::vector result; while ( inFile.good() ){ @@ -196,7 +258,7 @@ std::vector HatchLine::loadPatternDef(std::ifstream& inFile) return result; } -std::vector HatchLine::getPatternList(std::string& parmFile) +std::vector PATLineSpec::getPatternList(std::string& parmFile) { std::vector result; std::ifstream inFile; @@ -225,6 +287,26 @@ std::vector HatchLine::getPatternList(std::string& parmFile) return result; } +double PATLineSpec::getSlope(void) +{ + double angle = getAngle(); + + //only dealing with angles -180:180 for now + if (angle > 90.0) { + angle = -(180.0 - angle); + } else if (angle < -90.0) { + angle = (180 + angle); + } + double slope = tan(angle * M_PI/180.0); + return slope; +} + +bool PATLineSpec::isDashed(void) +{ + bool result = !m_dashParms.empty(); + return result; +} + //******************************************************** void DashSpec::dump(char* title) { diff --git a/src/Mod/TechDraw/App/HatchLine.h b/src/Mod/TechDraw/App/HatchLine.h index 3860353467..9ce3c44a7b 100644 --- a/src/Mod/TechDraw/App/HatchLine.h +++ b/src/Mod/TechDraw/App/HatchLine.h @@ -19,6 +19,8 @@ * Suite 330, Boston, MA 02111-1307, USA * * * ***************************************************************************/ + +//! HatchLine - Classes related to processing PAT files #ifndef _TechDraw_HATCHLINE_H_ #define _TechDraw_HATCHLINE_H_ @@ -29,9 +31,12 @@ #include #include +#include +#include #include -class TopoDS_Edge; +//class TopoDS_Edge; +//class Bnd_Box; namespace TechDrawGeometry { @@ -43,15 +48,32 @@ namespace TechDraw class DrawViewPart; class DrawUtil; +//DashSpec is the parsed portion of a PATLineSpec related to mark/space/dot +class TechDrawExport DashSpec +{ +public: + DashSpec() {} + DashSpec(std::vector p) { m_parms = p; } + ~DashSpec() {} + + double get(int i) {return m_parms.at(i); } + std::vector get(void) {return m_parms;} + bool empty(void) {return m_parms.empty();} + int size(void) {return m_parms.size();} + double length(void); + void dump(char* title); + +private: + std::vector m_parms; +}; -// HatchLine is the result of parsing a line from PAT file into accessible parameters -// e /HatchLine/PATSpecLine/ -class TechDrawExport HatchLine +//! PATLineSpec is the result of parsing a singleline from PAT file into accessible parameters +class TechDrawExport PATLineSpec { public: - HatchLine(); - HatchLine(std::string& lineSpec); - ~HatchLine(); + PATLineSpec(); + PATLineSpec(std::string& lineSpec); + ~PATLineSpec(); void load(std::string& lineSpec); @@ -61,10 +83,12 @@ public: double getOffset(void) {return m_offset;} std::vector getDashParms(void) {return m_dashParms;} - static std::vector getSpecsForPattern(std::string& parmFile, std::string& parmName); + static std::vector getSpecsForPattern(std::string& parmFile, std::string& parmName); static bool findPatternStart(std::ifstream& inFile, std::string& parmName); static std::vector loadPatternDef(std::ifstream& inFile); static std::vector getPatternList(std::string& parmFile); + + bool isDashed(void); void dump(char* title); @@ -76,48 +100,45 @@ private: Base::Vector3d m_origin; double m_interval; double m_offset; - std::vector m_dashParms; //why isn't this a DashSpec object? + DashSpec m_dashParms; }; -// a LineSet is all the generated edges for 1 HatchLine for 1 Face +//! a LineSet is all the generated edges for 1 PATLineSpec for 1 Face class TechDrawExport LineSet { public: LineSet() {} ~LineSet() {} - void setHatchLine(HatchLine s) { m_hatchLine = s; } + void setPATLineSpec(PATLineSpec s) { m_hatchLine = s; } void setEdges(std::vector e) {m_edges = e;} void setGeoms(std::vector g) {m_geoms = g;} + void setBBox(Bnd_Box bb) {m_box = bb;} - HatchLine getHatchLine(void) { return m_hatchLine; } - std::vector getDashSpec(void) { return m_hatchLine.getDashParms();} + PATLineSpec getPATLineSpec(void) { return m_hatchLine; } + double getOffset(void) { return m_hatchLine.getOffset(); } + double getAngle(void) { return m_hatchLine.getAngle(); } + DashSpec getDashSpec(void) { return m_hatchLine.getDashParms();} std::vector getEdges(void) { return m_edges; } + TopoDS_Edge getEdge(int i) {return m_edges.at(i);} std::vector getGeoms(void) { return m_geoms; } - //void clearGeom(void); + Base::Vector3d calcApparentStart(TechDrawGeometry::BaseGeom* g); + + Bnd_Box getBBox(void) {return m_box;} + double getMinX(void); + double getMaxX(void); + double getMinY(void); + double getMaxY(void); + + bool isDashed(void); private: std::vector m_edges; std::vector m_geoms; - HatchLine m_hatchLine; + PATLineSpec m_hatchLine; + Bnd_Box m_box; }; -class TechDrawExport DashSpec -{ -public: - DashSpec() {} - DashSpec(std::vector p) { m_parms = p; } - ~DashSpec() {} - - double get(int i) {return m_parms.at(i); } - std::vector get(void) {return m_parms;} - bool empty(void) {return m_parms.empty();} - int size(void) {return m_parms.size();} - void dump(char* title); - -private: - std::vector m_parms; -}; } //end namespace diff --git a/src/Mod/TechDraw/Gui/CommandDecorate.cpp b/src/Mod/TechDraw/Gui/CommandDecorate.cpp index 4f06f17dd3..bd8a8c501f 100644 --- a/src/Mod/TechDraw/Gui/CommandDecorate.cpp +++ b/src/Mod/TechDraw/Gui/CommandDecorate.cpp @@ -175,13 +175,13 @@ void CmdTechDrawNewGeomHatch::activated(int iMsg) geomhatch->Source.setValue(objFeat, subNames); Gui::ViewProvider* vp = Gui::Application::Instance->getDocument(getDocument())->getViewProvider(geomhatch); TechDrawGui::ViewProviderGeomHatch* hvp = dynamic_cast(vp); - if( hvp == nullptr ) { + if (!hvp) { + Base::Console().Log("ERROR - CommandDecorate - GeomHatch has no ViewProvider\n"); return; } -// if (!hvp) { // dialog to fill in hatch values - Gui::Control().showDialog(new TaskDlgGeomHatch(geomhatch,hvp)); + Gui::Control().showDialog(new TaskDlgGeomHatch(geomhatch,hvp,true)); commitCommand(); diff --git a/src/Mod/TechDraw/Gui/QGIFace.cpp b/src/Mod/TechDraw/Gui/QGIFace.cpp index 137e0d0c0f..e3fc49871d 100644 --- a/src/Mod/TechDraw/Gui/QGIFace.cpp +++ b/src/Mod/TechDraw/Gui/QGIFace.cpp @@ -41,6 +41,10 @@ #include #include +#include +#include +#include + #include #include @@ -50,9 +54,14 @@ #include +//debug +#include "QGICMark.h" +#include "ZVALUE.h" +// #include "Rez.h" #include "QGCustomSvg.h" #include "QGCustomRect.h" +#include "QGIViewPart.h" #include "QGIFace.h" using namespace TechDrawGui; @@ -66,7 +75,8 @@ QGIFace::QGIFace(int index) : { setFillMode(NoFill); isHatched(false); - setFlag(QGraphicsItem::ItemClipsChildrenToShape,true); +// setFlag(QGraphicsItem::ItemClipsChildrenToShape,true); + setFlag(QGraphicsItem::ItemClipsChildrenToShape,false); //setStyle(Qt::NoPen); //don't draw face lines, just fill for debugging setStyle(Qt::DashLine); @@ -99,18 +109,13 @@ void QGIFace::draw() setPath(m_outline); //Face boundary if (isHatched()) { - if (m_mode == GeomHatchFill) { //crosshatch - if (!m_geomHatchPaths.empty()) { //surrogate for LineSets.empty + if (m_mode == GeomHatchFill) { + if (!m_lineSets.empty()) { m_brush.setTexture(QPixmap()); m_fillStyle = m_styleDef; m_styleNormal = m_fillStyle; - int pathNo = 0; - for (auto& pp: m_geomHatchPaths) { - QGraphicsPathItem* fillItem = m_fillItems.at(pathNo); - fillItem->setPath(pp); - QPen geomPen = setGeomPen(pathNo); - fillItem->setPen(geomPen); - pathNo++; + for (auto& ls: m_lineSets) { + lineSetToFillItem(ls); } } } else if ((m_mode == FromFile) || @@ -217,27 +222,121 @@ void QGIFace::setOutline(const QPainterPath & path) void QGIFace::clearLineSets(void) { - m_geomHatchPaths.clear(); m_dashSpecs.clear(); clearFillItems(); } -//each line set needs a painterpath, a dashspec and a QGPItem to show them -void QGIFace::addLineSet(QPainterPath pp, std::vector dp) +void QGIFace::addLineSet(LineSet ls) { - m_geomHatchPaths.push_back(pp); - m_dashSpecs.push_back(DashSpec(dp)); - addFillItem(); -} + m_lineSets.push_back(ls); +} -QGraphicsPathItem* QGIFace::addFillItem() +void QGIFace::lineSetToFillItem(LineSet ls) { - QGraphicsPathItem* fillItem = new QGraphicsPathItem(); - fillItem->setParentItem(this); + for (auto& g: ls.getGeoms()) { + QGraphicsLineItem* fillItem = geomToLine(g); + QPen geomPen = setGeomPen(ls.getDashSpec()); + if (ls.isDashed()) { + double offset = calcOffset(g,ls); //offset in graphics coords(?) + geomPen.setDashOffset(offset); +// geomPen.setDashOffset(offset/getXForm()); //try to account for QGraphicsView Zoom level + } + fillItem->setPen(geomPen); + } +} + +QGraphicsLineItem* QGIFace::geomToLine(TechDrawGeometry::BaseGeom* base) +{ + QGraphicsLineItem* fillItem = new QGraphicsLineItem(this); + fillItem->setLine(Rez::guiX(base->getStartPoint().x), + Rez::guiX(-base->getStartPoint().y), + Rez::guiX(base->getEndPoint().x), + Rez::guiX(-base->getEndPoint().y)); m_fillItems.push_back(fillItem); return fillItem; } - + +QPen QGIFace::setGeomPen(DashSpec ourSpec) +{ + QPen result; + result.setWidthF(Rez::guiX(m_geomWeight)); +// result.setWidthF(1.0); + result.setColor(m_geomColor); + if (ourSpec.empty()) { + result.setStyle(Qt::SolidLine); + } else { + result.setStyle(Qt::CustomDashLine); + result.setDashPattern(decodeDashSpec(ourSpec)); + } + return result; +} + +double QGIFace::calcOffset(TechDrawGeometry::BaseGeom* g,LineSet ls) +{ + Base::Vector3d startPoint(g->getStartPoint().x,g->getStartPoint().y,0.0); + Base::Vector3d appStart = ls.calcApparentStart(g); + double distToStart = (startPoint - appStart).Length(); + double patternLength = ls.getDashSpec().length(); + + double penWidth = Rez::guiX(m_geomWeight); +// double penWidth = 1.0; + distToStart = Rez::guiX(distToStart); //distance in scene units/pixels? + patternLength = Rez::guiX(patternLength) * penWidth; //pattern as it will be rendered by QPen (length*weight) + double patternReps = distToStart / patternLength; + double remain = patternReps - floor(patternReps); //fraction of a pattern + double result = patternLength * remain; + return result; +} + +//!convert from PAT style "-1,0,-1,+1" in mm to Qt style "mark,space,mark,space" in penWidths +// the actual dash pattern/offset varies according to lineWeight, GraphicsView zoom level, scene unit size (and printer scale?). +// haven't figured out the actual algorithm. +// in Qt a dash length of l (8) with a pen of width w (2) yields a dash of length l*w (16), but this is only part of the equation. +QVector QGIFace::decodeDashSpec(DashSpec patDash) +{ + double penWidth = Rez::guiX(m_geomWeight); + double minPen = 0.01; //avoid trouble with cosmetic pen (zero width)? + if (penWidth <= minPen) { + penWidth = minPen; + } + double unitLength = penWidth; +// double unitLength = 1.0; + std::vector result; + for (auto& d: patDash.get()) { + double strokeLength; + if (DrawUtil::fpCompare(d,0.0)) { //pat dot + strokeLength = unitLength; + } else if (Rez::guiX(d) < 0) { //pat space + strokeLength = fabs(Rez::guiX(d)) / unitLength; + } else { //pat dash + strokeLength = Rez::guiX(d) / unitLength; + } +// //try to keep the pattern the same when View scales +// strokeLength = strokeLength/getXForm(); +// Base::Console().Message("TRACE - QGIF - d: %.3f strokeLength: %.3f\n",d,strokeLength); + result.push_back(strokeLength); + } + + return QVector::fromStdVector( result ); +} + +//! get zoom level (scale) from QGraphicsView +double QGIFace::getXForm(void) +{ + //try to keep the pattern the same when View scales + double result = 1.0; + auto s = scene(); + if (s) { + auto vs = s->views(); //ptrs to views + if (!vs.empty()) { + auto v = vs.at(0); + auto i = v->transform().inverted(); + result = i.m11(); + } + } + return result; +} + void QGIFace::clearFillItems(void) { for (auto& f: m_fillItems) { @@ -247,48 +346,14 @@ void QGIFace::clearFillItems(void) } } -//convert from PAT style "-1,0,-1,+1" to Qt style "mark,space,mark,space" -QVector QGIFace::decodeDashSpec(DashSpec patDash) +void QGIFace::makeMark(double x, double y) { - //Rez::guiX(something)? - double dotLength = 3.0; - double unitLength = 6.0; -// double penWidth = m_geomWeight; //mark, space and dot lengths are to be in terms of penWidth(Qt) or mm(PAT)?? -// //if we want it in terms of mm, we need to divide by penWidth? -// double minPen = 0.01; //avoid trouble with cosmetic pen (zero width) - std::vector result; - std::string prim; - for (auto& d: patDash.get()) { - double strokeLength; - if (DrawUtil::fpCompare(d,0.0)) { //pat dot - strokeLength = dotLength; - } else if (Rez::guiX(d) < 0) { //pat space - strokeLength = fabs(Rez::guiX(d)) * unitLength; - } else { //pat dash - strokeLength = Rez::guiX(d) * unitLength; - } - result.push_back(strokeLength); - } - return QVector::fromStdVector( result ); -} - - -QPen QGIFace::setGeomPen(int i) -{ - //m_dashSpecs[i].dump("spec test"); - DashSpec ourSpec = m_dashSpecs.at(i); - //ourSpec.dump("our spec"); - - QPen result; - result.setWidthF(Rez::guiX(m_geomWeight)); //Rez::guiX() ?? line weights are in mm? - result.setColor(m_geomColor); - if (ourSpec.empty()) { - result.setStyle(Qt::SolidLine); - } else { - result.setStyle(Qt::CustomDashLine); - result.setDashPattern(decodeDashSpec(ourSpec)); - } - return result; + QGICMark* cmItem = new QGICMark(-1); + cmItem->setParentItem(this); + cmItem->setPos(x,y); + cmItem->setThick(0.5); + cmItem->setSize(2.0); + cmItem->setZValue(ZVALUE::VERTEX); } void QGIFace::buildSvgHatch() diff --git a/src/Mod/TechDraw/Gui/QGIFace.h b/src/Mod/TechDraw/Gui/QGIFace.h index 3fd980bfc5..0b06d060cf 100644 --- a/src/Mod/TechDraw/Gui/QGIFace.h +++ b/src/Mod/TechDraw/Gui/QGIFace.h @@ -31,6 +31,7 @@ #include #include +#include #include "QGIPrimPath.h" @@ -101,17 +102,25 @@ public: //PAT fill parms & methods void setGeomHatchWeight(double w) { m_geomWeight = w; } - void clearLineSets(void); - void addLineSet(QPainterPath pp, std::vector dp); - QGraphicsPathItem* addFillItem(); - void clearFillItems(void); void setLineWeight(double w); + void clearLineSets(void); + void addLineSet(LineSet ls); + void clearFillItems(void); + + void lineSetToFillItem(LineSet ls); + QGraphicsLineItem* geomToLine(TechDrawGeometry::BaseGeom* base); + double calcOffset(TechDrawGeometry::BaseGeom* g,LineSet ls); + //bitmap texture fill parms method QPixmap textureFromBitmap(std::string fileSpec); QPixmap textureFromSvg(std::string fillSpec); protected: + void makeMark(double x, double y); + double getXForm(void); + + int projIndex; //index of face in Projection. -1 for SectionFace. QGCustomRect *m_rect; @@ -124,10 +133,10 @@ protected: bool m_isHatched; QGIFace::fillMode m_mode; - QPen setGeomPen(int i); + QPen setGeomPen(DashSpec ds); QVector decodeDashSpec(DashSpec d); - std::vector m_fillItems; - std::vector m_geomHatchPaths; // 0/1 dashspec per hatchpath + std::vector m_fillItems; + std::vector m_lineSets; std::vector m_dashSpecs; diff --git a/src/Mod/TechDraw/Gui/QGIPrimPath.cpp b/src/Mod/TechDraw/Gui/QGIPrimPath.cpp index 226c2184f2..56a9f95229 100644 --- a/src/Mod/TechDraw/Gui/QGIPrimPath.cpp +++ b/src/Mod/TechDraw/Gui/QGIPrimPath.cpp @@ -83,9 +83,9 @@ void QGIPrimPath::hoverEnterEvent(QGraphicsSceneHoverEvent *event) void QGIPrimPath::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) { - QGIView *view = dynamic_cast (parentItem()); //this is temp for debug?? - assert(view != 0); - Q_UNUSED(view); +// QGIView *view = dynamic_cast (parentItem()); //this is temp for debug?? +// assert(view != 0); +// Q_UNUSED(view); if(!isSelected() && !isHighlighted) { setPrettyNormal(); } diff --git a/src/Mod/TechDraw/Gui/QGIViewPart.cpp b/src/Mod/TechDraw/Gui/QGIViewPart.cpp index d27aec6606..8dae423e17 100644 --- a/src/Mod/TechDraw/Gui/QGIViewPart.cpp +++ b/src/Mod/TechDraw/Gui/QGIViewPart.cpp @@ -138,6 +138,13 @@ void QGIViewPart::setViewPartFeature(TechDraw::DrawViewPart *obj) } QPainterPath QGIViewPart::drawPainterPath(TechDrawGeometry::BaseGeom *baseGeom) const +{ + double rot = getViewObject()->Rotation.getValue(); + return geomToPainterPath(baseGeom,rot); +} + + +QPainterPath QGIViewPart::geomToPainterPath(TechDrawGeometry::BaseGeom *baseGeom, double rot) { QPainterPath path; @@ -152,7 +159,6 @@ QPainterPath QGIViewPart::drawPainterPath(TechDrawGeometry::BaseGeom *baseGeom) Rez::guiX(y), Rez::guiX(geom->radius * 2), Rez::guiX(geom->radius * 2)); //topleft@(x,y) radx,rady - //Base::Console().Message("TRACE -drawPainterPath - making an CIRCLE @(%.3f,%.3f) R:%.3f\n",x, y, geom->radius); } break; case TechDrawGeometry::ARCOFCIRCLE: { TechDrawGeometry::AOC *geom = static_cast(baseGeom); @@ -167,9 +173,6 @@ QPainterPath QGIViewPart::drawPainterPath(TechDrawGeometry::BaseGeom *baseGeom) Rez::guiX(geom->endPnt.y), Rez::guiX(geom->startPnt.x), Rez::guiX(geom->startPnt.y)); -// double x = geom->center.x - geom->radius; -// double y = geom->center.y - geom->radius; - //Base::Console().Message("TRACE -drawPainterPath - making an ARCOFCIRCLE @(%.3f,%.3f) R:%.3f\n",x, y, geom->radius); } break; case TechDrawGeometry::ELLIPSE: { TechDrawGeometry::Ellipse *geom = static_cast(baseGeom); @@ -202,7 +205,6 @@ QPainterPath QGIViewPart::drawPainterPath(TechDrawGeometry::BaseGeom *baseGeom) Rez::guiX(endX), Rez::guiX(endY)); - //Base::Console().Message("TRACE -drawPainterPath - making an ELLIPSE @(%.3f,%.3f) R1:%.3f R2:%.3f\n",geom->center.x,geom->center.y, geom->major, geom->minor); } break; case TechDrawGeometry::ARCOFELLIPSE: { TechDrawGeometry::AOE *geom = static_cast(baseGeom); @@ -217,7 +219,6 @@ QPainterPath QGIViewPart::drawPainterPath(TechDrawGeometry::BaseGeom *baseGeom) Rez::guiX(geom->endPnt.y), Rez::guiX(geom->startPnt.x), Rez::guiX(geom->startPnt.y)); - //Base::Console().Message("TRACE -drawPainterPath - making an ARCOFELLIPSE R1:%.3f R2:%.3f From: (%.3f,%.3f) To: (%.3f,%.3f)\n",geom->major, geom->minor,geom->startPnt.x, geom->startPnt.y,geom->endPnt.x, geom->endPnt.y); } break; case TechDrawGeometry::BEZIER: { @@ -225,7 +226,6 @@ QPainterPath QGIViewPart::drawPainterPath(TechDrawGeometry::BaseGeom *baseGeom) // Move painter to the beginning path.moveTo(Rez::guiX(geom->pnts[0].x), Rez::guiX(geom->pnts[0].y)); - //Base::Console().Message("TRACE -drawPainterPath - making an BEZIER From: (%.3f,%.3f)\n",geom->pnts[0].x,geom->pnts[0].y); if ( geom->poles == 2 ) { // Degree 1 bezier = straight line... @@ -254,7 +254,6 @@ QPainterPath QGIViewPart::drawPainterPath(TechDrawGeometry::BaseGeom *baseGeom) // Move painter to the beginning of our first segment path.moveTo(Rez::guiX(it->pnts[0].x), Rez::guiX(it->pnts[0].y)); - //Base::Console().Message("TRACE -drawPainterPath - making an BSPLINE From: (%.3f,%.3f)\n",it->pnts[0].x,it->pnts[0].y); for ( ; it != geom->segments.end(); ++it) { // At this point, the painter is either at the beginning @@ -282,19 +281,16 @@ QPainterPath QGIViewPart::drawPainterPath(TechDrawGeometry::BaseGeom *baseGeom) path.moveTo(Rez::guiX(geom->points[0].x), Rez::guiX(geom->points[0].y)); std::vector::const_iterator it = geom->points.begin(); - //Base::Console().Message("TRACE -drawPainterPath - making an GENERIC From: (%.3f,%.3f)\n",geom->points[0].x, geom->points[0].y); for(++it; it != geom->points.end(); ++it) { path.lineTo(Rez::guiX((*it).x), Rez::guiX((*it).y)); - //Base::Console().Message(">>>> To: (%.3f,%.3f)\n",(*it).x, (*it).y); } } break; default: - Base::Console().Error("Error - drawPainterPath - UNKNOWN geomType: %d\n",baseGeom->geomType); + Base::Console().Error("Error - geomToPainterPath - UNKNOWN geomType: %d\n",baseGeom->geomType); break; } - double rot = getViewObject()->Rotation.getValue(); - if (rot) { + if (rot != 0.0) { QTransform t; t.rotate(-rot); path = t.map(path); @@ -391,16 +387,11 @@ void QGIViewPart::drawViewPart() const std::vector &sourceNames = fGeom->Source.getSubValues(); if (!sourceNames.empty()) { int fdx = TechDraw::DrawUtil::getIndexFromName(sourceNames.at(0)); - std::vector lineSets = fGeom->getDrawableLines(fdx); + std::vector lineSets = fGeom->getTrimmedLines(fdx); if (!lineSets.empty()) { newFace->clearLineSets(); for (auto& ls: lineSets) { - QPainterPath bigPath; - for (auto& g: ls.getGeoms()) { - QPainterPath smallPath = drawPainterPath(g); - bigPath.addPath(smallPath); - } - newFace->addLineSet(bigPath,ls.getDashSpec()); + newFace->addLineSet(ls); } newFace->isHatched(true); newFace->setFillMode(QGIFace::GeomHatchFill); @@ -555,7 +546,6 @@ void QGIViewPart::removePrimitives() if (prim) { removeFromGroup(prim); scene()->removeItem(prim); -// deleteItems.append(prim); //pretty sure we could just delete here since not in scene anymore delete prim; } } @@ -722,7 +712,7 @@ void QGIViewPart::drawMatting() void QGIViewPart::pathArc(QPainterPath &path, double rx, double ry, double x_axis_rotation, bool large_arc_flag, bool sweep_flag, double x, double y, - double curx, double cury) const + double curx, double cury) { double sin_th, cos_th; double a00, a01, a10, a11; @@ -804,7 +794,7 @@ void QGIViewPart::pathArc(QPainterPath &path, double rx, double ry, double x_axi void QGIViewPart::pathArcSegment(QPainterPath &path, double xc, double yc, double th0, double th1, - double rx, double ry, double xAxisRotation) const + double rx, double ry, double xAxisRotation) { double sinTh, cosTh; double a00, a01, a10, a11; diff --git a/src/Mod/TechDraw/Gui/QGIViewPart.h b/src/Mod/TechDraw/Gui/QGIViewPart.h index b24170daa6..92f3000c21 100644 --- a/src/Mod/TechDraw/Gui/QGIViewPart.h +++ b/src/Mod/TechDraw/Gui/QGIViewPart.h @@ -66,23 +66,24 @@ public: virtual void draw() override; -protected: + static QPainterPath geomToPainterPath(TechDrawGeometry::BaseGeom *baseGeom, double rotation = 0.0); /// Helper for pathArc() /*! * x_axis_rotation is in radian */ - void pathArcSegment(QPainterPath &path, double xc, double yc, double th0, - double th1,double rx, double ry, double xAxisRotation) const; + static void pathArcSegment(QPainterPath &path, double xc, double yc, double th0, + double th1,double rx, double ry, double xAxisRotation); /// Draws an arc using QPainterPath path /*! * x_axis_rotation is in radian */ - void pathArc(QPainterPath &path, double rx, double ry, double x_axis_rotation, + static void pathArc(QPainterPath &path, double rx, double ry, double x_axis_rotation, bool large_arc_flag, bool sweep_flag, double x, double y, - double curx, double cury) const; + double curx, double cury); +protected: QPainterPath drawPainterPath(TechDrawGeometry::BaseGeom *baseGeom) const; void drawViewPart(); QGIFace* drawFace(TechDrawGeometry::Face* f, int idx); diff --git a/src/Mod/TechDraw/Gui/QGIViewSection.cpp b/src/Mod/TechDraw/Gui/QGIViewSection.cpp index 61ae49cb26..547a23751a 100644 --- a/src/Mod/TechDraw/Gui/QGIViewSection.cpp +++ b/src/Mod/TechDraw/Gui/QGIViewSection.cpp @@ -119,12 +119,12 @@ void QGIViewSection::drawSectionFace() if (!lineSets.empty()) { newFace->clearLineSets(); for (auto& ls: lineSets) { - QPainterPath bigPath; - for (auto& g: ls.getGeoms()) { - QPainterPath smallPath = drawPainterPath(g); - bigPath.addPath(smallPath); - } - newFace->addLineSet(bigPath,ls.getDashSpec()); +// QPainterPath bigPath; +// for (auto& g: ls.getGeoms()) { +// QPainterPath smallPath = drawPainterPath(g); +// bigPath.addPath(smallPath); +// } + newFace->addLineSet(ls); } } } diff --git a/src/Mod/TechDraw/Gui/TaskGeomHatch.cpp b/src/Mod/TechDraw/Gui/TaskGeomHatch.cpp index cdf9b463bb..eeba7f9e49 100644 --- a/src/Mod/TechDraw/Gui/TaskGeomHatch.cpp +++ b/src/Mod/TechDraw/Gui/TaskGeomHatch.cpp @@ -52,10 +52,11 @@ using namespace Gui; using namespace TechDraw; using namespace TechDrawGui; -TaskGeomHatch::TaskGeomHatch(TechDraw::DrawGeomHatch* inHatch,TechDrawGui::ViewProviderGeomHatch* inVp) : +TaskGeomHatch::TaskGeomHatch(TechDraw::DrawGeomHatch* inHatch,TechDrawGui::ViewProviderGeomHatch* inVp,bool mode) : ui(new Ui_TaskGeomHatch), m_hatch(inHatch), - m_Vp(inVp) + m_Vp(inVp), + m_createMode(mode) { ui->setupUi(this); connect(ui->fcFile, SIGNAL(fileNameSelected( const QString & )), this, SLOT(onFileChanged(void))); @@ -77,6 +78,12 @@ void TaskGeomHatch::initUi() std::vector names = HatchLine::getPatternList(m_file); QStringList qsNames = listToQ(names); ui->cbName->addItems(qsNames); + int nameIndex = ui->cbName->findText(QString::fromUtf8(m_name.data(),m_name.size())); + if (nameIndex > -1) { + ui->cbName->setCurrentIndex(nameIndex); + } else { + Base::Console().Warning("Warning - Pattern name not found in current PAT File\n"); + } ui->sbScale->setValue(m_scale); ui->sbWeight->setValue(m_weight); ui->ccColor->setColor(m_color.asValue()); @@ -121,16 +128,27 @@ bool TaskGeomHatch::accept() { updateValues(); Gui::Command::doCommand(Gui::Command::Gui,"Gui.ActiveDocument.resetEdit()"); + m_source->touch(); + m_source->getDocument()->recompute(); //TODO: this is only here to get graphics to update. + // sb "redraw graphics" since m_source geom has not changed. return true; } bool TaskGeomHatch::reject() { - std::string HatchName = m_hatch->getNameInDocument(); - Gui::Command::doCommand(Gui::Command::Gui,"App.activeDocument().removeObject('%s')",HatchName.c_str()); - Gui::Command::doCommand(Gui::Command::Gui,"Gui.ActiveDocument.resetEdit()"); - m_source->touch(); - m_source->getDocument()->recompute(); + if (getCreateMode()) { + std::string HatchName = m_hatch->getNameInDocument(); + Gui::Command::doCommand(Gui::Command::Gui,"App.activeDocument().removeObject('%s')",HatchName.c_str()); + Gui::Command::doCommand(Gui::Command::Gui,"Gui.ActiveDocument.resetEdit()"); + m_source->touch(); + m_source->getDocument()->recompute(); + } else { + m_hatch->FilePattern.setValue(m_origFile); + m_hatch->NamePattern.setValue(m_origName); + m_hatch->ScalePattern.setValue(m_origScale); + m_Vp->ColorPattern.setValue(m_origColor); + m_Vp->WeightPattern.setValue(m_origWeight); + } return false; } @@ -141,6 +159,14 @@ void TaskGeomHatch::getParameters() m_scale = m_hatch->ScalePattern.getValue(); m_color = m_Vp->ColorPattern.getValue(); m_weight = m_Vp->WeightPattern.getValue(); + if (!getCreateMode()) { + m_origFile = m_hatch->FilePattern.getValue(); + m_origName = m_hatch->NamePattern.getValue(); + m_origScale = m_hatch->ScalePattern.getValue(); + m_origColor = m_Vp->ColorPattern.getValue(); + m_origWeight = m_Vp->WeightPattern.getValue(); + } + } void TaskGeomHatch::changeEvent(QEvent *e) @@ -151,10 +177,11 @@ void TaskGeomHatch::changeEvent(QEvent *e) } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -TaskDlgGeomHatch::TaskDlgGeomHatch(TechDraw::DrawGeomHatch* inHatch, TechDrawGui::ViewProviderGeomHatch* inVp) : - TaskDialog() +TaskDlgGeomHatch::TaskDlgGeomHatch(TechDraw::DrawGeomHatch* inHatch, TechDrawGui::ViewProviderGeomHatch* inVp, bool mode) : + TaskDialog(), + viewProvider(nullptr) { - widget = new TaskGeomHatch(inHatch,inVp); + widget = new TaskGeomHatch(inHatch,inVp, mode); taskbox = new Gui::TaskView::TaskBox(Gui::BitmapFactory().pixmap("TechDraw_Tree_View"), widget->windowTitle(), true, 0); taskbox->groupLayout()->addWidget(widget); @@ -165,6 +192,11 @@ TaskDlgGeomHatch::~TaskDlgGeomHatch() { } +void TaskDlgGeomHatch::setCreateMode(bool b) +{ + widget->setCreateMode(b); +} + void TaskDlgGeomHatch::update() { //widget->updateTask(); diff --git a/src/Mod/TechDraw/Gui/TaskGeomHatch.h b/src/Mod/TechDraw/Gui/TaskGeomHatch.h index 5d5f9ebf16..6492278bac 100644 --- a/src/Mod/TechDraw/Gui/TaskGeomHatch.h +++ b/src/Mod/TechDraw/Gui/TaskGeomHatch.h @@ -49,12 +49,14 @@ class TaskGeomHatch : public QWidget Q_OBJECT public: - TaskGeomHatch(TechDraw::DrawGeomHatch* inHatch,TechDrawGui::ViewProviderGeomHatch* inVp); + TaskGeomHatch(TechDraw::DrawGeomHatch* inHatch,TechDrawGui::ViewProviderGeomHatch* inVp, bool mode); ~TaskGeomHatch(); public: virtual bool accept(); virtual bool reject(); + void setCreateMode(bool b) { m_createMode = b;} + bool getCreateMode() { return m_createMode; } protected Q_SLOTS: void onFileChanged(void); @@ -77,6 +79,13 @@ private: double m_scale; double m_weight; App::Color m_color; + std::string m_origFile; + std::string m_origName; + double m_origScale; + double m_origWeight; + App::Color m_origColor; + + bool m_createMode; }; @@ -85,8 +94,9 @@ class TaskDlgGeomHatch : public Gui::TaskView::TaskDialog Q_OBJECT public: - TaskDlgGeomHatch(TechDraw::DrawGeomHatch* inHatch,TechDrawGui::ViewProviderGeomHatch* inVp); + TaskDlgGeomHatch(TechDraw::DrawGeomHatch* inHatch,TechDrawGui::ViewProviderGeomHatch* inVp, bool mode); ~TaskDlgGeomHatch(); + const ViewProviderGeomHatch * getViewProvider() const { return viewProvider; } public: /// is called the TaskView when the dialog is opened @@ -101,10 +111,12 @@ public: virtual void helpRequested() { return;} virtual bool isAllowedAlterDocument(void) const { return false; } + void setCreateMode(bool b); void update(); protected: + const ViewProviderGeomHatch *viewProvider; private: TaskGeomHatch * widget; diff --git a/src/Mod/TechDraw/Gui/ViewProviderGeomHatch.cpp b/src/Mod/TechDraw/Gui/ViewProviderGeomHatch.cpp index ee377a36cc..68cac2b4b9 100644 --- a/src/Mod/TechDraw/Gui/ViewProviderGeomHatch.cpp +++ b/src/Mod/TechDraw/Gui/ViewProviderGeomHatch.cpp @@ -52,6 +52,7 @@ #include #include #include +#include "TaskGeomHatch.h" #include "ViewProviderDrawingView.h" #include "ViewProviderGeomHatch.h" @@ -98,23 +99,53 @@ std::vector ViewProviderGeomHatch::getDisplayModes(void) const return StrList; } -//for VP properties -void ViewProviderGeomHatch::onChanged(const App::Property* prop) +bool ViewProviderGeomHatch::setEdit(int ModNum) { - if (prop == &WeightPattern || - prop == &ColorPattern ) { - updateGraphic(); + Q_UNUSED(ModNum); + Gui::TaskView::TaskDialog *dlg = Gui::Control().activeDialog(); + TaskDlgGeomHatch *projDlg = qobject_cast(dlg); + if (projDlg && (projDlg->getViewProvider() != this)) + projDlg = 0; // somebody left task panel open + + // clear the selection (convenience) + Gui::Selection().clearSelection(); + + // start the edit dialog + if (projDlg) { + projDlg->setCreateMode(false); + Gui::Control().showDialog(projDlg); + } else { + Gui::Control().showDialog(new TaskDlgGeomHatch(getViewObject(),this,false)); } + return true; +} + +void ViewProviderGeomHatch::unsetEdit(int ModNum) +{ + if (ModNum == ViewProvider::Default) { + Gui::Control().closeDialog(); + } + else { + ViewProviderDocumentObject::unsetEdit(ModNum); + } +} + +bool ViewProviderGeomHatch::doubleClicked(void) +{ + setEdit(0); + return true; +} + +//for VP properties - but each letter/digit in property editor triggers this! +void ViewProviderGeomHatch::onChanged(const App::Property* prop) +{ Gui::ViewProviderDocumentObject::onChanged(prop); } -//for feature properties +//for feature properties - but each letter/digit in property editor triggers this! void ViewProviderGeomHatch::updateData(const App::Property* prop) { - if (prop == &(getViewObject()->ScalePattern)) { - updateGraphic(); - } Gui::ViewProviderDocumentObject::updateData(prop); } diff --git a/src/Mod/TechDraw/Gui/ViewProviderGeomHatch.h b/src/Mod/TechDraw/Gui/ViewProviderGeomHatch.h index 16d49888aa..03198f5f7f 100644 --- a/src/Mod/TechDraw/Gui/ViewProviderGeomHatch.h +++ b/src/Mod/TechDraw/Gui/ViewProviderGeomHatch.h @@ -56,6 +56,9 @@ public: virtual void attach(App::DocumentObject *); virtual void updateData(const App::Property*); virtual void onChanged(const App::Property *prop); + virtual bool setEdit(int ModNum); + virtual void unsetEdit(int ModNum); + virtual bool doubleClicked(void); virtual bool useNewSelectionModel(void) const {return false;} virtual void setDisplayMode(const char* ModeName);