-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathreduceCmd.cpp
182 lines (145 loc) · 4.84 KB
/
reduceCmd.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#include "reduceCmd.h"
#include <algorithm>
#include <stdio.h>
ReduceCmd::ReduceCmd() {
mMesh = MGlobal::executeCommandStringResult("ls -selection");
};
ReduceCmd::~ReduceCmd() {};
void* ReduceCmd::creater() {
return new ReduceCmd();
}
bool ReduceCmd::isUndoable() const {
return false;
}
MSyntax ReduceCmd::newSyntax() {
MSyntax syntax;
syntax.addFlag("-p", "-percentage", MSyntax::kUnsigned); // how to specify int value
syntax.setObjectType(MSyntax::kSelectionList, 1, 1);
syntax.useSelectionAsDefault(true); // use selection as selection list
syntax.enableEdit(false);
syntax.enableQuery(false);
return syntax;
}
MStatus ReduceCmd::getShapeNode(MDagPath &path) {
if (path.apiType() == MFn::kMesh)
return MS::kSuccess;
unsigned int numShapes;
path.numberOfShapesDirectlyBelow(numShapes);
for (unsigned int i = 0; i < numShapes; i++) {
path.extendToShapeDirectlyBelow(i);
if (!path.hasFn(MFn::kMesh)) {
path.pop(); // set path back to transform
continue;
}
MFnDagNode fnNode(path);
if (!fnNode.isIntermediateObject()) {
return MS::kSuccess;
}
path.pop();
}
return MS::kFailure; // didn't find shape node
}
MStatus ReduceCmd::doIt(const MArgList& argList) {
// doIt gets all the arguments and store them as instances
MArgDatabase argData(syntax(), argList); // syntax() is a built-in function to call our registered newSyntax()
/* get selected objects dagPath*/
MSelectionList selectedObj;
argData.getObjects(selectedObj);
selectedObj.getDagPath(0, m_basePath);
getShapeNode(m_basePath); //gets the shape node under transform
/* get flag */
if (argData.isFlagSet("-p")) argData.getFlagArgument("-p", 0, m_percentage);
else m_percentage = 70;
MItMeshVertex itVert(m_basePath);
m_count = itVert.count();
unsigned int targetCount = round(m_count*m_percentage/100); // get the desire poly-count
unsigned int modifyVert, collapseVert;
for (; m_count > targetCount; m_count--) {
computeAllEdgeCosts();
modifyVert = findMinCostVert();
collapseVert = mCollapseVert[modifyVert];
collapse(modifyVert, collapseVert);
M3dView::active3dView().refresh(true, true);
}
return MS::kSuccess;
}
void ReduceCmd::collapse(unsigned int u, unsigned int v) {
// move u to v
MFnMesh fnMesh(m_basePath);
MPoint vPos;
fnMesh.getPoint(v, vPos);
fnMesh.setPoint(u, vPos);
// collapse u to v
MGlobal::executeCommand("polyMergeVertex -d 0.01 -am 1 -cch 0 -ch 0 " + mMesh + ".vtx[" + u + "] " + mMesh + ".vtx[" + v + "] ");
//fnMesh.updateSurface();
}
void ReduceCmd::computeAllEdgeCosts() {
// iterate over input mesh
MItMeshVertex itMesh(m_basePath);
mLeastCost.clear();
mCollapseVert.clear();
MIntArray neighborIndices; // get nearby vertex
int currentId;
float leastCost = 1000.0f;
int collapseVert = -1;
float cost;
while (!itMesh.isDone()) {
currentId = itMesh.index();
itMesh.getConnectedVertices(neighborIndices);
for (unsigned int i = 0; i < neighborIndices.length(); i++) {
cost = computeEdgeCost(currentId, neighborIndices[i]);
if (cost < leastCost) {
leastCost = cost;
collapseVert = neighborIndices[i];
}
}
mLeastCost.append(leastCost); // store all the least cost of every vertex
mCollapseVert.append(collapseVert); // store the coresponding collapse destination vertex
itMesh.next();
}
}
float ReduceCmd::computeEdgeCost(int u, int v) {
MItMeshVertex itMesh(m_basePath);
MIntArray uConnectedFaces, vConnectedFaces;
itMesh.setIndex(u, u);
MPoint uPos = itMesh.position();
itMesh.getConnectedFaces(uConnectedFaces);
itMesh.setIndex(v, v);
MPoint vPos = itMesh.position();
itMesh.getConnectedFaces(vConnectedFaces);
MVector edge = uPos - vPos;
float edgeLength = edge.length();
MIntArray sharedFaces;
for (unsigned int i = 0; i < uConnectedFaces.length(); i++)
if(itMesh.connectedToFace(uConnectedFaces[i]))
sharedFaces.append(uConnectedFaces[i]);
MItMeshPolygon itFace(m_basePath);
MVector uNormal, vNormal;
float curvature = 0;
for (unsigned int i = 0; i < uConnectedFaces.length(); i++) {
float mincurv = 1;
itFace.getNormal(uConnectedFaces[i], uNormal);
for (unsigned int j = 0; j < sharedFaces.length(); j++) {
itFace.getNormal(sharedFaces[j], vNormal);
float dotProd = uNormal * vNormal;
curvature = std::min(mincurv, (1-dotProd)/2.0f);
}
curvature = std::max(curvature, mincurv);
}
return curvature * edgeLength;
}
unsigned int ReduceCmd::findMinCostVert() {
// return the least cost vert index
unsigned int leastIndex = 0;
for (unsigned int i = 0; i < mLeastCost.length(); i++)
if (mLeastCost[i] < mLeastCost[leastIndex])
leastIndex = i;
return leastIndex;
}
MStatus ReduceCmd::redoIt() {
return MS::kSuccess;
}
MStatus ReduceCmd::undoIt() {
// restore to initial state
return MS::kSuccess;
}