Add a command to show center of mass, assuming uniform density.

pull/168/head
EvilSpirit 2017-01-17 23:57:27 +07:00 committed by whitequark
parent 068191bf28
commit db75e06ecc
11 changed files with 82 additions and 4 deletions

View File

@ -39,15 +39,19 @@ New rendering features:
or not drawing them at all.
* The "Show/hide outlines" button is now independent from "Show/hide edges".
Other new features:
* New command-line interface, for batch exporting and more.
New measurement/analysis features:
* New command for measuring total length of selected entities,
"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,
"view → set to full scale".
* 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,
the entity from the current group is selected.
* When dragging an entity that shares a place with other entities,

View File

@ -770,6 +770,33 @@ void GraphicsWindow::Draw(Canvas *canvas) {
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.
if(SS.justExportedInfo.draw) {
Vector p, u, v;

View File

@ -359,6 +359,7 @@ void SolveSpaceUI::GenerateAll(Generate type, bool andFindFree, bool genForBBox)
FreeAllTemporary();
allConsistent = true;
SS.GW.persistentDirty = true;
SS.centerOfMass.dirty = true;
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() {
sys.dragged.Clear();

View File

@ -152,6 +152,7 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
{ 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 &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, N_("Show Degrees of &Freedom"), Command::SHOW_DOF, C|S|'F', TN, mAna },
{ 1, NULL, Command::NONE, 0, TN, NULL },
@ -793,6 +794,7 @@ void GraphicsWindow::MenuEdit(Command id) {
SS.TW.HideEditControl();
SS.nakedEdges.Clear();
SS.justExportedInfo.draw = false;
SS.centerOfMass.draw = false;
// This clears the marks drawn to indicate which points are
// still free to drag.
Param *p;

View File

@ -421,6 +421,10 @@ void Group::GenerateDisplayItems() {
// work correctly.
displayMesh.PrecomputeTransparency();
// Recalculate mass center if needed
if(SS.centerOfMass.draw && SS.centerOfMass.dirty && h.v == SS.GW.activeGroup.v) {
SS.UpdateCenterOfMass();
}
displayDirty = false;
}
}

View File

@ -345,6 +345,18 @@ uint32_t SMesh::FirstIntersectionWith(Point2d mp) const {
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()
{ return (STriangleLl *)AllocTemporary(sizeof(STriangleLl)); }
SKdNode *SKdNode::Alloc()

View File

@ -83,6 +83,10 @@ bool STriangle::Raytrace(const Vector &rayPoint, const Vector &rayDir,
return true;
}
double STriangle::SignedVolume() const {
return a.Dot(b.Cross(c)) / 6.0;
}
void STriangle::FlipNormal() {
swap(a, b);
swap(an, bn);

View File

@ -190,6 +190,7 @@ public:
STriangle Transform(Vector o, Vector u, Vector v) const;
bool Raytrace(const Vector &rayPoint, const Vector &rayDir,
double *t, Vector *inters) const;
double SignedVolume() const;
};
class SBsp2 {
@ -282,6 +283,8 @@ public:
void RemapFaces(Group *g, int remap);
uint32_t FirstIntersectionWith(Point2d mp) const;
Vector GetCenterOfMass() const;
};
// A linked list of triangles

View File

@ -311,6 +311,7 @@ void SolveSpaceUI::AfterNewFile() {
// Quit export mode
justExportedInfo.draw = false;
centerOfMass.draw = false;
exportMode = false;
// GenerateAll() expects the view to be valid, because it uses that to
@ -616,6 +617,13 @@ void SolveSpaceUI::MenuAnalyze(Command id) {
break;
}
case Command::CENTER_OF_MASS: {
SS.UpdateCenterOfMass();
SS.centerOfMass.draw = true;
InvalidateGraphics();
break;
}
case Command::VOLUME: {
SMesh *m = &(SK.GetGroup(SS.GW.activeGroup)->displayMesh);

View File

@ -810,6 +810,11 @@ public:
bool draw, showOrigin;
Vector pt, u, v;
} justExportedInfo;
struct {
bool draw;
bool dirty;
Vector position;
} centerOfMass;
class Clipboard {
public:
@ -857,6 +862,7 @@ public:
void WriteEqSystemForGroup(hGroup hg);
void MarkDraggedParams();
void ForceReferences();
void UpdateCenterOfMass();
bool ActiveGroupsOkay();

View File

@ -213,6 +213,7 @@ enum class Command : uint32_t {
INTERFERENCE,
NAKED_EDGES,
SHOW_DOF,
CENTER_OF_MASS,
TRACE_PT,
STOP_TRACING,
STEP_DIM,