Files
Dario Sassi f54f1f8969 EgtExchange 2.6l1 :
- aggiunta importazione formato OFF (Object File Format).
2024-11-29 18:18:28 +01:00

964 lines
33 KiB
C++

//----------------------------------------------------------------------------
// 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/EgtStringConverter.h"
#include "/EgtDev/Include/EgtPointerOwner.h"
#include <fstream>
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<IExportSvg*> ( 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<IGdbIterator> 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<IGdbIterator> 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( "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"))
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 = "<svg viewBox=\"" + ToString( - dExtraX, 0) + " " + ToString( - dExtraY, 0) + " " +
ToString( dDimX + 2 * dExtraX, 0) + " " + ToString( dDimY + 2 * dExtraY, 0) + "\"" +
" xmlns=\"http://www.w3.org/2000/svg\">" ;
if ( ! m_Writer.OutText( sOut))
return false ;
return true ;
}
//----------------------------------------------------------------------------
bool
ExportSvg::ExportFooter( void)
{
if ( ! m_Writer.OutText( "</svg>"))
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<IGeoPoint3d> pMyGpt( pGpt->Clone()) ;
if ( IsNull( pMyGpt))
return false ;
pMyGpt->ToGlob( frFrame) ;
// assegno tipo
string sOut = " <circle" ;
// aggiungo nome e Id
sOut += " id=\"" + sName + "\"" ;
// punto centro
Point3d ptCen = pGpt->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<ICurveLine> pMyLine( pLine->Clone()) ;
if ( IsNull( pMyLine))
return false ;
pMyLine->ToGlob( frFrame) ;
// eventuali curve per spessore e collegamenti
PtrOwner<ICurveLine> 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 = " <path" ;
// aggiungo nome e Id
sOut += " id=\"" + sName + "\"" ;
// aggiungo inizio dati geometrici
sOut += " d=\"" ;
// punto iniziale
sOut +=GetStartString( pMyLine) ;
// arco
sOut += GetCurveString( pMyLine) ;
// eventuale curva copia per spessore
if ( ! IsNull( pMyLine2)) {
sOut += GetStartString( pMyLine2) ;
sOut += GetCurveString( pMyLine2) ;
}
// eventuali collegamenti per spessore
for ( const auto& pLink : vMyLink) {
sOut += GetStartString( pLink) ;
sOut += GetCurveString( pLink) ;
}
// termino i dati geometrici
sOut += "\"" ;
// colore e spessore
sOut += " fill=\"" + ( bFill ? GetColorString( colObj) : "none") + "\" stroke=\"" + GetColorString( colObj) + "\" stroke-width=\"1\"" ;
// termino
sOut += " />" ;
// emetto
return m_Writer.OutText( sOut) ;
}
//----------------------------------------------------------------------------
bool
ExportSvg::ExportArc( const string& sName, const Color& colObj, const IGeoObj* pGeoObj, const Frame3d& frFrame, bool bFill)
{
// verifico oggetto
const ICurveArc* pArc = GetCurveArc( pGeoObj) ;
if ( pArc == nullptr)
return false ;
// lo copio e lo porto in globale
PtrOwner<ICurveComposite> pMyCompo( CreateCurveComposite()) ;
if ( IsNull( pMyCompo))
return false ;
pMyCompo->AddCurve( *pArc) ;
pMyCompo->ToGlob( frFrame) ;
// eventuali curve per spessore e collegamenti
PtrOwner<ICurveComposite> 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 = " <path" ;
// aggiungo nome e Id
sOut += " id=\"" + sName + "\"" ;
// aggiungo inizio dati geometrici
sOut += " d=\"" ;
// punto iniziale
sOut +=GetStartString( pMyCompo) ;
// arco
sOut += GetCurveString( pMyCompo) ;
// eventuale curva copia per spessore
if ( ! IsNull( pMyCompo2)) {
sOut += GetStartString( pMyCompo2) ;
sOut += GetCurveString( pMyCompo2) ;
}
// eventuali collegamenti per spessore
for ( const auto& pLink : vMyLink) {
sOut += GetStartString( pLink) ;
sOut += GetCurveString( pLink) ;
}
// termino i dati geometrici
sOut += "\"" ;
// colore e spessore
sOut += " fill=\"" + ( bFill ? GetColorString( colObj) : "none") + "\" stroke=\"" + GetColorString( colObj) + "\" stroke-width=\"1\"" ;
// termino
sOut += " />" ;
// emetto
return m_Writer.OutText( sOut) ;
}
//----------------------------------------------------------------------------
bool
ExportSvg::ExportBezier( const string& sName, const Color& colObj, const IGeoObj* pGeoObj, const Frame3d& frFrame, bool bFill)
{
// verifico oggetto
const ICurveBezier* pBez = GetCurveBezier( pGeoObj) ;
if ( pBez == nullptr)
return false ;
// la copio e la porto in globale
PtrOwner<ICurveBezier> pMyBez( pBez->Clone()) ;
if ( IsNull( pMyBez))
return false ;
pMyBez->ToGlob( frFrame) ;
// eventuali curve per spessore e collegamenti
PtrOwner<ICurveBezier> 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 = " <path" ;
// aggiungo nome e Id
sOut += " id=\"" + sName + "\"" ;
// aggiungo inizio dati geometrici
sOut += " d=\"" ;
// punto iniziale
sOut +=GetStartString( pMyBez) ;
// curva di Bezier
sOut += GetCurveString( pMyBez) ;
// eventuale curva copia per spessore
if ( ! IsNull( pMyBez2)) {
sOut += GetStartString( pMyBez2) ;
sOut += GetCurveString( pMyBez2) ;
}
// eventuali collegamenti per spessore
for ( const auto& pLink : vMyLink) {
sOut += GetStartString( pLink) ;
sOut += GetCurveString( pLink) ;
}
// termino i dati geometrici
sOut += "\"" ;
// colore e spessore
sOut += " fill=\"" + ( bFill ? GetColorString( colObj) : "none") + "\" stroke=\"" + GetColorString( colObj) + "\" stroke-width=\"1\"" ;
// termino
sOut += " />" ;
// emetto
return m_Writer.OutText( sOut) ;
}
//----------------------------------------------------------------------------
bool
ExportSvg::ExportComposite( const string& sName, const Color& colObj, const IGeoObj* pGeoObj, const Frame3d& frFrame, bool bFill)
{
// verifico oggetto
const ICurveComposite* pCompo = GetCurveComposite( pGeoObj) ;
if ( pCompo == nullptr)
return false ;
// la copio e la porto in globale
PtrOwner<ICurveComposite> pMyCompo( pCompo->Clone()) ;
if ( IsNull( pMyCompo))
return false ;
pMyCompo->ToGlob( frFrame) ;
// eventuali curve per spessore e collegamenti
PtrOwner<ICurveComposite> 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 = " <path" ;
// aggiungo nome e Id
sOut += " id=\"" + sName + "\"" ;
// aggiungo inizio dati geometrici
sOut += " d=\"" ;
// punto iniziale
sOut += GetStartString( pMyCompo) ;
// curva composita
sOut += GetCurveString( pMyCompo) ;
// eventuale curva copia per spessore
if ( ! IsNull( pMyCompo2)) {
sOut += GetStartString( pMyCompo2) ;
sOut += GetCurveString( pMyCompo2) ;
}
// eventuali collegamenti per spessore
for ( const auto& pLink : vMyLink) {
sOut += GetStartString( pLink) ;
sOut += GetCurveString( pLink) ;
}
// termino i dati geometrici
sOut += "\"" ;
// colore e spessore
sOut += " fill=\"" + ( bFill ? GetColorString( colObj) : "none") + "\" stroke=\"" + GetColorString( colObj) + "\" stroke-width=\"1\"" ;
// termino
sOut += " />" ;
// emetto
return m_Writer.OutText( sOut) ;
}
//----------------------------------------------------------------------------
bool
ExportSvg::ExportFlatRegion( const string& sName, const Color& colObj, const IGeoObj* pGeoObj, const Frame3d& frFrame)
{
// verifico oggetto
const ISurfFlatRegion* pSfr = GetSurfFlatRegion( pGeoObj) ;
if ( pSfr == nullptr)
return false ;
// verifico che almeno in parte guardi verso Z+ globale
Vector3d vtN = pSfr->GetNormVersor() ;
vtN.ToGlob( frFrame) ;
if ( vtN.z < EPS_SMALL)
return true ;
// questo oggetto deve avere fill
bool bFill = true ;
// assegno tipo
string sOut = " <path" ;
// aggiungo nome e Id
sOut += " id=\"" + sName + "\"" ;
// aggiungo inizio dati geometrici
sOut += " d=\"" ;
// ciclo sui chunk
for ( int nC = 0 ; nC < pSfr->GetChunkCount() ; ++ nC) {
// ciclo sui loop
for ( int nL = 0 ; nL < pSfr->GetLoopCount( nC) ; ++ nL) {
// recupero il loop
PtrOwner<ICurve> 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<ICurveComposite> 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 = " <path" ;
// aggiungo nome e Id
sOut += " id=\"" + sName + "\"" ;
// aggiungo inizio dati geometrici
sOut += " d=\"" ;
// ciclo sulle facce
for ( int nF = 0 ; nF < pStm->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<ICurveComposite> 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 = " <text" ;
// aggiungo nome e Id
sOut += " id=\"" + sName + "\"" ;
// recupero posizione
Point3d ptStart ; pText->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, "&", "&#38;") ;
ReplaceString( sText, "<", "&#60;") ;
sOut += sText ;
// termino
sOut += "</text>" ;
// 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<ICurveComposite> 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 ;
}