<commit_before>/*
    This file is part of the kolab resource - the implementation of the
    Kolab storage format. See www.kolab.org for documentation on this.

    Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include "kolabbase.h"

#include <kabc/addressee.h>
#include <kcal/incidence.h>
#include <kcal/journal.h>
#include <libkdepim/kpimprefs.h>
#include <ksystemtimezone.h>
#include <kdebug.h>
#include <QFile>

using namespace Kolab;

KolabBase::KolabBase( const QString& tz )
  : mCreationDate( QDateTime::currentDateTime() ),
    mLastModified( KDateTime::currentUtcDateTime() ),
    mSensitivity( Public ),
    mTimeZone( KSystemTimeZones::zone( tz ) ),
    mHasPilotSyncId( false ),  mHasPilotSyncStatus( false )
{
}

KolabBase::~KolabBase()
{
}

void KolabBase::setFields( const KCal::Incidence* incidence )
{
  // So far unhandled KCal::IncidenceBase fields:
  // mPilotID, mSyncStatus, mFloats

  setUid( incidence->uid() );
  setBody( incidence->description() );
  setCategories( incidence->categoriesStr() );
  setCreationDate( localToUTC( incidence->created() ) );
  setLastModified( incidence->lastModified() );
  setSensitivity( static_cast<Sensitivity>( incidence->secrecy() ) );
  // TODO: Attachments
}

void KolabBase::saveTo( KCal::Incidence* incidence ) const
{
  incidence->setUid( uid() );
  incidence->setDescription( body() );
  incidence->setCategories( categories() );
  incidence->setCreated( utcToLocal( creationDate() ) );
  incidence->setLastModified( lastModified() );
  switch( sensitivity() ) {
  case 1:
    incidence->setSecrecy( KCal::Incidence::SecrecyPrivate );
    break;
  case 2:
    incidence->setSecrecy( KCal::Incidence::SecrecyConfidential );
    break;
  default:
    incidence->setSecrecy( KCal::Incidence::SecrecyPublic );
    break;
  }

  // TODO: Attachments
}

void KolabBase::setFields( const KABC::Addressee* addressee )
{
  // An addressee does not have a creation date, so somehow we should
  // make one, if this is a new entry

  setUid( addressee->uid() );
  setBody( addressee->note() );
  setCategories( addressee->categories().join( "," ) );

  // Set creation-time and last-modification-time
  const QString creationString = addressee->custom( "KOLAB", "CreationDate" );
  kDebug(5006) <<"Creation time string:" << creationString;
  KDateTime creationDate;
  if ( creationString.isEmpty() ) {
    creationDate = KDateTime::currentDateTime(KDateTime::Spec( mTimeZone ) );
    kDebug(5006) <<"Creation date set to current time";
  }
  else {
    creationDate = stringToDateTime( creationString );
    kDebug(5006) <<"Creation date loaded";
  }
  KDateTime modified = KDateTime( addressee->revision(), mTimeZone );
  if ( !modified.isValid() )
    modified = KDateTime::currentUtcDateTime();
  setLastModified( modified );
  if ( modified < creationDate ) {
    // It's not possible that the modification date is earlier than creation
    creationDate = modified;
    kDebug(5006) <<"Creation date set to modification date";
  }
  setCreationDate( creationDate );
  const QString newCreationDate = dateTimeToString( creationDate );
  if ( creationString != newCreationDate ) {
    // We modified the creation date, so store it for future reference
    const_cast<KABC::Addressee*>( addressee )
      ->insertCustom( "KOLAB", "CreationDate", newCreationDate );
    kDebug(5006) <<"Creation date modified. New one:" << newCreationDate;
  }

  switch( addressee->secrecy().type() ) {
  case KABC::Secrecy::Private:
    setSensitivity( Private );
    break;
  case KABC::Secrecy::Confidential:
    setSensitivity( Confidential );
    break;
  default:
    setSensitivity( Public );
  }

  // TODO: Attachments
}

void KolabBase::saveTo( KABC::Addressee* addressee ) const
{
  addressee->setUid( uid() );
  addressee->setNote( body() );
  addressee->setCategories( categories().split( ',', QString::SkipEmptyParts ) );
  addressee->setRevision( lastModified().toZone( mTimeZone ).dateTime() );
  addressee->insertCustom( "KOLAB", "CreationDate",
                           dateTimeToString( creationDate() ) );

  switch( sensitivity() ) {
  case Private:
    addressee->setSecrecy( KABC::Secrecy( KABC::Secrecy::Private ) );
    break;
  case Confidential:
    addressee->setSecrecy( KABC::Secrecy( KABC::Secrecy::Confidential ) );
    break;
  default:
    addressee->setSecrecy( KABC::Secrecy( KABC::Secrecy::Public ) );
    break;
  }
  // TODO: Attachments
}

void KolabBase::setUid( const QString& uid )
{
  mUid = uid;
}

QString KolabBase::uid() const
{
  return mUid;
}

void KolabBase::setBody( const QString& body )
{
  mBody = body;
}

QString KolabBase::body() const
{
  return mBody;
}

void KolabBase::setCategories( const QString& categories )
{
  mCategories = categories;
}

QString KolabBase::categories() const
{
  return mCategories;
}

void KolabBase::setCreationDate( const KDateTime& date )
{
  mCreationDate = date;
}

KDateTime KolabBase::creationDate() const
{
  return mCreationDate;
}

void KolabBase::setLastModified( const KDateTime& date )
{
  mLastModified = date;
}

KDateTime KolabBase::lastModified() const
{
  return mLastModified;
}

void KolabBase::setSensitivity( Sensitivity sensitivity )
{
  mSensitivity = sensitivity;
}

KolabBase::Sensitivity KolabBase::sensitivity() const
{
  return mSensitivity;
}

void KolabBase::setPilotSyncId( unsigned long id )
{
  mHasPilotSyncId = true;
  mPilotSyncId = id;
}

bool KolabBase::hasPilotSyncId() const
{
  return mHasPilotSyncId;
}

unsigned long KolabBase::pilotSyncId() const
{
  return mPilotSyncId;
}

void KolabBase::setPilotSyncStatus( int status )
{
  mHasPilotSyncStatus = true;
  mPilotSyncStatus = status;
}

bool KolabBase::hasPilotSyncStatus() const
{
  return mHasPilotSyncStatus;
}

int KolabBase::pilotSyncStatus() const
{
  return mPilotSyncStatus;
}

bool KolabBase::loadEmailAttribute( QDomElement& element, Email& email )
{
  for ( QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
    if ( n.isComment() )
      continue;
    if ( n.isElement() ) {
      QDomElement e = n.toElement();
      const QString tagName = e.tagName();

      if ( tagName == "display-name" )
        email.displayName = e.text();
      else if ( tagName == "smtp-address" )
        email.smtpAddress = e.text();
      else
        // TODO: Unhandled tag - save for later storage
        kDebug() <<"Warning: Unhandled tag" << e.tagName();
    } else
      kDebug() <<"Node is not a comment or an element???";
  }

  return true;
}

void KolabBase::saveEmailAttribute( QDomElement& element, const Email& email,
                                    const QString& tagName ) const
{
  QDomElement e = element.ownerDocument().createElement( tagName );
  element.appendChild( e );
  writeString( e, "display-name", email.displayName );
  writeString( e, "smtp-address", email.smtpAddress );
}

bool KolabBase::loadAttribute( QDomElement& element )
{
  const QString tagName = element.tagName();
  switch ( tagName[0].toLatin1() ) {
  case 'u':
    if ( tagName == "uid" ) {
      setUid( element.text() );
      return true;
    }
    break;
  case 'b':
    if ( tagName == "body" ) {
      setBody( element.text() );
      return true;
    }
    break;
  case 'c':
    if ( tagName == "categories" ) {
      setCategories( element.text() );
      return true;
    }
    if ( tagName == "creation-date" ) {
      setCreationDate( stringToDateTime( element.text() ) );
      return true;
    }
    break;
  case 'l':
    if ( tagName == "last-modification-date" ) {
      setLastModified( stringToDateTime( element.text() ) );
      return true;
    }
    break;
  case 's':
    if ( tagName == "sensitivity" ) {
      setSensitivity( stringToSensitivity( element.text() ) );
      return true;
    }
    break;
  case 'p':
    if ( tagName == "product-id" )
      return true; // ignore this field
    if ( tagName == "pilot-sync-id" ) {
      setPilotSyncId( element.text().toULong() );
      return true;
    }
    if ( tagName == "pilot-sync-status" ) {
      setPilotSyncStatus( element.text().toInt() );
      return true;
    }
    break;
  default:
    break;
  }
  return false;
}

bool KolabBase::saveAttributes( QDomElement& element ) const
{
  writeString( element, "product-id", productID() );
  writeString( element, "uid", uid() );
  writeString( element, "body", body() );
  writeString( element, "categories", categories() );
  writeString( element, "creation-date", dateTimeToString( creationDate() ) );
  writeString( element, "last-modification-date",
               dateTimeToString( lastModified().toZone( mTimeZone ) ) );
  writeString( element, "sensitivity", sensitivityToString( sensitivity() ) );
  if ( hasPilotSyncId() )
    writeString( element, "pilot-sync-id", QString::number( pilotSyncId() ) );
  if ( hasPilotSyncStatus() )
    writeString( element, "pilot-sync-status", QString::number( pilotSyncStatus() ) );
  return true;
}

bool KolabBase::load( const QString& xml )
{
  QString errorMsg;
  int errorLine, errorColumn;
  QDomDocument document;
  bool ok = document.setContent( xml, &errorMsg, &errorLine, &errorColumn );

  if ( !ok ) {
    qWarning( "Error loading document: %s, line %d, column %d",
              qPrintable( errorMsg ), errorLine, errorColumn );
    return false;
  }

  // XML file loaded into tree. Now parse it
  return loadXML( document );
}

bool KolabBase::load( QFile& xml )
{
  QString errorMsg;
  int errorLine, errorColumn;
  QDomDocument document;
  bool ok = document.setContent( &xml, &errorMsg, &errorLine, &errorColumn );

  if ( !ok ) {
    qWarning( "Error loading document: %s, line %d, column %d",
              qPrintable( errorMsg ), errorLine, errorColumn );
    return false;
  }

  // XML file loaded into tree. Now parse it
  return loadXML( document );
}

QDomDocument KolabBase::domTree()
{
  QDomDocument document;

  QString p = "version=\"1.0\" encoding=\"UTF-8\"";
  document.appendChild(document.createProcessingInstruction( "xml", p ) );

  return document;
}

QString KolabBase::dateTimeToString( const KDateTime& time )
{
  return time.toString( KDateTime::ISODate );
}

QString KolabBase::dateToString( const QDate& date )
{
  return date.toString( Qt::ISODate );
}

KDateTime KolabBase::stringToDateTime( const QString& _date )
{
  QString date( _date );
  //deal with data from some clients that always append a Z to dates
  if ( date.endsWith( "ZZ" ) )
    date.truncate( date.length() - 1 );
  return KDateTime::fromString( date, KDateTime::ISODate );
}

QDate KolabBase::stringToDate( const QString& date )
{
  return QDate::fromString( date, Qt::ISODate );
}

QString KolabBase::sensitivityToString( Sensitivity s )
{
  switch( s ) {
  case Private: return "private";
  case Confidential: return "confidential";
  case Public: return "public";
  }

  return "What what what???";
}

KolabBase::Sensitivity KolabBase::stringToSensitivity( const QString& s )
{
  if ( s == "private" )
    return Private;
  if ( s == "confidential" )
    return Confidential;
  return Public;
}

QString KolabBase::colorToString( const QColor& color )
{
  // Color is in the format "#RRGGBB"
  return color.name();
}

QColor KolabBase::stringToColor( const QString& s )
{
  return QColor( s );
}

void KolabBase::writeString( QDomElement& element, const QString& tag,
                             const QString& tagString )
{
  if ( !tagString.isEmpty() ) {
    QDomElement e = element.ownerDocument().createElement( tag );
    QDomText t = element.ownerDocument().createTextNode( tagString );
    e.appendChild( t );
    element.appendChild( e );
  }
}

KDateTime KolabBase::localToUTC( const KDateTime& time ) const
{
  return time.toUtc();
}

KDateTime KolabBase::utcToLocal( const KDateTime& time ) const
{
  KDateTime dt = time;
  dt.setTimeSpec( KDateTime::UTC );
  return dt;
}
<commit_msg>Blocked revisions 961858 via svnmerge<commit_after>/*
    This file is part of the kolab resource - the implementation of the
    Kolab storage format. See www.kolab.org for documentation on this.

    Copyright (c) 2004 Bo Thorsen <bo@sonofthor.dk>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include "kolabbase.h"

#include <kabc/addressee.h>
#include <kcal/incidence.h>
#include <kcal/journal.h>
#include <libkdepim/kpimprefs.h>
#include <ksystemtimezone.h>
#include <kdebug.h>
#include <QFile>

using namespace Kolab;

KolabBase::KolabBase( const QString& tz )
  : mCreationDate( QDateTime::currentDateTime() ),
    mLastModified( KDateTime::currentUtcDateTime() ),
    mSensitivity( Public ),
    mTimeZone( KSystemTimeZones::zone( tz ) ),
    mHasPilotSyncId( false ),  mHasPilotSyncStatus( false )
{
}

KolabBase::~KolabBase()
{
}

void KolabBase::setFields( const KCal::Incidence* incidence )
{
  // So far unhandled KCal::IncidenceBase fields:
  // mPilotID, mSyncStatus, mFloats

  setUid( incidence->uid() );
  setBody( incidence->description() );
  setCategories( incidence->categoriesStr() );
  setCreationDate( localToUTC( incidence->created() ) );
  setLastModified( incidence->lastModified() );
  setSensitivity( static_cast<Sensitivity>( incidence->secrecy() ) );
  // TODO: Attachments
}

void KolabBase::saveTo( KCal::Incidence* incidence ) const
{
  incidence->setUid( uid() );
  incidence->setDescription( body() );
  incidence->setCategories( categories() );
  incidence->setCreated( utcToLocal( creationDate() ) );
  incidence->setLastModified( lastModified() );
  switch( sensitivity() ) {
  case 1:
    incidence->setSecrecy( KCal::Incidence::SecrecyPrivate );
    break;
  case 2:
    incidence->setSecrecy( KCal::Incidence::SecrecyConfidential );
    break;
  default:
    incidence->setSecrecy( KCal::Incidence::SecrecyPublic );
    break;
  }

  // TODO: Attachments
}

void KolabBase::setFields( const KABC::Addressee* addressee )
{
  // An addressee does not have a creation date, so somehow we should
  // make one, if this is a new entry

  setUid( addressee->uid() );
  setBody( addressee->note() );
  setCategories( addressee->categories().join( "," ) );

  // Set creation-time and last-modification-time
  const QString creationString = addressee->custom( "KOLAB", "CreationDate" );
  kDebug(5006) <<"Creation time string:" << creationString;
  KDateTime creationDate;
  if ( creationString.isEmpty() ) {
    creationDate = KDateTime::currentDateTime(KDateTime::Spec( mTimeZone ) );
    kDebug(5006) <<"Creation date set to current time";
  }
  else {
    creationDate = stringToDateTime( creationString );
    kDebug(5006) <<"Creation date loaded";
  }
  KDateTime modified = KDateTime( addressee->revision(), mTimeZone );
  if ( !modified.isValid() )
    modified = KDateTime::currentUtcDateTime();
  setLastModified( modified );
  if ( modified < creationDate ) {
    // It's not possible that the modification date is earlier than creation
    creationDate = modified;
    kDebug(5006) <<"Creation date set to modification date";
  }
  setCreationDate( creationDate );
  const QString newCreationDate = dateTimeToString( creationDate );
  if ( creationString != newCreationDate ) {
    // We modified the creation date, so store it for future reference
    const_cast<KABC::Addressee*>( addressee )
      ->insertCustom( "KOLAB", "CreationDate", newCreationDate );
    kDebug(5006) <<"Creation date modified. New one:" << newCreationDate;
  }

  switch( addressee->secrecy().type() ) {
  case KABC::Secrecy::Private:
    setSensitivity( Private );
    break;
  case KABC::Secrecy::Confidential:
    setSensitivity( Confidential );
    break;
  default:
    setSensitivity( Public );
  }

  // TODO: Attachments
}

void KolabBase::saveTo( KABC::Addressee* addressee ) const
{
  addressee->setUid( uid() );
  addressee->setNote( body() );
  addressee->setCategories( categories().split( ',', QString::SkipEmptyParts ) );
  addressee->setRevision( lastModified().toZone( mTimeZone ).dateTime() );
  addressee->insertCustom( "KOLAB", "CreationDate",
                           dateTimeToString( creationDate() ) );

  switch( sensitivity() ) {
  case Private:
    addressee->setSecrecy( KABC::Secrecy( KABC::Secrecy::Private ) );
    break;
  case Confidential:
    addressee->setSecrecy( KABC::Secrecy( KABC::Secrecy::Confidential ) );
    break;
  default:
    addressee->setSecrecy( KABC::Secrecy( KABC::Secrecy::Public ) );
    break;
  }
  // TODO: Attachments
}

void KolabBase::setUid( const QString& uid )
{
  mUid = uid;
}

QString KolabBase::uid() const
{
  return mUid;
}

void KolabBase::setBody( const QString& body )
{
  mBody = body;
}

QString KolabBase::body() const
{
  return mBody;
}

void KolabBase::setCategories( const QString& categories )
{
  mCategories = categories;
}

QString KolabBase::categories() const
{
  return mCategories;
}

void KolabBase::setCreationDate( const KDateTime& date )
{
  mCreationDate = date;
}

KDateTime KolabBase::creationDate() const
{
  return mCreationDate;
}

void KolabBase::setLastModified( const KDateTime& date )
{
  mLastModified = date;
}

KDateTime KolabBase::lastModified() const
{
  return mLastModified;
}

void KolabBase::setSensitivity( Sensitivity sensitivity )
{
  mSensitivity = sensitivity;
}

KolabBase::Sensitivity KolabBase::sensitivity() const
{
  return mSensitivity;
}

void KolabBase::setPilotSyncId( unsigned long id )
{
  mHasPilotSyncId = true;
  mPilotSyncId = id;
}

bool KolabBase::hasPilotSyncId() const
{
  return mHasPilotSyncId;
}

unsigned long KolabBase::pilotSyncId() const
{
  return mPilotSyncId;
}

void KolabBase::setPilotSyncStatus( int status )
{
  mHasPilotSyncStatus = true;
  mPilotSyncStatus = status;
}

bool KolabBase::hasPilotSyncStatus() const
{
  return mHasPilotSyncStatus;
}

int KolabBase::pilotSyncStatus() const
{
  return mPilotSyncStatus;
}

bool KolabBase::loadEmailAttribute( QDomElement& element, Email& email )
{
  for ( QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
    if ( n.isComment() )
      continue;
    if ( n.isElement() ) {
      QDomElement e = n.toElement();
      const QString tagName = e.tagName();

      if ( tagName == "display-name" )
        email.displayName = e.text();
      else if ( tagName == "smtp-address" )
        email.smtpAddress = e.text();
      else
        // TODO: Unhandled tag - save for later storage
        kDebug() <<"Warning: Unhandled tag" << e.tagName();
    } else
      kDebug() <<"Node is not a comment or an element???";
  }

  return true;
}

void KolabBase::saveEmailAttribute( QDomElement& element, const Email& email,
                                    const QString& tagName ) const
{
  QDomElement e = element.ownerDocument().createElement( tagName );
  element.appendChild( e );
  writeString( e, "display-name", email.displayName );
  writeString( e, "smtp-address", email.smtpAddress );
}

bool KolabBase::loadAttribute( QDomElement& element )
{
  const QString tagName = element.tagName();
  switch ( tagName[0].toLatin1() ) {
  case 'u':
    if ( tagName == "uid" ) {
      setUid( element.text() );
      return true;
    }
    break;
  case 'b':
    if ( tagName == "body" ) {
      setBody( element.text() );
      return true;
    }
    break;
  case 'c':
    if ( tagName == "categories" ) {
      setCategories( element.text() );
      return true;
    }
    if ( tagName == "creation-date" ) {
      setCreationDate( stringToDateTime( element.text() ) );
      return true;
    }
    break;
  case 'l':
    if ( tagName == "last-modification-date" ) {
      setLastModified( stringToDateTime( element.text() ) );
      return true;
    }
    break;
  case 's':
    if ( tagName == "sensitivity" ) {
      setSensitivity( stringToSensitivity( element.text() ) );
      return true;
    }
    break;
  case 'p':
    if ( tagName == "product-id" )
      return true; // ignore this field
    if ( tagName == "pilot-sync-id" ) {
      setPilotSyncId( element.text().toULong() );
      return true;
    }
    if ( tagName == "pilot-sync-status" ) {
      setPilotSyncStatus( element.text().toInt() );
      return true;
    }
    break;
  default:
    break;
  }
  return false;
}

bool KolabBase::saveAttributes( QDomElement& element ) const
{
  writeString( element, "product-id", productID() );
  writeString( element, "uid", uid() );
  writeString( element, "body", body() );
  writeString( element, "categories", categories() );
  writeString( element, "creation-date", dateTimeToString( creationDate() ) );
  writeString( element, "last-modification-date",
               dateTimeToString( lastModified().toZone( mTimeZone ) ) );
  writeString( element, "sensitivity", sensitivityToString( sensitivity() ) );
  if ( hasPilotSyncId() )
    writeString( element, "pilot-sync-id", QString::number( pilotSyncId() ) );
  if ( hasPilotSyncStatus() )
    writeString( element, "pilot-sync-status", QString::number( pilotSyncStatus() ) );
  return true;
}

bool KolabBase::load( const QString& xml )
{
  QString errorMsg;
  int errorLine, errorColumn;
  QDomDocument document;
  bool ok = document.setContent( xml, &errorMsg, &errorLine, &errorColumn );

  if ( !ok ) {
    qWarning( "Error loading document: %s, line %d, column %d",
              qPrintable( errorMsg ), errorLine, errorColumn );
    return false;
  }

  // XML file loaded into tree. Now parse it
  return loadXML( document );
}

bool KolabBase::load( QFile& xml )
{
  QString errorMsg;
  int errorLine, errorColumn;
  QDomDocument document;
  bool ok = document.setContent( &xml, &errorMsg, &errorLine, &errorColumn );

  if ( !ok ) {
    qWarning( "Error loading document: %s, line %d, column %d",
              qPrintable( errorMsg ), errorLine, errorColumn );
    return false;
  }

  // XML file loaded into tree. Now parse it
  return loadXML( document );
}

QDomDocument KolabBase::domTree()
{
  QDomDocument document;

  QString p = "version=\"1.0\" encoding=\"UTF-8\"";
  document.appendChild(document.createProcessingInstruction( "xml", p ) );

  return document;
}

QString KolabBase::dateTimeToString( const KDateTime& time )
{
  return time.toString( KDateTime::ISODate );
}

QString KolabBase::dateToString( const QDate& date )
{
  return date.toString( Qt::ISODate );
}

KDateTime KolabBase::stringToDateTime( const QString& _date )
{
  QString date( _date );
  //Deal with data from some clients that always append a Z to dates.
  //In Qt4, Qt::ISODate must see a trailing Z for UTC, so keep such.
  if ( date.endsWith( "ZZ" ) )
    date.chop( 1 );
  return KDateTime::fromString( date, KDateTime::ISODate );
}

QDate KolabBase::stringToDate( const QString& date )
{
  return QDate::fromString( date, Qt::ISODate );
}

QString KolabBase::sensitivityToString( Sensitivity s )
{
  switch( s ) {
  case Private: return "private";
  case Confidential: return "confidential";
  case Public: return "public";
  }

  return "What what what???";
}

KolabBase::Sensitivity KolabBase::stringToSensitivity( const QString& s )
{
  if ( s == "private" )
    return Private;
  if ( s == "confidential" )
    return Confidential;
  return Public;
}

QString KolabBase::colorToString( const QColor& color )
{
  // Color is in the format "#RRGGBB"
  return color.name();
}

QColor KolabBase::stringToColor( const QString& s )
{
  return QColor( s );
}

void KolabBase::writeString( QDomElement& element, const QString& tag,
                             const QString& tagString )
{
  if ( !tagString.isEmpty() ) {
    QDomElement e = element.ownerDocument().createElement( tag );
    QDomText t = element.ownerDocument().createTextNode( tagString );
    e.appendChild( t );
    element.appendChild( e );
  }
}

KDateTime KolabBase::localToUTC( const KDateTime& time ) const
{
  return time.toUtc();
}

KDateTime KolabBase::utcToLocal( const KDateTime& time ) const
{
  KDateTime dt = time;
  dt.setTimeSpec( KDateTime::UTC );
  return dt;
}
<|endoftext|>


<commit_before>/*  -*-c++-*-
 *  Copyright (C) 2008 Cedric Pinson <cedric.pinson@plopbyte.net>
 *  Copyright (C) 2017 Julien Valentin <mp3butcher@hotmail.com>
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
 */

