text: // (C) Copyright 1996-2006 by Autodesk, Inc. 
  //
  // Permission to use, copy, modify, and distribute this software in
  // object code form for any purpose and without fee is hereby granted, 
  // provided that the above copyright notice appears in all copies and 
  // that both that copyright notice and the limited warranty and
  // restricted rights notice below appear in all supporting 
  // documentation.
  //
  // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 
  // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
  // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE.  AUTODESK, INC. 
  // DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
  // UNINTERRUPTED OR ERROR FREE.
  //
  // Use, duplication, or disclosure by the U.S. Government is subject to 
  // restrictions set forth in FAR 52.227-19 (Commercial Computer
  // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
  // (Rights in Technical Data and Computer Software), as applicable.
  //
  // DESCRIPTION:
  //
  // Brep dump utilities.
  
  #include "brsample_pch.h"  //precompiled header
  
  
  
  // Abbreviations
  #include "acdbabb.h"
  
  
  
  
  // local function prototypes
  static AcBr::ErrorStatus brepDumpDown	(const AcBrBrep& brepEntity);
  static AcBr::ErrorStatus brepDumpUp		(const AcBrBrep& brepEntity);
  
  
  AcBr::ErrorStatus
  brepDump(const AcBrBrep& brepEntity)
  { 
      AcBr::ErrorStatus returnValue = AcBr::eOk;
  
  	// Validate the brep vs. the brep "owner"
  	AcBrBrep brepOwner;
  	returnValue = brepEntity.getBrep(brepOwner);
  	if (returnValue != AcBr::eOk) {
  		acutPrintf(ACRX_T("\n Error in AcBrBrep::getBrep:"));
  		errorReport(returnValue);
  		return returnValue;
  	}
  	if (!brepEntity.isEqualTo(&brepOwner)) {
  		acutPrintf(ACRX_T("\n Brep owner is out of sync with brep!"));
  		return (AcBr::ErrorStatus)Acad::eAmbiguousOutput;
  	}
  
  	// Query traversal direction for brep dump 
  	Adesk::Boolean downwards = Adesk::kTrue;
      ACHAR opt[128];
     	while (Adesk::kTrue) {
  		acutPrintf(ACRX_T("\nSelect Traversal Direction for Brep Dump: "));
  		acedInitGet(NULL, ACRX_T("Upwards Downwards"));
  		if (acedGetKword(ACRX_T("Upwards/<Downwards>: "), opt) == RTCAN)
  			return returnValue;
  
          // Map the user input to a valid traversal direction
  		if ((_tcscmp(opt, ACRX_T("Downwards")) == 0) || (_tcscmp(opt, ACRX_T("")) == 0)) {
              downwards = Adesk::kTrue;
              break;
          } else if ((_tcscmp(opt, ACRX_T("Upwards")) == 0)) {
              downwards = Adesk::kFalse;
              break;
  	    }
      }
  
  	// Switchable dump based on upwards vs. downwards traversal
  	if (downwards) brepDumpDown(brepEntity);
  	else brepDumpUp(brepEntity);
  
  	return returnValue;
  }
  
  
  static AcBr::ErrorStatus
  brepDumpDown(const AcBrBrep& brepEntity)
  { 
      AcBr::ErrorStatus returnValue = AcBr::eOk;
  
  	// make a global complex traverser
  	AcBrBrepComplexTraverser brepComplexTrav;
  	returnValue = brepComplexTrav.setBrep(brepEntity);
  	if (returnValue != AcBr::eOk) {
  		acutPrintf(ACRX_T("\n Error in AcBrBrepComplexTraverser::setBrep:"));
  		errorReport(returnValue);
  		return returnValue;
  	}
  
  	// dump the complexes
  	int complexCount = 0;
  	while (!brepComplexTrav.done() && (returnValue == AcBr::eOk)) {
  	    complexCount++;
  	    acutPrintf(ACRX_T("\n *Complex No: %d \n"), complexCount);
  
  		// make a complex shell traverser
  		AcBrComplexShellTraverser complexShellTrav;
  		returnValue = complexShellTrav.setComplex(brepComplexTrav);
  		if (returnValue != AcBr::eOk) {
  			acutPrintf(ACRX_T("\n Error in AcBrComplexShellTraverser::setComplex:"));
  			errorReport(returnValue);
  			return returnValue;
  		}
  
  		// dump the shells
  		int shellCount = 0;
  		while (!complexShellTrav.done() && (returnValue == AcBr::eOk)) {
  			shellCount++;
  			acutPrintf(ACRX_T("\n **Shell No: %d \n"), shellCount);
  
  			AcBrShell shell;
  			returnValue = complexShellTrav.getShell(shell);
  			 if (returnValue != AcBr::eOk) {	
  				acutPrintf(ACRX_T("\n Error in AcBrComplexShellTraverser::getShell:")); 
  				errorReport(returnValue);
  				return returnValue;
  			}
  			AcBr::ShellType stype;
  			shell.getType(stype);
  			shellTypeReport(stype);
  
  			// make a shell face traverser
  			AcBrShellFaceTraverser shellFaceTrav;
  			returnValue = shellFaceTrav.setShell(complexShellTrav);
  			if (returnValue != AcBr::eOk) {
  				acutPrintf(ACRX_T("\n Error in AcBrShellFaceTraverser::setShell:"));
  				errorReport(returnValue);
  				return returnValue;
  			}
  
  			// count the faces
  			int faceCount = 0;
  			while (!shellFaceTrav.done() && (returnValue == AcBr::eOk)) {
  				faceCount++;
  				acutPrintf(ACRX_T("\n ***Face No: %d \n"), faceCount);
  
  				AcBrFace currentFace;
  				returnValue = shellFaceTrav.getFace(currentFace);
  				if (returnValue != AcBr::eOk) {
  					acutPrintf(ACRX_T("\n Error in AcBrShellFaceTraverser::getFace:"));
  					errorReport(returnValue);
  					return returnValue;
  				}
  
      			// make sure that comparing different types returns kFalse
  				// rather than crashing!
  				if (currentFace.isEqualTo(&brepEntity)) {
  					acutPrintf(ACRX_T("\n Brep and face have the same contents (impossible!)"));
  					return (AcBr::ErrorStatus)eAmbiguousOutput;
  				}
  
  				int loopCount = 0;
  				AcBrFaceLoopTraverser faceLoopTrav;
  				returnValue = faceLoopTrav.setFace(shellFaceTrav);
  				if (returnValue != AcBr::eOk) {
  					// eDegenerateTopology means intrinsically bounded (e.g., sphere, torus)  
  					if (returnValue != AcBr::eDegenerateTopology) {
  						acutPrintf(ACRX_T("\n Error in AcBrFaceLoopTraverser::setFace:")); 
  						errorReport(returnValue);
  						return returnValue;
  					} else returnValue = AcBr::eOk;
  				} else while (!faceLoopTrav.done() && (returnValue == AcBr::eOk)) { 
  					loopCount++;
  					acutPrintf(ACRX_T("\n ****Loop No: %d \n"), loopCount);
  
  					AcBrLoop loop;
  					returnValue = faceLoopTrav.getLoop(loop);
  					 if (returnValue != AcBr::eOk) {	
  						acutPrintf(ACRX_T("\n Error in AcBrFaceLoopTraverser::getLoop:")); 
  						errorReport(returnValue);
  						return returnValue;
  					}
  					AcBr::LoopType ltype;
  					loop.getType(ltype);
  					loopTypeReport(ltype);
  
  					int edgeCount = 0;
  					AcBrLoopEdgeTraverser loopEdgeTrav;
  	    			returnValue = loopEdgeTrav.setLoop(faceLoopTrav);
  					if ((returnValue != AcBr::eOk) && (returnValue != AcBr::eDegenerateTopology)) {	 
  						// eDegenerateTopology means this edge is a singularity (loop-vertex)
  						acutPrintf(ACRX_T("\n Error in AcBrLoopEdgeTraverser::setLoop:")); 
  						errorReport(returnValue);
  						return returnValue;
  					} else while (!loopEdgeTrav.done() && (returnValue == AcBr::eOk)) { 
  						edgeCount++; 
  						acutPrintf(ACRX_T("\n *****Edge No: %d \n"), edgeCount);
  
  						AcBrEdge edgeEntity;
  						returnValue = loopEdgeTrav.getEdge(edgeEntity);
  						if (returnValue != AcBr::eOk) {
  							acutPrintf(ACRX_T("\n Error in AcBrLoopEdgeTraverser::getEdge:"));
  							errorReport(returnValue);
  							return returnValue;
  						}
  
      					// validate the 3d model space curve associated with this edge
              			AcGeCurve3d* curveGeometry = NULL;
  						AcGeCurve3d* nativeGeometry = NULL;
  
              			returnValue = getNativeOrientedCurve(loopEdgeTrav, curveGeometry, nativeGeometry);  
              			if (returnValue != AcBr::eOk) {
              				acutPrintf(ACRX_T("\n Error in getNativeOrientedCurve:"));
              				errorReport(returnValue);
  							delete curveGeometry;
  							delete nativeGeometry;
  							return returnValue;
              			}
  				
      					// validate the 2d parameter space curve associated with this edge
      					AcGeCurve2d* pcurveGeometry =  NULL;
      					AcGeNurbCurve2d nurbGeometry;
      					returnValue = getNativeParamCurve(loopEdgeTrav, pcurveGeometry, nurbGeometry);
      					if (returnValue != AcBr::eOk) {
      						acutPrintf(ACRX_T("\n Error in getNativeParamCurve:"));
      						errorReport(returnValue);
  							delete pcurveGeometry;
  							return returnValue;
      					}
  						if (pcurveGeometry != NULL) {
  							// Determine if the model space curve and parameter space curve
  							// agree in their orientation (2d curves are presented in loop perspective)
              				AcGeInterval crvIntrvl;
              				((AcGeExternalCurve3d*)curveGeometry)->getInterval(crvIntrvl);
              				AcGeInterval pcrvIntrvl;
              				((AcGeExternalCurve2d*)pcurveGeometry)->getInterval(pcrvIntrvl);
  							if (crvIntrvl != pcrvIntrvl) {
  								if ((crvIntrvl.upperBound() == -pcrvIntrvl.lowerBound())
  									&& (crvIntrvl.lowerBound() == -pcrvIntrvl.upperBound())) {
                  					acutPrintf(ACRX_T("\n ******Edge No. %d: Curve and Pcurve Orientations Oppose\n"),
                  						edgeCount);
  								} else {
                  					acutPrintf(ACRX_T("\n ******Edge No. %d: Curve and Pcurve Parameter Bounds Differ\n"),
                  						edgeCount);
                  					acutPrintf(ACRX_T(" *******Curve Parameterisation is ("));
  									acutPrintf(ACRX_T("%lf, "), crvIntrvl.lowerBound());
  									acutPrintf(ACRX_T("%lf "), crvIntrvl.upperBound());
  									acutPrintf(ACRX_T(")\n"));
                  					acutPrintf(ACRX_T(" *******Parameter Curve Parameterisation is ("));
  									acutPrintf(ACRX_T("%lf, "), pcrvIntrvl.lowerBound());
  									acutPrintf(ACRX_T("%lf "), pcrvIntrvl.upperBound());
  									acutPrintf(ACRX_T(")\n"));
  								}
  							}
  						}
  						delete pcurveGeometry;
  						delete curveGeometry;
  						delete nativeGeometry;
  
  						// Inform of any negated orientations, since the model space curve
  						// is returned as is (no curve reversal for usage by surface boundary)
              			Adesk::Boolean edgeOriented, loopOriented;
              			returnValue = loopEdgeTrav.getEdgeOrientToLoop(loopOriented);
              			if (returnValue != AcBr::eOk) {
              				acutPrintf(ACRX_T("\n Error in AcBrLoopEdgeTraverser::getEdgeOrientToLoop:"));
  							errorReport(returnValue);
              				return returnValue;
              			} 
              			returnValue = edgeEntity.getOrientToCurve(edgeOriented);
              			if (returnValue != AcBr::eOk) {
              				acutPrintf(ACRX_T("\n Error in AcBrEdge::getOrientToCurve:"));
  							errorReport(returnValue);
              				return returnValue;
              			} 
              			if (!loopOriented ^ !edgeOriented) {
              				acutPrintf(ACRX_T("\n ******Edge No. %d: Curve Orientation in Loop is Negative\n"),
              					edgeCount);
              			}
  
  						returnValue = loopEdgeTrav.next();
  						if (returnValue != AcBr::eOk) {
  							acutPrintf(ACRX_T("\n Error in AcBrLoopEdgeTraverser::next:"));
  							errorReport(returnValue);
  							return returnValue;
  		    			}
  					} // end edge while
  
  					acutPrintf(ACRX_T("\n *****Loop No. %d has %d edges\n"), loopCount, edgeCount);	  
  
  					int vtxCount = 0;
  					AcBrLoopVertexTraverser loopVtxTrav;
  	    			returnValue = loopVtxTrav.setLoop(faceLoopTrav);
  					if (returnValue != AcBr::eOk) {	 
  						acutPrintf(ACRX_T("\n Error in AcBrLoopVertexTraverser::setLoop:")); 
  						errorReport(returnValue);
  						return returnValue;
  					} else while (!loopVtxTrav.done() && (returnValue == AcBr::eOk)) { 
  						vtxCount++; 
  						acutPrintf(ACRX_T("\n *****Vertex No: %d \n"), vtxCount);
  
  						AcBrVertex loopPoint;
  						returnValue = loopVtxTrav.getVertex(loopPoint);
  						if (returnValue != AcBr::eOk) {
  							acutPrintf(ACRX_T("\n Error in AcBrLoopVertexTraverser::getVertex:"));
  							errorReport(returnValue);
  							return returnValue;
  						}
  						acutPrintf(ACRX_T("\nCoordinate of loop vertex: "));
  						returnValue = vertexDump(loopPoint);
  						if (returnValue != AcBr::eOk) {
  							acutPrintf(ACRX_T("\n Error in vertexDump:"));
  							errorReport(returnValue);
  							return returnValue;
  						}
  						
  						returnValue = loopVtxTrav.next();
  						if (returnValue != AcBr::eOk) {
  							acutPrintf(ACRX_T("\n Error in AcBrLoopVertexTraverser::next:"));
  							errorReport(returnValue);
  							return returnValue;
  		    			}
  					} // end vertex while
  
  					acutPrintf(ACRX_T("\n *****Loop No. %d has %d vertices\n"), loopCount, vtxCount);	  
  
  					returnValue = faceLoopTrav.next();
  	    			if (returnValue != AcBr::eOk) {
  		    			acutPrintf(ACRX_T("\n Error in AcBrFaceLoopTraverser::next:"));
  						errorReport(returnValue);
  						return returnValue;
  					}
      			} // end loop while
  
  				acutPrintf(ACRX_T("\n ****Face No. %d has %d loops\n"), faceCount, loopCount);	  
  
  				returnValue = shellFaceTrav.next();
  				if (returnValue != AcBr::eOk) {
  					acutPrintf(ACRX_T("\n Error in AcBrShellFaceTraverser::next:"));  
  					errorReport(returnValue);
  					return returnValue;
  				}
  
  			} // end face while
  
  			acutPrintf(ACRX_T("\n ***Shell No. %d has %d faces\n"), shellCount, faceCount);	  
  
  			returnValue = complexShellTrav.next();
  			if (returnValue != AcBr::eOk) {
  				acutPrintf(ACRX_T("\n Error in AcBrComplexShellTraverser::next:"));  
  				errorReport(returnValue);
  				return returnValue;
  			}
  
  		} // end shell while
  
  		acutPrintf(ACRX_T("\n **Complex No. %d has %d shells\n"), complexCount, shellCount);	  
  
  		returnValue = brepComplexTrav.next();
  		if (returnValue != AcBr::eOk) {
  			acutPrintf(ACRX_T("\n Error in AcBrBrepComplexTraverser::next:"));  
  			errorReport(returnValue);
  			return returnValue;
  		}
  
  	} // end complex while
  
  	acutPrintf(ACRX_T("\n *Brep has %d complexes\n"), complexCount);	  
  
  	return returnValue;
  }
  
  
  static AcBr::ErrorStatus
  brepDumpUp(const AcBrBrep& brepEntity)
  { 
      AcBr::ErrorStatus returnValue = AcBr::eOk;
  
  	// make a global vertex traverser
  	AcBrBrepVertexTraverser brepVtxTrav;
  	returnValue = brepVtxTrav.setBrep(brepEntity);
  	if (returnValue != AcBr::eOk) {
  		acutPrintf(ACRX_T("\n Error in AcBrBrepVertexTraverser::setBrep:"));
  		errorReport(returnValue);
  		return returnValue;
  	}
  
  	// dump the context around the vertices
  	int vtxCount = 0;
  	while (!brepVtxTrav.done() && (returnValue == AcBr::eOk)) {
  	    vtxCount++;
  	    acutPrintf(ACRX_T("\n *Vertex No: %d \n"), vtxCount);
  
  		AcBrVertex currentVertex;
  		returnValue = brepVtxTrav.getVertex(currentVertex);
  		if (returnValue != AcBr::eOk) {
  		    acutPrintf(ACRX_T("\n Error in AcBrBrepVertexTraverser::getVertex:"));
  			errorReport(returnValue);
  			return returnValue;
  		}
  
          int edgeCount = 0;
  		AcBrVertexEdgeTraverser vtxEdgeTrav;
  	    returnValue = vtxEdgeTrav.setVertex(currentVertex);
  		if (returnValue != AcBr::eOk) {
  			if (returnValue != AcBr::eDegenerateTopology) {	 
  				acutPrintf(ACRX_T("\n Error in AcBrVertexEdgeTraverser::setVertex:")); 
  				errorReport(returnValue);
  				return returnValue;
  			} else {
  				// eDegenerateTopology means this vertex is a singularity (vertex-loop)
  				AcBrVertexLoopTraverser vtxLoopTrav;
  				returnValue = vtxLoopTrav.setVertex(currentVertex);
  				if (returnValue != AcBr::eOk) {
  					acutPrintf(ACRX_T("\n Error in AcBrVertexLoopTraverser::setVertex:"));
  					errorReport(returnValue);
  					return returnValue;
  				} else {
  					AcBrLoop vtxLoop;
  					returnValue = vtxLoopTrav.getLoop(vtxLoop);
  				    if (returnValue != AcBr::eOk) {
  						acutPrintf(ACRX_T("\n Error in AcBrVertexLoopTraverser::getLoop:"));
  						errorReport(returnValue);
  						return returnValue;
  					}
              	    acutPrintf(ACRX_T("\n **Vertex No. %d is a vertex loop\n"), vtxCount);	  
  				} // end vertex loop
  			}
  		} else while (!vtxEdgeTrav.done() && (returnValue == AcBr::eOk)) { 
              edgeCount++; 
  		    acutPrintf(ACRX_T("\n **Edge No: %d \n"), edgeCount);
  
  			AcBrEdge edgeEntity;
  			returnValue = vtxEdgeTrav.getEdge(edgeEntity);
  			if (returnValue != AcBr::eOk) {
  				acutPrintf(ACRX_T("\n Error in AcBrVertexEdgeTraverser::getEdge:"));
  				errorReport(returnValue);
  				return returnValue;
  			}
  
  			AcBrEdgeLoopTraverser edgeLoopTrav;
  		    returnValue = edgeLoopTrav.setEdge(vtxEdgeTrav);
  		    if (returnValue != AcBr::eOk) {
  				acutPrintf(ACRX_T("\n Error in AcBrEdgeLoopTraverser::setEdge:"));
  			    errorReport(returnValue);
  				return returnValue;
  			}
  
              // count the radial faces around an edge
  		    int adjacentFaces = 0;
  			while (!edgeLoopTrav.done() && (returnValue == AcBr::eOk)) {
  			    adjacentFaces++;
  			    returnValue  = edgeLoopTrav.next();
      			if (returnValue != AcBr::eOk) {
      				acutPrintf(ACRX_T("\n Error in AcBrEdgeLoopTraverser::next:"));
      				errorReport(returnValue);
      				return returnValue;
                  }
  			} // end radial face while	 
  
  		    acutPrintf(ACRX_T("\n ***Edge No. %d has %d adjacent faces\n"),
  		        edgeCount, adjacentFaces);
  
  			returnValue = vtxEdgeTrav.next();
  			if (returnValue != AcBr::eOk) {
  				acutPrintf(ACRX_T("\n Error in AcBrVertexEdgeTraverser::next:"));
  				errorReport(returnValue);
  				return returnValue;
  		    }
  		} // end edge while
  
  	    acutPrintf(ACRX_T("\n **Vertex No. %d has %d edges\n"), vtxCount, edgeCount);	  
  
          // count the radial faces around a vertex
  		int adjacentFaces = 0;
  		AcBrVertexLoopTraverser vtxLoopTrav;
  	    returnValue = vtxLoopTrav.setVertex(currentVertex);
  		if (returnValue != AcBr::eOk) {
  			if (returnValue != AcBr::eDegenerateTopology) {	 
  				acutPrintf(ACRX_T("\n Error in AcBrVertexLoopTraverser::setVertex:")); 
  				errorReport(returnValue);
  				return returnValue;
  			}
  		} else while (!vtxLoopTrav.done() && (returnValue == AcBr::eOk)) { 
              adjacentFaces++; 
  			returnValue = vtxLoopTrav.next();
  			if (returnValue != AcBr::eOk) {
  				acutPrintf(ACRX_T("\n Error in AcBrVertexLoopTraverser::next:"));
  				errorReport(returnValue);
  				return returnValue;
  		    }
  		} // end radial face while
  
  	    acutPrintf(ACRX_T("\n **Vertex No. %d has %d adjacent faces\n"), vtxCount, adjacentFaces);	  
  
  		returnValue = brepVtxTrav.next();
  		if (returnValue != AcBr::eOk) {
  			acutPrintf(ACRX_T("\n Error in AcBrBrepVertexTraverser::next:"));  
  			errorReport(returnValue);
  			return returnValue;
  		}
  	}  // end vertex while
  
  	acutPrintf(ACRX_T("\n *Brep has %d vertices\n"), vtxCount);	  
  
  	return returnValue;
  }
  
  