Add a command to show center of mass, assuming uniform density.
parent
068191bf28
commit
db75e06ecc
12
CHANGELOG.md
12
CHANGELOG.md
|
@ -39,15 +39,19 @@ New rendering features:
|
||||||
or not drawing them at all.
|
or not drawing them at all.
|
||||||
* The "Show/hide outlines" button is now independent from "Show/hide edges".
|
* The "Show/hide outlines" button is now independent from "Show/hide edges".
|
||||||
|
|
||||||
Other new features:
|
New measurement/analysis features:
|
||||||
* New command-line interface, for batch exporting and more.
|
|
||||||
* New command for measuring total length of selected entities,
|
* New command for measuring total length of selected entities,
|
||||||
"Analyze → Measure Perimeter".
|
"Analyze → Measure Perimeter".
|
||||||
|
* New command for measuring center of mass, with live updates as the sketch
|
||||||
|
changes, "Analyze → Center of Mass".
|
||||||
|
* When selecting a point and a line, projected distance to to current
|
||||||
|
workplane is displayed.
|
||||||
|
|
||||||
|
Other new features:
|
||||||
|
* New command-line interface, for batch exporting and more.
|
||||||
* New link to match the on-screen size of the sketch with its actual size,
|
* New link to match the on-screen size of the sketch with its actual size,
|
||||||
"view → set to full scale".
|
"view → set to full scale".
|
||||||
* When zooming to fit, constraints are also considered.
|
* When zooming to fit, constraints are also considered.
|
||||||
* When selecting a point and a line, projected distance to to current
|
|
||||||
workplane is displayed.
|
|
||||||
* When clicking on an entity that shares a place with other entities,
|
* When clicking on an entity that shares a place with other entities,
|
||||||
the entity from the current group is selected.
|
the entity from the current group is selected.
|
||||||
* When dragging an entity that shares a place with other entities,
|
* When dragging an entity that shares a place with other entities,
|
||||||
|
|
27
src/draw.cpp
27
src/draw.cpp
|
@ -770,6 +770,33 @@ void GraphicsWindow::Draw(Canvas *canvas) {
|
||||||
canvas->DrawLine(SS.extraLine.ptA, SS.extraLine.ptB, hcsDatum);
|
canvas->DrawLine(SS.extraLine.ptA, SS.extraLine.ptB, hcsDatum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(SS.centerOfMass.draw && !SS.centerOfMass.dirty) {
|
||||||
|
Vector p = SS.centerOfMass.position;
|
||||||
|
Vector u = camera.projRight;
|
||||||
|
Vector v = camera.projUp;
|
||||||
|
|
||||||
|
const double size = 10.0;
|
||||||
|
const int subdiv = 16;
|
||||||
|
double h = Style::DefaultTextHeight() / camera.scale;
|
||||||
|
canvas->DrawVectorText(ssprintf("%.3f, %.3f, %.3f", p.x, p.y, p.z), h,
|
||||||
|
p.Plus(u.ScaledBy((size + 5.0)/scale)).Minus(v.ScaledBy(h / 2.0)),
|
||||||
|
u, v,hcsDatum);
|
||||||
|
u = u.WithMagnitude(size / scale);
|
||||||
|
v = v.WithMagnitude(size / scale);
|
||||||
|
|
||||||
|
canvas->DrawLine(p.Minus(u), p.Plus(u), hcsDatum);
|
||||||
|
canvas->DrawLine(p.Minus(v), p.Plus(v), hcsDatum);
|
||||||
|
Vector prev;
|
||||||
|
for(int i = 0; i <= subdiv; i++) {
|
||||||
|
double a = (double)i / subdiv * 2.0 * PI;
|
||||||
|
Vector point = p.Plus(u.ScaledBy(cos(a))).Plus(v.ScaledBy(sin(a)));
|
||||||
|
if(i > 0) {
|
||||||
|
canvas->DrawLine(point, prev, hcsDatum);
|
||||||
|
}
|
||||||
|
prev = point;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// A note to indicate the origin in the just-exported file.
|
// A note to indicate the origin in the just-exported file.
|
||||||
if(SS.justExportedInfo.draw) {
|
if(SS.justExportedInfo.draw) {
|
||||||
Vector p, u, v;
|
Vector p, u, v;
|
||||||
|
|
|
@ -359,6 +359,7 @@ void SolveSpaceUI::GenerateAll(Generate type, bool andFindFree, bool genForBBox)
|
||||||
FreeAllTemporary();
|
FreeAllTemporary();
|
||||||
allConsistent = true;
|
allConsistent = true;
|
||||||
SS.GW.persistentDirty = true;
|
SS.GW.persistentDirty = true;
|
||||||
|
SS.centerOfMass.dirty = true;
|
||||||
|
|
||||||
endMillis = GetMilliseconds();
|
endMillis = GetMilliseconds();
|
||||||
|
|
||||||
|
@ -418,6 +419,12 @@ void SolveSpaceUI::ForceReferences() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SolveSpaceUI::UpdateCenterOfMass() {
|
||||||
|
SMesh *m = &(SK.GetGroup(SS.GW.activeGroup)->displayMesh);
|
||||||
|
SS.centerOfMass.position = m->GetCenterOfMass();
|
||||||
|
SS.centerOfMass.dirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
void SolveSpaceUI::MarkDraggedParams() {
|
void SolveSpaceUI::MarkDraggedParams() {
|
||||||
sys.dragged.Clear();
|
sys.dragged.Clear();
|
||||||
|
|
||||||
|
|
|
@ -152,6 +152,7 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
|
||||||
{ 1, N_("Measure &Perimeter"), Command::PERIMETER, C|S|'P', TN, mAna },
|
{ 1, N_("Measure &Perimeter"), Command::PERIMETER, C|S|'P', TN, mAna },
|
||||||
{ 1, N_("Show &Interfering Parts"), Command::INTERFERENCE, C|S|'I', TN, mAna },
|
{ 1, N_("Show &Interfering Parts"), Command::INTERFERENCE, C|S|'I', TN, mAna },
|
||||||
{ 1, N_("Show &Naked Edges"), Command::NAKED_EDGES, C|S|'N', TN, mAna },
|
{ 1, N_("Show &Naked Edges"), Command::NAKED_EDGES, C|S|'N', TN, mAna },
|
||||||
|
{ 1, N_("Show &Center of Mass"), Command::CENTER_OF_MASS, C|S|'C', TN, mAna },
|
||||||
{ 1, NULL, Command::NONE, 0, TN, NULL },
|
{ 1, NULL, Command::NONE, 0, TN, NULL },
|
||||||
{ 1, N_("Show Degrees of &Freedom"), Command::SHOW_DOF, C|S|'F', TN, mAna },
|
{ 1, N_("Show Degrees of &Freedom"), Command::SHOW_DOF, C|S|'F', TN, mAna },
|
||||||
{ 1, NULL, Command::NONE, 0, TN, NULL },
|
{ 1, NULL, Command::NONE, 0, TN, NULL },
|
||||||
|
@ -793,6 +794,7 @@ void GraphicsWindow::MenuEdit(Command id) {
|
||||||
SS.TW.HideEditControl();
|
SS.TW.HideEditControl();
|
||||||
SS.nakedEdges.Clear();
|
SS.nakedEdges.Clear();
|
||||||
SS.justExportedInfo.draw = false;
|
SS.justExportedInfo.draw = false;
|
||||||
|
SS.centerOfMass.draw = false;
|
||||||
// This clears the marks drawn to indicate which points are
|
// This clears the marks drawn to indicate which points are
|
||||||
// still free to drag.
|
// still free to drag.
|
||||||
Param *p;
|
Param *p;
|
||||||
|
|
|
@ -421,6 +421,10 @@ void Group::GenerateDisplayItems() {
|
||||||
// work correctly.
|
// work correctly.
|
||||||
displayMesh.PrecomputeTransparency();
|
displayMesh.PrecomputeTransparency();
|
||||||
|
|
||||||
|
// Recalculate mass center if needed
|
||||||
|
if(SS.centerOfMass.draw && SS.centerOfMass.dirty && h.v == SS.GW.activeGroup.v) {
|
||||||
|
SS.UpdateCenterOfMass();
|
||||||
|
}
|
||||||
displayDirty = false;
|
displayDirty = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
12
src/mesh.cpp
12
src/mesh.cpp
|
@ -345,6 +345,18 @@ uint32_t SMesh::FirstIntersectionWith(Point2d mp) const {
|
||||||
return face;
|
return face;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector SMesh::GetCenterOfMass() const {
|
||||||
|
Vector center = {};
|
||||||
|
double vol = 0.0;
|
||||||
|
for(int i = 0; i < l.n; i++) {
|
||||||
|
STriangle &tr = l.elem[i];
|
||||||
|
double tvol = tr.SignedVolume();
|
||||||
|
center = center.Plus(tr.a.Plus(tr.b.Plus(tr.c)).ScaledBy(tvol / 4.0));
|
||||||
|
vol += tvol;
|
||||||
|
}
|
||||||
|
return center.ScaledBy(1.0 / vol);
|
||||||
|
}
|
||||||
|
|
||||||
STriangleLl *STriangleLl::Alloc()
|
STriangleLl *STriangleLl::Alloc()
|
||||||
{ return (STriangleLl *)AllocTemporary(sizeof(STriangleLl)); }
|
{ return (STriangleLl *)AllocTemporary(sizeof(STriangleLl)); }
|
||||||
SKdNode *SKdNode::Alloc()
|
SKdNode *SKdNode::Alloc()
|
||||||
|
|
|
@ -83,6 +83,10 @@ bool STriangle::Raytrace(const Vector &rayPoint, const Vector &rayDir,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double STriangle::SignedVolume() const {
|
||||||
|
return a.Dot(b.Cross(c)) / 6.0;
|
||||||
|
}
|
||||||
|
|
||||||
void STriangle::FlipNormal() {
|
void STriangle::FlipNormal() {
|
||||||
swap(a, b);
|
swap(a, b);
|
||||||
swap(an, bn);
|
swap(an, bn);
|
||||||
|
|
|
@ -190,6 +190,7 @@ public:
|
||||||
STriangle Transform(Vector o, Vector u, Vector v) const;
|
STriangle Transform(Vector o, Vector u, Vector v) const;
|
||||||
bool Raytrace(const Vector &rayPoint, const Vector &rayDir,
|
bool Raytrace(const Vector &rayPoint, const Vector &rayDir,
|
||||||
double *t, Vector *inters) const;
|
double *t, Vector *inters) const;
|
||||||
|
double SignedVolume() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SBsp2 {
|
class SBsp2 {
|
||||||
|
@ -282,6 +283,8 @@ public:
|
||||||
void RemapFaces(Group *g, int remap);
|
void RemapFaces(Group *g, int remap);
|
||||||
|
|
||||||
uint32_t FirstIntersectionWith(Point2d mp) const;
|
uint32_t FirstIntersectionWith(Point2d mp) const;
|
||||||
|
|
||||||
|
Vector GetCenterOfMass() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// A linked list of triangles
|
// A linked list of triangles
|
||||||
|
|
|
@ -311,6 +311,7 @@ void SolveSpaceUI::AfterNewFile() {
|
||||||
|
|
||||||
// Quit export mode
|
// Quit export mode
|
||||||
justExportedInfo.draw = false;
|
justExportedInfo.draw = false;
|
||||||
|
centerOfMass.draw = false;
|
||||||
exportMode = false;
|
exportMode = false;
|
||||||
|
|
||||||
// GenerateAll() expects the view to be valid, because it uses that to
|
// GenerateAll() expects the view to be valid, because it uses that to
|
||||||
|
@ -616,6 +617,13 @@ void SolveSpaceUI::MenuAnalyze(Command id) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case Command::CENTER_OF_MASS: {
|
||||||
|
SS.UpdateCenterOfMass();
|
||||||
|
SS.centerOfMass.draw = true;
|
||||||
|
InvalidateGraphics();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case Command::VOLUME: {
|
case Command::VOLUME: {
|
||||||
SMesh *m = &(SK.GetGroup(SS.GW.activeGroup)->displayMesh);
|
SMesh *m = &(SK.GetGroup(SS.GW.activeGroup)->displayMesh);
|
||||||
|
|
||||||
|
|
|
@ -810,6 +810,11 @@ public:
|
||||||
bool draw, showOrigin;
|
bool draw, showOrigin;
|
||||||
Vector pt, u, v;
|
Vector pt, u, v;
|
||||||
} justExportedInfo;
|
} justExportedInfo;
|
||||||
|
struct {
|
||||||
|
bool draw;
|
||||||
|
bool dirty;
|
||||||
|
Vector position;
|
||||||
|
} centerOfMass;
|
||||||
|
|
||||||
class Clipboard {
|
class Clipboard {
|
||||||
public:
|
public:
|
||||||
|
@ -857,6 +862,7 @@ public:
|
||||||
void WriteEqSystemForGroup(hGroup hg);
|
void WriteEqSystemForGroup(hGroup hg);
|
||||||
void MarkDraggedParams();
|
void MarkDraggedParams();
|
||||||
void ForceReferences();
|
void ForceReferences();
|
||||||
|
void UpdateCenterOfMass();
|
||||||
|
|
||||||
bool ActiveGroupsOkay();
|
bool ActiveGroupsOkay();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue