<commit_before>/*
The OpenTRV project licenses this file to you
under the Apache Licence, Version 2.0 (the "Licence");
you may not use this file except in compliance
with the Licence. You may obtain a copy of the Licence at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the Licence is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the Licence for the
specific language governing permissions and limitations
under the Licence.

Author(s) / Copyright (s): Damon Hart-Davis 2013--2015
*/

/*
 Real-time clock support and RTC-connected watchdog/reset.

 Implementation highly hardware specific.
 */

#ifdef ARDUINO_ARCH_AVR
#include <util/atomic.h>
#endif

#ifdef ARDUINO
#include <Arduino.h>
#endif

#if 0
#include "OTV0p2Base.h"
#endif

#include "OTV0P2BASE_EEPROM.h"
#include "OTV0P2BASE_Sleep.h"

#include "OTV0P2BASE_RTC.h"

namespace OTV0P2BASE
{

// Seconds for local time (and assumed UTC) in range [0,59].
// Volatile to allow for async update.
// Maintained locally or shadowed from external RTC.
// Read and write accesses assumed effectively atomic.
// NOT FOR DIRECT ACCESS OUTSIDE RTC ROUTINES.
volatile uint_fast8_t _secondsLT;

// Minutes since midnight for local time in range [0,1439].
// Must be accessed with interrupts disabled and as if volatile.
// Maintained locally or shadowed from external RTC.
// NOT FOR DIRECT ACCESS OUTSIDE RTC ROUTINES.
volatile uint_least16_t _minutesSinceMidnightLT;

// Whole days since the start of 2000/01/01 (ie the midnight between 1999 and 2000), local time.
// Must be accessed with interrupts disabled and as if volatile.
// This will roll in about 2179.
// NOT FOR DIRECT ACCESS OUTSIDE RTC ROUTINES.
volatile uint_least16_t _daysSince1999LT;

#ifdef ARDUINO_ARCH_AVR
// The encoding for the persisted HH:MM value is as follows.
// The top 5 bits are the hour in the range [0,23].
// The bottom 3 bits indicate the quarter hour as follows:
// 111 => :00, 110 => :15, 100 => :30, 000 => :45.
// Invalid values (in particular, 0xff, for an erased byte) are ignored.
// On the hour the full byte is erased and written, including all the lsbits at 1.
// At each quarter hour one of the lsbits is written to zero (no erase is needed).
// Thus an hour causes 1 erase and 4 writes (3 of which only affect one bit each).
// The AVR EEPROM is rated for 100k cycles per byte (or page, not clear from docs),
// where a cycle would normally be 1 erase and 1 write.
// At worst, providing that no redundant writes are done,
// this causes 35k operations per year for ~3 years of continuous operation.
// If changing the bits is the stressful part that wears the EEPROM,
// and given that each bit only sees one erase and (at most) one subsequent write to 0 each hour,
// it may be reasonable to hope for upwards of 12 years of operation,
// in which time the Flash program and other EEPROM contents may have evaporated anyway.
// It is best to keep this byte in an EEPROM page without any other critical data
// and/or that is subject to significant erase/write cycles of its own,
// and where bytes may not be truely independent for wear purposes.

// Persist software RTC information to non-volatile (EEPROM) store.
// This does not attempt to store full precision of time down to seconds,
// but enough to help avoid the clock slipping too much during (say) a battery change.
// There is no point calling this more than (say) once per minute,
// though it will simply return relatively quickly from redundant calls.
// The RTC data is stored so as not to wear out AVR EEPROM for at least several years.
// IMPLEMENTATION OF THIS AND THE eeprom_smart_xxx_byte() ROUTINES IS CRITICAL TO PERFORMANCE AND LONGEVITY.
void persistRTC()
  {
  ATOMIC_BLOCK (ATOMIC_RESTORESTATE)
    {
    uint8_t quarterHours = (_minutesSinceMidnightLT / 15);
    uint8_t targetByte = (quarterHours << 1) & ~7U; // Bit pattern now hhhhh000 where hhhhh is whole hours [0,23].
    switch(quarterHours & 3)
      {
      case 0: targetByte |= 7; break;
      case 1: targetByte |= 3; break;
      case 2: targetByte |= 1; break;
      }

    // Update if target HH:MM not already correct.
    const uint8_t persistedValue = eeprom_read_byte((uint8_t*)V0P2BASE_EE_START_RTC_HHMM_PERSIST);
    if(persistedValue != targetByte)
      {
      // Where it is not possible to get the target value just by setting bits to 0,
      // eg for a new hour (ie completely different hour to that in EEPROM and on roll to new hour),
      // then do a full erase/write...
      //if((0 == quarterHours) || ((persistedValue & 0xf8) != (targetByte & 0xf8)))
      if(targetByte != (persistedValue & targetByte))
        { eeprom_write_byte((uint8_t*)V0P2BASE_EE_START_RTC_HHMM_PERSIST, targetByte); }
      // Else do a write without erase, typically clearing the quarter bits one at a time...
      else
        { eeprom_smart_clear_bits((uint8_t*)V0P2BASE_EE_START_RTC_HHMM_PERSIST, targetByte); }

      // Also persist the current days if not up to date.
      const uint16_t days = eeprom_read_word((uint16_t*)V0P2BASE_EE_START_RTC_DAY_PERSIST);
      if(days != _daysSince1999LT) { eeprom_write_word((uint16_t*)V0P2BASE_EE_START_RTC_DAY_PERSIST, _daysSince1999LT); }
      }
    }
  }
#endif // ARDUINO_ARCH_AVR

#ifdef ARDUINO_ARCH_AVR
// Restore software RTC information from non-volatile (EEPROM) store, if possible.
// Returns true if the persisted data seemed valid and was restored, in full or part.
// To void on average using 15/2 minutes at each reset/restart,
// this starts the internal time a little over half way into the restored 15-minute slot.
// This restores the minutes and above but leaves seconds unset.
bool restoreRTC()
  {
  uint8_t persistedValue;
  ATOMIC_BLOCK (ATOMIC_RESTORESTATE)
    {
    // Restore the persisted days, though ignore if apparently unset (all 1s).
    const uint16_t days = eeprom_read_word((uint16_t*)V0P2BASE_EE_START_RTC_DAY_PERSIST);
    if(days != (uint16_t)~0U) { _daysSince1999LT = days; }

    // Now recover persisted HH:MM value.
    persistedValue = eeprom_read_byte((uint8_t*)V0P2BASE_EE_START_RTC_HHMM_PERSIST);
    }

  // Abort if value clearly invalid, eg likely an unprogrammed (0xff) byte.
  if(persistedValue >= (24 << 3)) { return(false); }

  uint_least16_t minutesSinceMidnight = (persistedValue >> 3) * 60;
  minutesSinceMidnight += 8; // Start just over half-way into one quantum to minimise average time lost on restart.
  const uint8_t lowBits = persistedValue & 7; // Extract quarter-hour bits.
  switch(lowBits)
    {
    case 0: minutesSinceMidnight += 45; break;
    case 1: minutesSinceMidnight += 30; break;
    case 3: minutesSinceMidnight += 15; break;
    case 7: break; // Nothing to add, but a valid 0-quarter bit pattern.
    default: return(false); // Invalid bit pattern: abort.
    }

  // Set the hours and minutes (atomically).
  // Deliberately leave the seconds unset to avoid units becoming too synchronised with one another, increasing TX collisions, etc.
  ATOMIC_BLOCK (ATOMIC_RESTORESTATE)
    { _minutesSinceMidnightLT = minutesSinceMidnight; }

  return(true);
  }
#endif // ARDUINO_ARCH_AVR

// Get minutes since midnight local time [0,1439].
// Useful to fetch time atomically for scheduling purposes.
// Preserves interrupt state.
// Thread-safe and ISR-safe ON AVR ONLY for now.
#ifndef getMinutesSinceMidnightLT
uint_least16_t getMinutesSinceMidnightLT()
  {
  uint_least16_t result;
#ifdef ARDUINO_ARCH_AVR
  ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
#endif // ARDUINO_ARCH_AVR
    { result = _minutesSinceMidnightLT; }
  return(result);
  }
#endif

#ifdef ARDUINO_ARCH_AVR
// Get local time minutes from RTC [0,59].
// Relatively slow.
// Thread-safe and ISR-safe.
uint_least8_t getMinutesLT() { return(getMinutesSinceMidnightLT() % 60); }
#endif

#ifdef ARDUINO_ARCH_AVR
// Get local time hours from RTC [0,23].
// Relatively slow.
// Thread-safe and ISR-safe.
uint_least8_t getHoursLT() { return(getMinutesSinceMidnightLT() / 60); }
#endif

#ifdef ARDUINO_ARCH_AVR
// Get whole days since the start of 2000/01/01 (ie the midnight between 1999 and 2000), local time.
// This will roll in about 2179, by which time I will not care.
// Thread-safe and ISR-safe.
uint_least16_t getDaysSince1999LT()
  {
  uint_least16_t result;
  ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
    { result = _daysSince1999LT; }
  return(result);
  }
#endif // ARDUINO_ARCH_AVR

#ifdef ARDUINO_ARCH_AVR
// Get previous hour in current local time, wrapping round from 0 to 23.
uint_least8_t getPrevHourLT()
  {
  const uint_least16_t h = OTV0P2BASE::getHoursLT();
  if(0 == h) { return(23); }
  return(h - 1);
  }
// Get next hour in current local time, wrapping round from 23 back to 0.
uint_least8_t getNextHourLT()
  {
  const uint_least16_t h = OTV0P2BASE::getHoursLT();
  if(h >= 23) { return(0); }
  return(h + 1);
  }
#endif

#ifdef ARDUINO_ARCH_AVR
// Set time as hours [0,23] and minutes [0,59].
// Will ignore attempts to set bad values and return false in that case.
// Returns true if all OK and the time has been set.
// Does not attempt to set seconds.
// Thread/interrupt safe, but do not call this from an ISR.
// Will persist time to survive reset / power-cycle as necessary.
bool setHoursMinutesLT(const uint8_t hours, const uint8_t minutes)
  {
  if((hours > 23) || (minutes > 59)) { return(false); } // Invalid time.
  const uint_least16_t computedMinutesSinceMidnightLT = (uint_least16_t) ((60 * (uint_least16_t)hours) + minutes);
  ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
    {
    if(computedMinutesSinceMidnightLT != _minutesSinceMidnightLT)
      {
      // If time has changed then store it locally and persist it if need be.
      _minutesSinceMidnightLT = computedMinutesSinceMidnightLT;
      persistRTC();
      }
    }
  return(true); // Assume set and persisted OK.
  }
#endif // ARDUINO_ARCH_AVR

// Set nominal seconds [0,59].
// Not persisted, may be offset from real time.
// Will ignore attempts to set bad values and return false in that case.
// Will drop the least significant bit if counting in 2s increments.
// Returns true if all OK and the time has been set.
// Thread/interrupt safe, but do not call this from an ISR.
bool setSeconds(const uint8_t seconds)
  {
  if(seconds > 59) { return(false); } // Invalid time.
#if defined(V0P2BASE_TWO_S_TICK_RTC_SUPPORT)
  _secondsLT = seconds & ~1; // Drop the bottom bit.  Assumed safe/atomic.
#else
  _secondsLT = seconds; // Assumed safe/atomic.
#endif
  return(true); // Assume set OK.
  }

// RTC-based watchdog, if enabled with enableRTCWatchdog(true),
// will force a reset if the resetRTCWatchDog() is not called
// between one RTC tick interrupt and the next.
//
// If true then the RTC-based watchdog mechanism is enabled.
static volatile bool _RTCWatchdogEnabled;
// If true, then enable the RTC-based watchdog; disable otherwise.
void enableRTCWatchdog(const bool enable) { _RTCWatchdogEnabled = enable; }
// If true on following tick, watchdog reset is triggered.
static volatile bool _RTCWatchdogResetNotCalled;
// Must be called between each 'tick' of the RTC clock if enabled, else system will reset.
void resetRTCWatchDog() { _RTCWatchdogResetNotCalled = false; }

#ifdef ARDUINO_ARCH_AVR
// Hook into TIMER2 overflow interrupt to drive RTC and provide slow wake-up tick.
ISR(TIMER2_OVF_vect)
  {
  // Maintain RTC, as energy-efficiently as reasonably possible.
  // An ISR so must not:
  //   * do anything expensive,
  //   * access EEPROM,
  //   * enable interrupts,
  //   * alter interrupt state from how it was on entry.
  register uint_fast8_t sTemp = _secondsLT; // Avoid some redundant memory accesses.
  sTemp += MAIN_TICK_S;
  if(sTemp > 59)
    {
    sTemp = 0; // Seconds roll.
    register uint_least16_t mTemp = _minutesSinceMidnightLT + 1; // Avoid some redundant memory accesses.
    if(mTemp > 1439)
      {
      mTemp = 0; // Minutes/hours roll.
      // Increment the day.
      ++_daysSince1999LT; // Don't currently prevent roll.
      }
    _minutesSinceMidnightLT = mTemp;
    }
  _secondsLT = sTemp;
  // Deal with watchdog, if enabled.
  if(_RTCWatchdogEnabled)
    {
    if(_RTCWatchdogResetNotCalled) {
#if 0
        OTV0P2BASE::serialPrintlnAndFlush(F("!WD"))
#endif
        forceReset();
    }
    _RTCWatchdogResetNotCalled = true;
    }
  }
#endif // ARDUINO_ARCH_AVR

}
<commit_msg>Fixed typo and added debug preprocessor paths<commit_after>/*
The OpenTRV project licenses this file to you
under the Apache Licence, Version 2.0 (the "Licence");
you may not use this file except in compliance
with the Licence. You may obtain a copy of the Licence at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the Licence is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the Licence for the
specific language governing permissions and limitations
under the Licence.

Author(s) / Copyright (s): Damon Hart-Davis 2013--2015
*/