#include <osgAnimation/VertexInfluence>
#include <osgAnimation/RigGeometry>
#include <osgAnimation/BoneMapVisitor>
#include <osg/Notify>
#include <iostream>
#include <algorithm>
#include <set>

using namespace osgAnimation;

struct invweight_ordered
{
    inline bool operator() (const BoneWeight& bw1, const BoneWeight& bw2) const
    {
        if (bw1.second > bw2.second)return true;
        if (bw1.second < bw2.second)return false;
        return(bw1.first < bw2.first);
    }
};

void VertexInfluenceMap::normalize(unsigned int numvert)
{

    typedef std::pair<float, std::vector<float*> > PerVertWeights;
    std::vector<PerVertWeights > localstore;
    localstore.resize(numvert);
    for(VertexInfluenceMap::iterator mapit = this->begin(); mapit != this->end(); ++mapit)
    {
        IndexWeightList &curvecinf = mapit->second;
        for(IndexWeightList::iterator curinf = curvecinf.begin(); curinf != curvecinf.end(); ++curinf)
        {
            VertexIndexWeight& inf = *curinf;
            localstore[inf.first].first += inf.second;
            localstore[inf.first].second.push_back(&inf.second);

        }
    }

    unsigned int vertid = 0;
    for(std::vector<PerVertWeights >::iterator itvert = localstore.begin();
    itvert != localstore.end();
    ++itvert, ++vertid)
    {
        PerVertWeights & weights = *itvert;
        if(weights.first< 1e-4)
        {
            OSG_WARN << "VertexInfluenceMap::normalize warning the vertex " <<vertid << " seems to have 0 weight, skip normalize for this vertex" << std::endl;
        }
        else
        {
            float mult = 1.0/weights.first;
            for (std::vector<float*>::iterator itf = weights.second.begin(); itf != weights.second.end(); ++itf)
            {
                **itf *= mult;
            }
        }
    }

}
///remove weakest influences in order to fit targetted numbonepervertex
void VertexInfluenceMap::cullInfluenceCountPerVertex(unsigned int numbonepervertex,float minweight, bool renormalize)
{

    typedef std::set<BoneWeight, invweight_ordered >  BoneWeightOrdered;
    std::map<int, BoneWeightOrdered > tempVec2Bones;
    for(VertexInfluenceMap::iterator mapit = this->begin(); mapit != this->end(); ++mapit)
    {
        const std::string& bonename = mapit->first;
        IndexWeightList &curvecinf = mapit->second;
        for(IndexWeightList::iterator curinf = curvecinf.begin(); curinf != curvecinf.end(); ++curinf)
        {
            VertexIndexWeight& inf = *curinf;
            if( bonename.empty())
            {
                OSG_WARN << "VertexInfluenceSet::cullInfluenceCountPerVertex warning vertex " << inf.first << " is not assigned to a bone" << std::endl;
            }
            else if(inf.second>minweight)
            {
                tempVec2Bones[inf.first].insert(BoneWeight(bonename, inf.second));
            }
        }
    }
    this->clear();
    for( std::map<int,BoneWeightOrdered >::iterator mapit = tempVec2Bones.begin(); mapit != tempVec2Bones.end(); ++mapit)
    {
        BoneWeightOrdered& bwset = mapit->second;
        unsigned int newsize = numbonepervertex<bwset.size()?numbonepervertex:bwset.size();
        float sum = 0.0f;
        while(bwset.size()>newsize)bwset.erase(*bwset.rbegin());
        if(renormalize)
        {
            for(BoneWeightOrdered::iterator bwit = bwset.begin(); bwit != bwset.end(); ++bwit)
            {
                sum += bwit->second;
            }

            if(sum > 1e-4)
            {
                sum = 1.0f/sum;
                for(BoneWeightOrdered::iterator bwit = bwset.begin(); bwit != bwset.end(); ++bwit)
                {
                    VertexInfluence & inf = (*this)[bwit->first];
                    inf.push_back(VertexIndexWeight(mapit->first, bwit->second*sum));
                    inf.setName(bwit->first);
                }
            }
        }
        else
        {
            for(BoneWeightOrdered::iterator bwit = bwset.begin(); bwit != bwset.end(); ++bwit)
            {
                VertexInfluence & inf = (*this)[bwit->first];
                inf.push_back(VertexIndexWeight(mapit->first,bwit->second));
                inf.setName(bwit->first);
            }
        }
    }
}

