// (Steve) #include using namespace std; #include "mathlib.h" #include "datalib.h" #include "slices.h" #define EPS_AREA .000001 // intersection and related routines SliceContourType CComponent::FindType(CList *pCListVerts) { FLOAT fNormalZ; BOOL result; result = CalculateNormalZ(&fNormalZ, pCListVerts); if (!result) return ctUnknown; if (fNormalZ >= 0) { if (fNormalZ < EPS_AREA) return ctUnknown; else return ctOuter; } else { // if (fNormalZ < 0) { if (fNormalZ > -EPS_AREA) return ctUnknown; else return ctInner; } } BOOL CComponent::CalculateNormalZ(FLOAT *pfNormalZ, CList *pCListVerts) { BOOL bCorrect; CListIter ListIter; Point *pPt; Point ptStart, ptPrev, ptCurr; bCorrect = TRUE; ListIter.Init(pCListVerts); *pfNormalZ = 0.0; pPt = ListIter.PeekFirst(); if (pPt) ptStart = *pPt; else return FALSE; ptPrev = ptStart; for ( pPt = ListIter.PeekNext(); pPt != NULL; pPt = ListIter.PeekNext()) { ptCurr = *pPt; *pfNormalZ += (ptPrev[Y] + ptCurr[Y])*(ptPrev[X] - ptCurr[X]); ptPrev = ptCurr; } ptCurr = ptStart; *pfNormalZ += (ptPrev[Y] + ptCurr[Y])*(ptPrev[X] - ptCurr[X]); return bCorrect; } VOID CComponent::NewPtInComponent(Point *pPt, CList *pCListVerts, UINT_32 *puiCounter, FLOAT fZ) { CComponent *pComponent = this; pCListVerts->InsertLast(pPt, 0); // OutputVertex((*puiCounter)++, pPt); #ifndef NDISPLAY glVertex3f((*pPt)(X), (*pPt)(Y), fZ); #endif if ((*pPt)(X) < pComponent->GetMinX()) pComponent->SetMinX((*pPt)(X)); if ((*pPt)(X) > pComponent->GetMaxX()) pComponent->SetMaxX((*pPt)(X)); if ((*pPt)(Y) < pComponent->GetMinY()) pComponent->SetMinY((*pPt)(Y)); if ((*pPt)(Y) > pComponent->GetMaxY()) pComponent->SetMaxY((*pPt)(Y)); } FLOAT FindArea(CList *pVertices) { return 0.0; } ////////////////////////////////////////////////////////////////////////////// // CComponent Class // CComponent::CComponent() { m_ctType = ctUnknown; m_ppClistContour = NULL; m_pClistContained = NULL; m_pCComponentContainer = NULL; m_fMinX = 0; m_fMaxX = 0; m_fMinY = 0; m_fMaxY = 0; m_uiFirstID = 0; m_uiLastID = 0; } VOID CComponent::Uninit() { m_ctType = ctUnknown; // Note that this doesn't free the contour list itself; it's a handle delete m_ppClistContour; InvalidateNesting(); m_fMinX = 0; m_fMaxX = 0; m_fMinY = 0; m_fMaxY = 0; m_uiFirstID = 0; m_uiLastID = 0; } VOID CComponent::RemoveFromContainer() { if (m_pCComponentContainer) { CList *pClistContained = m_pCComponentContainer->GetContained(); ASSERT(pClistContained); pClistContained->Remove(this); if (pClistContained->GetLength() == 0) { delete pClistContained; m_pCComponentContainer-> SetContained((CList *)NULL); } m_pCComponentContainer = NULL; } } VOID CComponent::SetContainerMutual(CComponent *pContainer) { CList *pListContained; SetContainer(pContainer); if (pContainer) { if (!(pListContained = pContainer->GetContained())) { pListContained = new CList; pListContained->Init(); pContainer->SetContained(pListContained); } pListContained->InsertLast(this, 0); } } VOID CComponent::InvalidateNesting() { // Null container pointers from each of the contained ones, then // delete the contained list. CListIter *pListIter; CComponent *pCComponentContained; // remove refs to it from all components it contains & delete contained list if (m_pClistContained) { pListIter = new CListIter; pListIter->Init(m_pClistContained); pCComponentContained = (CComponent *)pListIter->PeekFirst(); while (pCComponentContained) { ASSERT(pCComponentContained->GetContainer() == this); pCComponentContained->SetContainer((CComponent *)NULL); pCComponentContained = (CComponent *)pListIter->PeekNext(); } delete pListIter; delete (m_pClistContained); } m_pClistContained = NULL; // Remove ourself from container's contained list, then null container RemoveFromContainer(); } FLOAT CComponent::CalculateArea() { CCircObjectListIter IterContour; CList *pVertices; Point *pPtCur; CContourElt *pContEltCur, *pContEltFirst; CSliceInfo *pInfo; IterContour.Init(*m_ppClistContour); pVertices = new CList; pVertices->Init(); pContEltCur = pContEltFirst = IterContour.PeekFirst(); do { pInfo = (CSliceInfo *)(pContEltCur->GetEdge()->GetExtra()); if (pInfo->GetColinear() != TRUE) { pPtCur = pInfo->GetLastPt(); pVertices->InsertLast(pPtCur, 0); } pContEltCur = IterContour.PeekNext(); } while (pContEltFirst != pContEltCur); FLOAT area = FindArea(pVertices); return area; } VOID CComponent:: IntersectContour(FLOAT fZ, FLOAT fThickness, FLOAT fEps) { CComponent *pComponent = this; CCircObjectList *pCircListContour; CContourElt *pContEltCurr, *pContEltFirst; CCircObjectListIter *IterContour; static UINT_32 uiCounter = 1; Point *pPtCurr, *pPtPrev; Point *pPtFirst;//, *pPtSecond; #ifndef NDISPLAY Point *pPtFirstOut = NULL; #endif BOOL b2DiffPts = FALSE, b3DiffPts = FALSE; CLEDSliteEdgeUse *pledsEUCurr; CList *pCListVerts; CListIter ListIter; #ifdef REMOVE_COLINEAR Vector vCur, vPrev, vFirst; FLOAT fvCurLength, fvPrevLength, fvFirstLength; CLEDSliteEdgeUse *pledsEUPrev, *pledsEUFirst; fEps = .001f; // = m_fEps; #endif if ((!pComponent) || (!(pCircListContour = pComponent->GetContour())) ) return; pComponent->SetMinX(FLT_MAX); pComponent->SetMaxX(-FLT_MAX); pComponent->SetMinY(FLT_MAX); pComponent->SetMaxY(-FLT_MAX); pComponent->SetFirstID(uiCounter); pCListVerts = new CList; pCListVerts->Init(); IterContour = new CCircObjectListIter; IterContour->Init(pCircListContour); pContEltFirst = (CContourElt *) IterContour->PeekFirst(); pledsEUCurr = pContEltFirst->GetEdge(); #ifdef REMOVE_COLINEAR pledsEUFirst = pledsEUPrev = pledsEUCurr; #endif pPtFirst = pPtPrev = pPtCurr = ((CSliceInfo *)pledsEUCurr->GetExtra())-> UpdatePt(fZ, pledsEUCurr, fThickness); pContEltCurr = (CContourElt *) IterContour->PeekNext(); // hopefully, contours have more than one edge. ASSERT(pContEltCurr != pContEltFirst); do { pledsEUCurr = pContEltCurr->GetEdge(); pPtCurr = ((CSliceInfo *)pledsEUCurr->GetExtra())-> UpdatePt(fZ, pledsEUCurr, fThickness); if (pPtCurr && (pPtFirst == NULL)) { pPtFirst = pPtPrev = pPtCurr; #ifdef REMOVE_COLINEAR pledsEUFirst = pledsEUPrev = pledsEUCurr; #endif } // else if (pPtCurr && pPtPrev && (!(pPtCurr->EpsEq(*pPtPrev, fEps)))) { else if (pPtCurr && pPtPrev && ((*pPtCurr) != (*pPtPrev))) { #ifdef REMOVE_COLINEAR vCur = *pPtCurr - *pPtPrev; fvCurLength = vCur.Magnitude(); vCur.Normalize(); #endif if (!b2DiffPts) { // we haven't found 2nd distinct pt till now #ifdef REMOVE_COLINEAR vFirst = vCur; fvFirstLength = fvCurLength; #endif b2DiffPts = TRUE; } else if (b2DiffPts && (!b3DiffPts)) { // if (pPtCurr->EpsEq(*pPtFirst, fEps)) { if ((*pPtCurr)==(*pPtFirst)) { b2DiffPts = FALSE; } #ifdef REMOVE_COLINEAR else if (vCur == -vFirst) { // it's the new second point, and vector from first to second // may have reversed, so recalculate vCur = *pPtCurr - *pPtFirst; fvCurLength = vCur.Magnitude(); vCur.Normalize(); } // if vector neither equal nor opposite, now have 3 non-colinear pts else if (vCur != vFirst) { #else else { #endif b3DiffPts = TRUE; #ifndef NDISPLAY glBegin(GL_LINE_STRIP); #endif } } if (b3DiffPts) { #ifdef REMOVE_COLINEAR if (vCur != vPrev) { pComponent->NewPtInComponent(pPtPrev, pCListVerts, &uiCounter, fZ); #ifndef NDISPLAY if (pPtFirstOut == NULL) pPtFirstOut = pPtPrev; #endif } else { if ((fvCurLength > fEps) && (fvPrevLength > fEps)) ((CSliceInfo *)pledsEUPrev->GetExtra())->SetColinear(TRUE); } #else pComponent->NewPtInComponent(pPtPrev, pCListVerts, &uiCounter, fZ); #ifndef NDISPLAY if (pPtFirstOut == NULL) pPtFirstOut = pPtPrev; #endif #endif } #ifdef REMOVE_COLINEAR vPrev = vCur; fvPrevLength = fvCurLength; pledsEUPrev = pledsEUCurr; #endif pPtPrev = pPtCurr; } // if (*pPtCurr != *pPtPrev) pContEltCurr = (CContourElt *) IterContour->PeekNext(); } while (pContEltCurr != pContEltFirst) ; delete IterContour; if (!b3DiffPts) { pComponent->SetType(ctUnknown); pComponent->InvalidateNesting(); } else { // output first and last points if appropriate // if (!(pPtFirst->EpsEq(*pPtPrev,fEps))) { if ((*pPtFirst)!=(*pPtPrev)) { #ifdef REMOVE_COLINEAR vCur = *pPtFirst - *pPtPrev; fvCurLength = vCur.Magnitude(); vCur.Normalize(); if (vCur != vPrev) { pComponent->NewPtInComponent(pPtPrev, pCListVerts, &uiCounter, fZ); } else { if ((fvCurLength > fEps) && (fvPrevLength > fEps)) ((CSliceInfo *)pledsEUPrev->GetExtra())->SetColinear(TRUE); } if (vCur != vFirst) { pComponent->NewPtInComponent(pPtFirst, pCListVerts, &uiCounter, fZ); } else { if ((fvCurLength > fEps) && (fvFirstLength > fEps)) ((CSliceInfo *)pledsEUFirst->GetExtra())->SetColinear(TRUE); } #else pComponent->NewPtInComponent(pPtPrev, pCListVerts, &uiCounter, fZ); pComponent->NewPtInComponent(pPtFirst, pCListVerts, &uiCounter, fZ); #endif } else { #ifdef REMOVE_COLINEAR if (vPrev != vFirst) { pComponent->NewPtInComponent(pPtFirst, pCListVerts, &uiCounter, fZ); } else { if ((fvPrevLength > fEps) && (fvFirstLength > fEps)) ((CSliceInfo *)pledsEUFirst->GetExtra())->SetColinear(TRUE); } #else pComponent->NewPtInComponent(pPtFirst, pCListVerts, &uiCounter, fZ); #endif } if (pComponent->GetType() == ctUnknown) { /* DeriveType sometimes will give the wrong answer for a zero-area polygon; FindType is probably more reliable. if (pComponent->DeriveType() != FindType(pCListVerts)) { ASSERT(FALSE); } */ // pComponent->SetType(pComponent->DeriveType()); pComponent->SetType(FindType(pCListVerts)); } pComponent->SetLastID(uiCounter - 1); #ifndef NDISPLAY if (pPtFirstOut) glVertex3f((*pPtFirstOut)(X), (*pPtFirstOut)(Y), fZ); glEnd(); #endif #ifdef DEBUGAREA FLOAT fArea = pComponent->CalculateArea(); fprintf(stdout, "Area is %f\n", fArea); #endif } // delete pCListVerts; // return pCListVerts; // BUG!? Do I need to free the space for the points? // delete m_pCListVerts; m_pCListVerts = pCListVerts; }