Make the piecewise linear stuff for cubics and quadratics adaptive,

based on a chord tolerance. And rewrite the pwl circles to work
against a chord tolerance too (which they really were doing before,
but in funny units).

Also make "assemble" combine type do a union after interference
checking; was previously just copying, which meant that coplanar
faces could break subsequent operations.

And make right-clicking effectively toggle shift key, instead of
forcing it on; so you can pan or rotate with either right or middle
button.

[git-p4: depot-paths = "//depot/solvespace/": change = 1829]
This commit is contained in:
Jonathan Westhues 2008-07-09 21:26:08 -08:00
parent 6852b4134f
commit 7622534b2a
10 changed files with 111 additions and 53 deletions

View File

@ -22,7 +22,7 @@ void GraphicsWindow::MouseMoved(double x, double y, bool leftDown,
if(GraphicsEditControlIsVisible()) return; if(GraphicsEditControlIsVisible()) return;
if(rightDown) { if(rightDown) {
middleDown = true; middleDown = true;
shiftDown = true; shiftDown = !shiftDown;
} }
Point2d mp = { x, y }; Point2d mp = { x, y };

View File

@ -3,7 +3,7 @@
void Entity::LineDrawOrGetDistance(Vector a, Vector b) { void Entity::LineDrawOrGetDistance(Vector a, Vector b) {
if(dogd.drawing) { if(dogd.drawing) {
// Draw lines from active group in front of those from previous // Draw lines from active group in front of those from previous
glxDepthRangeOffset((group.v == SS.GW.activeGroup.v) ? 4 : 2); glxDepthRangeOffset((group.v == SS.GW.activeGroup.v) ? 4 : 3);
glBegin(GL_LINES); glBegin(GL_LINES);
glxVertex3v(a); glxVertex3v(a);
glxVertex3v(b); glxVertex3v(b);
@ -132,6 +132,41 @@ bool Entity::IsVisible(void) {
return true; return true;
} }
Vector Entity::BezierEval(double t, Vector p0, Vector p1, Vector p2, Vector p3)
{
return (p0.ScaledBy((1 - t)*(1 - t)*(1 - t))).Plus(
(p1.ScaledBy(3*t*(1 - t)*(1 - t))).Plus(
(p2.ScaledBy(3*t*t*(1 - t))).Plus(
(p3.ScaledBy(t*t*t)))));
}
void Entity::BezierPwl(double ta, double tb,
Vector p0, Vector p1, Vector p2, Vector p3)
{
Vector pa = BezierEval(ta, p0, p1, p2, p3);
Vector pb = BezierEval(tb, p0, p1, p2, p3);
double tm1 = (2*ta + tb) / 3;
double tm2 = (ta + 2*tb) / 3;
Vector pm1 = BezierEval(tm1, p0, p1, p2, p3);
Vector pm2 = BezierEval(tm2, p0, p1, p2, p3);
double d = max(pm1.DistanceToLine(pa, pb.Minus(pa)),
pm2.DistanceToLine(pa, pb.Minus(pa)));
double tol = 0.5*SS.chordTol/SS.GW.scale;
if((tb - ta) < 0.05 || d < tol) {
LineDrawOrGetDistanceOrEdge(pa, pb);
} else {
double tm = (ta + tb) / 2;
BezierPwl(ta, tm, p0, p1, p2, p3);
BezierPwl(tm, tb, p0, p1, p2, p3);
}
}
void Entity::DrawOrGetDistance(void) { void Entity::DrawOrGetDistance(void) {
// If an entity is invisible, then it doesn't get shown, and it doesn't // If an entity is invisible, then it doesn't get shown, and it doesn't
// contribute a distance for the selection, but it still generates edges. // contribute a distance for the selection, but it still generates edges.
@ -301,18 +336,7 @@ void Entity::DrawOrGetDistance(void) {
Vector p1 = SS.GetEntity(point[1])->PointGetNum(); Vector p1 = SS.GetEntity(point[1])->PointGetNum();
Vector p2 = SS.GetEntity(point[2])->PointGetNum(); Vector p2 = SS.GetEntity(point[2])->PointGetNum();
Vector p3 = SS.GetEntity(point[3])->PointGetNum(); Vector p3 = SS.GetEntity(point[3])->PointGetNum();
int i, n = (int)(15/sqrt(SS.meshTol)); BezierPwl(0, 1, p0, p1, p2, p3);
Vector prev = p0;
for(i = 1; i <= n; i++) {
double t = ((double)i)/n;
Vector p =
(p0.ScaledBy((1 - t)*(1 - t)*(1 - t))).Plus(
(p1.ScaledBy(3*t*(1 - t)*(1 - t))).Plus(
(p2.ScaledBy(3*t*t*(1 - t))).Plus(
(p3.ScaledBy(t*t*t)))));
LineDrawOrGetDistanceOrEdge(prev, p);
prev = p;
}
break; break;
} }

View File

@ -245,14 +245,16 @@ bool SMesh::MakeFromInterferenceCheck(SMesh *srca, SMesh *srcb, SMesh *error) {
// A that lie inside B, or vice versa. That's the interference, and // A that lie inside B, or vice versa. That's the interference, and
// we report it so that it can be flagged. // we report it so that it can be flagged.
// But as far as the actual model, we just copy everything over. // For the actual output, take the union.
int i; flipNormal = false;
for(i = 0; i < srca->l.n; i++) { keepCoplanar = false;
AddTriangle(&(srca->l.elem[i])); AddAgainstBsp(srcb, bspa);
}
for(i = 0; i < srcb->l.n; i++) { flipNormal = false;
AddTriangle(&(srcb->l.elem[i])); keepCoplanar = true;
} AddAgainstBsp(srca, bspb);
// And we're successful if the intersection was empty.
return (error->l.n == 0); return (error->l.n == 0);
} }

View File

@ -393,6 +393,10 @@ public:
void LineDrawOrGetDistanceOrEdge(Vector a, Vector b); void LineDrawOrGetDistanceOrEdge(Vector a, Vector b);
void DrawOrGetDistance(void); void DrawOrGetDistance(void);
void BezierPwl(double ta, double tb,
Vector p0, Vector p1, Vector p2, Vector p3);
Vector BezierEval(double t, Vector p0, Vector p1, Vector p2, Vector p3);
static void DrawAll(void); static void DrawAll(void);
void Draw(void); void Draw(void);
double GetDistance(Point2d mp); double GetDistance(Point2d mp);

View File

@ -23,8 +23,8 @@ void SolveSpace::Init(char *cmdLine) {
lightDir[1].x = CnfThawFloat( 1.0f, "LightDir_1_Right" ); lightDir[1].x = CnfThawFloat( 1.0f, "LightDir_1_Right" );
lightDir[1].y = CnfThawFloat( 0.0f, "LightDir_1_Up" ); lightDir[1].y = CnfThawFloat( 0.0f, "LightDir_1_Up" );
lightDir[1].z = CnfThawFloat( 0.0f, "LightDir_1_Forward" ); lightDir[1].z = CnfThawFloat( 0.0f, "LightDir_1_Forward" );
// Mesh tolerance // Chord tolerance
meshTol = CnfThawFloat(1.0f, "MeshTolerance"); chordTol = CnfThawFloat(2.0f, "ChordTolerance");
// View units // View units
viewUnits = (Unit)CnfThawDWORD((DWORD)UNIT_MM, "ViewUnits"); viewUnits = (Unit)CnfThawDWORD((DWORD)UNIT_MM, "ViewUnits");
// Camera tangent (determines perspective) // Camera tangent (determines perspective)
@ -79,8 +79,8 @@ void SolveSpace::Exit(void) {
CnfFreezeFloat((float)lightDir[1].x, "LightDir_1_Right"); CnfFreezeFloat((float)lightDir[1].x, "LightDir_1_Right");
CnfFreezeFloat((float)lightDir[1].y, "LightDir_1_Up"); CnfFreezeFloat((float)lightDir[1].y, "LightDir_1_Up");
CnfFreezeFloat((float)lightDir[1].z, "LightDir_1_Forward"); CnfFreezeFloat((float)lightDir[1].z, "LightDir_1_Forward");
// Mesh tolerance // Chord tolerance
CnfFreezeFloat((float)meshTol, "MeshTolerance"); CnfFreezeFloat((float)chordTol, "ChordTolerance");
// Display/entry units // Display/entry units
CnfFreezeDWORD((DWORD)viewUnits, "ViewUnits"); CnfFreezeDWORD((DWORD)viewUnits, "ViewUnits");
// Camera tangent (determines perspective) // Camera tangent (determines perspective)
@ -100,8 +100,22 @@ void SolveSpace::DoLater(void) {
} }
int SolveSpace::CircleSides(double r) { int SolveSpace::CircleSides(double r) {
int s = 7 + (int)(sqrt(r*SS.GW.scale/meshTol)); // Let the pwl segment be symmetric about the x axis; then the curve
return min(s, 40); // goes out to r, and if there's n segments, then the endpoints are
// at +/- (2pi/n)/2 = +/- pi/n. So the chord goes to x = r cos pi/n,
// from x = r, so it's
// tol = r - r cos pi/n
// tol = r(1 - cos pi/n)
// tol ~ r(1 - (1 - (pi/n)^2/2)) (Taylor expansion)
// tol = r((pi/n)^2/2)
// 2*tol/r = (pi/n)^2
// sqrt(2*tol/r) = pi/n
// n = pi/sqrt(2*tol/r);
double tol = chordTol/GW.scale;
int n = 3 + (int)(PI/sqrt(2*tol/r));
return max(7, min(n, 40));
} }
char *SolveSpace::MmToString(double v) { char *SolveSpace::MmToString(double v) {

View File

@ -290,6 +290,8 @@ public:
Vector TransformIntPoint(int x, int y); Vector TransformIntPoint(int x, int y);
void LineSegment(int x0, int y0, int x1, int y1); void LineSegment(int x0, int y0, int x1, int y1);
void Bezier(int x0, int y0, int x1, int y1, int x2, int y2); void Bezier(int x0, int y0, int x1, int y1, int x2, int y2);
void BezierPwl(double ta, double tb, Vector p0, Vector p1, Vector p2);
Vector BezierEval(double t, Vector p0, Vector p1, Vector p2);
}; };
class TtfFontList { class TtfFontList {
@ -354,7 +356,7 @@ public:
int modelColor[MODEL_COLORS]; int modelColor[MODEL_COLORS];
Vector lightDir[2]; Vector lightDir[2];
double lightIntensity[2]; double lightIntensity[2];
double meshTol; double chordTol;
double cameraTangent; double cameraTangent;
DWORD edgeColor; DWORD edgeColor;
float exportScale; float exportScale;

View File

@ -541,11 +541,11 @@ void TextWindow::ScreenChangeColor(int link, DWORD v) {
SS.TW.edit.meaning = EDIT_COLOR; SS.TW.edit.meaning = EDIT_COLOR;
SS.TW.edit.i = v; SS.TW.edit.i = v;
} }
void TextWindow::ScreenChangeMeshTolerance(int link, DWORD v) { void TextWindow::ScreenChangeChordTolerance(int link, DWORD v) {
char str[1024]; char str[1024];
sprintf(str, "%.2f", SS.meshTol); sprintf(str, "%.2f", SS.chordTol);
ShowTextEditControl(37, 3, str); ShowTextEditControl(37, 3, str);
SS.TW.edit.meaning = EDIT_MESH_TOLERANCE; SS.TW.edit.meaning = EDIT_CHORD_TOLERANCE;
} }
void TextWindow::ScreenChangeCameraTangent(int link, DWORD v) { void TextWindow::ScreenChangeCameraTangent(int link, DWORD v) {
char str[1024]; char str[1024];
@ -594,10 +594,10 @@ void TextWindow::ShowConfiguration(void) {
} }
Printf(false, ""); Printf(false, "");
Printf(false, "%Ft mesh tolerance (smaller is finer)%E"); Printf(false, "%Ft chord tolerance (in screen pixels)%E");
Printf(false, "%Ba %2 %Fl%Ll%f%D[change]%E; now %d triangles", Printf(false, "%Ba %2 %Fl%Ll%f%D[change]%E; now %d triangles",
SS.meshTol, SS.chordTol,
&ScreenChangeMeshTolerance, 0, &ScreenChangeChordTolerance, 0,
SS.GetGroup(SS.GW.activeGroup)->runningMesh.l.n); SS.GetGroup(SS.GW.activeGroup)->runningMesh.l.n);
Printf(false, ""); Printf(false, "");
@ -702,8 +702,8 @@ void TextWindow::EditControlDone(char *s) {
} }
break; break;
} }
case EDIT_MESH_TOLERANCE: { case EDIT_CHORD_TOLERANCE: {
SS.meshTol = min(10, max(0.1, atof(s))); SS.chordTol = min(10, max(0.1, atof(s)));
SS.GenerateAll(0, INT_MAX); SS.GenerateAll(0, INT_MAX);
break; break;
} }

39
ttf.cpp
View File

@ -690,23 +690,36 @@ void TtfFont::LineSegment(int x0, int y0, int x1, int y1) {
TransformIntPoint(x1, y1)); TransformIntPoint(x1, y1));
} }
void TtfFont::Bezier(int x0, int y0, int x1, int y1, int x2, int y2) { Vector TtfFont::BezierEval(double t, Vector p0, Vector p1, Vector p2) {
Entity *e = SS.GetEntity(entity); return (p0.ScaledBy((1 - t)*(1 - t))).Plus(
(p1.ScaledBy(2*t*(1 - t))).Plus(
(p2.ScaledBy(t*t))));
}
void TtfFont::BezierPwl(double ta, double tb, Vector p0, Vector p1, Vector p2) {
Vector pa = BezierEval(ta, p0, p1, p2);
Vector pb = BezierEval(tb, p0, p1, p2);
double tm = (ta + tb) / 2;
Vector pm = BezierEval(tm, p0, p1, p2);
double tol = 0.5*SS.chordTol/SS.GW.scale;
if((tb - ta) < 0.05 || pm.DistanceToLine(pa, pb.Minus(pa)) < tol) {
Entity *e = SS.GetEntity(entity);
e->LineDrawOrGetDistanceOrEdge(pa, pb);
} else {
BezierPwl(ta, tm, p0, p1, p2);
BezierPwl(tm, tb, p0, p1, p2);
}
}
void TtfFont::Bezier(int x0, int y0, int x1, int y1, int x2, int y2) {
Vector p0 = TransformIntPoint(x0, y0), Vector p0 = TransformIntPoint(x0, y0),
p1 = TransformIntPoint(x1, y1), p1 = TransformIntPoint(x1, y1),
p2 = TransformIntPoint(x2, y2); p2 = TransformIntPoint(x2, y2);
int i, n = max(2, (int)(4/sqrt(SS.meshTol))); BezierPwl(0, 1, p0, p1, p2);
Vector prev = p0;
for(i = 1; i <= n; i++) {
double t = ((double)i)/n;
Vector p =
(p0.ScaledBy((1 - t)*(1 - t))).Plus(
(p1.ScaledBy(2*t*(1 - t))).Plus(
(p2.ScaledBy(t*t))));
e->LineDrawOrGetDistanceOrEdge(prev, p);
prev = p;
}
} }

4
ui.h
View File

@ -62,7 +62,7 @@ public:
static const int EDIT_LIGHT_DIRECTION = 3; static const int EDIT_LIGHT_DIRECTION = 3;
static const int EDIT_LIGHT_INTENSITY = 4; static const int EDIT_LIGHT_INTENSITY = 4;
static const int EDIT_COLOR = 5; static const int EDIT_COLOR = 5;
static const int EDIT_MESH_TOLERANCE = 6; static const int EDIT_CHORD_TOLERANCE = 6;
static const int EDIT_CAMERA_TANGENT = 7; static const int EDIT_CAMERA_TANGENT = 7;
static const int EDIT_EDGE_COLOR = 8; static const int EDIT_EDGE_COLOR = 8;
static const int EDIT_EXPORT_SCALE = 9; static const int EDIT_EXPORT_SCALE = 9;
@ -129,7 +129,7 @@ public:
static void ScreenChangeLightDirection(int link, DWORD v); static void ScreenChangeLightDirection(int link, DWORD v);
static void ScreenChangeLightIntensity(int link, DWORD v); static void ScreenChangeLightIntensity(int link, DWORD v);
static void ScreenChangeColor(int link, DWORD v); static void ScreenChangeColor(int link, DWORD v);
static void ScreenChangeMeshTolerance(int link, DWORD v); static void ScreenChangeChordTolerance(int link, DWORD v);
static void ScreenChangeCameraTangent(int link, DWORD v); static void ScreenChangeCameraTangent(int link, DWORD v);
static void ScreenChangeEdgeColor(int link, DWORD v); static void ScreenChangeEdgeColor(int link, DWORD v);
static void ScreenChangeExportScale(int link, DWORD v); static void ScreenChangeExportScale(int link, DWORD v);

View File

@ -1,5 +1,4 @@
adaptive pwl for polynomial curves
some kind of rounding / chamfer some kind of rounding / chamfer
remove back button in browser? remove back button in browser?
auto-generate circles and faces when lathing auto-generate circles and faces when lathing