void VertexInfluenceMap::computePerVertexInfluenceList(std::vector<BoneWeightList>& vertex2Bones,unsigned int numvert)const
{
    vertex2Bones.resize(numvert);
    for (osgAnimation::VertexInfluenceMap::const_iterator it = begin(); it != end(); ++it)
    {
        const IndexWeightList& inflist = it->second;
        if (it->first.empty())
        {
            OSG_WARN << "VertexInfluenceMap::computePerVertexInfluenceList contains unamed bone IndexWeightList" << std::endl;
        }

        for(IndexWeightList::const_iterator infit = inflist.begin(); infit != inflist.end(); ++infit)
        {
            const VertexIndexWeight &iw = *infit;
            const unsigned int &index = iw.first;
            const float &weight = iw.second;
            vertex2Bones[index].push_back(BoneWeight(it->first, weight));;
        }
    }
}

// sort by name and weight
struct SortByNameAndWeight : public std::less<BoneWeight>
{
    bool operator()(const BoneWeight& b0, const BoneWeight& b1) const
    {
        if (b0.first < b1.first)
            return true;
        else if (b0.first > b1.first)
            return false;

        return (b0.second < b1.second);
    }
};

struct SortByBoneWeightList : public std::less<BoneWeightList>
{
    bool operator()(const BoneWeightList& b0,
                    const BoneWeightList& b1) const
    {
        if (b0.size() < b1.size())
            return true;
        else if (b0.size() > b1.size())
            return false;

        int size = b0.size();
        for (int i = 0; i < size; i++)
        {
            if (SortByNameAndWeight()(b0[i], b1[i]))
                return true;
            else if (SortByNameAndWeight()(b1[i], b0[i]))
                return false;
        }
        return false;
    }
};
void VertexInfluenceMap::computeMinimalVertexGroupList(std::vector<VertexGroup>& uniqVertexGroupList, unsigned int numvert) const
{
    uniqVertexGroupList.clear();
    std::vector<BoneWeightList> vertex2Bones;
    computePerVertexInfluenceList(vertex2Bones,numvert);
    typedef std::map<BoneWeightList,VertexGroup, SortByBoneWeightList> UnifyBoneGroup;
    UnifyBoneGroup unifyBuffer;

    unsigned int vertexID = 0;
    for (std::vector<BoneWeightList>::iterator it = vertex2Bones.begin(); it != vertex2Bones.end(); ++it,++vertexID)
    {
        BoneWeightList &boneweightlist = *it;
        // sort the vector to have a consistent key
        std::sort(boneweightlist.begin(), boneweightlist.end(), SortByNameAndWeight());

        // we use the vector<BoneWeight> as key to differentiate group
        UnifyBoneGroup::iterator result = unifyBuffer.find(boneweightlist);
        if (result == unifyBuffer.end())
        {
            unifyBuffer[boneweightlist].setBoneWeights(boneweightlist);
        }

        unifyBuffer[boneweightlist].vertIDs().push_back(vertexID);
    }

    if(vertex2Bones.size() == unifyBuffer.size())
    {
        OSG_WARN << "VertexInfluenceMap::computeMinimalVertexGroupList is useless no duplicate VertexGroup" << std::endl;
    }

    uniqVertexGroupList.reserve(unifyBuffer.size());
    for (UnifyBoneGroup::iterator it = unifyBuffer.begin(); it != unifyBuffer.end(); ++it)
    {
        uniqVertexGroupList.push_back(it->second);
    }
}

//Experimental Bone removal stuff
typedef std::vector<osgAnimation::RigGeometry*> RigList;
class CollectRigVisitor : public osg::NodeVisitor
{
public:
    META_NodeVisitor(osgAnimation, CollectRigVisitor)
    CollectRigVisitor();

    void apply(osg::Geometry& node);
    inline const RigList& getRigList() const{return _map;}

protected:
    RigList _map;
};

CollectRigVisitor::CollectRigVisitor() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}

void CollectRigVisitor::apply(osg::Geometry& node)
{
    RigGeometry* rig = dynamic_cast<RigGeometry*>(&node);
    if ( rig )
        _map.push_back(rig);
}

bool recursiveisUsefull( Bone* bone, std::set<std::string> foundnames)
{
    for(unsigned int i=0; i<bone->getNumChildren(); ++i)
    {
        Bone* child = dynamic_cast< Bone* >(bone->getChild(i));
        if(child)
        {
            if( foundnames.find(child->getName()) != foundnames.end() )
                return true;
            if( recursiveisUsefull(child,foundnames) )
                return true;
        }
    }
    return false;
}

