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.
|
||||
* 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,
|
||||
|
|
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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
12
src/mesh.cpp
12
src/mesh.cpp
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
Loading…
Reference in New Issue