From Mike Connell, "Here are some small fixes that allow you to specify the allowable deviation when creating polylines from arcs and circles in DXF files. Changes are against 2.8.0
It adds two options: Accuracy(x) - ensures the polyline will be within x units from the ideal arc/curve ImproveAccuracyOnly - do not use the given accuracy 'x', if it would result in a worse curve than with the previous (2.8.0) implementation for a particular arc/curve. As an added bonus there was a small bug in the existing implementation whereby the primitives were line strips but the vertices generated were actually suitable for GL_LINES, so the improved accuracy doesn't even have to come at a performance cost :-)"
This commit is contained in:
@@ -16,6 +16,8 @@
|
||||
#include "dxfBlock.h"
|
||||
#include "codeValue.h"
|
||||
|
||||
#include <osg/io_utils> // just for debugging
|
||||
|
||||
using namespace std;
|
||||
using namespace osg;
|
||||
|
||||
@@ -173,27 +175,41 @@ dxfCircle::drawScene(scene* sc)
|
||||
getOCSMatrix(_ocs, m);
|
||||
sc->ocs(m);
|
||||
std::vector<Vec3d> vlist;
|
||||
int numsteps = 360/5; // baaarghf.
|
||||
double angle_step = osg::DegreesToRadians((double)360.0 / (double) numsteps);
|
||||
double angle1 = 0.0f;
|
||||
double angle2 = 0.0f;
|
||||
|
||||
double theta=5.0; // we generate polyline from "spokes" at theta degrees at arc's center
|
||||
|
||||
if (_useAccuracy) {
|
||||
// we generate points on a polyline where each point lies on the arc, thus the maximum error occurs at the midpoint of each line segment where it lies furthest inside the arc
|
||||
// If we divide the segment in half and connect the bisection point to the arc's center, we have two rightangled triangles with
|
||||
// one side=r-maxError, hypotenuse=r, and internal angle at center is half the angle we will step with:
|
||||
double maxError=min(_maxError,_radius); // Avoid offending acos() in the edge case where allowable deviation is greater than radius.
|
||||
double newtheta=acos( (_radius-maxError) / _radius);
|
||||
newtheta=osg::RadiansToDegrees(newtheta)*2.0;
|
||||
|
||||
// Option to only use the new accuracy code when it would improve on the accuracy of the old method
|
||||
if (_improveAccuracyOnly) {
|
||||
theta=min(newtheta,theta);
|
||||
} else {
|
||||
theta=newtheta;
|
||||
}
|
||||
}
|
||||
theta=osg::DegreesToRadians(theta);
|
||||
|
||||
// We create an anglestep<=theta so that the line's points are evenly distributed around the circle
|
||||
unsigned int numsteps=floor(osg::PI*2/theta);
|
||||
if (numsteps<3) numsteps=3; // Sanity check: minimal representation of a circle is a tri
|
||||
double anglestep=osg::PI*2/numsteps;
|
||||
|
||||
double angle1 = 0.0;
|
||||
Vec3d a = _center;
|
||||
Vec3d b,c;
|
||||
for (int r = 0; r < numsteps; r++)
|
||||
{
|
||||
angle1 = angle2;
|
||||
if (r == numsteps - 1)
|
||||
angle2 = 0.0f;
|
||||
else
|
||||
angle2 += angle_step;
|
||||
Vec3d b;
|
||||
for(unsigned int r=0;r<=numsteps;r++) {
|
||||
b = a + Vec3d(_radius * (double) sin(angle1), _radius * (double) cos(angle1), 0);
|
||||
c = a + Vec3d(_radius * (double) sin(angle2), _radius * (double) cos(angle2), 0);
|
||||
// vlist.push_back(a);
|
||||
angle1 += anglestep;
|
||||
vlist.push_back(b);
|
||||
vlist.push_back(c);
|
||||
}
|
||||
sc->addLineStrip(getLayer(), _color, vlist);
|
||||
// sc->addTriangles(getLayer(), _color, vlist);
|
||||
|
||||
sc->addLineStrip(getLayer(), _color, vlist); // Should really add LineLoop implementation and save a vertex
|
||||
sc->ocs_clear();
|
||||
}
|
||||
|
||||
@@ -253,25 +269,46 @@ dxfArc::drawScene(scene* sc)
|
||||
start = _startAngle;
|
||||
end = _endAngle;
|
||||
}
|
||||
|
||||
double theta=5.0; // we generate polyline from "spokes" at theta degrees at arc's center
|
||||
|
||||
if (_useAccuracy) {
|
||||
// we generate points on a polyline where each point lies on the arc, thus the maximum error occurs at the midpoint of each line segment where it lies furthest inside the arc
|
||||
// If we divide the segment in half and connect the bisection point to the arc's center, we have two rightangled triangles with
|
||||
// one side=r-maxError, hypotenuse=r, and internal angle at center is half the angle we will step with:
|
||||
double maxError=min(_maxError,_radius); // Avoid offending acos() in the edge case where allowable deviation is greater than radius.
|
||||
double newtheta=acos( (_radius-maxError) / _radius);
|
||||
newtheta=osg::RadiansToDegrees(newtheta)*2.0;
|
||||
//cout<<"r="<<_radius<<" _me="<<_maxError<<" (_radius-_maxError)="<<(_radius-_maxError)<<" newtheta="<<newtheta<<endl;
|
||||
// Option to only use the new accuracy code when it would improve on the accuracy of the old method
|
||||
if (_improveAccuracyOnly) {
|
||||
theta=min(newtheta,theta);
|
||||
} else {
|
||||
theta=newtheta;
|
||||
}
|
||||
}
|
||||
|
||||
double angle_step = DegreesToRadians(end - start);
|
||||
int numsteps = (int)((end - start)/5.0); // hurmghf. say 5 degrees?
|
||||
if (numsteps * 5 < (end - start)) numsteps++;
|
||||
int numsteps = (int)((end - start)/theta);
|
||||
//cout<<"arc theta="<<osg::RadiansToDegrees(theta)<<" end="<<end<<" start="<<start<<" numsteps="<<numsteps<<" e-s/theta="<<((end-start)/theta)<<" end-start="<<(end-start)<<endl;
|
||||
if (numsteps * theta < (end - start)) numsteps++;
|
||||
numsteps=max(numsteps,2); // Whatever else, minimum representation of an arc is a straightline
|
||||
angle_step /= (double) numsteps;
|
||||
end = DegreesToRadians((-_startAngle)+90.0);
|
||||
start = DegreesToRadians((-_endAngle)+90.0);
|
||||
double angle1 = 0.0f;
|
||||
double angle2 = (start);
|
||||
double angle1 = start;
|
||||
|
||||
Vec3d a = _center;
|
||||
Vec3d b,c;
|
||||
for (int r = 0; r < numsteps; r++)
|
||||
Vec3d b;
|
||||
|
||||
for (int r = 0; r <= numsteps; r++)
|
||||
{
|
||||
angle1 = angle2;
|
||||
angle2 = angle1 + angle_step;
|
||||
b = a + Vec3d(_radius * (double) sin(angle1), _radius * (double) cos(angle1), 0);
|
||||
c = a + Vec3d(_radius * (double) sin(angle2), _radius * (double) cos(angle2), 0);
|
||||
angle1 += angle_step;
|
||||
vlist.push_back(b);
|
||||
vlist.push_back(c);
|
||||
}
|
||||
|
||||
|
||||
sc->addLineStrip(getLayer(), _color, vlist);
|
||||
sc->ocs_clear();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user