00001
00046 #include "DAG.h"
00047 #include "ShockGraph.h"
00048 #include "HelperFunctions.h"
00049 #include "Exceptions.h"
00050 #include <float.h>
00051 #include <stdio.h>
00052 #include <ctype.h>
00053
00054 #include "SGDistMeasurer.h"
00055
00056 #include <LEDA/graphwin.h>
00057 #include <LEDA/graph.h>
00058 #include <LEDA/node_array.h>
00059
00060 #include "VisualDAG.h"
00061 #include "ApproxPoly.h"
00062
00063 #define NSAMPLES 5
00064 #define VDIM 4
00065 #define DIMxSAMPLES (VDIM * NSAMPLES)
00066
00067 #define SA_GROWING_FACTOR 50
00068
00069 #ifdef WIN32
00070 #define FILE_SEP '\\'
00071 #else
00072 #define FILE_SEP '/'
00073 #endif
00074
00075 struct ER
00076 {
00077 leda_edge e;
00078 double r;
00079
00080 ER() { e = nil; r = 0.0; }
00081 ER(leda_edge edge, const double& radius) { e = edge; r = radius; }
00082
00092 static int CompareEdgesDescending(const void *elem1, const void *elem2 )
00093 {
00094 ER* p1 = (ER*) elem1;
00095 ER* p2 = (ER*) elem2;
00096
00097 return (p1->r < p2->r) ? 1:(p1->r > p2->r) ? -1:0;
00098 }
00099 };
00100
00101 void SmoothFluxPoints(sg::FluxPointList& fpl, const double& dSigma, const double& dSigmaRange);
00102 void GaussianSmooth(double *input, double *output, int length, const double& sigma, const double& sigma_range);
00103
00104 const char* ShockGraph::GetNextIdx()
00105 {
00106 static char szNum[100];
00107
00108 sprintf(szNum, "%d", ++nLastIndexUsed);
00109 return szNum;
00110 }
00111
00112 ShockGraph::ShockGraph()
00113 {
00114 area = 0;
00115 perimeter = 0;
00116 xmin = ymin = 0;
00117 xmax = ymax = 0;
00118 nLastIndexUsed = 0;
00119 m_pSkeleton = NULL;
00120
00121 ASSERT(!pDistMeasurer);
00122
00123 if (s_matchParams.nNodeDistFunc == 1)
00124 pDistMeasurer = new SGDistMeasurer1;
00125 else if (s_matchParams.nNodeDistFunc == 2)
00126 pDistMeasurer = new SGDistMeasurer2;
00127 else if (s_matchParams.nNodeDistFunc == 3)
00128 pDistMeasurer = new SGDistMeasurer3;
00129 else
00130 ASSERT(false);
00131 }
00132
00133 ShockGraph::~ShockGraph()
00134 {
00135 delete pDistMeasurer;
00136
00137
00138 }
00139
00140 void ShockGraph::Clear()
00141 {
00142 DAG::Clear();
00143
00144 area = 0.0;
00145 perimeter = 0.0;
00146 xmin = ymin = 0;
00147 xmax = ymax = 0;
00148 nLastIndexUsed = 0;
00149
00150 delete m_pSkeleton;
00151 m_pSkeleton = NULL;
00152 }
00153
00154 void ShockGraph::ComputeObjectViewName()
00155 {
00156 int i, j, k, lastFileSep;
00157 String viewName;
00158 const String path = GetDAGLbl();
00159 const int nLen = path.Len();
00160
00161 strObjectName.Clear();
00162
00163
00164
00165 for (i = nLen - 1; i >= 0 && path[i] != FILE_SEP; i--);
00166
00167 lastFileSep = i;
00168
00169 if (i > 0)
00170 {
00171
00172 for (j = i - 1; j >= 0 && path[j] != FILE_SEP; j--);
00173
00174
00175 strObjectName.ReSize(i - j);
00176
00177 for (j++, k = 0; j < i; j++, k++)
00178 strObjectName[k] = path[j];
00179
00180 strObjectName[k] = '\0';
00181
00182
00183 for (i++; i < nLen && !isdigit(path[i]); i++);
00184 }
00185 else
00186 {
00187
00188 for (i = 0; i < nLen && !isdigit(path[i]); i++);
00189
00190
00191
00192 strObjectName.ReSize(i + 1);
00193
00194 for (j = 0; j < i; j++)
00195 strObjectName[j] = path[j];
00196
00197 strObjectName[j] = '\0';
00198 }
00199
00200
00201 viewName.ReSize(nLen - i + 1);
00202
00203 for (k = 0; i <= nLen; i++, k++)
00204 viewName[k] = path[i];
00205
00206 nViewNumber = (viewName[0] != '\0') ? atoi(viewName):1;
00207 }
00208
00210 void ShockGraph::ComputeDerivedValues()
00211 {
00212 DAG::ComputeDerivedValues();
00213 ComputeObjectViewName();
00214 }
00215
00217 istream& ShockGraph::Read(istream& is, bool bOnlyDataForMatching )
00218 {
00219 DAG::Read(is, bOnlyDataForMatching);
00220
00221 is.read((char*) &area, sizeof(area));
00222 is.read((char*) &perimeter, sizeof(perimeter));
00223 is.read((char*) &xmin, sizeof(xmin));
00224 is.read((char*) &xmax, sizeof(xmax));
00225 is.read((char*) &ymin, sizeof(ymin));
00226 is.read((char*) &ymax, sizeof(ymax));
00227
00228 if (!bOnlyDataForMatching)
00229 {
00230
00231 is.read((char*) &m_pSkeleton, sizeof(m_pSkeleton));
00232 if (m_pSkeleton)
00233 {
00234 m_pSkeleton = new McGillSkeleton();
00235 m_pSkeleton->Read(is);
00236 }
00237 }
00238
00239 return is;
00240 }
00241
00243 ostream& ShockGraph::Write(ostream& os) const
00244 {
00245 DAG::Write(os);
00246
00247 os.write((char*) &area, sizeof(area));
00248 os.write((char*) &perimeter, sizeof(perimeter));
00249 os.write((char*) &xmin, sizeof(xmin));
00250 os.write((char*) &xmax, sizeof(xmax));
00251 os.write((char*) &ymin, sizeof(ymin));
00252 os.write((char*) &ymax, sizeof(ymax));
00253
00254
00255 os.write((char*) &m_pSkeleton, sizeof(m_pSkeleton));
00256 if (m_pSkeleton)
00257 m_pSkeleton->Write(os);
00258
00259 return os;
00260 }
00261
00263 void ShockGraph::Print(ostream& os) const
00264 {
00265 DAG::Print(os);
00266
00267 os << "\nShockGraph specific:\n";
00268
00269 PRINT_OPEN(os, area);
00270 PRINT(os, perimeter);
00271 PRINT(os, xmin);
00272 PRINT(os, xmax);
00273 PRINT(os, ymin);
00274 PRINT_CLOSE(os, ymax);
00275 }
00276
00278 DAG& ShockGraph::operator=(const DAG& rhs)
00279 {
00280 DAG::operator=(rhs);
00281
00282 const ShockGraph* pRhs = dynamic_cast<const ShockGraph*>(&rhs);
00283
00284 if (!pRhs)
00285 THROW_EXCEPTION("Invalid pointer type.");
00286
00287 area = pRhs->area;
00288 perimeter = pRhs->perimeter;
00289
00290 xmin = pRhs->xmin;
00291 ymin = pRhs->ymin;
00292 xmax = pRhs->xmax;
00293 ymax = pRhs->ymax;
00294
00295 return *this;
00296 }
00297
00301 double ShockGraph::NodeDistance(leda_node u, const DAG& from, leda_node v) const
00302 {
00303 ASSERT(pDistMeasurer);
00304
00305 return pDistMeasurer->GetDistance(*this, u, from, v);
00306 }
00307
00312 bool ShockGraph::AreNodesRelated(leda_node u, const DAG& from, leda_node v) const
00313 {
00314 return true;
00315 }
00316
00318 DAG* ShockGraph::CreateObject() const
00319 {
00320 return new ShockGraph();
00321 }
00322
00324 DAGNodePtr ShockGraph::CreateNodeObject(NODE_LABEL lbl) const
00325 {
00326 return new SGNode(lbl, TEST_NODE);
00327 }
00328
00333 DAGNodePtr ShockGraph::ReadNode(istream& is) const
00334 {
00335 DAGNodePtr node(new SGNode);
00336
00337 node->Read(is);
00338
00339 return node;
00340 }
00341
00343 String ShockGraph::ClassName() const
00344 {
00345 return "ShockGraph";
00346 }
00347
00348 NODE_LABEL ShockGraph::GetNodeLbl(leda_node v) const
00349 {
00350 char szLbl[100];
00351 const char* szNodeLbl = (const char*)DAG::GetNodeLbl(v);
00352
00353 sprintf(szLbl, "%s:%d", szNodeLbl, NodeType(v) % 100);
00354
00355 return szLbl;
00356 }
00357
00358
00359
00360
00361 bool ShockGraph::ComputeFromPPMFile(const char* szFileName,
00362 double cutoff, double sigma, double range)
00363 {
00364 #ifdef COMPILE_OLD_SG_CODE
00365 MGShockGraph sg;
00366
00367 if (!sg.ComputeFromPPMFile(szFileName, cutoff, sigma, range) || !Translate(sg))
00368 return false;
00369
00370 SetDAGLbl(szFileName);
00371
00372 ComputeDerivedValues();
00373 #endif //COMPILE_OLD_SG_CODE
00374
00375 return true;
00376 }
00377
00378 #ifdef COMPILE_OLD_SG_CODE
00379
00380 bool ShockGraph::ComputeFromMemory(Pixmap& image, double cutoff, double sigma, double range)
00381 {
00382 MGShockGraph sg;
00383
00384 if (!sg.ComputeFromMemory(image, cutoff, sigma, range) || !Translate(sg))
00385 return false;
00386
00387 SetDAGLbl(image.name);
00388
00389 ComputeDerivedValues();
00390
00391 return true;
00392 }
00393
00395 bool ShockGraph::Translate(const MGShockGraph& sg)
00396 {
00397 leda_d_array<long, leda_node> map;
00398 int i, j, ptCount;
00399 SGNode* pNode;
00400 double seg1, seg2;
00401
00402 Clear();
00403
00404 for (i = 0; i < sg.GetNodeCount(); i++)
00405 {
00406 const Vertex* v = sg.GetNode(i);
00407 MGShockGraph::SGSegment branch = sg.GetSegment(v);
00408
00409 pNode = new SGNode(branch.GetId(), branch.GetType());
00410
00411 branch.GetContourLength(seg1, seg2);
00412 pNode->SetContourLength(seg1, seg2);
00413
00414 ptCount = branch.GetPointCount();
00415 pNode->m_shocks.ReSize((ptCount > 0) ? ptCount:0);
00416
00417 for (j = 0; j < ptCount; j++)
00418 {
00419 const MGShockGraph::SGPoint& pt = branch[j];
00420 ShockInfo& si = pNode->m_shocks[j];
00421
00422 si.xcoord = pt.x;
00423 si.ycoord = pt.y;
00424 si.radius = pt.r;
00425 si.speed = pt.s;
00426 si.dr_ds = pt.dr_ds;
00427 si.color = pt.color;
00428
00429
00430 if (pt.x < xmin) xmin = pt.x;
00431 if (pt.x > xmax) xmax = pt.x;
00432 if (pt.y < ymin) ymin = pt.y;
00433 if (pt.y > ymax) ymax = pt.y;
00434 }
00435
00436 map[(long)v] = NewNode(pNode);
00437 }
00438
00439 for (i = 0; i < sg.GetEdgeCount(); i++)
00440 {
00441 const Edge* e = sg.GetEdge(i);
00442
00443 ASSERT(map.defined((long)e->vFrom) && map.defined((long)e->vTo));
00444
00445
00446
00447 NewEdge(map[(long)e->vTo], map[(long)e->vFrom]);
00448 }
00449
00450 return true;
00451 }
00452
00453 #endif //COMPILE_OLD_SG_CODE
00454
00455
00456
00457 char* get_arr(int *rows, int *cols, const char* shapefile)
00458 {
00459 char *arr;
00460 int k, i, j;
00461
00462 pixval maxval;
00463 pixel **pixels;
00464
00465 FILE* ppmshape = fopen(shapefile, "r");
00466
00467 pixels = ppm_readppm(ppmshape, cols, rows, &maxval);
00468 fclose(ppmshape);
00469
00470 arr = (char*)malloc((*cols)*(*rows));
00471
00472 for(i = 0, k = 0; i < *rows; i++)
00473 for(j = 0; j < *cols; j++, k++)
00474 {
00475 char r, g, b;
00476
00477 r = (0xff * PPM_GETR(pixels[i][j])) / maxval;
00478 g = (0xff * PPM_GETR(pixels[i][j])) / maxval;
00479 b = (0xff * PPM_GETR(pixels[i][j])) / maxval;
00480
00481 if(r==0 && b==0 && g==0)
00482 arr[k] = 0;
00483 else
00484 arr[k] = 0xff;
00485 }
00486
00487 ppm_freearray(pixels, *rows);
00488
00489 return arr;
00490 };
00491
00497 void ShockGraph::LabelEndPoints(SGNode* pNode, sg::FluxPointList& fpl, sg::DDSNode* n1, sg::DDSNode* n2)
00498 {
00499 sg::DDSEdgeVect *e0, *eN;
00500
00501 if (n1->getPoint() == fpl[0].p)
00502 {
00503 ASSERT(n2->getPoint() == fpl[fpl.size() - 1].p);
00504
00505 e0 = &n1->getEdges();
00506 eN = &n2->getEdges();
00507 }
00508 else
00509 {
00510 ASSERT(n1->getPoint() == fpl[fpl.size() - 1].p && n2->getPoint() == fpl[0].p);
00511
00512 e0 = &n2->getEdges();
00513 eN = &n1->getEdges();
00514 }
00515
00516 pNode->m_nEndPt0 = (e0->size() == 1) ? TERMINAL_POINT:JOINT_POINT;
00517 pNode->m_nEndPtN = (eN->size() == 1) ? TERMINAL_POINT:JOINT_POINT;
00518 }
00519
00520 SGNode* ShockGraph::CopyNodeInfo(sg::DDSEdge* ddsEdge, leda_node u, SGNode* pNode)
00521 {
00522 sg::FluxPointList& fpl = ddsEdge->getFluxPoints();
00523 int num_pts = fpl.size();
00524 ASSERT(num_pts > 0);
00525 double dx, dy;
00526
00527
00528
00529 pNode->m_shocks.ReSize(num_pts);
00530
00531 for (int j = 0; j < num_pts; j++)
00532 {
00533 const sg::FluxPoint& pt = fpl[j];
00534 ShockInfo& si = pNode->m_shocks[j];
00535
00536 si.xcoord = pt.p.x;
00537 si.ycoord = pt.p.y;
00538 si.radius = fabs(pt.dist);
00539 si.color = 0;
00540
00541
00542 if (isnan(si.radius) && !finite(si.radius))
00543 {
00544 cerr << "\nShock point has a NaN as radius." << endl;
00545
00546 si.radius = (j > 0) ? pNode->m_shocks[j - 1].radius:0.5;
00547 }
00548
00549 if (j > 0)
00550 {
00551 ShockInfo& prevSi = pNode->m_shocks[j - 1];
00552
00553 dx = si.xcoord - prevSi.xcoord;
00554 dy = si.ycoord - prevSi.ycoord;
00555
00556 si.dr = si.radius - prevSi.radius;
00557 si.speed = sqrt(dx * dx + dy * dy);
00558 si.dr_ds = si.dr / si.speed;
00559
00560
00561 si.dir = (fabs(si.dr_ds) <= compParams.dMinSlope) ? 0:int(si.dr / fabs(si.dr));
00562 }
00563 else
00564 {
00565 si.dr = 0;
00566 si.speed = 0;
00567 si.dr_ds = 0;
00568 si.dir = 0;
00569 }
00570 }
00571
00572 LabelEndPoints(pNode, fpl, ddsEdge->getN1(), ddsEdge->getN2());
00573
00574 return GroupShockPoints(u, pNode);
00575 }
00576
00581 SGNode* ShockGraph::GroupShockPoints(leda_node u, SGNode* pNode)
00582 {
00583 ShockBranch& pts = pNode->m_shocks;
00584
00585 SGNode* pNewNode;
00586 SGNode* pReturnNode = NULL;
00587
00588 int i, from;
00589 double m, nextSlope;
00590
00591 int d0, dN;
00592 POINTS data = pNode->GetVelocityRadiusArray(d0, dN);
00593
00594 double x0 = data[0].x;
00595
00596
00597 ApproxPoly poly(data.GetSize() / compParams.dMinError, compParams.dMinSlope, 10.0);
00598
00599 if (DAG::IsDbgMode())
00600 {
00601 cout << "disp('Fitting node: " << pNode->GetNodeLbl() << " in " << GetDAGLbl() << "');\n";
00602 poly.SetDbgMode(true);
00603 }
00604
00605 poly.Fit(data);
00606
00607 int nSize = poly.m_knots.GetSize();
00608 ASSERT(nSize >= 1);
00609 int dir, ptIdx;
00610 SmartArray<SEGMENT> approx_segs;
00611
00612 for (from = 0, i = 0; i < nSize; i++)
00613 {
00614 approx_segs.AddTail(poly.m_knots[i].seg);
00615
00616 dir = poly.m_knots[i].dir;
00617 ptIdx = poly.m_knots[i].nIndex + d0;
00618
00619 if (i < nSize - 1)
00620 {
00621
00622 if (ptIdx - from < 2)
00623 continue;
00624
00625
00626
00627 if (dir == poly.m_knots[i + 1].dir)
00628 {
00629 if (dir == 0)
00630 continue;
00631
00632
00633 double m0 = fabs(poly.m_knots[i].seg.m);
00634 double m1 = fabs(poly.m_knots[i + 1].seg.m);
00635 double mr = fabs(m1 - m0) / MAX(m0, m1);
00636
00637 if (DAG::IsDbgMode())
00638 {
00639 cout << "disp('Acc change: " << mr << ", Max:" << compParams.dMaxAccelChg << "');\n";
00640 poly.SetDbgMode(true);
00641 }
00642
00643 if (mr < compParams.dMaxAccelChg)
00644 continue;
00645 }
00646
00647 pNewNode = SplitNode(u, pNode, ptIdx - from, approx_segs[approx_segs.GetSize() - 1], poly.m_knots[i + 1].seg);
00648 }
00649 else
00650 pNewNode = pNode;
00651
00652
00653 if (pReturnNode == NULL)
00654 pReturnNode = pNewNode;
00655
00656 pNewNode->SetNodeType(dir == 0 ? SHOCK_3:SHOCK_1);
00657 pNewNode->m_shocks.SetDir(dir);
00658
00659
00660
00661 pNewNode->m_shocks.SetSegments(approx_segs, from == 0 ? 0.0:approx_segs[0].p0.x - x0);
00662
00663 pNewNode->ComputeDerivedValues();
00664
00665 from = ptIdx;
00666 approx_segs.Clear();
00667 }
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683 return pReturnNode;
00684 }
00685
00686
00687
00688
00689
00690 SGNode* ShockGraph::SplitNode(leda_node v, SGNode* pNode, int nEnd, SEGMENT& leftSeg, SEGMENT& rightSeg)
00691 {
00692 SGNode* pNewNode = new SGNode(GetNextIdx(), 0);
00693 ShockBranch& newPts = pNewNode->m_shocks;
00694 ShockBranch& pts = pNode->m_shocks;
00695
00696
00697 pNewNode->m_shocks = pts.Left(nEnd);
00698
00699
00700 pts = pts.Right(nEnd);
00701
00702
00703 leda_node u = NewNode(pNewNode);
00704
00705
00706 pNewNode->m_nEndPt0 = pNode->m_nEndPt0;
00707 pNewNode->m_nEndPtN = SPLIT_POINT;
00708 pNode->m_nEndPt0 = SPLIT_POINT;
00709
00710
00711
00712 double jointRadius = (leftSeg.Y1() + rightSeg.Y0()) / 2.0;
00713 pNewNode->m_shocks[pNewNode->m_shocks.GetSize() - 1].radius = jointRadius;
00714 pts[0].radius = jointRadius;
00715 leftSeg.p1.y = jointRadius;
00716 rightSeg.p0.y = jointRadius;
00717
00718
00719 leda_edge e = first_in_edge(v);
00720
00721 if (e != nil)
00722 {
00723 NewEdge(source(e), u);
00724 ASSERT(in_succ(e) == nil);
00725 DelEdge(e);
00726 }
00727
00728
00729 NewEdge(u, v);
00730
00731 return pNewNode;
00732 }
00733
00737 void ShockGraph::ConnectNodes(leda_node u, SGNode* pNode, sg::DDSEdge* e, sg::DDSNode* n)
00738 {
00739 using namespace sg;
00740
00741
00742 DDSEdgeVect& edges = n->getEdges();
00743 DDSEdgeVect::iterator I;
00744 DDSEdge* ee;
00745 SGNode* pNewNode;
00746 leda_node v;
00747
00748 for(I = edges.begin(); I != edges.end(); I++)
00749 {
00750 ee = *I;
00751
00752 if (e != ee)
00753 {
00754 pNewNode = new SGNode(GetNextIdx(), SHOCK_base);
00755 v = NewNode(pNewNode);
00756 NewEdge(u, v);
00757
00758 CopyNodeInfo(ee, v, pNewNode);
00759 ConnectNodes(v, pNewNode, ee, ee->getN1() != n ? ee->getN1():ee->getN2());
00760 }
00761 }
00762 }
00763
00773 void ShockGraph::RevertEdge(leda_edge pxEdge)
00774 {
00775 leda_node parent = source(pxEdge);
00776 leda_node x = target(pxEdge);
00777 leda_edge e;
00778
00779 rev_edge(pxEdge);
00780
00781
00782
00783 const ShockInfo& inPt = GetJointPoint(parent, x);
00784
00785 forall_adj_edges(e, parent)
00786 if (GetJointPoint(parent, target(e)) == inPt)
00787 move_edge(e, x, target(e));
00788 }
00789
00794 void ShockGraph::Relabel3As2or4(leda_node v)
00795 {
00796 ASSERT(NodeType(v) == SHOCK_3);
00797
00798 int parentType = NodeType(GetFirstParent(v));
00799
00800 if (parentType == ROOT)
00801 UnsafeGetSGNode(v)->SetNodeType(SHOCK_4);
00802 else if(outdeg(v) == 0 && indeg(v) == 2)
00803 UnsafeGetSGNode(v)->SetNodeType(SHOCK_2);
00804
00805
00806
00807 if (compParams.nSlipt3s != 0 && parentType == ROOT)
00808 {
00809 const SGNode& x = *GetSGNode(v);
00810
00811 const ShockInfo& leftPt = x[0];
00812 const ShockInfo& rightPt = x[x.GetSize() - 1];
00813
00814 leda_node leftChild = NewNode(new SGNode(x));
00815 leda_node rightChild = NewNode(new SGNode(x));
00816 leda_edge e;
00817
00818 forall_adj_edges(e, v)
00819 {
00820 if (GetJointPoint(v, target(e)) == leftPt)
00821 move_edge(e, leftChild, target(e));
00822 else
00823 {
00824 ASSERT(GetJointPoint(v, target(e)) == rightPt);
00825 move_edge(e, rightChild, target(e));
00826 }
00827 }
00828
00829
00830 NewEdge(v, rightChild);
00831 NewEdge(v, leftChild);
00832 }
00833 }
00834
00843 void ShockGraph::Insert4sAnd2s()
00844 {
00845 leda_node u, v;
00846 leda_edge e;
00847 bool bAllType1SameDir;
00848 int dir;
00849
00850 forall_nodes(u, *this)
00851 {
00852 if (NodeType(u) == SHOCK_1 && outdeg(u) > 0)
00853 {
00854 bAllType1SameDir = true;
00855 dir = GetBranchDir(u, GetFirstChild(u));
00856
00857
00858 forall_adj_nodes(v, u)
00859 {
00860 if (NodeType(v) != SHOCK_1 || GetBranchDir(v, u) != dir)
00861 {
00862 bAllType1SameDir = false;
00863 break;
00864 }
00865 }
00866
00867 if (bAllType1SameDir)
00868 {
00869 const ShockBranch& pts = GetSGNode(u)->m_shocks;
00870 int type = dir == 1 ? SHOCK_2:SHOCK_4;
00871
00872 if (type == SHOCK_2 && outdeg(u) != 1)
00873 return;
00874
00875 SGNode* pNewNode = new SGNode(GetNextIdx(), type);
00876 pNewNode->m_shocks.AddTail(GetJointPoint(u, GetFirstChild(u)));
00877 pNewNode->ComputeDerivedValues();
00878
00879 bool localMinOrMax = false;
00880
00881
00882
00883 if (type == SHOCK_4)
00884 {
00885 if (pNewNode->m_shocks > GetSGNode(u)->m_shocks)
00886 {
00887 localMinOrMax = true;
00888
00889 forall_adj_nodes(v, u)
00890 {
00891 if (!(pNewNode->m_shocks > GetSGNode(v)->m_shocks))
00892 {
00893 localMinOrMax = false;
00894 break;
00895 }
00896 }
00897 }
00898 }
00899 else if (type == SHOCK_2)
00900 {
00901 if (GetSGNode(u)->m_shocks > pNewNode->m_shocks && GetSGNode(GetFirstChild(u))->m_shocks > pNewNode->m_shocks)
00902 localMinOrMax = true;
00903 }
00904
00905 if (localMinOrMax)
00906 {
00907 v = NewNode(pNewNode);
00908
00909 forall_adj_edges(e, u)
00910 move_edge(e, v, target(e));
00911
00912 NewEdge(u, v);
00913 }
00914 else
00915 delete pNewNode;
00916 }
00917 }
00918 }
00919 }
00920
00921 void ShockGraph::ComputeNodeRole(leda_node v)
00922 {
00923 NODE_ROLE role;
00924 int nType = NodeType(v);
00925
00926 if (nType == ROOT)
00927 role = BIRTH;
00928 else if (nType == SHOCK_2 || (nType == SHOCK_3 && outdeg(v) == 0))
00929 role = UNION;
00930 else if (outdeg(v) == 0)
00931 role = DEATH;
00932 else
00933 role = PROTRUSION;
00934
00935 UnsafeGetSGNode(v)->SetNodeRole(role);
00936 }
00937
00941 sg::DDSkeleton* ShockGraph::ComputeDDSkeleton(const char* szPPMFileName)
00942 {
00943 using namespace sg;
00944
00945 cout << endl << "Reading " << szPPMFileName << "... " << flush;
00946
00947 int i, j, rows, cols, format;
00948 pixval maxval;
00949
00950 FILE* fp = fopen(szPPMFileName, "r");
00951
00952 if (fp == NULL)
00953 {
00954 cerr << "Can't open " << szPPMFileName << endl;
00955 return NULL;
00956 }
00957
00958 ppm_readppminit(fp, &cols, &rows, &maxval, &format);
00959 fclose(fp);
00960
00961
00962 char *a = get_arr(&rows, &cols, szPPMFileName);
00963
00964
00965
00966 sg::SimpleShapeMaker ssm(cols, rows);
00967
00968
00969 for (i=0; i < rows; i++)
00970 for (j=0; j < cols; j++)
00971 ssm(j,i) = a[i*cols + j];
00972
00973
00974 free(a);
00975
00976
00977 SimpleShape ss = *((SimpleShape*)ssm.getShape());
00978
00979
00980 ss.getBounds(&xmin,&xmax, &ymin,&ymax);
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992 DistanceTransform dt(&ss);
00993
00994
00995 DivergenceMap dm(dt);
00996
00997 cout << "making skeleton... " << flush;
00998
00999
01000
01001 DivergenceSkeletonMaker dsm(dm);
01002 double thresh=-2.0, mag=1.0;
01003
01004 ASSERT(compParams.dSkTreshold >= 0);
01005
01006 return dsm.getDiscreteDivergenceSkeleton(1.0 / mag, -compParams.dSkTreshold);
01007 }
01008
01013 void ShockGraph::DetectLigatureNodes(sg::DDSkeleton* sk)
01014 {
01015 using namespace sg;
01016
01017 DDSEdgeVect& edges = sk->getEdges();
01018 DDSEdgeVect::iterator I;
01019 DDSEdge* e;
01020
01021 vector<Curve*>* v = sk->getShape()->getCurves();
01022 Curve* c = *v->begin();
01023 DiscreteSegCurve dsc = *(DiscreteSegCurve *)c;
01024
01025 PRINT(cout, v->size());
01026
01027 for(I = edges.begin(); I != edges.end(); I++)
01028 {
01029 e = *I;
01030
01031 Point pRt1 = dsc.atT(e->rightT1());
01032 Point pRt2 = dsc.atT(e->rightT2());
01033 Point pLt1 = dsc.atT(e->leftT1());
01034 Point pLt2 = dsc.atT(e->leftT2());
01035
01036 PRINT_OPEN(cout, e->hasRight());
01037 PRINT(cout, pRt1);
01038 PRINT(cout, pRt2);
01039 PRINTN(cout, e->hasLeft());
01040 PRINT(cout, pLt1);
01041 PRINT(cout, pLt2);
01042 PRINTN(cout, e->getFluxPoints().front().val);
01043 PRINT_CLOSE(cout, e->getFluxPoints().back().val);
01044 }
01045 }
01046
01053 bool ShockGraph::ComputeSGFromDDSkeleton(sg::DDSkeleton* sk)
01054 {
01055 using namespace sg;
01056
01057 cerr << "labeling skeleton... " << flush;
01058
01059
01060
01061 SGNode* pNode = new SGNode(GetNextIdx(), SHOCK_base);
01062 leda_node u = NewNode(pNode);
01063 DDSEdge* se = *sk->getEdges().begin();
01064
01065 SGNode* pFirstNode = CopyNodeInfo(se, u, pNode);
01066
01067 ConnectNodes(u, pNode, se, se->getN1());
01068 ConnectNodes(u, pFirstNode, se, se->getN2());
01069
01070 Insert4sAnd2s();
01071
01072
01073 bool bContinue;
01074 leda_edge e;
01075 int nNoInfLoop = 0, i;
01076
01077
01078
01079 do
01080 {
01081 ASSERT(nNoInfLoop++ < 1000);
01082 bContinue = false;
01083
01084 forall_edges(e, *this)
01085 {
01086 const ShockBranch& tgt = GetSGNode(target(e))->m_shocks;
01087 const ShockBranch& src = GetSGNode(source(e))->m_shocks;
01088
01089 if (tgt > src)
01090 {
01091 RevertEdge(e);
01092 bContinue = true;
01093 }
01094 }
01095 } while (bContinue);
01096
01097
01098 leda_node root = NewNode(new SGNode("#", ROOT));
01099 leda_node v;
01100 int nodeType;
01101
01102
01103
01104 forall_nodes(v, *this)
01105 {
01106 if (v != root && indeg(v) == 0)
01107 NewEdge(root, v);
01108
01109 nodeType = NodeType(v);
01110
01111 if (nodeType == SHOCK_3)
01112 Relabel3As2or4(v);
01113
01114
01115 ASSERT (nodeType == ROOT ||
01116 nodeType == SHOCK_1 ||
01117 nodeType == SHOCK_3 ||
01118 (nodeType == SHOCK_2 && indeg(v) == 2 && outdeg(v) == 0) ||
01119 (nodeType == SHOCK_4 && indeg(v) == 1 && NodeType(GetFirstParent(v)) == ROOT));
01120
01121 ComputeNodeRole(v);
01122 }
01123
01124 ComputeDerivedValues();
01125
01126 cerr << "(" << GetObjName() << ", " << GetViewNumber() << ") done!" << flush;
01127
01128 return true;
01129 }
01130
01131 bool ShockGraph::ComputeFromPPMFile2(const char* szFileName, const SGCP& sgparams)
01132 {
01133 Clear();
01134
01135 compParams = sgparams;
01136 SetDAGLbl(szFileName);
01137
01138 sg::DDSkeleton* pDDS = ComputeDDSkeleton(szFileName);
01139
01140 if (!pDDS)
01141 return false;
01142
01143 m_pSkeleton = new McGillSkeleton(pDDS);
01144
01145 return ComputeSGFromDDSkeleton(((McGillSkeleton*)m_pSkeleton)->GetSkeleton());
01146 }
01147
01148 bool ShockGraph::RecomputeFromSkeleton(const SGCP& sgparams)
01149 {
01150
01151 String strLbl = GetDAGLbl();
01152 DAG::Clear();
01153 nLastIndexUsed = 0;
01154
01155 compParams = sgparams;
01156 SetDAGLbl(strLbl);
01157
01158 return ComputeSGFromDDSkeleton(((McGillSkeleton*)m_pSkeleton)->GetSkeleton());
01159 }
01160
01161 void SmoothFluxPoints(sg::FluxPointList& fpl, const double& dSigma, const double& dSigmaRange)
01162 {
01163 int i, nLen = fpl.size();
01164
01165 double* in = new double[nLen];
01166 double* out = new double[nLen];
01167
01168 for (i = 0; i < nLen; i++)
01169 in[i] = fpl[i].dist;
01170
01171 GaussianSmooth(in, out, nLen, dSigma, dSigmaRange);
01172
01173 for (i = 0; i < nLen; i++)
01174 fpl[i].dist = out[i];
01175
01176 delete[] in;
01177 delete[] out;
01178 }
01179
01189 void GaussianSmooth(double *input, double *output, int length,
01190 const double& sigma, const double& sigma_range)
01191 {
01192 static double* kernel = NULL;
01193 static double prev_sigma, prev_sigma_range;
01194 static double kernelsum;
01195 static int w2;
01196 int i, x;
01197
01198 if (kernel && (sigma != prev_sigma || sigma_range != prev_sigma_range))
01199 {
01200 delete[] kernel;
01201 kernel = NULL;
01202 }
01203
01204
01205 if (!kernel)
01206 {
01207 w2 = (int)rint(sigma_range * sigma);
01208 if (w2 < 1) w2 = 1;
01209 int w = (2 * w2) + 1;
01210
01211 kernel = new double[w];
01212 kernelsum = 0.0;
01213 prev_sigma = sigma;
01214 prev_sigma_range = sigma_range;
01215
01216 for (double* kp = kernel, x = -w2; x <= w2; kp++,x++)
01217 {
01218 *kp = (1 / (sqrt(2 * M_PI) * sigma)) * exp((double)(x * x)/(-2 * sigma * sigma));
01219 kernelsum += *kp;
01220 }
01221 }
01222
01223 PRINT(cerr, kernelsum);
01224
01225 double sum;
01226
01227
01228 for (x = 0; x < length; x++)
01229 {
01230 sum = 0.0;
01231
01232 for (i = -w2; i <= w2; i++)
01233 {
01234 if ((x + i) < 0){
01235 sum += kernel[i + w2] * input[0];
01236 }
01237 else if ((x + i) >= length){
01238 sum += kernel[i + w2] * input[length - 1];
01239 }
01240 else{
01241 sum += kernel[i + w2] * input[x + i];
01242 }
01243 }
01244
01245 output[x] = sum / kernelsum;
01246 }
01247 }
01248
01253 int ShockGraph::GetBranchDir(leda_node u, leda_node wrtV) const
01254 {
01255 const ShockInfo& pt = GetJointPoint(u, wrtV);
01256
01257 return GetSGNode(u)->GetBranchDir(pt == GetSGNode(u)->m_shocks[0] ?
01258 ShockBranch::FORWARD:ShockBranch::BACKWARD);
01259 }
01260
01261 const ShockInfo& ShockGraph::GetJointPoint(leda_node u, leda_node v) const
01262 {
01263 const SGNode* pNodeU = GetSGNode(u);
01264 const SGNode* pNodeV = GetSGNode(v);
01265
01266 const ShockInfo& uStart = pNodeU->m_shocks[0];
01267 const ShockInfo& uEnd = pNodeU->m_shocks.GetTail();
01268
01269 const ShockInfo& vStart = pNodeV->m_shocks[0];
01270 const ShockInfo& vEnd = pNodeV->m_shocks.GetTail();
01271
01272 if (uStart == vStart || uStart == vEnd)
01273 return uStart;
01274 else if (uEnd == vStart || uEnd == vEnd)
01275 return uEnd;
01276
01277 ASSERT(false);
01278 return vStart;
01279 }
01280
01281
01282