//---------------------------------------------------------------------------- // EgalTech 2019-2019 //---------------------------------------------------------------------------- // File : ExportStl.cpp Data : 15.09.19 Versione : 2.1i2 // Contenuto : Implementazione della classe per l'esportazione in formato SVG. // // // // Modifiche : 15.09.19 DS Creazione modulo. // // //---------------------------------------------------------------------------- //--------------------------- Include ---------------------------------------- #include "stdafx.h" #include "ExportSvg.h" #include "DllMain.h" #include "/EgtDev/Include/EExDllMain.h" #include "/EgtDev/Include/EGkGeomDB.h" #include "/EgtDev/Include/EGkGeoPoint3d.h" #include "/EgtDev/Include/EGkCurveLine.h" #include "/EgtDev/Include/EGkCurveArc.h" #include "/EgtDev/Include/EGkCurveBezier.h" #include "/EgtDev/Include/EGkCurveComposite.h" #include "/EgtDev/Include/EGkSurfFlatRegion.h" #include "/EgtDev/Include/EGkSurfTriMesh.h" #include "/EgtDev/Include/EGkExtText.h" #include "/EgtDev/Include/EGkGdbIterator.h" #include "/EgtDev/Include/EGkStringUtils3d.h" #include "/EgtDev/Include/EGnStringUtils.h" #include "/EgtDev/Include/SELkKeyProc.h" #include "/EgtDev/Include/EgtKeyCodes.h" #include "/EgtDev/Include/EgtStringConverter.h" #include "/EgtDev/Include/EgtPointerOwner.h" #include using namespace std ; //---------------------------------------------------------------------------- IExportSvg* CreateExportSvg( void) { // verifico la chiave e le opzioni if ( ! VerifyKey( KEYOPT_EEX_EXPBASE)) return nullptr ; // creo l'oggetto return static_cast ( new(nothrow) ExportSvg) ; } //---------------------------------------------------------------------------- bool ExportSvg::SetOptions( int nFilter) { m_nFilter = nFilter ; return true ; } //---------------------------------------------------------------------------- bool ExportSvg::Export( IGeomDB* pGDB, int nId, const string& sFile) { // verifico il DB geometrico if ( pGDB == nullptr) { LOG_ERROR( GetEExLogger(), "ExportSvg : Error on GeomDB") return false ; } // verifico l'Id dell'oggetto da esportare if ( ! pGDB->ExistsObj( nId)) { LOG_ERROR( GetEExLogger(), "ExportSvg : Error on Id") return false ; } // apro il file di testo in scrittura m_Writer.Close() ; if ( ! m_Writer.Init( sFile)) { LOG_ERROR( GetEExLogger(), "ExportSvg : Error on open file") return false ; } // Inizializzazioni m_vtMove = V_NULL ; m_usNames.clear() ; bool bOk = true ; // recupero l'elenco degli oggetti da esportare e il loro ingombro totale INTDBLVECTOR vEnt ; BBox3d b3All ; CalcEntBBox( pGDB, nId, vEnt, b3All) ; // ordino gli oggetti secondo la Z crescente stable_sort( vEnt.begin(), vEnt.end(), []( const INTDBL& a, const INTDBL& b) { return a.second < b.second ; }) ; // scrivo la sezione di intestazione double dDimX = b3All.GetDimX() ; double dDimY = b3All.GetDimY() ; if ( ! ExportHeader( dDimX, dDimY)) bOk = false ; // scrivo le entità if ( ! ExportEntities( pGDB, vEnt, b3All)) bOk = false ; // terminazione file if ( ! ExportFooter()) bOk = false ; // chiudo il file if ( ! m_Writer.Close()) bOk = false ; return bOk ; } //---------------------------------------------------------------------------- bool ExportSvg::CalcEntBBox( IGeomDB* pGDB, int nId, INTDBLVECTOR& vEnt, BBox3d& b3Box) { // reset del bounding box b3Box.Reset() ; // creo un iteratore PtrOwner pIter( CreateGdbIterator( pGDB)) ; if ( IsNull( pIter)) return false ; pIter->GoTo( nId) ; // eseguo il calcolo return CalcGdbObjectEntBBox( *pIter, vEnt, b3Box) ; } //---------------------------------------------------------------------------- bool ExportSvg::CalcGdbObjectEntBBox( const IGdbIterator& iIter, INTDBLVECTOR& vEnt, BBox3d& b3Box) { // se gruppo if ( iIter.GetGdbType() == GDB_TY_GROUP) { // esploro il gruppo return CalcGdbGroupEntBBox( iIter, vEnt, b3Box) ; } // se oggetto geometrico else if ( iIter.GetGdbType() == GDB_TY_GEO) { // recupero il livello dell'oggetto int nLev = GDB_LV_USER ; iIter.GetCalcLevel( nLev) ; // recupero il modo dell'oggetto int nMode = GDB_MD_STD ; iIter.GetCalcMode( nMode) ; // recupero lo stato dell'oggetto int nStat = GDB_ST_ON ; iIter.GetCalcStatus( nStat) ; // se il filtro lo abilita if ( TestFilter( nLev, nMode, nStat)) { BBox3d b3Tmp ; if ( iIter.GetGlobalBBox( b3Tmp, BBF_EXACT)) { vEnt.emplace_back( iIter.GetId(), ( b3Tmp.GetMin().z + b3Tmp.GetMax().z) / 2) ; b3Box.Add( b3Tmp) ; } } return true ; } // altrimenti errore else return false ; } //---------------------------------------------------------------------------- bool ExportSvg::CalcGdbGroupEntBBox( const IGdbIterator& iIter, INTDBLVECTOR& vEnt, BBox3d& b3Box) { // creo un iteratore PtrOwner pIter( CreateGdbIterator( iIter.GetGDB())) ; if ( IsNull( pIter)) return false ; // scandisco il gruppo bool bOk = true ; for ( bool bNext = pIter->GoToFirstInGroup( iIter) ; bNext ; bNext = pIter->GoToNext()) { if ( ! CalcGdbObjectEntBBox( *pIter, vEnt, b3Box)) bOk = false ; } return bOk ; } //---------------------------------------------------------------------------- bool ExportSvg::ExportHeader( double dDimX, double dDimY) { if ( ! m_Writer.OutText( "")) return false ; const double MIN_DIM = 10 ; dDimX = max( dDimX, MIN_DIM) ; dDimY = max( dDimY, MIN_DIM) ; const double COEFF = 0.05 ; double dExtraX = COEFF * dDimX ; double dExtraY = COEFF * dDimY ; string sOut = "" ; if ( ! m_Writer.OutText( sOut)) return false ; return true ; } //---------------------------------------------------------------------------- bool ExportSvg::ExportFooter( void) { if ( ! m_Writer.OutText( "")) return false ; return true ; } //---------------------------------------------------------------------------- bool ExportSvg::ExportEntities( IGeomDB* pGDB, const INTDBLVECTOR& vEnt, const BBox3d& b3All) { // determino il vettore movimento (le Z sono ignorate) m_vtMove = ( b3All.IsEmpty() ? V_NULL : Point3d( 0, 0, 0) - Point3d( b3All.GetMin().x, b3All.GetMax().y, 0)) ; // ciclo sulle entità da esportare bool bOk = true ; for ( int i = 0 ; i < int( vEnt.size()) ; ++i) { // recupero l'oggetto geometrico const IGeoObj* pGeoObj = pGDB->GetGeoObj( vEnt[i].first) ; if ( pGeoObj == nullptr) { bOk = false ; continue ; } // recupero il riferimento globale dell'oggetto Frame3d frFrame ; if ( ! pGDB->GetGlobFrame( vEnt[i].first, frFrame)) { bOk = false ; continue ; } // recupero eventuale nome string sName = "" ; if ( pGDB->GetName( vEnt[i].first, sName)) { if ( m_usNames.find( sName) == m_usNames.end()) m_usNames.emplace( sName) ; else sName += "_" + ToString( vEnt[i].first) ; } else sName += "_" + ToString( vEnt[i].first) ; // recupero il colore Color colObj ; pGDB->GetCalcMaterial( vEnt[i].first, colObj) ; // emetto l'oggetto switch ( pGeoObj->GetType()) { case GEO_PNT3D : if ( ! ExportPoint( sName, colObj, pGeoObj, frFrame)) bOk = false ; break ; case CRV_LINE : if ( ! ExportLine( sName, colObj, pGeoObj, frFrame)) bOk = false ; break ; case CRV_ARC : if ( ! ExportArc( sName, colObj, pGeoObj, frFrame, false)) bOk = false ; break ; case CRV_BEZIER : if ( ! ExportBezier( sName, colObj, pGeoObj, frFrame, false)) bOk = false ; break ; case CRV_COMPO : if ( ! ExportComposite( sName, colObj, pGeoObj, frFrame, false)) bOk = false ; break ; case SRF_FLATRGN : if ( ! ExportFlatRegion( sName, colObj, pGeoObj, frFrame)) bOk = false ; break ; case SRF_TRIMESH : if ( ! ExportTriMesh( sName, colObj, pGeoObj, frFrame)) bOk = false ; break ; case EXT_TEXT : if ( ! ExportText( sName, colObj, pGeoObj, frFrame)) bOk = false ; break ; } } return bOk ; } //---------------------------------------------------------------------------- bool ExportSvg::TestFilter( int nLev, int nMode, int nStat) { if ( ( nLev == GDB_LV_USER && ( m_nFilter & EEXFLT_LEVUSER) == 0) || ( nLev == GDB_LV_SYSTEM && ( m_nFilter & EEXFLT_LEVSYSTEM) == 0) || ( nLev == GDB_LV_TEMP && ( m_nFilter & EEXFLT_LEVTEMP) == 0)) return false ; if ( ( nMode == GDB_MD_STD && ( m_nFilter & EEXFLT_MODESTD) == 0) || ( nMode == GDB_MD_LOCKED && ( m_nFilter & EEXFLT_MODELOCKED) == 0) || ( nMode == GDB_MD_HIDDEN && ( m_nFilter & EEXFLT_MODEHIDDEN) == 0)) return false ; if ( ( nStat == GDB_ST_OFF && ( m_nFilter & EEXFLT_STAOFF) == 0) || ( nStat == GDB_ST_ON && ( m_nFilter & EEXFLT_STAON) == 0) || ( nStat == GDB_ST_SEL && ( m_nFilter & EEXFLT_STASEL) == 0)) return false ; return true ; } //---------------------------------------------------------------------------- bool ExportSvg::ExportPoint( const string& sName, const Color& colObj, const IGeoObj* pGeoObj, const Frame3d& frFrame) { // verifico oggetto const IGeoPoint3d* pGpt = GetGeoPoint3d( pGeoObj) ; if ( pGpt == nullptr) return false ; // lo copio e lo porto in globale PtrOwner pMyGpt( pGpt->Clone()) ; if ( IsNull( pMyGpt)) return false ; pMyGpt->ToGlob( frFrame) ; // assegno tipo string sOut = " GetPoint() ; ptCen.ToGlob( frFrame) ; ptCen += m_vtMove ; sOut += " cx=\"" + ToString( ptCen.x, 3) + "\" cy=\"" + ToString( -ptCen.y, 3) + "\" r=\"2\"" ; // colore e spessore sOut += " fill=\"" + GetColorString( colObj) + "\" stroke=\"" + GetColorString( colObj) + "\" stroke-width=\"1\"" ; // termino sOut += " />" ; // emetto return m_Writer.OutText( sOut) ; } //---------------------------------------------------------------------------- static bool AddLink( const Point3d& ptStart, const Vector3d& vtDir, double dLen, const Frame3d& frFrame, ICRVLINEPOVECTOR& vLink) { if ( ! ptStart.IsValid() || vtDir.IsSmall() || abs( dLen) < 2 * EPS_SMALL) return false ; vLink.emplace_back( CreateCurveLine()) ; vLink.back()->SetPVL( ptStart, vtDir, dLen) ; vLink.back()->ToGlob( frFrame) ; return true ; } //---------------------------------------------------------------------------- bool ExportSvg::ExportLine( const string& sName, const Color& colObj, const IGeoObj* pGeoObj, const Frame3d& frFrame) { // verifico oggetto const ICurveLine* pLine = GetCurveLine( pGeoObj) ; if ( pLine == nullptr) return false ; // la copio e la porto in globale PtrOwner pMyLine( pLine->Clone()) ; if ( IsNull( pMyLine)) return false ; pMyLine->ToGlob( frFrame) ; // eventuali curve per spessore e collegamenti PtrOwner pMyLine2 ; ICRVLINEPOVECTOR vMyLink ; Vector3d vtExtr ; double dThick ; if ( pLine->GetExtrusion( vtExtr) && ! vtExtr.IsSmallXY() && pLine->GetThickness( dThick) && abs( dThick) > EPS_SMALL) { // curva sullo spessore pMyLine2.Set( pLine->Clone()) ; if ( IsNull( pMyLine2)) return false ; pMyLine2->Translate( dThick * vtExtr) ; pMyLine2->ToGlob( frFrame) ; // collegamenti for ( double dU = 0 ; dU < 1 + EPS_PARAM ; dU += 1) { Point3d ptP ; pLine->GetPointD1D2( dU, ICurve::FROM_MINUS, ptP) ; AddLink( ptP, vtExtr, dThick, frFrame, vMyLink) ; } } // porto nel piano XY globale (se si riduce ad un punto la salto) if ( ! pMyLine->Scale( GLOB_FRM, 1, 1, 0)) return true ; // trasformo anche l'eventuale copia if ( ! IsNull( pMyLine2)) pMyLine2->Scale( GLOB_FRM, 1, 1, 0) ; // trasformo anche gli eventuali collegamenti for ( auto& pLink : vMyLink) pLink->Scale( GLOB_FRM, 1, 1, 0) ; // questo oggetto non può avere fill bool bFill = false ; // assegno tipo string sOut = " pMyCompo( CreateCurveComposite()) ; if ( IsNull( pMyCompo)) return false ; pMyCompo->AddCurve( *pArc) ; pMyCompo->ToGlob( frFrame) ; // eventuali curve per spessore e collegamenti PtrOwner pMyCompo2 ; ICRVLINEPOVECTOR vMyLink ; Vector3d vtExtr ; double dThick ; if ( pArc->GetExtrusion( vtExtr) && ! vtExtr.IsSmallXY() && pArc->GetThickness( dThick) && abs( dThick) > EPS_SMALL) { // curva sullo spessore pMyCompo2.Set( CreateCurveComposite()) ; if ( IsNull( pMyCompo2)) return false ; pMyCompo2->AddCurve( *pArc) ; pMyCompo2->Translate( dThick * vtExtr) ; pMyCompo2->ToGlob( frFrame) ; // collegamenti for ( double dU = 0 ; dU < 1 + EPS_PARAM ; dU += 0.25) { Point3d ptP ; pArc->GetPointD1D2( dU, ICurve::FROM_MINUS, ptP) ; AddLink( ptP, vtExtr, dThick, frFrame, vMyLink) ; } } // verifico se la curva giace in un piano parallelo a XY globale Plane3d plPlane ; if ( ! pMyCompo->IsFlat( plPlane, false, 10 * EPS_SMALL) || ! AreSameOrOppositeVectorApprox( plPlane.GetVersN(), Z_AX)) { // porto nel piano XY globale pMyCompo->Scale( GLOB_FRM, 1, 1, 0) ; // trasformo anche l'eventuale copia if ( ! IsNull( pMyCompo2)) pMyCompo2->Scale( GLOB_FRM, 1, 1, 0) ; // trasformo anche gli eventuali collegamenti for ( auto& pLink : vMyLink) pLink->Scale( GLOB_FRM, 1, 1, 0) ; } // assegno tipo string sOut = " pMyBez( pBez->Clone()) ; if ( IsNull( pMyBez)) return false ; pMyBez->ToGlob( frFrame) ; // eventuali curve per spessore e collegamenti PtrOwner pMyBez2 ; ICRVLINEPOVECTOR vMyLink ; Vector3d vtExtr ; double dThick ; if ( pBez->GetExtrusion( vtExtr) && ! vtExtr.IsSmallXY() && pBez->GetThickness( dThick) && abs( dThick) > EPS_SMALL) { // curva sullo spessore pMyBez2.Set( pBez->Clone()) ; if ( IsNull( pMyBez2)) return false ; pMyBez2->Translate( dThick * vtExtr) ; pMyBez2->ToGlob( frFrame) ; // collegamenti for ( double dU = 0 ; dU < 1 + EPS_PARAM ; dU += 0.25) { Point3d ptP ; pBez->GetPointD1D2( dU, ICurve::FROM_MINUS, ptP) ; AddLink( ptP, vtExtr, dThick, frFrame, vMyLink) ; } } // verifico se la curva giace in un piano parallelo a XY globale Plane3d plPlane ; if ( ! pMyBez->IsFlat( plPlane, false, 10 * EPS_SMALL) || ! AreSameOrOppositeVectorApprox( plPlane.GetVersN(), Z_AX)) { // la porto nel piano XY globale (se si riduce ad un punto la salto) if ( ! pMyBez->Scale( GLOB_FRM, 1, 1, 0)) return true ; // trasformo anche l'eventuale copia if ( ! IsNull( pMyBez2)) pMyBez2->Scale( GLOB_FRM, 1, 1, 0) ; // trasformo anche gli eventuali collegamenti for ( auto& pLink : vMyLink) pLink->Scale( GLOB_FRM, 1, 1, 0) ; } // assegno tipo string sOut = " pMyCompo( pCompo->Clone()) ; if ( IsNull( pMyCompo)) return false ; pMyCompo->ToGlob( frFrame) ; // eventuali curve per spessore e collegamenti PtrOwner pMyCompo2 ; ICRVLINEPOVECTOR vMyLink ; Vector3d vtExtr ; double dThick ; if ( pCompo->GetExtrusion( vtExtr) && ! vtExtr.IsSmallXY() && pCompo->GetThickness( dThick) && abs( dThick) > EPS_SMALL) { // curva sullo spessore pMyCompo2.Set( pCompo->Clone()) ; if ( IsNull( pMyCompo2)) return false ; pMyCompo2->Translate( dThick * vtExtr) ; pMyCompo2->ToGlob( frFrame) ; // collegamenti const ICurve* pSmpCrv = pCompo->GetFirstCurve() ; while ( pSmpCrv != nullptr) { // tipo di curva int nType = pSmpCrv->GetType() ; // step sui collegamenti a seconda del tipo double dDelta = 1 ; if ( nType == CRV_ARC) dDelta = 0.5 ; else if ( nType == CRV_BEZIER) dDelta = 0.25 ; // calcolo i collegamenti for ( double dU = 0 ; dU < 1 - EPS_PARAM ; dU += dDelta) { Point3d ptP ; pSmpCrv->GetPointD1D2( dU, ICurve::FROM_MINUS, ptP) ; AddLink( ptP, vtExtr, dThick, frFrame, vMyLink) ; } // passo alla curva successiva pSmpCrv = pCompo->GetNextCurve() ; } Point3d ptEnd ; pCompo->GetEndPoint( ptEnd) ; AddLink( ptEnd, vtExtr, dThick, frFrame, vMyLink) ; } // verifico se la curva giace in un piano parallelo a XY globale Plane3d plPlane ; if ( ! pMyCompo->IsFlat( plPlane, false, 10 * EPS_SMALL) || ! AreSameOrOppositeVectorApprox( plPlane.GetVersN(), Z_AX)) { // la porto nel piano XY globale (se si riduce ad un punto la salto) if ( ! pMyCompo->Scale( GLOB_FRM, 1, 1, 0)) return true ; // trasformo anche l'eventuale copia if ( ! IsNull( pMyCompo2)) pMyCompo2->Scale( GLOB_FRM, 1, 1, 0) ; // trasformo anche gli eventuali collegamenti for ( auto& pLink : vMyLink) pLink->Scale( GLOB_FRM, 1, 1, 0) ; } // assegno tipo string sOut = " GetNormVersor() ; vtN.ToGlob( frFrame) ; if ( vtN.z < EPS_SMALL) return true ; // questo oggetto deve avere fill bool bFill = true ; // assegno tipo string sOut = " GetChunkCount() ; ++ nC) { // ciclo sui loop for ( int nL = 0 ; nL < pSfr->GetLoopCount( nC) ; ++ nL) { // recupero il loop PtrOwner pLoop( pSfr->GetLoop( nC, nL)) ; if ( IsNull( pLoop)) return false ; // porto la curva in globale pLoop->ToGlob( frFrame) ; // se necessario, proietto sul piano XY globale if ( ! AreSameOrOppositeVectorApprox( vtN, Z_AX)) { // se arco devo convertirlo in composita if ( pLoop->GetType() == CRV_ARC) { PtrOwner pMyCompo( CreateCurveComposite()) ; if ( IsNull( pMyCompo)) return false ; pMyCompo->AddCurve( Release( pLoop)) ; pLoop.Set( pMyCompo) ; } pLoop->Scale( GLOB_FRM, 1, 1, 0) ; } // punto iniziale sOut += GetStartString( pLoop) ; // curva if ( pLoop->GetType() == CRV_LINE) sOut += GetCurveString( GetCurveLine( pLoop)) ; else if ( pLoop->GetType() == CRV_ARC) sOut += GetCurveString( GetCurveArc( pLoop)) ; else if ( pLoop->GetType() == CRV_BEZIER) sOut += GetCurveString( GetCurveBezier( pLoop)) ; else if ( pLoop->GetType() == CRV_COMPO) sOut += GetCurveString( GetCurveComposite( pLoop)) ; else return false ; } } // termino i dati geometrici sOut += "\"" ; // colore e spessore sOut += " fill=\"" + ( bFill ? GetColorString( colObj) : "none") + "\" fill-opacity=\"" + ToString( colObj.GetAlpha(), 2) + "\" stroke=\"" + GetColorString( colObj) + "\" stroke-opacity=\"" + ToString( colObj.GetAlpha(), 2) + "\" stroke-width=\"1\"" ; // termino sOut += " />" ; // emetto return m_Writer.OutText( sOut) ; } //---------------------------------------------------------------------------- bool ExportSvg::ExportTriMesh( const string& sName, const Color& colObj, const IGeoObj* pGeoObj, const Frame3d& frFrame) { // verifico oggetto const ISurfTriMesh* pStm = GetSurfTriMesh( pGeoObj) ; if ( pStm == nullptr) return false ; // almeno una faccia deve guardare verzo Z+ globale bool bTop = false ; for ( int nF = 0 ; nF < pStm->GetFacetCount() ; ++ nF) { Vector3d vtN ; if ( pStm->GetFacetNormal( nF, vtN) && vtN.ToGlob( frFrame) && vtN.z > EPS_SMALL) { bTop = true ; break ; } } if ( ! bTop) return true ; // questo oggetto deve avere fill bool bFill = true ; // assegno tipo string sOut = " GetFacetCount() ; ++ nF) { // verifico che guardi verso l'alto Vector3d vtN ; if ( ! pStm->GetFacetNormal( nF, vtN) || ! vtN.ToGlob( frFrame) || vtN.z < EPS_SMALL) continue ; POLYLINEVECTOR vPL ; if ( ! pStm->GetFacetLoops( nF, vPL)) continue ; // ciclo sui loop di una faccia for ( int nL = 0 ; nL < int( vPL.size()) ; ++ nL) { PtrOwner pLoop( CreateCurveComposite()) ; if ( IsNull( pLoop) || ! pLoop->FromPolyLine( vPL[nL])) return false ; // porto in globale pLoop->ToGlob( frFrame) ; // punto iniziale sOut += GetStartString( pLoop) ; // curva sOut += GetCurveString( pLoop) ; } } // termino i dati geometrici sOut += "\"" ; // colore e spessore sOut += " fill=\"" + ( bFill ? GetColorString( colObj) : "none") + "\" fill-opacity=\"" + ToString( colObj.GetAlpha(), 2) + "\" stroke=\"" + GetColorString( colObj) + "\" stroke-opacity=\"" + ToString( colObj.GetAlpha(), 2) + "\" stroke-width=\"1\"" ; // termino sOut += " />" ; // emetto return m_Writer.OutText( sOut) ; } //---------------------------------------------------------------------------- bool ExportSvg::ExportText( const string& sName, const Color& colObj, const IGeoObj* pGeoObj, const Frame3d& frFrame) { // verifico oggetto const IExtText* pText = GetExtText( pGeoObj) ; if ( pText == nullptr) return false ; // verifico giacitura nel piano XY Vector3d vtN = pText->GetNormVersor() ; vtN.ToGlob( frFrame) ; if ( ! AreSameOrOppositeVectorApprox( vtN, Z_AX)) return true ; // assegno tipo string sOut = " GetStartPoint( ptStart) ; ptStart.ToGlob( frFrame) ; ptStart += m_vtMove ; sOut += " transform=\"translate(" + ToString( ptStart.x, 3) + "," + ToString( -ptStart.y, 3) + ")" ; // eventuale rotazione Vector3d vtDir = pText->GetDirVersor() ; vtDir.ToGlob( frFrame) ; double dAngH ; vtDir.ToSpherical( nullptr, nullptr, &dAngH) ; sOut += "rotate(" + ToString( -dAngH, 3) + ")\"" ; // famiglia del font string sFont = pText->GetFont() ; sOut += " font-family=\"" + sFont + "\"" ; // dimensione del font double dH = pText->GetHeight() ; sOut += " font-size=\"" + ToString( dH, 3) + "\"" ; // lunghezza suggerita Point3d ptEnd ; pText->GetEndPoint( ptEnd) ; ptEnd.ToGlob( frFrame) ; ptEnd += m_vtMove ; double dLen = DistXY( ptStart, ptEnd) ; sOut += " textLength=\"" + ToString( dLen, 3) + "\"" ; // colore sOut += " fill=\"" + GetColorString( colObj) + "\">" ; // recupero il contenuto e converto i caratteri speciali string sText = pText->GetText() ; ReplaceString( sText, "&", "&") ; ReplaceString( sText, "<", "<") ; sOut += sText ; // termino sOut += "" ; // emetto return m_Writer.OutText( sOut) ; } //---------------------------------------------------------------------------- string ExportSvg::GetStartString( const ICurve* pCrv) { // verifica if ( pCrv == nullptr) return "" ; Point3d ptStart ; pCrv->GetStartPoint( ptStart) ; ptStart += m_vtMove ; return " M " + ToString( ptStart.x, 3) + "," + ToString( -ptStart.y, 3) ; } //---------------------------------------------------------------------------- string ExportSvg::GetCurveString( const ICurveLine* pLine) { // verifica if ( pLine == nullptr) return "" ; // recupero il punto finale Point3d ptEnd = pLine->GetEnd() ; ptEnd += m_vtMove ; // aggiungo il punto return " L " + ToString( ptEnd.x, 3) + "," + ToString( -ptEnd.y, 3) ; } //---------------------------------------------------------------------------- string ExportSvg::GetCurveString( const ICurveArc* pArc) { // verifica if ( pArc == nullptr) return "" ; // recupero i dati geometrici dell'arco (estremi, angolo al centro e senso) Point3d ptStart ; pArc->GetStartPoint( ptStart) ; ptStart += m_vtMove ; Point3d ptEnd ; pArc->GetEndPoint( ptEnd) ; ptEnd += m_vtMove ; double dRad = pArc->GetRadius() ; bool bCCW = ( ( pArc->GetAngCenter() > 0 && pArc->GetNormVersor().IsZplus()) || ( pArc->GetAngCenter() < 0 && pArc->GetNormVersor().IsZminus())) ; // se arco esportabile in una parte if ( abs( pArc->GetAngCenter()) <= ANG_STRAIGHT + 10 * EPS_ANG_SMALL) { return " A " + ToString( dRad, 3) + "," + ToString( dRad, 3) + " 0 0," + ( bCCW ? "0 " : "1 ") + ToString( ptEnd.x, 3) + "," + ToString( -ptEnd.y, 3) ; } // altrimenti lo esporto in due parti else { // recupero il punto medio Point3d ptMid ; pArc->GetMidPoint( ptMid) ; ptMid += m_vtMove ; return " A " + ToString( dRad, 3) + "," + ToString( dRad, 3) + " 0 0," + ( bCCW ? "0 " : "1 ") + ToString( ptMid.x, 3) + "," + ToString( -ptMid.y, 3) + " A " + ToString( dRad, 3) + "," + ToString( dRad, 3) + " 0 0," + ( bCCW ? "0 " : "1 ") + ToString( ptEnd.x, 3) + "," + ToString( -ptEnd.y, 3) ; } } //---------------------------------------------------------------------------- string ExportSvg::GetCurveString( const ICurveBezier* pBez) { // verifica if ( pBez == nullptr) return "" ; // approssimo con archi e rette const double BEZ_LIN_APPROX = 0.01 ; const double BEZ_ANG_APPROX_DEG = 5.0 ; PtrOwner pCC( CreateCurveComposite()) ; PolyArc PA ; if ( ! pBez->ApproxWithArcs( BEZ_LIN_APPROX, BEZ_ANG_APPROX_DEG, PA) || ! pCC->FromPolyArc( PA)) return "" ; return GetCurveString( pCC) ; } //---------------------------------------------------------------------------- string ExportSvg::GetCurveString( const ICurveComposite* pCompo) { // verifica if ( pCompo == nullptr) return "" ; // ciclo sulle curve elementari string sOut ; const ICurve* pCrv = pCompo->GetFirstCurve() ; while ( pCrv != nullptr) { if ( pCrv->GetType() == CRV_LINE) sOut += GetCurveString( GetCurveLine( pCrv)) ; else if ( pCrv->GetType() == CRV_ARC) sOut += GetCurveString( GetCurveArc( pCrv)) ; else if ( pCrv->GetType() == CRV_BEZIER) sOut += GetCurveString( GetCurveBezier( pCrv)) ; else return "" ; pCrv = pCompo->GetNextCurve() ; } return sOut ; } //---------------------------------------------------------------------------- string ExportSvg::GetColorString( const Color& colObj) { string sCol = "rgb(" + ToString( colObj.GetIntRed()) + "," + ToString( colObj.GetIntGreen()) + "," + ToString( colObj.GetIntBlue()) + ")" ; return sCol ; }