void VertexInfluenceMap::removeUnexpressedBones(Skeleton &skel) const
{
    BoneMapVisitor mapVisitor;
    skel.accept(mapVisitor);

    CollectRigVisitor rigvis;
    skel.accept(rigvis);

    RigList  rigs = rigvis.getRigList();
    BoneMap boneMap = mapVisitor.getBoneMap();

    unsigned int removed=0;
    Bone* child, *par;

    std::set<std::string> usebones;
    for(RigList::iterator rigit = rigs.begin(); rigit != rigs.end(); ++rigit)
    {
        for(VertexInfluenceMap::iterator mapit = (*rigit)->getInfluenceMap()->begin();
            mapit != (*rigit)->getInfluenceMap()->end();
            ++mapit)
        {
            usebones.insert((*mapit).first);
        }
    }

    for(BoneMap::iterator bmit = boneMap.begin(); bmit != boneMap.end();)
    {
        if(usebones.find(bmit->second->getName()) == usebones.end())
        {
            if( !(par = bmit->second->getBoneParent()) )
            {
                ++bmit;
                continue;
            }

            Bone * bone2rm = bmit->second.get();

            if( recursiveisUsefull(bone2rm,usebones))
            {
                ++bmit;
                continue;
            }

            ///Bone can be removed
            ++ removed;
            OSG_INFO<<"removing useless bone: "<< bone2rm->getName() <<std::endl;
            osg::NodeList nodes;

            for(unsigned int numchild = 0; numchild < bone2rm->getNumChildren(); numchild++)
            {
                if( (child = dynamic_cast<Bone*>(bone2rm->getChild(numchild))) )
                {
                    if(par!=child &&child!=bone2rm) {
                        par->addChild(child);
                        nodes.push_back(child);
                    }
                }
            }
            for(unsigned int i=0; i<nodes.size(); ++i)
            {
                bone2rm->removeChild(nodes[i]);
            }
            par->removeChild(bone2rm);

            ///rebuild bonemap after bone removal
            BoneMapVisitor mapVis ;
            skel.accept(mapVis);
            boneMap = mapVis.getBoneMap();
            bmit = boneMap.begin();

        }
        else
        {
            ++bmit;
        }
    }
    OSG_WARN<<"Number of bone removed "<<removed<<std::endl;
}
<commit_msg>Code readability improvements<commit_after>/*  -*-c++-*-
 *  Copyright (C) 2008 Cedric Pinson <cedric.pinson@plopbyte.net>
 *  Copyright (C) 2017 Julien Valentin <mp3butcher@hotmail.com>
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
 */

#include <osgAnimation/VertexInfluence>
#include <osgAnimation/RigGeometry>
#include <osgAnimation/BoneMapVisitor>
#include <osg/Notify>
#include <iostream>
#include <algorithm>
#include <set>

using namespace osgAnimation;

struct invweight_ordered
{
    inline bool operator() (const BoneWeight& bw1, const BoneWeight& bw2) const
    {
        if (bw1.second > bw2.second)return true;
        if (bw1.second < bw2.second)return false;
        return(bw1.first < bw2.first);
    }
};

void VertexInfluenceMap::normalize(unsigned int numvert)
{

    typedef std::pair<float, std::vector<float*> > PerVertWeights;
    std::vector<PerVertWeights > localstore;
    localstore.resize(numvert);
    for(VertexInfluenceMap::iterator mapit = this->begin(); mapit != this->end(); ++mapit)
    {
        IndexWeightList &curvecinf = mapit->second;
        for(IndexWeightList::iterator curinf = curvecinf.begin(); curinf != curvecinf.end(); ++curinf)
        {
            VertexIndexWeight& inf = *curinf;
            localstore[inf.first].first += inf.second;
            localstore[inf.first].second.push_back(&inf.second);
        }
    }

    unsigned int vertid = 0;
    for(std::vector<PerVertWeights >::iterator itvert = localstore.begin();
        itvert != localstore.end();
        ++itvert, ++vertid)
    {
        PerVertWeights & weights = *itvert;
        if(weights.first< 1e-4)
        {
            OSG_WARN << "VertexInfluenceMap::normalize warning the vertex " <<vertid << " seems to have 0 weight, skip normalize for this vertex" << std::endl;
        }
        else
        {
            float mult = 1.0/weights.first;
            for (std::vector<float*>::iterator itf = weights.second.begin(); itf != weights.second.end(); ++itf)
            {
                **itf *= mult;
            }
        }
    }

}
///remove weakest influences in order to fit targetted numbonepervertex
void VertexInfluenceMap::cullInfluenceCountPerVertex(unsigned int numbonepervertex,float minweight, bool renormalize)
{

    typedef std::set<BoneWeight, invweight_ordered >  BoneWeightOrdered;
    std::map<int, BoneWeightOrdered > tempVec2Bones;
    for(VertexInfluenceMap::iterator mapit = this->begin(); mapit != this->end(); ++mapit)
    {
        const std::string& bonename = mapit->first;
        IndexWeightList &curvecinf = mapit->second;
        for(IndexWeightList::iterator curinf = curvecinf.begin(); curinf != curvecinf.end(); ++curinf)
        {
            VertexIndexWeight& inf = *curinf;
            if( bonename.empty())
            {
                OSG_WARN << "VertexInfluenceSet::cullInfluenceCountPerVertex warning vertex " << inf.first << " is not assigned to a bone" << std::endl;
            }
            else if(inf.second>minweight)
            {
                tempVec2Bones[inf.first].insert(BoneWeight(bonename, inf.second));
            }
        }
    }
    this->clear();
    for( std::map<int,BoneWeightOrdered >::iterator mapit = tempVec2Bones.begin(); mapit != tempVec2Bones.end(); ++mapit)
    {
        BoneWeightOrdered& bwset = mapit->second;
        unsigned int newsize = numbonepervertex<bwset.size()?numbonepervertex:bwset.size();
        float sum = 0.0f;
        while(bwset.size()>newsize)bwset.erase(*bwset.rbegin());
        if(renormalize)
        {
            for(BoneWeightOrdered::iterator bwit = bwset.begin(); bwit != bwset.end(); ++bwit)
            {
                sum += bwit->second;
            }

            if(sum > 1e-4)
            {
                sum = 1.0f/sum;
                for(BoneWeightOrdered::iterator bwit = bwset.begin(); bwit != bwset.end(); ++bwit)
                {
                    VertexInfluence & inf = (*this)[bwit->first];
                    inf.push_back(VertexIndexWeight(mapit->first, bwit->second*sum));
                    inf.setName(bwit->first);
                }
            }
        }
        else
        {
            for(BoneWeightOrdered::iterator bwit = bwset.begin(); bwit != bwset.end(); ++bwit)
            {
                VertexInfluence & inf = (*this)[bwit->first];
                inf.push_back(VertexIndexWeight(mapit->first,bwit->second));
                inf.setName(bwit->first);
            }
        }
    }
}

void VertexInfluenceMap::computePerVertexInfluenceList(std::vector<BoneWeightList>& vertex2Bones,unsigned int numvert)const
{
    vertex2Bones.resize(numvert);
    for (osgAnimation::VertexInfluenceMap::const_iterator it = begin(); it != end(); ++it)
    {
        const IndexWeightList& inflist = it->second;
        if (it->first.empty())
        {
            OSG_WARN << "VertexInfluenceMap::computePerVertexInfluenceList contains unamed bone IndexWeightList" << std::endl;
        }

        for(IndexWeightList::const_iterator infit = inflist.begin(); infit != inflist.end(); ++infit)
        {
            const VertexIndexWeight &iw = *infit;
            const unsigned int &index = iw.first;
            const float &weight = iw.second;
            vertex2Bones[index].push_back(BoneWeight(it->first, weight));;
        }
    }
}

// sort by name and weight
struct SortByNameAndWeight : public std::less<BoneWeight>
{
    bool operator()(const BoneWeight& b0, const BoneWeight& b1) const
    {
        if (b0.first < b1.first)
            return true;
        else if (b0.first > b1.first)
            return false;

        return (b0.second < b1.second);
    }
};

struct SortByBoneWeightList : public std::less<BoneWeightList>
{
    bool operator()(const BoneWeightList& b0,
                    const BoneWeightList& b1) const
    {
        if (b0.size() < b1.size())
            return true;
        else if (b0.size() > b1.size())
            return false;

        int size = b0.size();
        for (int i = 0; i < size; i++)
        {
            if (SortByNameAndWeight()(b0[i], b1[i]))
                return true;
            else if (SortByNameAndWeight()(b1[i], b0[i]))
                return false;
        }
        return false;
    }
};
void VertexInfluenceMap::computeMinimalVertexGroupList(std::vector<VertexGroup>& uniqVertexGroupList, unsigned int numvert) const
{
    uniqVertexGroupList.clear();
    std::vector<BoneWeightList> vertex2Bones;
    computePerVertexInfluenceList(vertex2Bones,numvert);
    typedef std::map<BoneWeightList,VertexGroup, SortByBoneWeightList> UnifyBoneGroup;
    UnifyBoneGroup unifyBuffer;

    unsigned int vertexID = 0;
    for (std::vector<BoneWeightList>::iterator it = vertex2Bones.begin(); it != vertex2Bones.end(); ++it,++vertexID)
    {
        BoneWeightList &boneweightlist = *it;
        // sort the vector to have a consistent key
        std::sort(boneweightlist.begin(), boneweightlist.end(), SortByNameAndWeight());

        // we use the vector<BoneWeight> as key to differentiate group
        UnifyBoneGroup::iterator result = unifyBuffer.find(boneweightlist);
        if (result == unifyBuffer.end())
        {
            unifyBuffer[boneweightlist].setBoneWeights(boneweightlist);
        }

        unifyBuffer[boneweightlist].vertIDs().push_back(vertexID);
    }

    if(vertex2Bones.size() == unifyBuffer.size())
    {
        OSG_WARN << "VertexInfluenceMap::computeMinimalVertexGroupList is useless no duplicate VertexGroup" << std::endl;
    }

    uniqVertexGroupList.reserve(unifyBuffer.size());
    for (UnifyBoneGroup::iterator it = unifyBuffer.begin(); it != unifyBuffer.end(); ++it)
    {
        uniqVertexGroupList.push_back(it->second);
    }
}

//Experimental Bone removal stuff
typedef std::vector<osgAnimation::RigGeometry*> RigList;
class CollectRigVisitor : public osg::NodeVisitor
{
public:
    META_NodeVisitor(osgAnimation, CollectRigVisitor)
    CollectRigVisitor();

    void apply(osg::Geometry& node);
    inline const RigList& getRigList() const{return _map;}

protected:
    RigList _map;
};

CollectRigVisitor::CollectRigVisitor() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}

void CollectRigVisitor::apply(osg::Geometry& node)
{
    RigGeometry* rig = dynamic_cast<RigGeometry*>(&node);
    if ( rig )
        _map.push_back(rig);
}

bool recursiveisUsefull( Bone* bone, std::set<std::string> foundnames)
{
    for(unsigned int i=0; i<bone->getNumChildren(); ++i)
    {
        Bone* child = dynamic_cast< Bone* >(bone->getChild(i));
        if(child)
        {
            if( foundnames.find(child->getName()) != foundnames.end() )
                return true;
            if( recursiveisUsefull(child,foundnames) )
                return true;
        }
    }
    return false;
}

void VertexInfluenceMap::removeUnexpressedBones(Skeleton &skel) const
{
    BoneMapVisitor mapVisitor;
    skel.accept(mapVisitor);

    CollectRigVisitor rigvis;
    skel.accept(rigvis);

    RigList  rigs = rigvis.getRigList();
    BoneMap boneMap = mapVisitor.getBoneMap();

    unsigned int removed=0;
    Bone* child, *par;

    std::set<std::string> usebones;
    for(RigList::iterator rigit = rigs.begin(); rigit != rigs.end(); ++rigit)
    {
        for(VertexInfluenceMap::iterator mapit = (*rigit)->getInfluenceMap()->begin();
            mapit != (*rigit)->getInfluenceMap()->end();
            ++mapit)
        {
            usebones.insert((*mapit).first);
        }
    }

    for(BoneMap::iterator bmit = boneMap.begin(); bmit != boneMap.end();)
    {
        if(usebones.find(bmit->second->getName()) == usebones.end())
        {
            if( !(par = bmit->second->getBoneParent()) )
            {
                ++bmit;
                continue;
            }

            Bone * bone2rm = bmit->second.get();

            if( recursiveisUsefull(bone2rm,usebones))
            {
                ++bmit;
                continue;
            }

            ///Bone can be removed
            ++ removed;
            OSG_INFO<<"removing useless bone: "<< bone2rm->getName() <<std::endl;
            osg::NodeList nodes;

            for(unsigned int numchild = 0; numchild < bone2rm->getNumChildren(); numchild++)
            {
                if( (child = dynamic_cast<Bone*>(bone2rm->getChild(numchild))) )
                {
                    if(par!=child &&child!=bone2rm)
                    {
                        par->addChild(child);
                        nodes.push_back(child);
                    }
                }
            }

            for(unsigned int i=0; i<nodes.size(); ++i)
            {
                bone2rm->removeChild(nodes[i]);
            }
            par->removeChild(bone2rm);

            ///rebuild bonemap after bone removal
            BoneMapVisitor mapVis ;
            skel.accept(mapVis);
            boneMap = mapVis.getBoneMap();
            bmit = boneMap.begin();

        }
        else
        {
            ++bmit;
        }
    }
    OSG_WARN<<"Number of bone removed "<<removed<<std::endl;
}
<|endoftext|>


<commit_before>//===-- SelectionDAGPrinter.cpp - Implement SelectionDAG::viewGraph() -----===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This implements the SelectionDAG::viewGraph method.
//
//===----------------------------------------------------------------------===//

#include "ScheduleDAGSDNodes.h"
#include "llvm/Constants.h"
#include "llvm/Function.h"
#include "llvm/Assembly/Writer.h"
#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/PseudoSourceValue.h"
#include "llvm/Analysis/DebugInfo.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/GraphWriter.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Config/config.h"
#include <fstream>
using namespace llvm;

namespace llvm {
  template<>
  struct DOTGraphTraits<SelectionDAG*> : public DefaultDOTGraphTraits {
    static bool hasEdgeDestLabels() {
      return true;
    }

    static unsigned numEdgeDestLabels(const void *Node) {
      return ((const SDNode *) Node)->getNumValues();
    }

    static std::string getEdgeDestLabel(const void *Node, unsigned i) {
      return ((const SDNode *) Node)->getValueType(i).getMVTString();
    }

    /// edgeTargetsEdgeSource - This method returns true if this outgoing edge
    /// should actually target another edge source, not a node.  If this method is
    /// implemented, getEdgeTarget should be implemented.
    template<typename EdgeIter>
    static bool edgeTargetsEdgeSource(const void *Node, EdgeIter I) {
      return true;
    }

    /// getEdgeTarget - If edgeTargetsEdgeSource returns true, this method is
    /// called to determine which outgoing edge of Node is the target of this
    /// edge.
    template<typename EdgeIter>
    static EdgeIter getEdgeTarget(const void *Node, EdgeIter I) {
      SDNode *TargetNode = *I;
      SDNodeIterator NI = SDNodeIterator::begin(TargetNode);
      std::advance(NI, I.getNode()->getOperand(I.getOperand()).getResNo());
      return NI;
    }

    static std::string getGraphName(const SelectionDAG *G) {
      return G->getMachineFunction().getFunction()->getName();
    }

    static bool renderGraphFromBottomUp() {
      return true;
    }

    static bool hasNodeAddressLabel(const SDNode *Node,
                                    const SelectionDAG *Graph) {
      return true;
    }

    /// If you want to override the dot attributes printed for a particular
    /// edge, override this method.
    template<typename EdgeIter>
    static std::string getEdgeAttributes(const void *Node, EdgeIter EI) {
      SDValue Op = EI.getNode()->getOperand(EI.getOperand());
      MVT VT = Op.getValueType();
      if (VT == MVT::Flag)
        return "color=red,style=bold";
      else if (VT == MVT::Other)
        return "color=blue,style=dashed";
      return "";
    }

    static std::string getNodeLabel(const SDNode *Node,
                                    const SelectionDAG *Graph,
                                    bool ShortNames);
    static std::string getNodeAttributes(const SDNode *N,
                                         const SelectionDAG *Graph) {
#ifndef NDEBUG
      const std::string &Attrs = Graph->getGraphAttrs(N);
      if (!Attrs.empty()) {
        if (Attrs.find("shape=") == std::string::npos)
          return std::string("shape=Mrecord,") + Attrs;
        else
          return Attrs;
      }
#endif
      return "shape=Mrecord";
    }

    static void addCustomGraphFeatures(SelectionDAG *G,
                                       GraphWriter<SelectionDAG*> &GW) {
      GW.emitSimpleNode(0, "plaintext=circle", "GraphRoot");
      if (G->getRoot().getNode())
        GW.emitEdge(0, -1, G->getRoot().getNode(), G->getRoot().getResNo(),
                    "color=blue,style=dashed");
    }
  };
}

std::string DOTGraphTraits<SelectionDAG*>::getNodeLabel(const SDNode *Node,
                                                        const SelectionDAG *G,
                                                        bool ShortNames) {
  std::string Op = Node->getOperationName(G);

  if (const ConstantSDNode *CSDN = dyn_cast<ConstantSDNode>(Node)) {
    Op += ": " + utostr(CSDN->getZExtValue());
  } else if (const ConstantFPSDNode *CSDN = dyn_cast<ConstantFPSDNode>(Node)) {
    Op += ": " + ftostr(CSDN->getValueAPF());
  } else if (const GlobalAddressSDNode *GADN =
             dyn_cast<GlobalAddressSDNode>(Node)) {
    Op += ": " + GADN->getGlobal()->getName();
    if (int64_t Offset = GADN->getOffset()) {
      if (Offset > 0)
        Op += "+" + itostr(Offset);
      else
        Op += itostr(Offset);
    }
    if (unsigned char TF = GADN->getTargetFlags())
      Op += " [TF=" + utostr(TF) + "]";

  } else if (const FrameIndexSDNode *FIDN = dyn_cast<FrameIndexSDNode>(Node)) {
    Op += " " + itostr(FIDN->getIndex());
  } else if (const JumpTableSDNode *JTDN = dyn_cast<JumpTableSDNode>(Node)) {
    Op += " " + itostr(JTDN->getIndex());
    if (unsigned char TF = JTDN->getTargetFlags())
      Op += " [TF=" + utostr(TF) + "]";
  } else if (const ConstantPoolSDNode *CP = dyn_cast<ConstantPoolSDNode>(Node)){
    if (CP->isMachineConstantPoolEntry()) {
      Op += '<';
      {
        raw_string_ostream OSS(Op);
        OSS << *CP->getMachineCPVal();
      }
      Op += '>';
    } else {
      if (ConstantFP *CFP = dyn_cast<ConstantFP>(CP->getConstVal()))
        Op += "<" + ftostr(CFP->getValueAPF()) + ">";
      else if (ConstantInt *CI = dyn_cast<ConstantInt>(CP->getConstVal()))
        Op += "<" + utostr(CI->getZExtValue()) + ">";
      else {
        Op += '<';
        {
          raw_string_ostream OSS(Op);
          WriteAsOperand(OSS, CP->getConstVal(), false);
        }
        Op += '>';
      }
    }
    Op += " A=" + itostr(CP->getAlignment());
    if (unsigned char TF = CP->getTargetFlags())
      Op += " TF=" + utostr(TF);
  } else if (const BasicBlockSDNode *BBDN = dyn_cast<BasicBlockSDNode>(Node)) {
    Op = "BB: ";
    const Value *LBB = (const Value*)BBDN->getBasicBlock()->getBasicBlock();
    if (LBB)
      Op += LBB->getName();
    //Op += " " + (const void*)BBDN->getBasicBlock();
  } else if (const RegisterSDNode *R = dyn_cast<RegisterSDNode>(Node)) {
    if (G && R->getReg() != 0 &&
        TargetRegisterInfo::isPhysicalRegister(R->getReg())) {
      Op = Op + " " +
        G->getTarget().getRegisterInfo()->getName(R->getReg());
    } else {
      Op += " #" + utostr(R->getReg());
    }
  } else if (const DbgStopPointSDNode *D = dyn_cast<DbgStopPointSDNode>(Node)) {
    DICompileUnit CU(cast<GlobalVariable>(D->getCompileUnit()));
    std::string FN;
    Op += ": " + CU.getFilename(FN);
    Op += ":" + utostr(D->getLine());
    if (D->getColumn() != 0)
      Op += ":" + utostr(D->getColumn());
  } else if (const LabelSDNode *L = dyn_cast<LabelSDNode>(Node)) {
    Op += ": LabelID=" + utostr(L->getLabelID());
  } else if (const CallSDNode *C = dyn_cast<CallSDNode>(Node)) {
    Op += ": CallingConv=" + utostr(C->getCallingConv());
    if (C->isVarArg())
      Op += ", isVarArg";
    if (C->isTailCall())
      Op += ", isTailCall";
  } else if (const ExternalSymbolSDNode *ES =
             dyn_cast<ExternalSymbolSDNode>(Node)) {
    Op += "'" + std::string(ES->getSymbol()) + "'";
  } else if (const SrcValueSDNode *M = dyn_cast<SrcValueSDNode>(Node)) {
    if (M->getValue())
      Op += "<" + M->getValue()->getName() + ">";
    else
      Op += "<null>";
  } else if (const MemOperandSDNode *M = dyn_cast<MemOperandSDNode>(Node)) {
    const Value *V = M->MO.getValue();
    Op += '<';
    if (!V) {
      Op += "(unknown)";
    } else if (const PseudoSourceValue *PSV = dyn_cast<PseudoSourceValue>(V)) {
      // PseudoSourceValues don't have names, so use their print method.
      raw_string_ostream OSS(Op);
      PSV->print(OSS);
    } else {
      Op += V->getName();
    }
    Op += '+' + itostr(M->MO.getOffset()) + '>';
  } else if (const ARG_FLAGSSDNode *N = dyn_cast<ARG_FLAGSSDNode>(Node)) {
    Op = Op + " AF=" + N->getArgFlags().getArgFlagsString();
  } else if (const VTSDNode *N = dyn_cast<VTSDNode>(Node)) {
    Op = Op + " VT=" + N->getVT().getMVTString();
  } else if (const LoadSDNode *LD = dyn_cast<LoadSDNode>(Node)) {
    bool doExt = true;
    switch (LD->getExtensionType()) {
    default: doExt = false; break;
    case ISD::EXTLOAD:
      Op = Op + "<anyext ";
      break;
    case ISD::SEXTLOAD:
      Op = Op + " <sext ";
      break;
    case ISD::ZEXTLOAD:
      Op = Op + " <zext ";
      break;
    }
    if (doExt)
      Op += LD->getMemoryVT().getMVTString() + ">";
    if (LD->isVolatile())
      Op += "<V>";
    Op += LD->getIndexedModeName(LD->getAddressingMode());
    if (LD->getAlignment() > 1)
      Op += " A=" + utostr(LD->getAlignment());
  } else if (const StoreSDNode *ST = dyn_cast<StoreSDNode>(Node)) {
    if (ST->isTruncatingStore())
      Op += "<trunc " + ST->getMemoryVT().getMVTString() + ">";
    if (ST->isVolatile())
      Op += "<V>";
    Op += ST->getIndexedModeName(ST->getAddressingMode());
    if (ST->getAlignment() > 1)
      Op += " A=" + utostr(ST->getAlignment());
  }

#if 0
  Op += " Id=" + itostr(Node->getNodeId());
#endif

  return Op;
}

/// viewGraph - Pop up a ghostview window with the reachable parts of the DAG
/// rendered using 'dot'.
///
void SelectionDAG::viewGraph(const std::string &Title) {
// This code is only for debugging!
#ifndef NDEBUG
  ViewGraph(this, "dag." + getMachineFunction().getFunction()->getName(), false,
            Title);
#else
  cerr << "SelectionDAG::viewGraph is only available in debug builds on "
       << "systems with Graphviz or gv!\n";
#endif  // NDEBUG
}

// This overload is defined out-of-line here instead of just using a
// default parameter because this is easiest for gdb to call.
void SelectionDAG::viewGraph() {
  viewGraph("");
}

/// clearGraphAttrs - Clear all previously defined node graph attributes.
/// Intended to be used from a debugging tool (eg. gdb).
void SelectionDAG::clearGraphAttrs() {
#ifndef NDEBUG
  NodeGraphAttrs.clear();
#else
  cerr << "SelectionDAG::clearGraphAttrs is only available in debug builds"
       << " on systems with Graphviz or gv!\n";
#endif
}

/// setGraphAttrs - Set graph attributes for a node. (eg. "color=red".)
///
void SelectionDAG::setGraphAttrs(const SDNode *N, const char *Attrs) {
#ifndef NDEBUG
  NodeGraphAttrs[N] = Attrs;
#else
  cerr << "SelectionDAG::setGraphAttrs is only available in debug builds"
       << " on systems with Graphviz or gv!\n";
#endif
}

/// getGraphAttrs - Get graph attributes for a node. (eg. "color=red".)
/// Used from getNodeAttributes.
const std::string SelectionDAG::getGraphAttrs(const SDNode *N) const {
#ifndef NDEBUG
  std::map<const SDNode *, std::string>::const_iterator I =
    NodeGraphAttrs.find(N);

  if (I != NodeGraphAttrs.end())
    return I->second;
  else
    return "";
#else
  cerr << "SelectionDAG::getGraphAttrs is only available in debug builds"
       << " on systems with Graphviz or gv!\n";
  return std::string("");
#endif
}

/// setGraphColor - Convenience for setting node color attribute.
///
void SelectionDAG::setGraphColor(const SDNode *N, const char *Color) {
#ifndef NDEBUG
  NodeGraphAttrs[N] = std::string("color=") + Color;
#else
  cerr << "SelectionDAG::setGraphColor is only available in debug builds"
       << " on systems with Graphviz or gv!\n";
#endif
}

/// setSubgraphColorHelper - Implement setSubgraphColor.  Return
/// whether we truncated the search.
///
bool SelectionDAG::setSubgraphColorHelper(SDNode *N, const char *Color, DenseSet<SDNode *> &visited,
                                          int level, bool &printed) {
  bool hit_limit = false;

#ifndef NDEBUG
  if (level >= 20) {
    if (!printed) {
      printed = true;
      DOUT << "setSubgraphColor hit max level\n";
    }
    return true;
  }

  unsigned oldSize = visited.size();
  visited.insert(N);
  if (visited.size() != oldSize) {
    setGraphColor(N, Color);
    for(SDNodeIterator i = SDNodeIterator::begin(N), iend = SDNodeIterator::end(N);
        i != iend;
        ++i) {
      hit_limit = setSubgraphColorHelper(*i, Color, visited, level+1, printed) || hit_limit;
    }
  }
#else
  cerr << "SelectionDAG::setSubgraphColor is only available in debug builds"
       << " on systems with Graphviz or gv!\n";
#endif
  return hit_limit;
}

/// setSubgraphColor - Convenience for setting subgraph color attribute.
///
void SelectionDAG::setSubgraphColor(SDNode *N, const char *Color) {
#ifndef NDEBUG
  DenseSet<SDNode *> visited;
  bool printed = false;
  if (setSubgraphColorHelper(N, Color, visited, 0, printed)) {
    // Visually mark that we hit the limit
    if (strcmp(Color, "red") == 0) {
      setSubgraphColorHelper(N, "blue", visited, 0, printed);
    }
    else if (strcmp(Color, "yellow") == 0) {
      setSubgraphColorHelper(N, "green", visited, 0, printed);
    }
  }

#else
  cerr << "SelectionDAG::setSubgraphColor is only available in debug builds"
       << " on systems with Graphviz or gv!\n";
#endif
}

std::string ScheduleDAGSDNodes::getGraphNodeLabel(const SUnit *SU) const {
  std::string s;
  raw_string_ostream O(s);
  O << "SU(" << SU->NodeNum << "): ";
  if (SU->getNode()) {
    SmallVector<SDNode *, 4> FlaggedNodes;
    for (SDNode *N = SU->getNode(); N; N = N->getFlaggedNode())
      FlaggedNodes.push_back(N);
    while (!FlaggedNodes.empty()) {
      O << DOTGraphTraits<SelectionDAG*>::getNodeLabel(FlaggedNodes.back(),
                                                       DAG, false);
      FlaggedNodes.pop_back();
      if (!FlaggedNodes.empty())
        O << "\n    ";
    }
  } else {
    O << "CROSS RC COPY";
  }
  return O.str();
}

void ScheduleDAGSDNodes::getCustomGraphFeatures(GraphWriter<ScheduleDAG*> &GW) const {
  if (DAG) {
    // Draw a special "GraphRoot" node to indicate the root of the graph.
    GW.emitSimpleNode(0, "plaintext=circle", "GraphRoot");
    const SDNode *N = DAG->getRoot().getNode();
    if (N && N->getNodeId() != -1)
      GW.emitEdge(0, -1, &SUnits[N->getNodeId()], -1,
                  "color=blue,style=dashed");
  }
}
<commit_msg>implement DOTGraphTraits<SelectionDAG*>::getNodeLabel in terms of SDNode::print_details to eliminate a ton of near-duplicate code.<commit_after>//===-- SelectionDAGPrinter.cpp - Implement SelectionDAG::viewGraph() -----===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This implements the SelectionDAG::viewGraph method.
//
//===----------------------------------------------------------------------===//

#include "ScheduleDAGSDNodes.h"
#include "llvm/Constants.h"
#include "llvm/Function.h"
#include "llvm/Assembly/Writer.h"
#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/PseudoSourceValue.h"
#include "llvm/Analysis/DebugInfo.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/GraphWriter.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Config/config.h"
#include <fstream>
using namespace llvm;

namespace llvm {
  template<>
  struct DOTGraphTraits<SelectionDAG*> : public DefaultDOTGraphTraits {
    static bool hasEdgeDestLabels() {
      return true;
    }

    static unsigned numEdgeDestLabels(const void *Node) {
      return ((const SDNode *) Node)->getNumValues();
    }

    static std::string getEdgeDestLabel(const void *Node, unsigned i) {
      return ((const SDNode *) Node)->getValueType(i).getMVTString();
    }

    /// edgeTargetsEdgeSource - This method returns true if this outgoing edge
    /// should actually target another edge source, not a node.  If this method is
    /// implemented, getEdgeTarget should be implemented.
    template<typename EdgeIter>
    static bool edgeTargetsEdgeSource(const void *Node, EdgeIter I) {
      return true;
    }

    /// getEdgeTarget - If edgeTargetsEdgeSource returns true, this method is
    /// called to determine which outgoing edge of Node is the target of this
    /// edge.
    template<typename EdgeIter>
    static EdgeIter getEdgeTarget(const void *Node, EdgeIter I) {
      SDNode *TargetNode = *I;
      SDNodeIterator NI = SDNodeIterator::begin(TargetNode);
      std::advance(NI, I.getNode()->getOperand(I.getOperand()).getResNo());
      return NI;
    }

    static std::string getGraphName(const SelectionDAG *G) {
      return G->getMachineFunction().getFunction()->getName();
    }

    static bool renderGraphFromBottomUp() {
      return true;
    }

    static bool hasNodeAddressLabel(const SDNode *Node,
                                    const SelectionDAG *Graph) {
      return true;
    }

    /// If you want to override the dot attributes printed for a particular
    /// edge, override this method.
    template<typename EdgeIter>
    static std::string getEdgeAttributes(const void *Node, EdgeIter EI) {
      SDValue Op = EI.getNode()->getOperand(EI.getOperand());
      MVT VT = Op.getValueType();
      if (VT == MVT::Flag)
        return "color=red,style=bold";
      else if (VT == MVT::Other)
        return "color=blue,style=dashed";
      return "";
    }

    static std::string getNodeLabel(const SDNode *Node,
                                    const SelectionDAG *Graph,
                                    bool ShortNames);
    static std::string getNodeAttributes(const SDNode *N,
                                         const SelectionDAG *Graph) {
#ifndef NDEBUG
      const std::string &Attrs = Graph->getGraphAttrs(N);
      if (!Attrs.empty()) {
        if (Attrs.find("shape=") == std::string::npos)
          return std::string("shape=Mrecord,") + Attrs;
        else
          return Attrs;
      }
#endif
      return "shape=Mrecord";
    }

    static void addCustomGraphFeatures(SelectionDAG *G,
                                       GraphWriter<SelectionDAG*> &GW) {
      GW.emitSimpleNode(0, "plaintext=circle", "GraphRoot");
      if (G->getRoot().getNode())
        GW.emitEdge(0, -1, G->getRoot().getNode(), G->getRoot().getResNo(),
                    "color=blue,style=dashed");
    }
  };
}

std::string DOTGraphTraits<SelectionDAG*>::getNodeLabel(const SDNode *Node,
                                                        const SelectionDAG *G,
                                                        bool ShortNames) {
  std::string Result = Node->getOperationName(G);
  {
    raw_string_ostream OS(Result);
    Node->print_details(OS, G);
  }
  return Result;
}

/// viewGraph - Pop up a ghostview window with the reachable parts of the DAG
/// rendered using 'dot'.
///
void SelectionDAG::viewGraph(const std::string &Title) {
// This code is only for debugging!
#ifndef NDEBUG
  ViewGraph(this, "dag." + getMachineFunction().getFunction()->getName(), false,
            Title);
#else
  cerr << "SelectionDAG::viewGraph is only available in debug builds on "
       << "systems with Graphviz or gv!\n";
#endif  // NDEBUG
}

// This overload is defined out-of-line here instead of just using a
// default parameter because this is easiest for gdb to call.
void SelectionDAG::viewGraph() {
  viewGraph("");
}

/// clearGraphAttrs - Clear all previously defined node graph attributes.
/// Intended to be used from a debugging tool (eg. gdb).
void SelectionDAG::clearGraphAttrs() {
#ifndef NDEBUG
  NodeGraphAttrs.clear();
#else
  cerr << "SelectionDAG::clearGraphAttrs is only available in debug builds"
       << " on systems with Graphviz or gv!\n";
#endif
}

/// setGraphAttrs - Set graph attributes for a node. (eg. "color=red".)
///
void SelectionDAG::setGraphAttrs(const SDNode *N, const char *Attrs) {
#ifndef NDEBUG
  NodeGraphAttrs[N] = Attrs;
#else
  cerr << "SelectionDAG::setGraphAttrs is only available in debug builds"
       << " on systems with Graphviz or gv!\n";
#endif
}

/// getGraphAttrs - Get graph attributes for a node. (eg. "color=red".)
/// Used from getNodeAttributes.
const std::string SelectionDAG::getGraphAttrs(const SDNode *N) const {
#ifndef NDEBUG
  std::map<const SDNode *, std::string>::const_iterator I =
    NodeGraphAttrs.find(N);

  if (I != NodeGraphAttrs.end())
    return I->second;
  else
    return "";
#else
  cerr << "SelectionDAG::getGraphAttrs is only available in debug builds"
       << " on systems with Graphviz or gv!\n";
  return std::string("");
#endif
}

/// setGraphColor - Convenience for setting node color attribute.
///
void SelectionDAG::setGraphColor(const SDNode *N, const char *Color) {
#ifndef NDEBUG
  NodeGraphAttrs[N] = std::string("color=") + Color;
#else
  cerr << "SelectionDAG::setGraphColor is only available in debug builds"
       << " on systems with Graphviz or gv!\n";
#endif
}

/// setSubgraphColorHelper - Implement setSubgraphColor.  Return
/// whether we truncated the search.
///
bool SelectionDAG::setSubgraphColorHelper(SDNode *N, const char *Color, DenseSet<SDNode *> &visited,
                                          int level, bool &printed) {
  bool hit_limit = false;

#ifndef NDEBUG
  if (level >= 20) {
    if (!printed) {
      printed = true;
      DOUT << "setSubgraphColor hit max level\n";
    }
    return true;
  }

  unsigned oldSize = visited.size();
  visited.insert(N);
  if (visited.size() != oldSize) {
    setGraphColor(N, Color);
    for(SDNodeIterator i = SDNodeIterator::begin(N), iend = SDNodeIterator::end(N);
        i != iend;
        ++i) {
      hit_limit = setSubgraphColorHelper(*i, Color, visited, level+1, printed) || hit_limit;
    }
  }
#else
  cerr << "SelectionDAG::setSubgraphColor is only available in debug builds"
       << " on systems with Graphviz or gv!\n";
#endif
  return hit_limit;
}

/// setSubgraphColor - Convenience for setting subgraph color attribute.
///
void SelectionDAG::setSubgraphColor(SDNode *N, const char *Color) {
#ifndef NDEBUG
  DenseSet<SDNode *> visited;
  bool printed = false;
  if (setSubgraphColorHelper(N, Color, visited, 0, printed)) {
    // Visually mark that we hit the limit
    if (strcmp(Color, "red") == 0) {
      setSubgraphColorHelper(N, "blue", visited, 0, printed);
    }
    else if (strcmp(Color, "yellow") == 0) {
      setSubgraphColorHelper(N, "green", visited, 0, printed);
    }
  }

#else
  cerr << "SelectionDAG::setSubgraphColor is only available in debug builds"
       << " on systems with Graphviz or gv!\n";
#endif
}

std::string ScheduleDAGSDNodes::getGraphNodeLabel(const SUnit *SU) const {
  std::string s;
  raw_string_ostream O(s);
  O << "SU(" << SU->NodeNum << "): ";
  if (SU->getNode()) {
    SmallVector<SDNode *, 4> FlaggedNodes;
    for (SDNode *N = SU->getNode(); N; N = N->getFlaggedNode())
      FlaggedNodes.push_back(N);
    while (!FlaggedNodes.empty()) {
      O << DOTGraphTraits<SelectionDAG*>::getNodeLabel(FlaggedNodes.back(),
                                                       DAG, false);
      FlaggedNodes.pop_back();
      if (!FlaggedNodes.empty())
        O << "\n    ";
    }
  } else {
    O << "CROSS RC COPY";
  }
  return O.str();
}

void ScheduleDAGSDNodes::getCustomGraphFeatures(GraphWriter<ScheduleDAG*> &GW) const {
  if (DAG) {
    // Draw a special "GraphRoot" node to indicate the root of the graph.
    GW.emitSimpleNode(0, "plaintext=circle", "GraphRoot");
    const SDNode *N = DAG->getRoot().getNode();
    if (N && N->getNodeId() != -1)
      GW.emitEdge(0, -1, &SUnits[N->getNodeId()], -1,
                  "color=blue,style=dashed");
  }
}
<|endoftext|>


<commit_before>#include "get_new_points.hxx"

#include "eval_weighted.hxx"
#include "poles_prefactor.hxx"
#include "power_prefactor.hxx"

#include "../sdp_solve.hxx"
#include "../ostream_set.hxx"

std::vector<El::BigFloat>
compute_optimal(const std::vector<Positive_Matrix_With_Prefactor> &matrices,
                const std::vector<El::BigFloat> &objectives,
                const std::vector<El::BigFloat> &normalization,
                const SDP_Solver_Parameters &parameters)
{
  size_t num_weights(normalization.size());

  const size_t num_blocks(matrices.size());
  std::vector<El::BigFloat> weights(num_weights, 0);
  std::vector<std::set<El::BigFloat>> points(num_blocks);
  std::vector<std::vector<El::BigFloat>> new_points(num_blocks);

  // Need to have a point at zero and infinity
  // GMP does not have a special infinity value, so we use max double.
  const El::BigFloat infinity(std::numeric_limits<double>::max());
  const El::BigFloat min_x(0), max_x(infinity);
  for(size_t block(0); block < num_blocks; ++block)
    {
      points.at(block).emplace(min_x);
      points.at(block).emplace(1);
      // for(double x(min_x); x < max_x; x *= 4)
      //   points.at(block).emplace(x);

      new_points.at(block).emplace_back(max_x);
    }

  bool has_new_points(true);

  while(has_new_points)
    {
      has_new_points = false;
      size_t num_constraints(0);
      std::vector<size_t> matrix_dimensions;
      for(size_t block(0); block != num_blocks; ++block)
        {
          for(auto &point : new_points.at(block))
            {
              points.at(block).emplace(point);
            }
          num_constraints += points.at(block).size();
          matrix_dimensions.insert(matrix_dimensions.end(),
                                   points.at(block).size(),
                                   matrices[block].polynomials.size());
          if(El::mpi::Rank() == 0)
            {
              std::cout << "points: " << block << " " << points.at(block)
                        << "\n";
            }
        }

      if(El::mpi::Rank() == 0)
        {
          std::cout << "num_constraints: " << num_constraints << "\n";
        }
      // std::cout << "matrix_dimensions: " << matrix_dimensions << "\n";

      Block_Info block_info(matrix_dimensions, parameters.procs_per_node,
                            parameters.proc_granularity, parameters.verbosity);
      El::Grid grid(block_info.mpi_comm.value);
      std::vector<El::BigFloat> prefactors;
      prefactors.reserve(num_constraints);
      std::vector<std::vector<El::BigFloat>> primal_objective_c;
      primal_objective_c.reserve(num_constraints);
      std::vector<El::Matrix<El::BigFloat>> free_var_matrix;
      free_var_matrix.reserve(num_constraints);

      // TODO: This is duplicated from sdp2input/write_output/write_output.cxx
      auto max_normalization(normalization.begin());
      for(auto n(normalization.begin()); n != normalization.end(); ++n)
        {
          if(Abs(*n) > Abs(*max_normalization))
            {
              max_normalization = n;
            }
        }
      const int64_t max_index(
        std::distance(normalization.begin(), max_normalization));

      for(size_t block(0); block != num_blocks; ++block)
        {
          for(auto &x : points.at(block))
            {
              if(x == infinity)
                {
                  prefactors.push_back(1);
                }
              else
                {
                  prefactors.push_back(
                    power_prefactor(matrices[block].damped_rational.base, x)
                    * poles_prefactor(matrices[block].damped_rational.poles,
                                      x));
                }
              auto &prefactor(prefactors.back());
              const size_t dim(matrices[block].polynomials.size());
              free_var_matrix.emplace_back(
                dim * (dim + 1) / 2,
                matrices[block].polynomials.at(0).at(0).size() - 1);
              auto &free_var(free_var_matrix.back());

              primal_objective_c.emplace_back();
              auto &primal(primal_objective_c.back());

              size_t flattened_matrix_row(0);
              for(size_t matrix_row(0); matrix_row != dim; ++matrix_row)
                for(size_t matrix_column(0); matrix_column <= matrix_row;
                    ++matrix_column)
                  {
                    if(x == infinity)
                      {
                        int64_t max_degree(0);
                        for(auto &poly : matrices[block]
                                           .polynomials.at(matrix_row)
                                           .at(matrix_column))
                          max_degree = std::max(max_degree, poly.degree());
                        if(matrices[block]
                             .polynomials.at(matrix_row)
                             .at(matrix_column)
                             .at(max_index)
                             .degree()
                           < max_degree)
                          {
                            primal.push_back(0);
                          }
                        else
                          {
                            primal.push_back(matrices[block]
                                               .polynomials.at(matrix_row)
                                               .at(matrix_column)
                                               .at(max_index)
                                               .coefficients.at(max_degree)
                                             / normalization.at(max_index));
                          }
                        auto &primal_constant(primal.back());
                        for(int64_t column(0); column != free_var.Width();
                            ++column)
                          {
                            const int64_t index(
                              column + (column < max_index ? 0 : 1));
                            if(matrices[block]
                                 .polynomials.at(matrix_row)
                                 .at(matrix_column)
                                 .at(index)
                                 .degree()
                               < max_degree)
                              {
                                free_var(flattened_matrix_row, column)
                                  = primal_constant * normalization.at(index);
                              }
                            else
                              {
                                free_var(flattened_matrix_row, column)
                                  = primal_constant * normalization.at(index)
                                    - matrices[block]
                                        .polynomials.at(matrix_row)
                                        .at(matrix_column)
                                        .at(index)
                                        .coefficients.at(max_degree);
                              }
                          }
                      }
                    else
                      {
                        primal.push_back(prefactor
                                         * matrices[block]
                                             .polynomials.at(matrix_row)
                                             .at(matrix_column)
                                             .at(max_index)(x)
                                         / normalization.at(max_index));

                        auto &primal_constant(primal.back());
                        for(int64_t column(0); column != free_var.Width();
                            ++column)
                          {
                            const int64_t index(
                              column + (column < max_index ? 0 : 1));
                            free_var(flattened_matrix_row, column)
                              = primal_constant * normalization.at(index)
                                - prefactor
                                    * matrices[block]
                                        .polynomials.at(matrix_row)
                                        .at(matrix_column)
                                        .at(index)(x);
                          }
                      }
                    ++flattened_matrix_row;
                  }
            }
        }

      SDP sdp(objectives, normalization, prefactors, primal_objective_c,
              free_var_matrix, block_info, grid);

      SDP_Solver solver(parameters, block_info, grid,
                        sdp.dual_objective_b.Height());

      for(auto &block : solver.y.blocks)
        {
          if(block.GlobalCol(0) == 0)
            {
              for(int64_t row(0); row != block.LocalHeight(); ++row)
                {
                  int64_t global_row(block.GlobalRow(row));
                  const int64_t index(global_row
                                      + (global_row < max_index ? 0 : 1));
                  block.SetLocal(row, 0, weights.at(index));
                }
            }
        }

      Timers timers(parameters.verbosity >= Verbosity::debug);
      SDP_Solver_Terminate_Reason reason
        = solver.run(parameters, block_info, sdp, grid, timers);
      if(reason != SDP_Solver_Terminate_Reason::PrimalDualOptimal)
        {
          std::stringstream ss;
          ss << "Can not find solution: " << reason;
          throw std::runtime_error(ss.str());
        }

      // y is duplicated among cores, so only need to print out copy on
      // the root node.
      // THe weight at max_index is determined by the normalization condition
      // dot(norm,weights)=1
      weights.at(max_index) = 1;
      for(int64_t block_row(0); block_row != solver.y.blocks.at(0).Height();
          ++block_row)
        {
          const int64_t index(block_row + (block_row < max_index ? 0 : 1));
          weights.at(index) = solver.y.blocks.at(0).Get(block_row, 0);
          weights.at(max_index) -= weights.at(index) * normalization.at(index);
        }
      weights.at(max_index) /= normalization.at(max_index);

      if(El::mpi::Rank() == 0)
        {
          std::cout.precision(10);
          std::cout << "weight: " << weights << "\n";

          El::BigFloat optimal(0);
          for(size_t index(0); index < objectives.size(); ++index)
            {
              optimal += objectives[index] * weights[index];
            }
          std::cout << "optimal: " << optimal << "\n";
        }
      for(size_t block(0); block != num_blocks; ++block)
        {
          // 0.01 should be a small enough relative error so that we are
          // in the regime of convergence.  Then the error estimates will
          // work
          // Mesh mesh(*(points.at(block).begin()), *(points.at(block).rbegin()),
          Mesh mesh(*(points.at(block).begin()), El::BigFloat(100),
                    [&](const El::BigFloat &x) {
                      return eval_weighted(matrices[block], x, weights);
                    },
                    0.01);
          new_points.at(block) = get_new_points(mesh);
          for(auto &point : new_points.at(block))
            {
              has_new_points
                = has_new_points || (points.at(block).count(point) == 0);
            }
        }
    }
  // if(El::mpi::Rank() == 0)
  //   {
  //     std::cout << "weights: " << weights << "\n";
  //   }
  return weights;
}
<commit_msg>Set max_degree correctly, once for the entire matrix<commit_after>#include "get_new_points.hxx"