/*
 Real-time clock support and RTC-connected watchdog/reset.

 Implementation highly hardware specific.
 */

#ifdef ARDUINO_ARCH_AVR
#include <util/atomic.h>
#endif

#ifdef ARDUINO
#include <Arduino.h>
#endif

#ifdef DEBUG
#include "OTV0p2Base.h"
#endif

#include "OTV0P2BASE_EEPROM.h"
#include "OTV0P2BASE_Sleep.h"

#include "OTV0P2BASE_RTC.h"

namespace OTV0P2BASE
{

// Seconds for local time (and assumed UTC) in range [0,59].
// Volatile to allow for async update.
// Maintained locally or shadowed from external RTC.
// Read and write accesses assumed effectively atomic.
// NOT FOR DIRECT ACCESS OUTSIDE RTC ROUTINES.
volatile uint_fast8_t _secondsLT;

// Minutes since midnight for local time in range [0,1439].
// Must be accessed with interrupts disabled and as if volatile.
// Maintained locally or shadowed from external RTC.
// NOT FOR DIRECT ACCESS OUTSIDE RTC ROUTINES.
volatile uint_least16_t _minutesSinceMidnightLT;

// Whole days since the start of 2000/01/01 (ie the midnight between 1999 and 2000), local time.
// Must be accessed with interrupts disabled and as if volatile.
// This will roll in about 2179.
// NOT FOR DIRECT ACCESS OUTSIDE RTC ROUTINES.
volatile uint_least16_t _daysSince1999LT;

#ifdef ARDUINO_ARCH_AVR
// The encoding for the persisted HH:MM value is as follows.
// The top 5 bits are the hour in the range [0,23].
// The bottom 3 bits indicate the quarter hour as follows:
// 111 => :00, 110 => :15, 100 => :30, 000 => :45.
// Invalid values (in particular, 0xff, for an erased byte) are ignored.
// On the hour the full byte is erased and written, including all the lsbits at 1.
// At each quarter hour one of the lsbits is written to zero (no erase is needed).
// Thus an hour causes 1 erase and 4 writes (3 of which only affect one bit each).
// The AVR EEPROM is rated for 100k cycles per byte (or page, not clear from docs),
// where a cycle would normally be 1 erase and 1 write.
// At worst, providing that no redundant writes are done,
// this causes 35k operations per year for ~3 years of continuous operation.
// If changing the bits is the stressful part that wears the EEPROM,
// and given that each bit only sees one erase and (at most) one subsequent write to 0 each hour,
// it may be reasonable to hope for upwards of 12 years of operation,
// in which time the Flash program and other EEPROM contents may have evaporated anyway.
// It is best to keep this byte in an EEPROM page without any other critical data
// and/or that is subject to significant erase/write cycles of its own,
// and where bytes may not be truely independent for wear purposes.

// Persist software RTC information to non-volatile (EEPROM) store.
// This does not attempt to store full precision of time down to seconds,
// but enough to help avoid the clock slipping too much during (say) a battery change.
// There is no point calling this more than (say) once per minute,
// though it will simply return relatively quickly from redundant calls.
// The RTC data is stored so as not to wear out AVR EEPROM for at least several years.
// IMPLEMENTATION OF THIS AND THE eeprom_smart_xxx_byte() ROUTINES IS CRITICAL TO PERFORMANCE AND LONGEVITY.
void persistRTC()
  {
  ATOMIC_BLOCK (ATOMIC_RESTORESTATE)
    {
    uint8_t quarterHours = (_minutesSinceMidnightLT / 15);
    uint8_t targetByte = (quarterHours << 1) & ~7U; // Bit pattern now hhhhh000 where hhhhh is whole hours [0,23].
    switch(quarterHours & 3)
      {
      case 0: targetByte |= 7; break;
      case 1: targetByte |= 3; break;
      case 2: targetByte |= 1; break;
      }

    // Update if target HH:MM not already correct.
    const uint8_t persistedValue = eeprom_read_byte((uint8_t*)V0P2BASE_EE_START_RTC_HHMM_PERSIST);
    if(persistedValue != targetByte)
      {
      // Where it is not possible to get the target value just by setting bits to 0,
      // eg for a new hour (ie completely different hour to that in EEPROM and on roll to new hour),
      // then do a full erase/write...
      //if((0 == quarterHours) || ((persistedValue & 0xf8) != (targetByte & 0xf8)))
      if(targetByte != (persistedValue & targetByte))
        { eeprom_write_byte((uint8_t*)V0P2BASE_EE_START_RTC_HHMM_PERSIST, targetByte); }
      // Else do a write without erase, typically clearing the quarter bits one at a time...
      else
        { eeprom_smart_clear_bits((uint8_t*)V0P2BASE_EE_START_RTC_HHMM_PERSIST, targetByte); }

      // Also persist the current days if not up to date.
      const uint16_t days = eeprom_read_word((uint16_t*)V0P2BASE_EE_START_RTC_DAY_PERSIST);
      if(days != _daysSince1999LT) { eeprom_write_word((uint16_t*)V0P2BASE_EE_START_RTC_DAY_PERSIST, _daysSince1999LT); }
      }
    }
  }
#endif // ARDUINO_ARCH_AVR

#ifdef ARDUINO_ARCH_AVR
// Restore software RTC information from non-volatile (EEPROM) store, if possible.
// Returns true if the persisted data seemed valid and was restored, in full or part.
// To void on average using 15/2 minutes at each reset/restart,
// this starts the internal time a little over half way into the restored 15-minute slot.
// This restores the minutes and above but leaves seconds unset.
bool restoreRTC()
  {
  uint8_t persistedValue;
  ATOMIC_BLOCK (ATOMIC_RESTORESTATE)
    {
    // Restore the persisted days, though ignore if apparently unset (all 1s).
    const uint16_t days = eeprom_read_word((uint16_t*)V0P2BASE_EE_START_RTC_DAY_PERSIST);
    if(days != (uint16_t)~0U) { _daysSince1999LT = days; }

    // Now recover persisted HH:MM value.
    persistedValue = eeprom_read_byte((uint8_t*)V0P2BASE_EE_START_RTC_HHMM_PERSIST);
    }

  // Abort if value clearly invalid, eg likely an unprogrammed (0xff) byte.
  if(persistedValue >= (24 << 3)) { return(false); }

  uint_least16_t minutesSinceMidnight = (persistedValue >> 3) * 60;
  minutesSinceMidnight += 8; // Start just over half-way into one quantum to minimise average time lost on restart.
  const uint8_t lowBits = persistedValue & 7; // Extract quarter-hour bits.
  switch(lowBits)
    {
    case 0: minutesSinceMidnight += 45; break;
    case 1: minutesSinceMidnight += 30; break;
    case 3: minutesSinceMidnight += 15; break;
    case 7: break; // Nothing to add, but a valid 0-quarter bit pattern.
    default: return(false); // Invalid bit pattern: abort.
    }

  // Set the hours and minutes (atomically).
  // Deliberately leave the seconds unset to avoid units becoming too synchronised with one another, increasing TX collisions, etc.
  ATOMIC_BLOCK (ATOMIC_RESTORESTATE)
    { _minutesSinceMidnightLT = minutesSinceMidnight; }

  return(true);
  }
#endif // ARDUINO_ARCH_AVR

// Get minutes since midnight local time [0,1439].
// Useful to fetch time atomically for scheduling purposes.
// Preserves interrupt state.
// Thread-safe and ISR-safe ON AVR ONLY for now.
#ifndef getMinutesSinceMidnightLT
uint_least16_t getMinutesSinceMidnightLT()
  {
  uint_least16_t result;
#ifdef ARDUINO_ARCH_AVR
  ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
#endif // ARDUINO_ARCH_AVR
    { result = _minutesSinceMidnightLT; }
  return(result);
  }
#endif

#ifdef ARDUINO_ARCH_AVR
// Get local time minutes from RTC [0,59].
// Relatively slow.
// Thread-safe and ISR-safe.
uint_least8_t getMinutesLT() { return(getMinutesSinceMidnightLT() % 60); }
#endif

#ifdef ARDUINO_ARCH_AVR
// Get local time hours from RTC [0,23].
// Relatively slow.
// Thread-safe and ISR-safe.
uint_least8_t getHoursLT() { return(getMinutesSinceMidnightLT() / 60); }
#endif

#ifdef ARDUINO_ARCH_AVR
// Get whole days since the start of 2000/01/01 (ie the midnight between 1999 and 2000), local time.
// This will roll in about 2179, by which time I will not care.
// Thread-safe and ISR-safe.
uint_least16_t getDaysSince1999LT()
  {
  uint_least16_t result;
  ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
    { result = _daysSince1999LT; }
  return(result);
  }
#endif // ARDUINO_ARCH_AVR

#ifdef ARDUINO_ARCH_AVR
// Get previous hour in current local time, wrapping round from 0 to 23.
uint_least8_t getPrevHourLT()
  {
  const uint_least16_t h = OTV0P2BASE::getHoursLT();
  if(0 == h) { return(23); }
  return(h - 1);
  }
// Get next hour in current local time, wrapping round from 23 back to 0.
uint_least8_t getNextHourLT()
  {
  const uint_least16_t h = OTV0P2BASE::getHoursLT();
  if(h >= 23) { return(0); }
  return(h + 1);
  }
#endif

#ifdef ARDUINO_ARCH_AVR
// Set time as hours [0,23] and minutes [0,59].
// Will ignore attempts to set bad values and return false in that case.
// Returns true if all OK and the time has been set.
// Does not attempt to set seconds.
// Thread/interrupt safe, but do not call this from an ISR.
// Will persist time to survive reset / power-cycle as necessary.
bool setHoursMinutesLT(const uint8_t hours, const uint8_t minutes)
  {
  if((hours > 23) || (minutes > 59)) { return(false); } // Invalid time.
  const uint_least16_t computedMinutesSinceMidnightLT = (uint_least16_t) ((60 * (uint_least16_t)hours) + minutes);
  ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
    {
    if(computedMinutesSinceMidnightLT != _minutesSinceMidnightLT)
      {
      // If time has changed then store it locally and persist it if need be.
      _minutesSinceMidnightLT = computedMinutesSinceMidnightLT;
      persistRTC();
      }
    }
  return(true); // Assume set and persisted OK.
  }
#endif // ARDUINO_ARCH_AVR

// Set nominal seconds [0,59].
// Not persisted, may be offset from real time.
// Will ignore attempts to set bad values and return false in that case.
// Will drop the least significant bit if counting in 2s increments.
// Returns true if all OK and the time has been set.
// Thread/interrupt safe, but do not call this from an ISR.
bool setSeconds(const uint8_t seconds)
  {
  if(seconds > 59) { return(false); } // Invalid time.
#if defined(V0P2BASE_TWO_S_TICK_RTC_SUPPORT)
  _secondsLT = seconds & ~1; // Drop the bottom bit.  Assumed safe/atomic.
#else
  _secondsLT = seconds; // Assumed safe/atomic.
#endif
  return(true); // Assume set OK.
  }

// RTC-based watchdog, if enabled with enableRTCWatchdog(true),
// will force a reset if the resetRTCWatchDog() is not called
// between one RTC tick interrupt and the next.
//
// If true then the RTC-based watchdog mechanism is enabled.
static volatile bool _RTCWatchdogEnabled;
// If true, then enable the RTC-based watchdog; disable otherwise.
void enableRTCWatchdog(const bool enable) { _RTCWatchdogEnabled = enable; }
// If true on following tick, watchdog reset is triggered.
static volatile bool _RTCWatchdogResetNotCalled;
// Must be called between each 'tick' of the RTC clock if enabled, else system will reset.
void resetRTCWatchDog() { _RTCWatchdogResetNotCalled = false; }

#ifdef ARDUINO_ARCH_AVR
// Hook into TIMER2 overflow interrupt to drive RTC and provide slow wake-up tick.
ISR(TIMER2_OVF_vect)
  {
  // Maintain RTC, as energy-efficiently as reasonably possible.
  // An ISR so must not:
  //   * do anything expensive,
  //   * access EEPROM,
  //   * enable interrupts,
  //   * alter interrupt state from how it was on entry.
  register uint_fast8_t sTemp = _secondsLT; // Avoid some redundant memory accesses.
  sTemp += MAIN_TICK_S;
  if(sTemp > 59)
    {
    sTemp = 0; // Seconds roll.
    register uint_least16_t mTemp = _minutesSinceMidnightLT + 1; // Avoid some redundant memory accesses.
    if(mTemp > 1439)
      {
      mTemp = 0; // Minutes/hours roll.
      // Increment the day.
      ++_daysSince1999LT; // Don't currently prevent roll.
      }
    _minutesSinceMidnightLT = mTemp;
    }
  _secondsLT = sTemp;
  // Deal with watchdog, if enabled.
  if(_RTCWatchdogEnabled)
    {
    if(_RTCWatchdogResetNotCalled) {
#ifdef DEBUG
		// Notify that the watchdog has been triggered.
        OTV0P2BASE::serialPrintlnAndFlush(F("!WD"));
#endif
        forceReset();
    }
    _RTCWatchdogResetNotCalled = true;
    }
  }
#endif // ARDUINO_ARCH_AVR

}
<|endoftext|>


<commit_before>#include "CameraDefinition.h"

#include <cmath>
#include "PackStream.h"
#include "BoundingBox.h"

CameraDefinition::CameraDefinition(DefinitionNode *parent):
    DefinitionNode(parent, "camera", "camera")
{
    location.x = 0.0;
    location.y = 0.0;
    location.z = 0.0;
    direction.phi = 0.0;
    direction.theta = 0.0;
    direction.r = 1.0;
    roll = 0.0;

    width = 1.0;
    height = 1.0;
    perspective.yfov = 1.0;
    perspective.xratio = 1.0;
    perspective.znear = 1.0;
    perspective.zfar = 1000.0;

    validate();
}

void CameraDefinition::save(PackStream* stream) const
{
    location.save(stream);
    stream->write(&direction.r);
    stream->write(&direction.phi);
    stream->write(&direction.theta);
    stream->write(&roll);
    stream->write(&perspective.yfov);
}

void CameraDefinition::load(PackStream* stream)
{
    location.load(stream);
    stream->read(&direction.r);
    stream->read(&direction.phi);
    stream->read(&direction.theta);
    stream->read(&roll);
    stream->read(&perspective.yfov);

    validate();
}

void CameraDefinition::copy(DefinitionNode* _destination) const
{
    CameraDefinition* destination = (CameraDefinition*)_destination;

    destination->location = location;
    destination->direction = direction;
    destination->roll = roll;

    destination->perspective = perspective;

    destination->validate();
}

void CameraDefinition::validate()
{
    if (location.y > 300.0)
    {
        location.y = 300.0;
    }

    forward.x = 1.0;
    forward.y = 0.0;
    forward.z = 0.0;
    right.x = 0.0;
    right.y = 0.0;
    right.z = 1.0;
    up.x = 0.0;
    up.y = 1.0;
    up.z = 0.0;

    Matrix4 rotation = Matrix4::newRotateEuler(direction.phi, direction.theta, roll);

    forward = rotation.multPoint(forward);
    right = rotation.multPoint(right);
    up = rotation.multPoint(up);

    target = location.add(direction);

    Matrix4 mperspective = Matrix4::newPerspective(perspective.yfov, perspective.xratio, perspective.znear, perspective.zfar);
    unperspective = mperspective.inversed();

    projector = mperspective.mult(Matrix4::newLookAt(location, target, up));
    unprojector = projector.inversed();

    inv_x_factor = 1.0 / (0.5 * width);
    inv_y_factor = 1.0 / (0.5 * height);
}

double CameraDefinition::getRealDepth(const Vector3 &projected) const
{
    Vector3 v(projected.x * inv_x_factor - 1.0, -(projected.y * inv_x_factor - 1.0), projected.z);
    return unperspective.transform(v).z;
}

void CameraDefinition::setLocation(const Vector3 &location)
{
    this->location = location;

    validate();
}

void CameraDefinition::setLocationCoords(double x, double y, double z)
{
    location = Vector3(x, y, z);

    validate();
}

void CameraDefinition::setTarget(const Vector3 &target)
{
    Vector3 forward;

    forward = target.sub(location);
    if (forward.getNorm() < 0.0000001)
    {
        return;
    }

    direction = forward.toSpherical();

    validate();
}

void CameraDefinition::setTargetCoords(double x, double y, double z)
{
    setTarget(Vector3(x, y, z));
}

void CameraDefinition::setRoll(double angle)
{
    roll = angle;

    validate();
}

void CameraDefinition::setZoomToTarget(double zoom)
{
    direction.r = zoom;
    location = target.add(Vector3(direction).scale(-1.0));

    validate();
}

void CameraDefinition::setFov(double fov)
{
    perspective.yfov = fov;

    validate();
}

void CameraDefinition::strafeForward(double value)
{
    location = location.add(forward.scale(value));

    validate();
}

void CameraDefinition::strafeRight(double value)
{
    location = location.add(right.scale(value));

    validate();
}

void CameraDefinition::strafeUp(double value)
{
    location = location.add(up.scale(value));

    validate();
}

void CameraDefinition::rotateYaw(double value)
{
    direction.phi += value;

    validate();
}

void CameraDefinition::rotatePitch(double value)
{
    direction.theta += value;

    validate();
}

void CameraDefinition::rotateRoll(double value)
{
    roll += value;

    validate();
}

void CameraDefinition::setRenderSize(int width, int height)
{
    this->width = (double)width;
    this->height = (double)height;
    perspective.xratio = this->width / this->height;

    validate();
}

Vector3 CameraDefinition::project(const Vector3 &point) const
{
    Vector3 tpoint = projector.transform(point);
    if (tpoint.z < 1.0)
    {
        tpoint.x = -tpoint.x;
        tpoint.y = -tpoint.y;
    }
    tpoint.x = (tpoint.x + 1.0) * 0.5 * width;
    tpoint.y = (-tpoint.y + 1.0) * 0.5 * height;
    return tpoint;
}

Vector3 CameraDefinition::unproject(const Vector3 &point) const
{
    Vector3 tpoint(point.x / (0.5 * width) - 1.0, -(point.y / (0.5 * height) - 1.0), point.z);
    if (tpoint.z < 1.0)
    {
        tpoint.x = -tpoint.x;
        tpoint.y = -tpoint.y;
    }
    return unprojector.transform(tpoint);
}

int CameraDefinition::isBoxInView(const Vector3 &center, double xsize, double ysize, double zsize) const
{
    BoundingBox box;

    box.pushPoint(center.add(Vector3(-xsize, -ysize, -zsize)));
    box.pushPoint(center.add(Vector3(xsize, ysize, zsize)));

    return isUnprojectedBoxInView(box);
}

int CameraDefinition::isUnprojectedBoxInView(const BoundingBox &box) const
{
    BoundingBox projected;

    projected.pushPoint(project(Vector3(box.xmin, box.ymin, box.zmin)));
    projected.pushPoint(project(Vector3(box.xmax, box.ymin, box.zmin)));
    projected.pushPoint(project(Vector3(box.xmin, box.ymax, box.zmin)));
    projected.pushPoint(project(Vector3(box.xmax, box.ymax, box.zmin)));
    projected.pushPoint(project(Vector3(box.xmin, box.ymin, box.zmax)));
    projected.pushPoint(project(Vector3(box.xmax, box.ymin, box.zmax)));
    projected.pushPoint(project(Vector3(box.xmin, box.ymax, box.zmax)));
    projected.pushPoint(project(Vector3(box.xmax, box.ymax, box.zmax)));

    return isProjectedBoxInView(projected);
}

int CameraDefinition::isProjectedBoxInView(const BoundingBox &box) const
{
    if (box.xmin <= width && box.xmax >= 0.0 && box.ymin <= height && box.ymax >= 0.0 && box.zmax >= perspective.znear)
    {
        double dx = box.xmax - box.xmin;
        double dy = box.ymax - box.ymin;

        return (int)ceil(dx) * (int)ceil(dy);
    }
    else
    {
        return 0;
    }
}

bool CameraDefinition::transitionToAnother(const CameraDefinition *wanted, double factor)
{
    double dx, dy, dz, dr, dphi, dtheta, droll;

    dx = wanted->location.x - location.x;
    dy = wanted->location.y - location.y;
    dz = wanted->location.z - location.z;
    dr = wanted->direction.r - direction.r;
    dphi = wanted->direction.phi - direction.phi;
    dtheta = wanted->direction.theta - direction.theta;
    droll = wanted->roll - roll;

    if (fabs(dx) < 0.000001 && fabs(dy) < 0.000001 && fabs(dz) < 0.000001 && fabs(dr) < 0.000001 && fabs(dphi) < 0.000001 && fabs(dtheta) < 0.000001 && fabs(droll) < 0.000001)
    {
        return false;
    }
    else
    {
        location.x += dx * factor;
        location.y += dy * factor;
        location.z += dz * factor;
        direction.r += dr * factor;
        direction.phi += dphi * factor;
        direction.theta += dtheta * factor;
        roll += droll * factor;

        validate();
        return true;
    }
}
<commit_msg>Fixed camera Z-culling planes<commit_after>#include "CameraDefinition.h"

#include <cmath>
#include "PackStream.h"
#include "BoundingBox.h"

CameraDefinition::CameraDefinition(DefinitionNode *parent):
    DefinitionNode(parent, "camera", "camera")
{
    location.x = 0.0;
    location.y = 0.0;
    location.z = 0.0;
    direction.phi = 0.0;
    direction.theta = 0.0;
    direction.r = 1.0;
    roll = 0.0;

    width = 1.0;
    height = 1.0;
    perspective.yfov = 1.0;
    perspective.xratio = 1.0;
    perspective.znear = 0.5;
    perspective.zfar = 20000.0;

    validate();
}

void CameraDefinition::save(PackStream* stream) const
{
    location.save(stream);
    stream->write(&direction.r);
    stream->write(&direction.phi);
    stream->write(&direction.theta);
    stream->write(&roll);
    stream->write(&perspective.yfov);
}

void CameraDefinition::load(PackStream* stream)
{
    location.load(stream);
    stream->read(&direction.r);
    stream->read(&direction.phi);
    stream->read(&direction.theta);
    stream->read(&roll);
    stream->read(&perspective.yfov);

    validate();
}

void CameraDefinition::copy(DefinitionNode* _destination) const
{
    CameraDefinition* destination = (CameraDefinition*)_destination;

    destination->location = location;
    destination->direction = direction;
    destination->roll = roll;

    destination->perspective = perspective;

    destination->validate();
}

void CameraDefinition::validate()
{
    if (location.y > 300.0)
    {
        location.y = 300.0;
    }

    forward.x = 1.0;
    forward.y = 0.0;
    forward.z = 0.0;
    right.x = 0.0;
    right.y = 0.0;
    right.z = 1.0;
    up.x = 0.0;
    up.y = 1.0;
    up.z = 0.0;

    Matrix4 rotation = Matrix4::newRotateEuler(direction.phi, direction.theta, roll);

    forward = rotation.multPoint(forward);
    right = rotation.multPoint(right);
    up = rotation.multPoint(up);

    target = location.add(direction);

    Matrix4 mperspective = Matrix4::newPerspective(perspective.yfov, perspective.xratio, perspective.znear, perspective.zfar);
    unperspective = mperspective.inversed();

    projector = mperspective.mult(Matrix4::newLookAt(location, target, up));
    unprojector = projector.inversed();

    inv_x_factor = 1.0 / (0.5 * width);
    inv_y_factor = 1.0 / (0.5 * height);
}

double CameraDefinition::getRealDepth(const Vector3 &projected) const
{
    Vector3 v(projected.x * inv_x_factor - 1.0, -(projected.y * inv_x_factor - 1.0), projected.z);
    return unperspective.transform(v).z;
}

void CameraDefinition::setLocation(const Vector3 &location)
{
    this->location = location;

    validate();
}

void CameraDefinition::setLocationCoords(double x, double y, double z)
{
    location = Vector3(x, y, z);

    validate();
}

void CameraDefinition::setTarget(const Vector3 &target)
{
    Vector3 forward;

    forward = target.sub(location);
    if (forward.getNorm() < 0.0000001)
    {
        return;
    }

    direction = forward.toSpherical();

    validate();
}

void CameraDefinition::setTargetCoords(double x, double y, double z)
{
    setTarget(Vector3(x, y, z));
}

void CameraDefinition::setRoll(double angle)
{
    roll = angle;

    validate();
}

void CameraDefinition::setZoomToTarget(double zoom)
{
    direction.r = zoom;
    location = target.add(Vector3(direction).scale(-1.0));

    validate();
}

void CameraDefinition::setFov(double fov)
{
    perspective.yfov = fov;

    validate();
}

void CameraDefinition::strafeForward(double value)
{
    location = location.add(forward.scale(value));

    validate();
}

void CameraDefinition::strafeRight(double value)
{
    location = location.add(right.scale(value));

    validate();
}

void CameraDefinition::strafeUp(double value)
{
    location = location.add(up.scale(value));

    validate();
}

void CameraDefinition::rotateYaw(double value)
{
    direction.phi += value;

    validate();
}

void CameraDefinition::rotatePitch(double value)
{
    direction.theta += value;

    validate();
}

void CameraDefinition::rotateRoll(double value)
{
    roll += value;

    validate();
}

void CameraDefinition::setRenderSize(int width, int height)
{
    this->width = (double)width;
    this->height = (double)height;
    perspective.xratio = this->width / this->height;

    validate();
}

Vector3 CameraDefinition::project(const Vector3 &point) const
{
    Vector3 tpoint = projector.transform(point);
    if (tpoint.z < 1.0)
    {
        tpoint.x = -tpoint.x;
        tpoint.y = -tpoint.y;
    }
    tpoint.x = (tpoint.x + 1.0) * 0.5 * width;
    tpoint.y = (-tpoint.y + 1.0) * 0.5 * height;
    return tpoint;
}

Vector3 CameraDefinition::unproject(const Vector3 &point) const
{
    Vector3 tpoint(point.x / (0.5 * width) - 1.0, -(point.y / (0.5 * height) - 1.0), point.z);
    if (tpoint.z < 1.0)
    {
        tpoint.x = -tpoint.x;
        tpoint.y = -tpoint.y;
    }
    return unprojector.transform(tpoint);
}

int CameraDefinition::isBoxInView(const Vector3 &center, double xsize, double ysize, double zsize) const
{
    BoundingBox box;

    box.pushPoint(center.add(Vector3(-xsize, -ysize, -zsize)));
    box.pushPoint(center.add(Vector3(xsize, ysize, zsize)));

    return isUnprojectedBoxInView(box);
}

int CameraDefinition::isUnprojectedBoxInView(const BoundingBox &box) const
{
    BoundingBox projected;

    projected.pushPoint(project(Vector3(box.xmin, box.ymin, box.zmin)));
    projected.pushPoint(project(Vector3(box.xmax, box.ymin, box.zmin)));
    projected.pushPoint(project(Vector3(box.xmin, box.ymax, box.zmin)));
    projected.pushPoint(project(Vector3(box.xmax, box.ymax, box.zmin)));
    projected.pushPoint(project(Vector3(box.xmin, box.ymin, box.zmax)));
    projected.pushPoint(project(Vector3(box.xmax, box.ymin, box.zmax)));
    projected.pushPoint(project(Vector3(box.xmin, box.ymax, box.zmax)));
    projected.pushPoint(project(Vector3(box.xmax, box.ymax, box.zmax)));

    return isProjectedBoxInView(projected);
}

int CameraDefinition::isProjectedBoxInView(const BoundingBox &box) const
{
    if (box.xmin <= width && box.xmax >= 0.0 && box.ymin <= height && box.ymax >= 0.0 && box.zmax >= perspective.znear)
    {
        double dx = box.xmax - box.xmin;
        double dy = box.ymax - box.ymin;

        return (int)ceil(dx) * (int)ceil(dy);
    }
    else
    {
        return 0;
    }
}

bool CameraDefinition::transitionToAnother(const CameraDefinition *wanted, double factor)
{
    double dx, dy, dz, dr, dphi, dtheta, droll;

    dx = wanted->location.x - location.x;
    dy = wanted->location.y - location.y;
    dz = wanted->location.z - location.z;
    dr = wanted->direction.r - direction.r;
    dphi = wanted->direction.phi - direction.phi;
    dtheta = wanted->direction.theta - direction.theta;
    droll = wanted->roll - roll;

    if (fabs(dx) < 0.000001 && fabs(dy) < 0.000001 && fabs(dz) < 0.000001 && fabs(dr) < 0.000001 && fabs(dphi) < 0.000001 && fabs(dtheta) < 0.000001 && fabs(droll) < 0.000001)
    {
        return false;
    }
    else
    {
        location.x += dx * factor;
        location.y += dy * factor;
        location.z += dz * factor;
        direction.r += dr * factor;
        direction.phi += dphi * factor;
        direction.theta += dtheta * factor;
        roll += droll * factor;

        validate();
        return true;
    }
}
<|endoftext|>


<commit_before>//
// Created by Vadim N. on 04/04/2015.
//
//#include <omp.h>
//#include <stdio.h>
//
//int main() {
//#pragma omp parallel
//    printf("Hello from thread %d, nthreads %d\n", omp_get_thread_num(), omp_get_num_threads());
//}

#include <ostream>

#include "Model"

using namespace ymir;

/**
 * \brief Main function of a script for computing generation probabitilies. It has
 * a strict order of input arguments in console:
 * argv[0] - name of the script (default);
 * argv[1] - path to an input file;
 * argv[2] - path to a model;
 * argv[3] - path to an output file;
 * argv[4] - 0 if model should use stored gene usage; 1 if model should recompute gene usage from the input file.
 * argv[5] - 'n' for nucleotide sequences, 'a' for amino acid sequences.
 */
int main(int argc, char* argv[]) {
    std::string in_file_path(argv[1]),
            model_path(argv[2]),
            out_file_path(argv[3]);
    bool recompute_genes = std::stoi(argv[4]);

    std::cout << "Input file:\t" << in_file_path << std::endl;
    std::cout << "Model path:\t" << model_path << std::endl;
    std::cout << "Output file:\t" << out_file_path << std::endl;
    std::cout << std::endl;

    ProbabilisticAssemblingModel model(model_path);
    std::cout << std::endl;

    if (model.status()) {

        //
        // Nucleotide
        //
//        if (argv[5] == "n") {
        ParserNuc parser(new NaiveCDR3NucleotideAligner(model.gene_segments(), VDJAlignerParameters(3)));
        ClonesetNuc cloneset;

        auto alignment_column_options = AlignmentColumnOptions(AlignmentColumnOptions::REALIGN_PROVIDED,
                                                               AlignmentColumnOptions::OVERWRITE,
                                                               AlignmentColumnOptions::REALIGN_PROVIDED);

        auto vdj_aligner_parameters_nuc = VDJAlignerParameters(3,
                                                               VDJAlignmentEventScore(AlignmentEventScore(1, -1, 1),
                                                                                AlignmentEventScore(1, -1, 1),
                                                                                AlignmentEventScore(1, -1, 1)),
                                                               VDJAlignmentScoreThreshold(2, 2, 2));

        auto vdj_aligner_parameters_aa =  VDJAlignerParameters(3,
                                                               VDJAlignmentEventScore(AlignmentEventScore(1, -1, 1),
                                                                                AlignmentEventScore(1, -1, 1),
                                                                                AlignmentEventScore(1, -1, 1)),
                                                               VDJAlignmentScoreThreshold(1, 1, 1));

        if (parser.openAndParse(in_file_path,
                                &cloneset,
                                model.gene_segments(),
                                model.recombination(),
                                alignment_column_options,
                                vdj_aligner_parameters_nuc))
        {
            if (recompute_genes) {
                std::cout << std::endl;
                std::cout << "Recomputing gene usage on " << (size_t) cloneset.noncoding().size() << " clonotypes." << std::endl;
                model.updateGeneUsage(cloneset);
            }
            std::cout << std::endl;

            std::vector<prob_t> prob_vec;
            std::vector<size_t> noncoding_indices;
            std::vector<prob_t> coding_probs;

            if (argv[5][0] == 'n') {
                prob_vec = model.computeFullProbabilities(cloneset, NO_ERRORS);
            } else {
                ClonesetAA cloneset_aa;

                std::cout << "Converting nucleotide clonotypes to amino acid clonotypes..." << std::endl;
                noncoding_indices = CDR3AminoAcidAligner(model.gene_segments(), vdj_aligner_parameters_aa).toAminoAcid(cloneset, &cloneset_aa, true);
                std::cout << "Done." << std::endl << std::endl;

                coding_probs = model.computeFullProbabilities(cloneset_aa);
            }

            std::ofstream ofs;
            ofs.open(out_file_path);

            std::cout << std::endl;
            std::cout << "Generation probabilities statistics:" << std::endl;
            prob_summary(prob_vec);

            if (ofs.is_open()) {
                // Write nucleotide probabilities.
                if (prob_vec.size()) {
                    for (auto i = 0; i < prob_vec.size(); ++i) {
                        ofs << prob_vec[i] << std::endl;
                    }
                }

                // Write amino acid probabilities.
                else {
                    size_t k = 0, j = 0;
                    for (auto i = 0; i < cloneset.size(); ++i) {
                        if (k != noncoding_indices.size() && i == noncoding_indices[k]) {
                            ofs << "-1" << std::endl;
                            ++k;
                        } else {
                            ofs << coding_probs[j] << std::endl;
                            ++j;
                        }
                    }
                }
            } else {
                std::cout << "Problems with the output stream. Terminating..." << std::endl;
            }
            ofs.close();
        } else {
            std::cout << "Problems in parsing the input file. Terminating..." << std::endl;
        }
//        }

        //
        // Amino acid
        //
//        else {
//            ParserAA parser;
//            ClonesetAA cloneset;
//
//            if (parser.openAndParse(in_file_path,
//                                    &cloneset,
//                                    model.gene_segments(),
//                                    model.recombination(),
//                                    AlignmentColumnOptions(AlignmentColumnOptions::USE_PROVIDED,
//                                                           AlignmentColumnOptions::USE_PROVIDED,
//                                                           AlignmentColumnOptions::OVERWRITE))) {
////                if (recompute_genes) {
////                    std::cout << std::endl;
////                    std::cout << "Recomputing gene usage on " << (size_t) cloneset.noncoding().size() << " clonotypes." << std::endl;
////                    model.updateGeneUsage(cloneset);
////                }
//
//                std::cout << std::endl;
//                auto prob_vec = model.computeFullProbabilities(cloneset);
//
//                std::ofstream ofs;
//                ofs.open(out_file_path);
//
//                std::cout << std::endl;
//                std::cout << "Generation probabilities statistics:" << std::endl;
//                prob_summary(prob_vec);
//
//                if (ofs.is_open()) {
//                    for (auto i = 0; i < prob_vec.size(); ++i) {
//                        ofs << prob_vec[i] << std::endl;
//                    }
//                } else {
//                    std::cout << "Problems with the output stream. Terminating..." << std::endl;
//                }
//                ofs.close();
//            } else {
//                std::cout << "Problems in parsing the input file. Terminating..." << std::endl;
//            }
//        }

    } else {
        std::cout << "Problems with the model. Terminating..." << std::endl;
    }

    return 0;
}<commit_msg>change scores a bit<commit_after>//
// Created by Vadim N. on 04/04/2015.
//
//#include <omp.h>
//#include <stdio.h>
//
//int main() {
//#pragma omp parallel
//    printf("Hello from thread %d, nthreads %d\n", omp_get_thread_num(), omp_get_num_threads());
//}

#include <ostream>

#include "Model"

using namespace ymir;

/**
 * \brief Main function of a script for computing generation probabitilies. It has
 * a strict order of input arguments in console:
 * argv[0] - name of the script (default);
 * argv[1] - path to an input file;
 * argv[2] - path to a model;
 * argv[3] - path to an output file;
 * argv[4] - 0 if model should use stored gene usage; 1 if model should recompute gene usage from the input file.
 * argv[5] - 'n' for nucleotide sequences, 'a' for amino acid sequences.
 */
int main(int argc, char* argv[]) {
    std::string in_file_path(argv[1]),
            model_path(argv[2]),
            out_file_path(argv[3]);
    bool recompute_genes = std::stoi(argv[4]);

    std::cout << "Input file:\t" << in_file_path << std::endl;
    std::cout << "Model path:\t" << model_path << std::endl;
    std::cout << "Output file:\t" << out_file_path << std::endl;
    std::cout << std::endl;

    ProbabilisticAssemblingModel model(model_path);
    std::cout << std::endl;

    if (model.status()) {

        //
        // Nucleotide
        //
//        if (argv[5] == "n") {
        ParserNuc parser(new NaiveCDR3NucleotideAligner(model.gene_segments(), VDJAlignerParameters(3)));
        ClonesetNuc cloneset;

        auto alignment_column_options = AlignmentColumnOptions(AlignmentColumnOptions::REALIGN_PROVIDED,
                                                               AlignmentColumnOptions::OVERWRITE,
                                                               AlignmentColumnOptions::REALIGN_PROVIDED);

        auto vdj_aligner_parameters_nuc = VDJAlignerParameters(3,
                                                               VDJAlignmentEventScore(AlignmentEventScore(1, -1, 1),
                                                                                AlignmentEventScore(1, -1, 1),
                                                                                AlignmentEventScore(1, -1, 1)),
                                                               VDJAlignmentScoreThreshold(6, 3, 5));

//        auto vdj_aligner_parameters_aa =  VDJAlignerParameters(3,
//                                                               VDJAlignmentEventScore(AlignmentEventScore(1, -1, 1),
//                                                                                AlignmentEventScore(1, -1, 1),
//                                                                                AlignmentEventScore(1, -1, 1)),
//                                                               VDJAlignmentScoreThreshold(1, 1, 1));

        if (parser.openAndParse(in_file_path,
                                &cloneset,
                                model.gene_segments(),
                                model.recombination(),
                                alignment_column_options,
                                vdj_aligner_parameters_nuc))
        {
            if (recompute_genes) {
                std::cout << std::endl;
                std::cout << "Recomputing gene usage on " << (size_t) cloneset.noncoding().size() << " clonotypes." << std::endl;
                model.updateGeneUsage(cloneset);
            }
            std::cout << std::endl;

            std::vector<prob_t> prob_vec;
            std::vector<size_t> noncoding_indices;
            std::vector<prob_t> coding_probs;

            if (argv[5][0] == 'n') {
                prob_vec = model.computeFullProbabilities(cloneset, NO_ERRORS);
            } else {
                ClonesetAA cloneset_aa;

                std::cout << "Converting nucleotide clonotypes to amino acid clonotypes..." << std::endl;
                noncoding_indices = CDR3AminoAcidAligner(model.gene_segments(), vdj_aligner_parameters_aa).toAminoAcid(cloneset, &cloneset_aa, true);
                std::cout << "Done." << std::endl << std::endl;

                coding_probs = model.computeFullProbabilities(cloneset_aa);
            }

            std::ofstream ofs;
            ofs.open(out_file_path);

            std::cout << std::endl;
            std::cout << "Generation probabilities statistics:" << std::endl;
            prob_summary(prob_vec);

            if (ofs.is_open()) {
                // Write nucleotide probabilities.
                if (prob_vec.size()) {
                    for (auto i = 0; i < prob_vec.size(); ++i) {
                        ofs << prob_vec[i] << std::endl;
                    }
                }

                // Write amino acid probabilities.
                else {
                    size_t k = 0, j = 0;
                    for (auto i = 0; i < cloneset.size(); ++i) {
                        if (k != noncoding_indices.size() && i == noncoding_indices[k]) {
                            ofs << "-1" << std::endl;
                            ++k;
                        } else {
                            ofs << coding_probs[j] << std::endl;
                            ++j;
                        }
                    }
                }
            } else {
                std::cout << "Problems with the output stream. Terminating..." << std::endl;
            }
            ofs.close();
        } else {
            std::cout << "Problems in parsing the input file. Terminating..." << std::endl;
        }
//        }

        //
        // Amino acid
        //
//        else {
//            ParserAA parser;
//            ClonesetAA cloneset;
//
//            if (parser.openAndParse(in_file_path,
//                                    &cloneset,
//                                    model.gene_segments(),
//                                    model.recombination(),
//                                    AlignmentColumnOptions(AlignmentColumnOptions::USE_PROVIDED,
//                                                           AlignmentColumnOptions::USE_PROVIDED,
//                                                           AlignmentColumnOptions::OVERWRITE))) {
////                if (recompute_genes) {
////                    std::cout << std::endl;
////                    std::cout << "Recomputing gene usage on " << (size_t) cloneset.noncoding().size() << " clonotypes." << std::endl;
////                    model.updateGeneUsage(cloneset);
////                }
//
//                std::cout << std::endl;
//                auto prob_vec = model.computeFullProbabilities(cloneset);
//
//                std::ofstream ofs;
//                ofs.open(out_file_path);
//
//                std::cout << std::endl;
//                std::cout << "Generation probabilities statistics:" << std::endl;
//                prob_summary(prob_vec);
//
//                if (ofs.is_open()) {
//                    for (auto i = 0; i < prob_vec.size(); ++i) {
//                        ofs << prob_vec[i] << std::endl;
//                    }
//                } else {
//                    std::cout << "Problems with the output stream. Terminating..." << std::endl;
//                }
//                ofs.close();
//            } else {
//                std::cout << "Problems in parsing the input file. Terminating..." << std::endl;
//            }
//        }

    } else {
        std::cout << "Problems with the model. Terminating..." << std::endl;
    }

    return 0;
}<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (c) 2004 Jürgen Riegel <juergen.riegel@web.de>              *
 *   Copyright (c) 2012 Luke Parry <l.parry@warwick.ac.uk>                 *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   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., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"

#ifndef _PreComp_
#endif

/// Here the FreeCAD includes sorted by Base,App,Gui......
#include <Base/Console.h>
#include <Base/Parameter.h>
#include <Base/Exception.h>
#include <Base/Sequencer.h>
#include <App/Application.h>
#include <App/Document.h>
#include <App/DocumentObject.h>

#include <Mod/TechDraw/App/LineGroup.h>

#include "ViewProviderDimension.h"

using namespace TechDrawGui;

PROPERTY_SOURCE(TechDrawGui::ViewProviderDimension, TechDrawGui::ViewProviderDrawingView)

//**************************************************************************
// Construction/Destruction

ViewProviderDimension::ViewProviderDimension()
{
    sPixmap = "TechDraw_Dimension";

    static const char *group = "Dim Format";

    Base::Reference<ParameterGrp> hGrp = App::GetApplication().GetUserParameter()
                                         .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/Labels");
    std::string fontName = hGrp->GetASCII("LabelFont", "osifont");

    hGrp = App::GetApplication().GetUserParameter()
                                         .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/Dimensions");
    double fontSize = hGrp->GetFloat("FontSize", 3.5);
    ADD_PROPERTY_TYPE(Font ,(fontName.c_str()),group,App::Prop_None, "The name of the font to use");
    ADD_PROPERTY_TYPE(Fontsize,(fontSize)    ,group,(App::PropertyType)(App::Prop_None),"Dimension text size in units");

    hGrp = App::GetApplication().GetUserParameter().GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/Decorations");
    std::string lgName = hGrp->GetASCII("LineGroup","FC 0.70mm");
    auto lg = TechDraw::LineGroup::lineGroupFactory(lgName);
    double weight = lg->getWeight("Thin");
    delete lg;                                   //Coverity CID 174670
    ADD_PROPERTY_TYPE(LineWidth,(weight)    ,group,(App::PropertyType)(App::Prop_None),"Dimension line weight");

    hGrp = App::GetApplication().GetUserParameter()
                                        .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/Dimensions");
    App::Color fcColor;
    fcColor.setPackedValue(hGrp->GetUnsigned("Color", 0x00000000));
    ADD_PROPERTY_TYPE(Color,(fcColor),group,App::Prop_None,"The color of the Dimension");

    ADD_PROPERTY_TYPE(FlipArrowheads ,(false),group,App::Prop_None,"Reverse the normal direction of arrowheads on dimline");

}

ViewProviderDimension::~ViewProviderDimension()
{
}

void ViewProviderDimension::attach(App::DocumentObject *pcFeat)
{
    // call parent attach method
    ViewProviderDrawingView::attach(pcFeat);
}

void ViewProviderDimension::setDisplayMode(const char* ModeName)
{
    ViewProviderDrawingView::setDisplayMode(ModeName);
}

std::vector<std::string> ViewProviderDimension::getDisplayModes(void) const
{
    // get the modes of the father
    std::vector<std::string> StrList = ViewProviderDrawingView::getDisplayModes();

    return StrList;
}

void ViewProviderDimension::updateData(const App::Property* p)
{
    if (p == &(getViewObject()->Type)) {
        if (getViewObject()->Type.isValue("DistanceX")) {
            sPixmap = "TechDraw_Dimension_Horizontal";
        } else if (getViewObject()->Type.isValue("DistanceY")) {
            sPixmap = "TechDraw_Dimension_Vertical";
        } else if (getViewObject()->Type.isValue("Radius")) {
            sPixmap = "TechDraw_Dimension_Radius";
        } else if (getViewObject()->Type.isValue("Diameter")) {
            sPixmap = "TechDraw_Dimension_Diameter";
        } else if (getViewObject()->Type.isValue("Angle")) {
            sPixmap = "TechDraw_Dimension_Angle";
        }
    }
    ViewProviderDrawingView::updateData(p);
}

void ViewProviderDimension::onChanged(const App::Property* p)
{
    if ((p == &Font)  ||
        (p == &Fontsize) ||
        (p == &LineWidth) ||
        (p == &FlipArrowheads)) {
        QGIView* qgiv = getQView();
        if (qgiv) {
            qgiv->updateView(true);
        }
    }
    Gui::ViewProviderDocumentObject::onChanged(p);
}

TechDraw::DrawViewDimension* ViewProviderDimension::getViewObject() const
{
    return dynamic_cast<TechDraw::DrawViewDimension*>(pcObject);
}
<commit_msg>Correct tree icon for Angle3Pt<commit_after>/***************************************************************************
 *   Copyright (c) 2004 Jürgen Riegel <juergen.riegel@web.de>              *
 *   Copyright (c) 2012 Luke Parry <l.parry@warwick.ac.uk>                 *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   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., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"

#ifndef _PreComp_
#endif

/// Here the FreeCAD includes sorted by Base,App,Gui......
#include <Base/Console.h>
#include <Base/Parameter.h>
#include <Base/Exception.h>
#include <Base/Sequencer.h>
#include <App/Application.h>
#include <App/Document.h>
#include <App/DocumentObject.h>

#include <Mod/TechDraw/App/LineGroup.h>

#include "ViewProviderDimension.h"

using namespace TechDrawGui;

PROPERTY_SOURCE(TechDrawGui::ViewProviderDimension, TechDrawGui::ViewProviderDrawingView)

//**************************************************************************
// Construction/Destruction

ViewProviderDimension::ViewProviderDimension()
{
    sPixmap = "TechDraw_Dimension";

    static const char *group = "Dim Format";

    Base::Reference<ParameterGrp> hGrp = App::GetApplication().GetUserParameter()
                                         .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/Labels");
    std::string fontName = hGrp->GetASCII("LabelFont", "osifont");

    hGrp = App::GetApplication().GetUserParameter()
                                         .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/Dimensions");
    double fontSize = hGrp->GetFloat("FontSize", 3.5);
    ADD_PROPERTY_TYPE(Font ,(fontName.c_str()),group,App::Prop_None, "The name of the font to use");
    ADD_PROPERTY_TYPE(Fontsize,(fontSize)    ,group,(App::PropertyType)(App::Prop_None),"Dimension text size in units");

    hGrp = App::GetApplication().GetUserParameter().GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/Decorations");
    std::string lgName = hGrp->GetASCII("LineGroup","FC 0.70mm");
    auto lg = TechDraw::LineGroup::lineGroupFactory(lgName);
    double weight = lg->getWeight("Thin");
    delete lg;                                   //Coverity CID 174670
    ADD_PROPERTY_TYPE(LineWidth,(weight)    ,group,(App::PropertyType)(App::Prop_None),"Dimension line weight");

    hGrp = App::GetApplication().GetUserParameter()
                                        .GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("Mod/TechDraw/Dimensions");
    App::Color fcColor;
    fcColor.setPackedValue(hGrp->GetUnsigned("Color", 0x00000000));
    ADD_PROPERTY_TYPE(Color,(fcColor),group,App::Prop_None,"The color of the Dimension");

    ADD_PROPERTY_TYPE(FlipArrowheads ,(false),group,App::Prop_None,"Reverse the normal direction of arrowheads on dimline");

}

ViewProviderDimension::~ViewProviderDimension()
{
}

void ViewProviderDimension::attach(App::DocumentObject *pcFeat)
{
    // call parent attach method
    ViewProviderDrawingView::attach(pcFeat);
}

void ViewProviderDimension::setDisplayMode(const char* ModeName)
{
    ViewProviderDrawingView::setDisplayMode(ModeName);
}

std::vector<std::string> ViewProviderDimension::getDisplayModes(void) const
{
    // get the modes of the father
    std::vector<std::string> StrList = ViewProviderDrawingView::getDisplayModes();

    return StrList;
}

void ViewProviderDimension::updateData(const App::Property* p)
{
    if (p == &(getViewObject()->Type)) {
        if (getViewObject()->Type.isValue("DistanceX")) {
            sPixmap = "TechDraw_Dimension_Horizontal";
        } else if (getViewObject()->Type.isValue("DistanceY")) {
            sPixmap = "TechDraw_Dimension_Vertical";
        } else if (getViewObject()->Type.isValue("Radius")) {
            sPixmap = "TechDraw_Dimension_Radius";
        } else if (getViewObject()->Type.isValue("Diameter")) {
            sPixmap = "TechDraw_Dimension_Diameter";
        } else if (getViewObject()->Type.isValue("Angle")) {
            sPixmap = "TechDraw_Dimension_Angle";
        } else if (getViewObject()->Type.isValue("Angle3Pt")) {
            sPixmap = "TechDraw_Dimension_Angle3Pt";
        }
    }
    ViewProviderDrawingView::updateData(p);
}

void ViewProviderDimension::onChanged(const App::Property* p)
{
    if ((p == &Font)  ||
        (p == &Fontsize) ||
        (p == &LineWidth) ||
        (p == &FlipArrowheads)) {
        QGIView* qgiv = getQView();
        if (qgiv) {
            qgiv->updateView(true);
        }
    }
    Gui::ViewProviderDocumentObject::onChanged(p);
}

TechDraw::DrawViewDimension* ViewProviderDimension::getViewObject() const
{
    return dynamic_cast<TechDraw::DrawViewDimension*>(pcObject);
}
<|endoftext|>


<commit_before>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2009 Scientific Computing and Imaging Institute,
   University of Utah.

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/

//    File   : ReportNrrdInfo.cc
//    Author : Martin Cole
//    Date   : Tue Feb  4 08:55:34 2003

#include <Modules/Legacy/Teem/Misc/ReportNrrdInfo.h>
#include <Core/Datatypes/Legacy/Nrrd/NrrdData.h>
#include <Core/Algorithms/Base/AlgorithmVariableNames.h>
#include <Core/Datatypes/Legacy/Base/PropertyManager.h>

using namespace SCIRun;
using namespace SCIRun::Modules::Teem;
using namespace SCIRun::Dataflow::Networks;
using namespace Core::Algorithms;

const ModuleLookupInfo ReportNrrdInfo::staticInfo_("ReportNrrdInfo", "Misc", "Teem");

ReportNrrdInfo::ReportNrrdInfo() : Module(staticInfo_)
{
  INITIALIZE_PORT(Query_Nrrd);
}

void ReportNrrdInfo::setStateDefaults()
{
}

template <typename T>
void
ReportNrrdInfo::update_axis_var(std::ostringstream& info, const char *name, int axis, const T& val,
                          const char *pname)
{
  info << "set " << get_id() << "-" << name << axis << " {" << val << "}\n";
}

static const char *nrrd_kind_strings[] = { // nrrdKinds, Matches teem 1.9!
  "nrrdKindUnknown",
  "nrrdKindDomain",            //  1: any image domain
  "nrrdKindSpace",             //  2: a spatial domain
  "nrrdKindTime",              //  3: a temporal domain
  // -------------------------- end domain kinds
  // -------------------------- begin range kinds
  "nrrdKindList",              //  4: any list of values, non-resample-able
  "nrrdKindPoint",             //  5: coords of a point
  "nrrdKindVector",            //  6: coeffs of (contravariant) vector
  "nrrdKindCovariantVector",   //  7: coeffs of covariant vector (eg gradient)
  "nrrdKindNormal",            //  8: coeffs of unit-length covariant vector
  // -------------------------- end arbitrary size kinds
  // -------------------------- begin size-specific kinds
  "nrrdKindStub",              //  9: axis with one sample (a placeholder)
  "nrrdKindScalar",            // 10: effectively, same as a stub
  "nrrdKindComplex",           // 11: real and imaginary components
  "nrrdKind2Vector",           // 12: 2 component vector
  "nrrdKind3Color",            // 13: ANY 3-component color value
  "nrrdKindRGBColor",          // 14: RGB, no colorimetry
  "nrrdKindHSVColor",          // 15: HSV, no colorimetry
  "nrrdKindXYZColor",          // 16: perceptual primary colors
  "nrrdKind4Color",            // 17: ANY 4-component color value
  "nrrdKindRGBAColor",         // 18: RGBA, no colorimetry
  "nrrdKind3Vector",           // 19: 3-component vector
  "nrrdKind3Gradient",         // 20: 3-component covariant vector
  "nrrdKind3Normal",           // 21: 3-component covector, assumed normalized
  "nrrdKind4Vector",           // 22: 4-component vector
  "nrrdKindQuaternion",        // 23: (w,x,y,z), not necessarily normalized
  "nrrdKind2DSymMatrix",       // 24: Mxx Mxy Myy
  "nrrdKind2DMaskedSymMatrix", // 25: mask Mxx Mxy Myy
  "nrrdKind2DMatrix",          // 26: Mxx Mxy Myx Myy
  "nrrdKind2DMaskedMatrix",    // 27: mask Mxx Mxy Myx Myy
  "nrrdKind3DSymMatrix",       // 28: Mxx Mxy Mxz Myy Myz Mzz
  "nrrdKind3DMaskedSymMatrix", // 29: mask Mxx Mxy Mxz Myy Myz Mzz
  "nrrdKind3DMatrix",          // 30: Mxx Mxy Mxz Myx Myy Myz Mzx Mzy Mzz
  "nrrdKind3DMaskedMatrix",    // 31: mask Mxx Mxy Mxz Myx Myy Myz Mzx Mzy Mzz
  "nrrdKindLast"
};

void
ReportNrrdInfo::update_input_attributes(NrrdDataHandle nh)
{
  std::ostringstream info;

  std::string name;
  if (!nh->properties().get_property( "Name", name))
    name = "Unknown";
  info << "Name: " << name << "\n";

  std::string nrrdtype, stmp;
  get_nrrd_compile_type(nh->getNrrd()->type, nrrdtype, stmp);
  info << "Type: " << nrrdtype << "\n";
  info << "Dimension: " << nh->getNrrd()->dim << "\n";

  // space origin
  std::ostringstream spaceor;
  spaceor << "[ ";
  unsigned int last_dim = nh->getNrrd()->spaceDim - 1;
  for (unsigned int p = 0; p < nh->getNrrd()->spaceDim; ++p)
  {
    spaceor << nh->getNrrd()->spaceOrigin[p];
    if (p < last_dim)
      spaceor << ", ";
  }
  spaceor << " ]";
  info << "Origin: " << spaceor.str() << "\n";

  // TODO: Set Origin here.

  bool haveSpaceInfo=false;
  for (unsigned int i = 0; i < nh->getNrrd()->dim; i++)
    if (airExists(nh->getNrrd()->axis[i].spaceDirection[0])) haveSpaceInfo=true;

  // Go through all axes...
  for (unsigned int i = 0; i < nh->getNrrd()->dim; i++)
  {
    std::string labelstr;
    if (nh->getNrrd()->axis[i].label == 0 ||
        std::string(nh->getNrrd()->axis[i].label).length() == 0)
    {
      labelstr = "---";
    }
    else
    {
      labelstr = nh->getNrrd()->axis[i].label;
    }
    update_axis_var(info, "label", i, labelstr, "Label");

    int k = nh->getNrrd()->axis[i].kind;
    if (k < 0 || k >= nrrdKindLast) k = 0;
    const char *kindstr = nrrd_kind_strings[k];
    update_axis_var(info, "kind", i, kindstr, "Kind");

    update_axis_var(info, "size", i, nh->getNrrd()->axis[i].size, "Size");

    update_axis_var(info, "min", i, nh->getNrrd()->axis[i].min, "Min");
    update_axis_var(info, "max", i, nh->getNrrd()->axis[i].max, "Max");

    std::string locstr;
    switch (nh->getNrrd()->axis[i].center)
    {
    case nrrdCenterUnknown :
      locstr = "Unknown";
      break;
    case nrrdCenterNode :
      locstr = "Node";
      break;
    case nrrdCenterCell :
      locstr = "Cell";
      break;
    }
    update_axis_var(info, "center", i, locstr, "Center");

    if (!haveSpaceInfo) { // no "spaceDirection" info, just "spacing"
      update_axis_var(info, "spacing", i, (nh->getNrrd()->axis[i].spacing), "Spacing");
    } else {
      std::ostringstream spacedir;
      spacedir << "[ ";
      double l2 = 0;
      for (unsigned int p = 0; p < nh->getNrrd()->spaceDim; ++p)
      {
        double tmp = nh->getNrrd()->axis[i].spaceDirection[p];
        spacedir << tmp;
        l2 += tmp*tmp;
        if (p < last_dim)
          spacedir << ", ";
      }
      spacedir << " ]";
      update_axis_var(info, "spaceDir", i, spacedir.str(), "Spacing Direction");
      update_axis_var(info, "spacing", i, (sqrt(l2)), "Spacing");
    }
  }
  get_state()->setTransientValue(Variables::ObjectInfo, info.str());
}

void
ReportNrrdInfo::execute()
{
  auto nh = getRequiredInput(Query_Nrrd);
  update_input_attributes(nh);
}
<commit_msg>Most of #1200<commit_after>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2009 Scientific Computing and Imaging Institute,
   University of Utah.

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/

//    File   : ReportNrrdInfo.cc
//    Author : Martin Cole
//    Date   : Tue Feb  4 08:55:34 2003

#include <Modules/Legacy/Teem/Misc/ReportNrrdInfo.h>
#include <Core/Datatypes/Legacy/Nrrd/NrrdData.h>
#include <Core/Algorithms/Base/AlgorithmVariableNames.h>
#include <Core/Datatypes/Legacy/Base/PropertyManager.h>

using namespace SCIRun;
using namespace SCIRun::Modules::Teem;
using namespace SCIRun::Dataflow::Networks;
using namespace Core::Algorithms;

const ModuleLookupInfo ReportNrrdInfo::staticInfo_("ReportNrrdInfo", "Misc", "Teem");

ReportNrrdInfo::ReportNrrdInfo() : Module(staticInfo_)
{
  INITIALIZE_PORT(Query_Nrrd);
}

void ReportNrrdInfo::setStateDefaults()
{
}

template <typename T>
void
ReportNrrdInfo::update_axis_var(std::ostringstream& info, const char *name, int axis, const T& val,
                          const char *pname)
{
  info << name << " " << axis << ": value = " << val << "\n";
}

static const char *nrrd_kind_strings[] = { // nrrdKinds, Matches teem 1.9!
  "nrrdKindUnknown",
  "nrrdKindDomain",            //  1: any image domain
  "nrrdKindSpace",             //  2: a spatial domain
  "nrrdKindTime",              //  3: a temporal domain
  // -------------------------- end domain kinds
  // -------------------------- begin range kinds
  "nrrdKindList",              //  4: any list of values, non-resample-able
  "nrrdKindPoint",             //  5: coords of a point
  "nrrdKindVector",            //  6: coeffs of (contravariant) vector
  "nrrdKindCovariantVector",   //  7: coeffs of covariant vector (eg gradient)
  "nrrdKindNormal",            //  8: coeffs of unit-length covariant vector
  // -------------------------- end arbitrary size kinds
  // -------------------------- begin size-specific kinds
  "nrrdKindStub",              //  9: axis with one sample (a placeholder)
  "nrrdKindScalar",            // 10: effectively, same as a stub
  "nrrdKindComplex",           // 11: real and imaginary components
  "nrrdKind2Vector",           // 12: 2 component vector
  "nrrdKind3Color",            // 13: ANY 3-component color value
  "nrrdKindRGBColor",          // 14: RGB, no colorimetry
  "nrrdKindHSVColor",          // 15: HSV, no colorimetry
  "nrrdKindXYZColor",          // 16: perceptual primary colors
  "nrrdKind4Color",            // 17: ANY 4-component color value
  "nrrdKindRGBAColor",         // 18: RGBA, no colorimetry
  "nrrdKind3Vector",           // 19: 3-component vector
  "nrrdKind3Gradient",         // 20: 3-component covariant vector
  "nrrdKind3Normal",           // 21: 3-component covector, assumed normalized
  "nrrdKind4Vector",           // 22: 4-component vector
  "nrrdKindQuaternion",        // 23: (w,x,y,z), not necessarily normalized
  "nrrdKind2DSymMatrix",       // 24: Mxx Mxy Myy
  "nrrdKind2DMaskedSymMatrix", // 25: mask Mxx Mxy Myy
  "nrrdKind2DMatrix",          // 26: Mxx Mxy Myx Myy
  "nrrdKind2DMaskedMatrix",    // 27: mask Mxx Mxy Myx Myy
  "nrrdKind3DSymMatrix",       // 28: Mxx Mxy Mxz Myy Myz Mzz
  "nrrdKind3DMaskedSymMatrix", // 29: mask Mxx Mxy Mxz Myy Myz Mzz
  "nrrdKind3DMatrix",          // 30: Mxx Mxy Mxz Myx Myy Myz Mzx Mzy Mzz
  "nrrdKind3DMaskedMatrix",    // 31: mask Mxx Mxy Mxz Myx Myy Myz Mzx Mzy Mzz
  "nrrdKindLast"
};

void
ReportNrrdInfo::update_input_attributes(NrrdDataHandle nh)
{
  std::ostringstream info;

  std::string name;
  if (!nh->properties().get_property( "Name", name))
    name = "Unknown";
  info << "Name: " << name << "\n";

  std::string nrrdtype, stmp;
  get_nrrd_compile_type(nh->getNrrd()->type, nrrdtype, stmp);
  info << "Type: " << nrrdtype << "\n";
  info << "Dimension: " << nh->getNrrd()->dim << "\n";

  // space origin
  std::ostringstream spaceor;
  spaceor << "[ ";
  unsigned int last_dim = nh->getNrrd()->spaceDim - 1;
  for (unsigned int p = 0; p < nh->getNrrd()->spaceDim; ++p)
  {
    spaceor << nh->getNrrd()->spaceOrigin[p];
    if (p < last_dim)
      spaceor << ", ";
  }
  spaceor << " ]";
  info << "Origin: " << spaceor.str() << "\n";

  // TODO: Set Origin here.

  bool haveSpaceInfo=false;
  for (unsigned int i = 0; i < nh->getNrrd()->dim; i++)
    if (airExists(nh->getNrrd()->axis[i].spaceDirection[0])) haveSpaceInfo=true;

  // Go through all axes...
  for (unsigned int i = 0; i < nh->getNrrd()->dim; i++)
  {
    std::string labelstr;
    if (nh->getNrrd()->axis[i].label == 0 ||
        std::string(nh->getNrrd()->axis[i].label).length() == 0)
    {
      labelstr = "---";
    }
    else
    {
      labelstr = nh->getNrrd()->axis[i].label;
    }
    update_axis_var(info, "label", i, labelstr, "Label");

    int k = nh->getNrrd()->axis[i].kind;
    if (k < 0 || k >= nrrdKindLast) k = 0;
    const char *kindstr = nrrd_kind_strings[k];
    update_axis_var(info, "kind", i, kindstr, "Kind");

    update_axis_var(info, "size", i, nh->getNrrd()->axis[i].size, "Size");

    update_axis_var(info, "min", i, nh->getNrrd()->axis[i].min, "Min");
    update_axis_var(info, "max", i, nh->getNrrd()->axis[i].max, "Max");

    std::string locstr;
    switch (nh->getNrrd()->axis[i].center)
    {
    case nrrdCenterUnknown :
      locstr = "Unknown";
      break;
    case nrrdCenterNode :
      locstr = "Node";
      break;
    case nrrdCenterCell :
      locstr = "Cell";
      break;
    }
    update_axis_var(info, "center", i, locstr, "Center");

    if (!haveSpaceInfo) { // no "spaceDirection" info, just "spacing"
      update_axis_var(info, "spacing", i, (nh->getNrrd()->axis[i].spacing), "Spacing");
    } else {
      std::ostringstream spacedir;
      spacedir << "[ ";
      double l2 = 0;
      for (unsigned int p = 0; p < nh->getNrrd()->spaceDim; ++p)
      {
        double tmp = nh->getNrrd()->axis[i].spaceDirection[p];
        spacedir << tmp;
        l2 += tmp*tmp;
        if (p < last_dim)
          spacedir << ", ";
      }
      spacedir << " ]";
      update_axis_var(info, "spaceDir", i, spacedir.str(), "Spacing Direction");
      update_axis_var(info, "spacing", i, (sqrt(l2)), "Spacing");
    }
  }
  get_state()->setTransientValue(Variables::ObjectInfo, info.str());
}

void
ReportNrrdInfo::execute()
{
  auto nh = getRequiredInput(Query_Nrrd);
  update_input_attributes(nh);
}
<|endoftext|>