void Model::storeActiveNodeGeometry() { if (activeNode == nullptr) return; QSet<Structure::Node*> nodes; nodes << activeNode; // Apply to group if in any for(auto g : groupsOf(activeNode->id)){ for(auto nid : g){ nodes << getNode(nid); } } for(auto n : nodes) { // Store initial node and mesh geometries n->property["restNodeGeometry"].setValue(n->controlPoints()); n->property["restNodeCentroid"].setValue(n->center()); auto mesh = getMesh(n->id); Array1D_Vector3 meshPoints; for (auto v : mesh->vertices()) meshPoints.push_back(mesh->vertex_coordinates()[v]); n->property["restMeshGeometry"].setValue(meshPoints); } }
void Model::createSheetFromPoints(QVector<QVector3D> &points) { if (points.size() < 2) return; // Convert corner points to Vector3 Array1D_Vector3 cp; for(auto p : points) cp.push_back(Vector3(p[0],p[1],p[2])); // midpoint of diagonal Vector3 center = 0.5 * (cp[1] + cp[2]); // Extent Vector3 du = cp[0] - cp[2], dv = cp[0] - cp[1]; double u = du.norm(), v = dv.norm(); // Create sheet auto newSheetGeometry = NURBS::NURBSRectangled::createSheet(u, v, center, du.normalized(), dv.normalized()); QString newSheetID = QString("sheetNode%1").arg((nodes.empty()? -1 : nodes.back()->property["index"].toInt())+1); auto newSheet = new Structure::Sheet(newSheetGeometry, newSheetID); // Add sheet activeNode = this->addNode(newSheet); generateSurface(); }
void Model::modifyLastAdded(QVector<QVector3D> &guidePoints) { if (guidePoints.size() < 2 || activeNode == nullptr) return; Structure::Curve* curve = dynamic_cast<Structure::Curve*>(activeNode); Structure::Sheet* sheet = dynamic_cast<Structure::Sheet*>(activeNode); auto fp = guidePoints.takeFirst(); Vector3 axis(fp.x(),fp.y(),fp.z()); int skipAxis = -1; if (axis.isApprox(-Vector3::UnitX())) skipAxis = 0; if (axis.isApprox(-Vector3::UnitY())) skipAxis = 1; if (axis.isApprox(Vector3::UnitZ())) skipAxis = 2; // Smooth curve guidePoints = GeometryHelper::smooth(GeometryHelper::uniformResampleCount(guidePoints, 20), 5); // Convert to Vector3 Array1D_Vector3 gpoint; for(auto p : guidePoints) gpoint.push_back(Vector3(p[0],p[1],p[2])); if(curve) { auto oldPoints = curve->controlPoints(); auto newPoints = oldPoints; for(size_t i = 0; i < oldPoints.size(); i++){ for(int j = 0; j < 3; j++){ if(j == skipAxis) newPoints[i][j] = oldPoints[i][j]; else newPoints[i][j] = gpoint[i][j]; } } curve->setControlPoints(newPoints); } if(sheet) { auto oldPoints = sheet->controlPoints(); auto newPoints = oldPoints; Vector3 centroid = sheet->position(Eigen::Vector4d(0.5, 0.5, 0, 0)); Vector3 delta = gpoint.front() - centroid; for(size_t i = 0; i < oldPoints.size(); i++){ for (int j = 0; j < 3; j++){ if (j == skipAxis) continue; newPoints[i][j] += delta[j]; } } sheet->setControlPoints(newPoints); sheet->surface.quads.clear(); } generateSurface(); }
void DeformationPath::badMorphing() { for(double t = 0; t <= 1.0; t += scheduler->timeStep) { // Current nodes geometry QMap<Structure::Node*, Array1D_Vector3> startGeometry; for(auto n : scheduler->activeGraph->nodes) { if(n->property["taskTypeReal"].toInt() == Task::GROW) { Array1D_Vector3 pnts = n->controlPoints(); Vector3 p = pnts.front(); Array1D_Vector3 newpnts(pnts.size(), p); for(auto & p: newpnts) p += Eigen::Vector3d(starlab::uniformRand(), starlab::uniformRand(), starlab::uniformRand()) * 1e-5; n->setControlPoints(newpnts); } if(n->property["taskTypeReal"].toInt() == Task::SHRINK) { auto tn = scheduler->targetGraph->getNode( n->property["correspond"].toString() ); Array1D_Vector3 pnts = tn->controlPoints(); Vector3 p = pnts[pnts.size() / 2]; Array1D_Vector3 newpnts(pnts.size(), p); for(auto & p: newpnts) p += Eigen::Vector3d(starlab::uniformRand(), starlab::uniformRand(), starlab::uniformRand()) * 1e-5; tn->setControlPoints(newpnts); } startGeometry[n] = n->controlPoints(); } // Morph nodes for(auto n : scheduler->activeGraph->nodes) { auto tn = scheduler->targetGraph->getNode( n->property["correspond"].toString() ); if(!tn) continue; Array1D_Vector3 finalGeometry = tn->controlPoints(); Array1D_Vector3 newGeometry; for(int i = 0; i < (int) finalGeometry.size(); i++) newGeometry.push_back( AlphaBlend(t, startGeometry[n][i], Vector3(finalGeometry[i])) ); n->setControlPoints( newGeometry ); n->property["t"].setValue( t ); if(t > 0.5 && n->property["taskTypeReal"].toInt() == Task::SHRINK) n->property["shrunk"].setValue( true ); } scheduler->allGraphs.push_back( new Structure::Graph( *scheduler->activeGraph ) ); } property["progressDone"] = true; }
Array1D_Real NURBSCurve<Real>::insertKnot(Real u, int k, int s, int r, Array1D_Vector3 & Qw, int * uq) { Array1D_Real UP = GetKnotVector(); Array1D_Vector3 Pw = mCtrlPoint; Array1D_Real UQ; Array1D_Vector3 Rw; Scalar alpha; int L = 0; int order = this->GetDegree() + 1; int p = order - 1; int np = Pw.size() - 1; int mp = np+p+1; int nq = np+r; // Define array UQ.resize(mp+r+1); Qw.resize(nq+1); Rw.resize(p+1); // Load new knot vector for (int i=0; i<=k; i++) UQ[i] = UP[i]; for (int i=1; i<=r; i++) UQ[k+i] = u; for (int i=k+1; i<=mp; i++) UQ[i+r] = UP[i]; // Save unaltered control points for (int i=0; i<=k-p; i++) Qw[i] = Pw[i]; for (int i=k-s; i<=np; i++) Qw[i+r] = Pw[i]; for (int i=0; i<=p-s; i++) Rw[i] = Pw[k-p+i]; // Insert the knot r times for (int j=1; j<=r; j++) { L = k-p+j; for (int i=0; i<=p-j-s; i++) { alpha = (u-UP[L+i])/(UP[i+k+1]-UP[L+i]); Rw[i] = alpha*Rw[i+1] + (1.0 - alpha) * Rw[i]; } Qw[L] = Rw[0]; Qw[k+r-j-s] = Rw[p-j-s]; } // Load remaining control points for (int i=L+1; i<k-s; i++) Qw[i] = Rw[i-L]; if(uq) *uq = k-p+1; return UQ; }
Real NURBSCurve<Real>::KnotRemovalError( int r, int s ) { Array1D_Real U = GetKnotVector(); Array1D_Vector3 P = mCtrlPoint; Array1D_Vector3 temp(P.size(), Vector3(0,0,0)) ; int deg_ = GetDegree(); int ord = deg_+1 ; int last = r-s ; int first = r-deg_ ; int off ; int i,j,ii,jj ; Real alfi,alfj ; Real u ; u = U[r] ; off = first-1; temp[0] = P[off] ; temp[last+1-off] = P[last+1] ; i=first ; j=last ; ii=1 ; jj=last-off ; while(j-i>0) { alfi = (u-U[i])/(U[i+ord]-U[i]) ; alfj = (u-U[j])/(U[j+ord]-U[j]) ; temp[ii] = (P[i]-(1.0-alfi)*temp[ii-1])/alfi ; temp[jj] = (P[j]-alfj*temp[jj+1])/(1.0-alfj) ; ++i ; ++ii ; --j ; --jj ; } if(j-i<0) { return (temp[ii-1]-temp[jj+1]).norm() ; } else { alfi=(u-U[i])/(U[i+ord]-U[i]) ; return (P[i]-alfi*temp[ii+1]+(1.0-alfi)*temp[ii-1]).norm() ; } }
Array1D_Vector3 Sheet::discretizedAsCurve(Scalar resolution) { // Return a representative curve along the longest side at the middle of the sheet NURBS::NURBSCurved curve; Vector3 uDir = surface.mCtrlPoint.front().back() - surface.mCtrlPoint.front().front(); Vector3 vDir = surface.mCtrlPoint.back().front() - surface.mCtrlPoint.front().front(); double projux = abs(dot(Vector3d(1,0,0), uDir.normalized())); double projvx = abs(dot(Vector3d(1,0,0), vDir.normalized())); //bool isU = uDir.norm() > vDir.norm(); bool isU = projux > projvx; if( isU ) { int v = (surface.mNumUCtrlPoints - 1) * 0.5; curve = NURBS::NURBSCurved(surface.GetControlPointsV(v), surface.GetControlWeightsV(v)); } else { int u = (surface.mNumVCtrlPoints - 1) * 0.5; curve = NURBS::NURBSCurved(surface.GetControlPointsU(u), surface.GetControlWeightsU(u)); } Array1D_Vector3 result; Scalar curveLength = curve.GetLength(0,1); // Degenerate cases bool validControlPoints = std::isfinite(curve.mCtrlPoint.front().x()); if( !validControlPoints ){ result.clear(); for(int i = 0; i < 4; i++) result.push_back(Vector3(0,0,0)); return result; } if( !std::isfinite(curveLength) || curveLength < resolution ) return curve.mCtrlPoint; int np = qMax(2.0, 1.0 + (curveLength / resolution)); curve.SubdivideByLength(np, result); return result; }
void Model::createCurveFromPoints(QVector<QVector3D> & points) { if(points.size() < 2) return; // Nicer curve points = GeometryHelper::smooth(GeometryHelper::uniformResampleCount(points, 20), 5); // Create curve Array1D_Vector3 controlPoints; for(auto p : points) controlPoints.push_back(Vector3(p[0],p[1],p[2])); auto newCurveGeometry = NURBS::NURBSCurved::createCurveFromPoints(controlPoints); QString newCurveID = QString("curveNode%1").arg((nodes.empty()? -1 : nodes.back()->property["index"].toInt())+1); auto newCurve = new Structure::Curve(newCurveGeometry, newCurveID); // Add curve activeNode = this->addNode(newCurve); generateSurface(); }
void TaskSheet::executeCrossingSheet( double t ) { Node *n = node(), *tn = targetNode(); QVector<Link*> edges = active->getEdges( property["edges"].value< QVector<int> >() ); if (property.contains("path")) { Vector3 p0 = n->position(Vec4d(0,0,0,0)); Vector3 delta(0,0,0); if(!edges.isEmpty()) { p0 = edges.front()->position(n->id); // Blend Deltas Structure::Link *slink = edges.front(); Structure::Link* tlink = target->getEdge(slink->property["correspond"].toInt()); Vector3 d1 = slink->position(n->id) - slink->positionOther(n->id); Vector3 d2 = tlink->position(tn->id) - tlink->positionOther(tn->id); delta = AlphaBlend(t, d1, d2); } executeMorphSheet(t); // Cancel any absolute movement if(!edges.isEmpty()) n->moveBy(p0 - edges.front()->position(n->id)); // Move it to the correct position Array1D_Vector3 path = property["path"].value< Array1D_Vector3 >(); int idx = t * (path.size() - 1); Vector3 oldPosOnMe = p0; Vector3 newPosOnMe = path[idx] + delta; n->moveBy(newPosOnMe - p0); } }
void TaskSheet::executeMorphSheet( double t ) { Structure::Node * n = node(); Structure::Sheet * sheet = (Structure::Sheet *)n; // Decode SheetEncoding cpCoords = property["cpCoords"].value<SheetEncoding>(); SheetEncoding cpCoordsT = property["cpCoordsT"].value<SheetEncoding>(); RMF::Frame sframe = property["sframe"].value<RMF::Frame>(); RMF::Frame tframe = property["tframe"].value<RMF::Frame>(); QVector<double> rot = property["rotation"].value< QVector<double> >(); Eigen::Quaterniond rotation(rot[0],rot[1],rot[2],rot[3]), eye = Eigen::Quaterniond::Identity(); // Source sheet Eigen::Vector3d R = (sframe.r), S = (sframe.s), T = (sframe.t); R = eye.slerp(t, rotation) * R; S = eye.slerp(t, rotation) * S; T = eye.slerp(t, rotation) * T; RMF::Frame curFrame ((R),(S),(T)); curFrame.center = tframe.center = AlphaBlend(t, sframe.center, tframe.center); Array1D_Vector3 newPnts = Sheet::decodeSheet( cpCoords, curFrame.center, curFrame.r, curFrame.s, curFrame.t ); Array1D_Vector3 newPntsT = Sheet::decodeSheet( cpCoordsT, tframe.center, tframe.r, tframe.s, tframe.t ); Array1D_Vector3 blendedPnts; for(int i = 0; i < (int)newPnts.size(); i++) { blendedPnts.push_back( AlphaBlend(t, newPnts[i], newPntsT[i]) ); } sheet->setControlPoints( blendedPnts ); }
NURBSCurve<Real>::NURBSCurve ( const Array1D_Vector3 & ctrlPoint, const Array1D_Real & ctrlWeight, int degree, bool loop, bool open) : SingleCurve<Real>((Real)0, (Real)1), mLoop(loop) { int numCtrlPoints = ctrlPoint.size(); assertion(numCtrlPoints >= 2, "Invalid input\n"); assertion(1 <= degree && degree <= numCtrlPoints-1, "Invalid input\n"); mNumCtrlPoints = numCtrlPoints; mReplicate = (loop ? (open ? 1 : degree) : 0); CreateControl(ctrlPoint, ctrlWeight); mBasis.Create(mNumCtrlPoints + mReplicate, degree, open); }
Array1D_Vector3 NURBSCurve<Real>::removeKnots(int iterations) { NURBSCurve<Real> curCurve = *this; for(int itr = 0; itr < iterations; itr++) { Array1D_Real U = curCurve.GetKnotVector(); Array1D_Vector3 P = curCurve.mCtrlPoint; int p = curCurve.GetDegree(); QMap<Real, int> errors; for(int i = p + 1; i < (int)U.size() - 1; i++) { if(U[i] < U[i+1]) errors[ curCurve.KnotRemovalError(i, 1) ] = i; } int r = errors.values().at(itr); // Knot to remove int num = 1; int s = 1; int deg_ = curCurve.GetDegree(); int m = U.size() ; int ord = deg_+1 ; int fout = (2*r-s-deg_)/2 ; int last = r-s ; int first = r-deg_ ; Real alfi, alfj ; int i,j,k,ii,jj,off ; Real u ; Array1D_Vector3 temp( 2*deg_+1, Vector3(0,0,0) ) ; u = U[r] ; int t; for(t=0; t<num; ++t) { off = first-1 ; temp[0] = P[off] ; temp[last+1-off] = P[last+1] ; i = first; j = last ; ii = 1 ; jj = last-off ; while(j-i > t) { alfi = (u-U[i])/(U[i+ord+t]-U[i]) ; alfj = (u-U[j-t])/(U[j+ord]-U[j-t]) ; temp[ii] = (P[i]-(1.0-alfi)*temp[ii-1])/alfi ; temp[jj] = (P[j]-alfj*temp[jj+1])/(1.0-alfj) ; ++i ; ++ii ; --j ; --jj ; } i = first ; j = last ; while(j-i>t) { P[i] = temp[i-off] ; P[j] = temp[j-off] ; ++i; --j ; } --first ; ++last ; } if(t == 0) return P; for(k=r+1; k<m ; ++k) U[k-t] = U[k] ; j = fout ; i=j ; // Pj thru Pi will be overwritten for(k=1; k<t; k++) if( (k%2) == 1) ++i ; else --j ; for(k=i+1; k<(int)P.size() ; k++) {// Shift P[j++] = P[k] ; } P.resize(P.size() - t); curCurve = createCurveFromPoints(P); } return curCurve.mCtrlPoint; }
void NURBSCurve<Real>::refine(Array1D_Real & insknts, Array1D_Vector3 & Qw, Array1D_Real & Ubar ) { // Input Array1D_Real X = insknts; Array1D_Vector3 Pw = this->mCtrlPoint; Array1D_Real U = GetKnotVector(); int s = insknts.size(); int order = this->GetDegree() + 1; int p = order - 1; int n = Pw.size() - 1; int r = X.size() - 1; int m = n+p+1; // Output Qw.resize ( n+s+1, Vector3(0,0,0) ); Ubar.resize ( m+s+1, 0 ); int a = findSpan(n,p,X[0],U); int b = findSpan(n,p,X[r],U) + 1; int j = 0; for(j=0 ; j<=a-p; j++) Qw[j] = Pw[j]; for(j=b-1; j<=n ; j++) Qw[j+r+1] = Pw[j]; for(j=0 ; j<=a ; j++) Ubar[j] = U[j]; for(j=b+p; j<=m ; j++) Ubar[j+r+1] = U[j]; int i = b+p-1; int k = b+p+r; Real alfa = 0; for (int j=r; j>=0; j--) { while (X[j] <= U[i] && i > a) { Qw[k-p-1] = Pw[i-p-1]; Ubar[k] = U[i]; k = k - 1; i = i - 1; } Qw[k-p-1] = Qw[k-p]; for (int l=1; l<=p; l++) { int ind = k-p+l; alfa = Ubar[k+l] - X[j]; if (fabs(alfa) == 0.0) { Qw[ind-1] = Qw[ind]; } else { alfa = alfa / (Ubar[k+l] - U[i-p+l]); Qw[ind-1] = alfa * Qw[ind-1] + (1.0 - alfa) * Qw[ind]; } } Ubar[k] = X[j]; k = k - 1; } }