#include "eval_weighted.hxx"
#include "poles_prefactor.hxx"
#include "power_prefactor.hxx"

#include "../sdp_solve.hxx"
#include "../ostream_set.hxx"

std::vector<El::BigFloat>
compute_optimal(const std::vector<Positive_Matrix_With_Prefactor> &matrices,
                const std::vector<El::BigFloat> &objectives,
                const std::vector<El::BigFloat> &normalization,
                const SDP_Solver_Parameters &parameters)
{
  size_t num_weights(normalization.size());

  const size_t num_blocks(matrices.size());
  std::vector<El::BigFloat> weights(num_weights, 0);
  std::vector<std::set<El::BigFloat>> points(num_blocks);
  std::vector<std::vector<El::BigFloat>> new_points(num_blocks);

  // Need to have a point at zero and infinity
  // GMP does not have a special infinity value, so we use max double.
  const El::BigFloat infinity(std::numeric_limits<double>::max());
  const El::BigFloat min_x(0), max_x(infinity);
  for(size_t block(0); block < num_blocks; ++block)
    {
      points.at(block).emplace(min_x);
      points.at(block).emplace(1);
      // for(double x(min_x); x < max_x; x *= 4)
      //   points.at(block).emplace(x);

      new_points.at(block).emplace_back(max_x);
    }

  bool has_new_points(true);

  while(has_new_points)
    {
      has_new_points = false;
      size_t num_constraints(0);
      std::vector<size_t> matrix_dimensions;
      for(size_t block(0); block != num_blocks; ++block)
        {
          for(auto &point : new_points.at(block))
            {
              points.at(block).emplace(point);
            }
          num_constraints += points.at(block).size();
          matrix_dimensions.insert(matrix_dimensions.end(),
                                   points.at(block).size(),
                                   matrices[block].polynomials.size());
          if(El::mpi::Rank() == 0)
            {
              std::cout << "points: " << block << " " << points.at(block)
                        << "\n";
            }
        }

      if(El::mpi::Rank() == 0)
        {
          std::cout << "num_constraints: " << num_constraints << "\n";
        }
      // std::cout << "matrix_dimensions: " << matrix_dimensions << "\n";

      Block_Info block_info(matrix_dimensions, parameters.procs_per_node,
                            parameters.proc_granularity, parameters.verbosity);
      El::Grid grid(block_info.mpi_comm.value);
      std::vector<El::BigFloat> prefactors;
      prefactors.reserve(num_constraints);
      std::vector<std::vector<El::BigFloat>> primal_objective_c;
      primal_objective_c.reserve(num_constraints);
      std::vector<El::Matrix<El::BigFloat>> free_var_matrix;
      free_var_matrix.reserve(num_constraints);

      // TODO: This is duplicated from sdp2input/write_output/write_output.cxx
      auto max_normalization(normalization.begin());
      for(auto n(normalization.begin()); n != normalization.end(); ++n)
        {
          if(Abs(*n) > Abs(*max_normalization))
            {
              max_normalization = n;
            }
        }
      const int64_t max_index(
        std::distance(normalization.begin(), max_normalization));

      for(size_t block(0); block != num_blocks; ++block)
        {
          for(auto &x : points.at(block))
            {
              if(x == infinity)
                {
                  prefactors.push_back(1);
                }
              else
                {
                  prefactors.push_back(
                    power_prefactor(matrices[block].damped_rational.base, x)
                    * poles_prefactor(matrices[block].damped_rational.poles,
                                      x));
                }
              auto &prefactor(prefactors.back());
              const size_t dim(matrices[block].polynomials.size());
              free_var_matrix.emplace_back(
                dim * (dim + 1) / 2,
                matrices[block].polynomials.at(0).at(0).size() - 1);
              auto &free_var(free_var_matrix.back());

              primal_objective_c.emplace_back();
              auto &primal(primal_objective_c.back());

              int64_t max_degree(0);
              for(auto &row: matrices[block].polynomials)
                for(auto &column: row)
                  for(auto &poly: column)
                    {
                      max_degree = std::max(max_degree, poly.degree());
                    }

              size_t flattened_matrix_row(0);
              for(size_t matrix_row(0); matrix_row != dim; ++matrix_row)
                for(size_t matrix_column(0); matrix_column <= matrix_row;
                    ++matrix_column)
                  {
                    if(x == infinity)
                      {
                        if(matrices[block]
                             .polynomials.at(matrix_row)
                             .at(matrix_column)
                             .at(max_index)
                             .degree()
                           < max_degree)
                          {
                            primal.push_back(0);
                          }
                        else
                          {
                            primal.push_back(matrices[block]
                                               .polynomials.at(matrix_row)
                                               .at(matrix_column)
                                               .at(max_index)
                                               .coefficients.at(max_degree)
                                             / normalization.at(max_index));
                          }
                        auto &primal_constant(primal.back());
                        for(int64_t column(0); column != free_var.Width();
                            ++column)
                          {
                            const int64_t index(
                              column + (column < max_index ? 0 : 1));
                            if(matrices[block]
                                 .polynomials.at(matrix_row)
                                 .at(matrix_column)
                                 .at(index)
                                 .degree()
                               < max_degree)
                              {
                                free_var(flattened_matrix_row, column)
                                  = primal_constant * normalization.at(index);
                              }
                            else
                              {
                                free_var(flattened_matrix_row, column)
                                  = primal_constant * normalization.at(index)
                                    - matrices[block]
                                        .polynomials.at(matrix_row)
                                        .at(matrix_column)
                                        .at(index)
                                        .coefficients.at(max_degree);
                              }
                          }
                      }
                    else
                      {
                        primal.push_back(prefactor
                                         * matrices[block]
                                             .polynomials.at(matrix_row)
                                             .at(matrix_column)
                                             .at(max_index)(x)
                                         / normalization.at(max_index));

                        auto &primal_constant(primal.back());
                        for(int64_t column(0); column != free_var.Width();
                            ++column)
                          {
                            const int64_t index(
                              column + (column < max_index ? 0 : 1));
                            free_var(flattened_matrix_row, column)
                              = primal_constant * normalization.at(index)
                                - prefactor
                                    * matrices[block]
                                        .polynomials.at(matrix_row)
                                        .at(matrix_column)
                                        .at(index)(x);
                          }
                      }
                    ++flattened_matrix_row;
                  }
            }
        }

      SDP sdp(objectives, normalization, prefactors, primal_objective_c,
              free_var_matrix, block_info, grid);

      SDP_Solver solver(parameters, block_info, grid,
                        sdp.dual_objective_b.Height());

      for(auto &block : solver.y.blocks)
        {
          if(block.GlobalCol(0) == 0)
            {
              for(int64_t row(0); row != block.LocalHeight(); ++row)
                {
                  int64_t global_row(block.GlobalRow(row));
                  const int64_t index(global_row
                                      + (global_row < max_index ? 0 : 1));
                  block.SetLocal(row, 0, weights.at(index));
                }
            }
        }

      Timers timers(parameters.verbosity >= Verbosity::debug);
      SDP_Solver_Terminate_Reason reason
        = solver.run(parameters, block_info, sdp, grid, timers);
      if(reason != SDP_Solver_Terminate_Reason::PrimalDualOptimal)
        {
          std::stringstream ss;
          ss << "Can not find solution: " << reason;
          throw std::runtime_error(ss.str());
        }

      // y is duplicated among cores, so only need to print out copy on
      // the root node.
      // THe weight at max_index is determined by the normalization condition
      // dot(norm,weights)=1
      weights.at(max_index) = 1;
      for(int64_t block_row(0); block_row != solver.y.blocks.at(0).Height();
          ++block_row)
        {
          const int64_t index(block_row + (block_row < max_index ? 0 : 1));
          weights.at(index) = solver.y.blocks.at(0).Get(block_row, 0);
          weights.at(max_index) -= weights.at(index) * normalization.at(index);
        }
      weights.at(max_index) /= normalization.at(max_index);

      if(El::mpi::Rank() == 0)
        {
          std::cout.precision(10);
          std::cout << "weight: " << weights << "\n";

          El::BigFloat optimal(0);
          for(size_t index(0); index < objectives.size(); ++index)
            {
              optimal += objectives[index] * weights[index];
            }
          std::cout << "optimal: " << optimal << "\n";
        }
      for(size_t block(0); block != num_blocks; ++block)
        {
          // 0.01 should be a small enough relative error so that we are
          // in the regime of convergence.  Then the error estimates will
          // work
          // Mesh mesh(*(points.at(block).begin()), *(points.at(block).rbegin()),
          Mesh mesh(*(points.at(block).begin()), El::BigFloat(100),
                    [&](const El::BigFloat &x) {
                      return eval_weighted(matrices[block], x, weights);
                    },
                    0.01);
          new_points.at(block) = get_new_points(mesh);
          for(auto &point : new_points.at(block))
            {
              has_new_points
                = has_new_points || (points.at(block).count(point) == 0);
            }
        }
    }
  // if(El::mpi::Rank() == 0)
  //   {
  //     std::cout << "weights: " << weights << "\n";
  //   }
  return weights;
}
<|endoftext|>