DrawGeomHatch improvements

-draw & align dash patterns correctly on all QPainters using QGPathItem
-Allow patterns to start with space
-ensure horiz & vert lines pass through pattern origin
-Scalable complex patterns
This commit is contained in:
WandererFan
2017-03-27 21:10:33 -04:00
committed by wmayer
parent 5cef451f95
commit 235f0a93c6
5 changed files with 443 additions and 96 deletions

View File

@@ -289,7 +289,7 @@ std::vector<TopoDS_Edge> DrawGeomHatch::makeEdgeOverlay(PATLineSpec hl, Bnd_Box
Base::Vector3d start;
Base::Vector3d end;
Base::Vector3d origin = hl.getOrigin();
double interval = hl.getInterval() * scale;
double interval = hl.getIntervalX() * scale;
double angle = hl.getAngle();
//only dealing with angles -180:180 for now
@@ -301,29 +301,33 @@ std::vector<TopoDS_Edge> DrawGeomHatch::makeEdgeOverlay(PATLineSpec hl, Bnd_Box
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;
interval = hl.getInterval() * scale;
double atomY = origin.y;
int repeatUp = (int) fabs((maxY - atomY)/interval);
int repeatDown = (int) fabs(((atomY - minY)/interval));
int repeatTotal = repeatUp + repeatDown + 1;
double yStart = atomY - repeatDown * interval;
// 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);
Base::Vector3d newStart(minX,yStart + float(i)*interval,0);
Base::Vector3d newEnd(maxX,yStart + 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;
interval = hl.getInterval() * scale;
double atomX = origin.x;
int repeatRight = (int) fabs((maxX - atomX)/interval);
int repeatLeft = (int) fabs((atomX - minX)/interval);
int repeatTotal = repeatRight + repeatLeft + 1;
double xStart = atomX - repeatLeft * interval;
// 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);
Base::Vector3d newStart(xStart + float(i)*interval,minY,0);
Base::Vector3d newEnd(xStart + float(i)*interval,maxY,0);
TopoDS_Edge newLine = makeLine(newStart,newEnd);
result.push_back(newLine);
}
@@ -334,12 +338,12 @@ std::vector<TopoDS_Edge> DrawGeomHatch::makeEdgeOverlay(PATLineSpec hl, Bnd_Box
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);
int repeatRight = (int) fabs((maxX - xLeftAtom)/interval);
int repeatLeft = (int) fabs((xRightAtom - minX)/interval);
double leftStartX = xLeftAtom - (repeatLeft * interval);
double leftEndX = xRightAtom - (repeatLeft * interval);
int repeatTotal = repeatRight + repeatLeft;
int repeatTotal = repeatRight + repeatLeft + 1;
//make repeats
for (int i = 0; i < repeatTotal; i++) {
@@ -353,11 +357,11 @@ std::vector<TopoDS_Edge> DrawGeomHatch::makeEdgeOverlay(PATLineSpec hl, Bnd_Box
// 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
int repeatRight = (int) fabs((maxX - xLeftAtom)/interval); //number of lines to Right of Atom
int repeatLeft = (int) fabs((xRightAtom - minX)/interval); //number of lines to Left of Atom
double leftEndX = xLeftAtom - (repeatLeft * interval);
double leftStartX = xRightAtom - (repeatLeft * interval);
int repeatTotal = repeatRight + repeatLeft;
int repeatTotal = repeatRight + repeatLeft + 1;
// make repeats
for (int i = 0; i < repeatTotal; i++) {

View File

@@ -28,6 +28,7 @@
#include <QFile>
#include <QFileInfo>
#include <stdexcept>
#include <cmath>
#endif
#include <TopoDS_Vertex.hxx>
@@ -78,8 +79,7 @@ bool LineSet::isDashed(void)
return result;
}
//TODO: needs to incorporate deltaX parameter
//! calculates the apparent start point for dashed lines
//! calculates the apparent start point (ie start of overlay line) for dashed lines
Base::Vector3d LineSet::calcApparentStart(TechDrawGeometry::BaseGeom* g)
{
Base::Vector3d result;
@@ -99,6 +99,128 @@ Base::Vector3d LineSet::calcApparentStart(TechDrawGeometry::BaseGeom* g)
return result;
}
Base::Vector3d LineSet::getUnitDir(void)
{
Base::Vector3d result;
Base::Vector3d start(m_geoms.at(0)->getStartPoint().x,
m_geoms.at(0)->getStartPoint().y,
0.0);
Base::Vector3d end(m_geoms.at(0)->getEndPoint().x,
m_geoms.at(0)->getEndPoint().y,
0.0);
result = end - start;
result.Normalize();
return result;
}
Base::Vector3d LineSet::getUnitOrtho()
{
Base::Vector3d result;
Base::Vector3d unit = getUnitDir();
Base::Vector3d X(1.0,0.0,0.0);
Base::Vector3d Y(0.0,1.0,0.0);
if (unit.IsEqual(X,0.000001)) {
result = Y;
} else if (unit.IsEqual(Y,0.000001)) {
result = X;
} else {
double unitX = unit.x;
double unitY = unit.y;
result = Base::Vector3d(unitY,-unitX, 0.0); //perpendicular
}
result.Normalize(); //probably redundant
return result;
}
Base::Vector3d LineSet::findAtomStart(void)
{
Base::Vector3d result;
Base::Vector3d origin = getOrigin();
double angle = getAngle();
if (angle == 0.0) {
result = Base::Vector3d(getMinX(),origin.y,0.0);
} else if ( (angle == 90.0) ||
(angle == -90.0) ) {
result = Base::Vector3d(origin.x,getMinY(),0.0);
} else {
double minY = getMinY();
double x = origin.x - (origin.y - minY)/getSlope();
result = Base::Vector3d(x,minY,0.0);
}
return result;
}
Base::Vector3d LineSet::getPatternStartPoint(TechDrawGeometry::BaseGeom* g, double &offset, double scale)
{
Base::Vector3d result = getOrigin();
Base::Vector3d atomStart = findAtomStart();
Base::Vector3d thisStart = calcApparentStart(g);
double angle = getAngle();
double patternLength = scale * getPatternLength();
Base::Vector3d lineOrigin;
double distX,distY;
int overlayIndex = 0;
//interval & offset are not patternscaled
//figure out which line this is in the overlay
if (angle == 0.0) { //odd case - horizontal line
distY = (thisStart.y - atomStart.y); //this is patternscaled
overlayIndex = (int) round(distY/(scale * getIntervalY())); //this is +/-
lineOrigin = getOrigin() + distY * Base::Vector3d(0.0,1.0,0.0); //move u/d
} else {
distX = (thisStart.x - atomStart.x); //this is patternscaled
overlayIndex = (int) round(distX/(scale * getIntervalX()));
lineOrigin = getOrigin() + overlayIndex * (scale * getInterval()) * getUnitOrtho();
}
lineOrigin = lineOrigin + (overlayIndex * (scale * getOffset())) * getUnitDir(); //move along line
//is lineOrigin on line of g? should be within fp error
Base::Vector3d gStart(g->getStartPoint().x,
g->getStartPoint().y,
0.0);
Base::Vector3d gEnd(g->getEndPoint().x,
g->getEndPoint().y,
0.0);
double lenStartOrg = (gStart - lineOrigin).Length();
double lenEndOrg = (gEnd - lineOrigin).Length();
double lenStartEnd = (gStart - gEnd).Length();
if ( (lenStartOrg <= lenStartEnd) &&
(lenEndOrg <= lenStartEnd) ) { //origin is in g
result = lineOrigin;
offset = 0.0;
} else {
//find a point where pattern repeats within g
double patsStartOrg = lenStartOrg/patternLength; //# pattern repeats from lineOrigin to start
double patsEndOrg = lenEndOrg/patternLength;
if (lenStartOrg < lenEndOrg) { //origin is before start
double c = ceil(patsStartOrg);
if (c <= patsEndOrg) { //c is an integer pattern count in [patsStartOrg,patsEndOrg]
result = lineOrigin + c*patternLength*getUnitDir();
offset = 0.0;
} else {
// //ugly case - partial pattern
result = gStart;
offset = patsStartOrg - (int)patsStartOrg; //fraction of a patternLength
offset = offset * patternLength;
}
} else if (lenStartOrg > lenEndOrg) { //origin is after end
double c = ceil(patsEndOrg);
if (c <= patsStartOrg) { //c is an integer pattern count in [patsStartOrg,patsEndOrg]
result = lineOrigin - c*patternLength*getUnitDir();
offset = 0.0;
} else {
result = gStart;
offset = ceil(patsStartOrg) - patsStartOrg; //fraction of a patternLength patstartorg to repeat point
offset = offset * patternLength;
}
} else {
Base::Console().Log("ERROR - HL::getPatternStart - something has gone wrong!\n");
}
}
return result;
}
//*******************************************
PATLineSpec::PATLineSpec()
@@ -307,7 +429,52 @@ bool PATLineSpec::isDashed(void)
return result;
}
//! X component of distance between lines
double PATLineSpec::getIntervalX(void)
{
if (getAngle() == 0.0) {
return 0.0;
} else if ((getAngle() == 90.0) || (getAngle() == -90.0)) {
return getInterval();
} else {
double perpAngle = fabs(getAngle() - 90.0);
return fabs(getInterval() / cos(perpAngle * M_PI/180.0));
}
}
//! Y component of distance between lines
double PATLineSpec::getIntervalY(void)
{
if (getAngle() == 0.0) {
return getInterval();
} else if ((getAngle() == 90.0) || (getAngle() == -90.0)) {
return 0.0;
} else {
double perpAngle = fabs(getAngle() - 90.0);
return fabs(getInterval() * tan(perpAngle * M_PI/180.0));
}
}
//********************************************************
double DashSpec::length(void)
{
double result = 0.0;
for (auto& c: get()) {
result += fabs(c);
}
return result;
}
DashSpec DashSpec::reversed(void)
{
std::vector<double> p = get();
std::reverse(p.begin(),p.end());
DashSpec result(p);
return result;
}
void DashSpec::dump(char* title)
{
std::stringstream ss;

View File

@@ -62,6 +62,7 @@ public:
int size(void) {return m_parms.size();}
double length(void);
void dump(char* title);
DashSpec reversed(void);
private:
std::vector<double> m_parms;
@@ -80,8 +81,12 @@ public:
double getAngle(void) {return m_angle;}
Base::Vector3d getOrigin(void) {return m_origin;}
double getInterval(void) {return m_interval;}
double getIntervalX(void);
double getIntervalY(void);
double getOffset(void) {return m_offset;}
std::vector<double> getDashParms(void) {return m_dashParms;}
double getSlope(void);
double getLength(void) {return m_dashParms.length(); }
DashSpec getDashParms(void) {return m_dashParms;}
static std::vector<PATLineSpec> getSpecsForPattern(std::string& parmFile, std::string& parmName);
static bool findPatternStart(std::ifstream& inFile, std::string& parmName);
@@ -115,14 +120,26 @@ public:
void setGeoms(std::vector<TechDrawGeometry::BaseGeom*> g) {m_geoms = g;}
void setBBox(Bnd_Box bb) {m_box = bb;}
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<TopoDS_Edge> getEdges(void) { return m_edges; }
TopoDS_Edge getEdge(int i) {return m_edges.at(i);}
std::vector<TopoDS_Edge> getEdges(void) { return m_edges; }
TopoDS_Edge getEdge(int i) {return m_edges.at(i);}
std::vector<TechDrawGeometry::BaseGeom*> getGeoms(void) { return m_geoms; }
Base::Vector3d calcApparentStart(TechDrawGeometry::BaseGeom* g);
PATLineSpec getPATLineSpec(void) { return m_hatchLine; }
double getOffset(void) { return m_hatchLine.getOffset(); } //delta X offset
double getAngle(void) { return m_hatchLine.getAngle(); }
Base::Vector3d getOrigin(void) { return m_hatchLine.getOrigin(); }
double getInterval(void) {return m_hatchLine.getInterval(); } //space between lines
double getIntervalX(void) { return m_hatchLine.getIntervalX(); } //interval X-component
double getIntervalY(void) { return m_hatchLine.getIntervalY(); } //interval Y-component
double getSlope(void) { return m_hatchLine.getSlope(); }
double getPatternLength(void) { return m_hatchLine.getLength(); }
Base::Vector3d getUnitDir(void);
Base::Vector3d getUnitOrtho(void);
DashSpec getDashSpec(void) { return m_hatchLine.getDashParms();}
Base::Vector3d calcApparentStart(TechDrawGeometry::BaseGeom* g);
Base::Vector3d findAtomStart(void);
Base::Vector3d getLineOrigin(void); //point corresponding to pattern origin for this line (O + n*intervalX)
Base::Vector3d getPatternStartPoint(TechDrawGeometry::BaseGeom* g, double &offset, double scale = 1.0);
Bnd_Box getBBox(void) {return m_box;}
double getMinX(void);