<commit_before>#ifndef _SDD_HOM_INTERSECTION_HH_
#define _SDD_HOM_INTERSECTION_HH_

#include <algorithm>  // all_of, copy
#include <deque>
#include <initializer_list>
#include <iosfwd>
#include <stdexcept>  //invalid_argument
#include <unordered_map>

#include <boost/container/flat_set.hpp>

#include "sdd/dd/definition.hh"
#include "sdd/dd/top.hh"
#include "sdd/hom/context_fwd.hh"
#include "sdd/hom/definition_fwd.hh"
#include "sdd/hom/evaluation_error.hh"
#include "sdd/hom/identity.hh"
#include "sdd/hom/local.hh"
#include "sdd/order/order.hh"
#include "sdd/util/packed.hh"

namespace sdd { namespace hom {

/*------------------------------------------------------------------------------------------------*/

/// @internal
/// @brief Intersection homomorphism.
template <typename C>
class intersection
{
public:

  /// @brief The type of the homomorphism operands' set.
  using operands_type = boost::container::flat_set<homomorphism<C>>;

private:

  /// @brief The homomorphism operands' set.
  const operands_type operands_;

public:

  /// @brief Constructor.
  intersection(operands_type&& operands)
    : operands_(std::move(operands))
  {}

  /// @brief Evaluation.
  SDD<C>
  operator()(context<C>& cxt, const order<C>& o, const SDD<C>& x)
  const
  {
    dd::intersection_builder<C, SDD<C>> intersection_operands;
    intersection_operands.reserve(operands_.size());
    for (const auto& op : operands_)
    {
      intersection_operands.add(op(cxt, o, x));
    }
    try
    {
      return dd::intersection(cxt.sdd_context(), std::move(intersection_operands));
    }
    catch (top<C>& t)
    {
      evaluation_error<C> e(x);
      e.add_top(t);
      throw e;
    }
  }

  /// @brief Skip variable predicate.
  bool
  skip(const order<C>& o)
  const noexcept
  {
    return std::all_of( operands_.begin(), operands_.end()
                      , [&o](const homomorphism<C>& h){return h.skip(o);});
  }

  /// @brief Selector predicate
  bool
  selector()
  const noexcept
  {
    return std::all_of( operands_.begin(), operands_.end()
                      , [](const homomorphism<C>& h){return h.selector();});
  }

  const operands_type&
  operands()
  const noexcept
  {
    return operands_;
  }
};

/*------------------------------------------------------------------------------------------------*/

/// @internal
/// @brief Equality of two intersection.
/// @related intersection
template <typename C>
inline
bool
operator==(const intersection<C>& lhs, const intersection<C>& rhs)
noexcept
{
  return lhs.operands() == rhs.operands();
}

/// @internal
/// @related intersection
template <typename C>
std::ostream&
operator<<(std::ostream& os, const intersection<C>& s)
{
  os << "(";
  std::copy( s.operands().begin(), std::prev(s.operands().end())
           , std::ostream_iterator<homomorphism<C>>(os, " & "));
  return os << *std::prev(s.operands().end()) << ")";
}

/*------------------------------------------------------------------------------------------------*/

/// @internal
/// @brief Help optimize an intersection's operands.
template <typename C>
struct intersection_builder_helper
{
  using result_type   = void;
  using operands_type = typename intersection<C>::operands_type;
  using hom_list_type = std::deque<homomorphism<C>> ;
  using locals_type   = std::unordered_map<order_position_type, hom_list_type>;

  operands_type& operands_;
  locals_type& locals_;

  intersection_builder_helper(operands_type& operands, locals_type& locals)
  noexcept
    : operands_(operands)
    , locals_(locals)
  {}

  /// @brief Flatten nested intersections.
  void
  operator()(const intersection<C>& s, const homomorphism<C>&)
  const
  {
    for (const auto& op : s.operands())
    {
      visit_self(*this, op);
    }
  }

  /// @brief Regroup locals.
  void
  operator()(const local<C>& l, const homomorphism<C>&)
  const
  {
    auto insertion = locals_.emplace(l.target(), hom_list_type());
    insertion.first->second.emplace_back(l.hom());
  }

  /// @brief Insert normally all other operands.
  template <typename T>
  void
  operator()(const T&, const homomorphism<C>& h)
  const
  {
    operands_.insert(h);
  }

};

} // namespace hom

/*------------------------------------------------------------------------------------------------*/

/// @brief Create the Intersection homomorphism.
/// @related homomorphism
template <typename C, typename InputIterator>
homomorphism<C>
Intersection(const order<C>& o, InputIterator begin, InputIterator end)
{
  const std::size_t size = std::distance(begin, end);

  if (size == 0)
  {
    throw std::invalid_argument("Empty operands at Intersection construction.");
  }

  typename hom::intersection<C>::operands_type operands;
  operands.reserve(size);

  typename hom::intersection_builder_helper<C>::locals_type locals;
  hom::intersection_builder_helper<C> ib {operands, locals};
  for (; begin != end; ++begin)
  {
    visit_self(ib, *begin);
  }

  // insert remaining locals
  for (const auto& l : locals)
  {
    operands.insert(Local<C>(l.first, Intersection<C>(o, l.second.begin(), l.second.end())));
  }

  if (operands.size() == 1)
  {
    return *operands.begin();
  }
  else
  {
    operands.shrink_to_fit();
    return homomorphism<C>::create(mem::construct<hom::intersection<C>>(), std::move(operands));
  }
}

/*------------------------------------------------------------------------------------------------*/

/// @brief Create the Intersection homomorphism.
/// @related homomorphism
template <typename C>
homomorphism<C>
Intersection(const order<C>& o, std::initializer_list<homomorphism<C>> operands)
{
  return Intersection<C>(o, operands.begin(), operands.end());
}

/*------------------------------------------------------------------------------------------------*/

} // namespace sdd

namespace std {

/*------------------------------------------------------------------------------------------------*/

/// @internal
/// @brief Hash specialization for sdd::hom::intersection.
template <typename C>
struct hash<sdd::hom::intersection<C>>
{
  std::size_t
  operator()(const sdd::hom::intersection<C>& s)
  const
  {
    return sdd::util::hash(s.operands().begin(), s.operands().end());
  }
};

/*------------------------------------------------------------------------------------------------*/

} // namespace std

#endif // _SDD_HOM_INTERSECTION_HH_
<commit_msg>Add a const_iterator to an intersection's operands.<commit_after>#ifndef _SDD_HOM_INTERSECTION_HH_
#define _SDD_HOM_INTERSECTION_HH_

#include <algorithm>  // all_of, copy
#include <deque>
#include <initializer_list>
#include <iosfwd>
#include <stdexcept>  //invalid_argument
#include <unordered_map>

#include <boost/container/flat_set.hpp>

#include "sdd/dd/definition.hh"
#include "sdd/dd/top.hh"
#include "sdd/hom/context_fwd.hh"
#include "sdd/hom/definition_fwd.hh"
#include "sdd/hom/evaluation_error.hh"
#include "sdd/hom/identity.hh"
#include "sdd/hom/local.hh"
#include "sdd/order/order.hh"
#include "sdd/util/packed.hh"

namespace sdd { namespace hom {

/*------------------------------------------------------------------------------------------------*/

/// @internal
/// @brief Intersection homomorphism.
template <typename C>
class intersection
{
public:

  /// @brief The type of the homomorphism operands' set.
  using operands_type = boost::container::flat_set<homomorphism<C>>;

  /// @brief The type of a const iterator on this intersection's operands.
  using const_iterator = typename operands_type::const_iterator;

private:

  /// @brief The homomorphism operands' set.
  const operands_type operands_;

public:

  /// @brief Constructor.
  intersection(operands_type&& operands)
    : operands_(std::move(operands))
  {}

  /// @brief Evaluation.
  SDD<C>
  operator()(context<C>& cxt, const order<C>& o, const SDD<C>& x)
  const
  {
    dd::intersection_builder<C, SDD<C>> intersection_operands;
    intersection_operands.reserve(operands_.size());
    for (const auto& op : operands_)
    {
      intersection_operands.add(op(cxt, o, x));
    }
    try
    {
      return dd::intersection(cxt.sdd_context(), std::move(intersection_operands));
    }
    catch (top<C>& t)
    {
      evaluation_error<C> e(x);
      e.add_top(t);
      throw e;
    }
  }

  /// @brief Skip variable predicate.
  bool
  skip(const order<C>& o)
  const noexcept
  {
    return std::all_of( operands_.begin(), operands_.end()
                      , [&o](const homomorphism<C>& h){return h.skip(o);});
  }

  /// @brief Selector predicate
  bool
  selector()
  const noexcept
  {
    return std::all_of( operands_.begin(), operands_.end()
                      , [](const homomorphism<C>& h){return h.selector();});
  }

  /// @brief Get an iterator to the first operand.
  ///
  /// O(1).
  const_iterator
  begin()
  const noexcept
  {
    return operands_.begin();
  }

  /// @brief Get an iterator to the end of operands.
  ///
  /// O(1).
  const_iterator
  end()
  const noexcept
  {
    return operands_.end();
  }

  const operands_type&
  operands()
  const noexcept
  {
    return operands_;
  }
};

/*------------------------------------------------------------------------------------------------*/

/// @internal
/// @brief Equality of two intersection.
/// @related intersection
template <typename C>
inline
bool
operator==(const intersection<C>& lhs, const intersection<C>& rhs)
noexcept
{
  return lhs.operands() == rhs.operands();
}

/// @internal
/// @related intersection
template <typename C>
std::ostream&
operator<<(std::ostream& os, const intersection<C>& s)
{
  os << "(";
  std::copy( s.operands().begin(), std::prev(s.operands().end())
           , std::ostream_iterator<homomorphism<C>>(os, " & "));
  return os << *std::prev(s.operands().end()) << ")";
}

/*------------------------------------------------------------------------------------------------*/

/// @internal
/// @brief Help optimize an intersection's operands.
template <typename C>
struct intersection_builder_helper
{
  using result_type   = void;
  using operands_type = typename intersection<C>::operands_type;
  using hom_list_type = std::deque<homomorphism<C>> ;
  using locals_type   = std::unordered_map<order_position_type, hom_list_type>;

  operands_type& operands_;
  locals_type& locals_;

  intersection_builder_helper(operands_type& operands, locals_type& locals)
  noexcept
    : operands_(operands)
    , locals_(locals)
  {}

  /// @brief Flatten nested intersections.
  void
  operator()(const intersection<C>& s, const homomorphism<C>&)
  const
  {
    for (const auto& op : s.operands())
    {
      visit_self(*this, op);
    }
  }

  /// @brief Regroup locals.
  void
  operator()(const local<C>& l, const homomorphism<C>&)
  const
  {
    auto insertion = locals_.emplace(l.target(), hom_list_type());
    insertion.first->second.emplace_back(l.hom());
  }

  /// @brief Insert normally all other operands.
  template <typename T>
  void
  operator()(const T&, const homomorphism<C>& h)
  const
  {
    operands_.insert(h);
  }

};

} // namespace hom

/*------------------------------------------------------------------------------------------------*/

/// @brief Create the Intersection homomorphism.
/// @related homomorphism
template <typename C, typename InputIterator>
homomorphism<C>
Intersection(const order<C>& o, InputIterator begin, InputIterator end)
{
  const std::size_t size = std::distance(begin, end);

  if (size == 0)
  {
    throw std::invalid_argument("Empty operands at Intersection construction.");
  }

  typename hom::intersection<C>::operands_type operands;
  operands.reserve(size);

  typename hom::intersection_builder_helper<C>::locals_type locals;
  hom::intersection_builder_helper<C> ib {operands, locals};
  for (; begin != end; ++begin)
  {
    visit_self(ib, *begin);
  }

  // insert remaining locals
  for (const auto& l : locals)
  {
    operands.insert(Local<C>(l.first, Intersection<C>(o, l.second.begin(), l.second.end())));
  }

  if (operands.size() == 1)
  {
    return *operands.begin();
  }
  else
  {
    operands.shrink_to_fit();
    return homomorphism<C>::create(mem::construct<hom::intersection<C>>(), std::move(operands));
  }
}

/*------------------------------------------------------------------------------------------------*/

/// @brief Create the Intersection homomorphism.
/// @related homomorphism
template <typename C>
homomorphism<C>
Intersection(const order<C>& o, std::initializer_list<homomorphism<C>> operands)
{
  return Intersection<C>(o, operands.begin(), operands.end());
}

/*------------------------------------------------------------------------------------------------*/

} // namespace sdd

namespace std {

/*------------------------------------------------------------------------------------------------*/

/// @internal
/// @brief Hash specialization for sdd::hom::intersection.
template <typename C>
struct hash<sdd::hom::intersection<C>>
{
  std::size_t
  operator()(const sdd::hom::intersection<C>& s)
  const
  {
    return sdd::util::hash(s.operands().begin(), s.operands().end());
  }
};

/*------------------------------------------------------------------------------------------------*/

} // namespace std

#endif // _SDD_HOM_INTERSECTION_HH_
<|endoftext|>


<commit_before>
#include "wke/wke2.h"
#include "wke/wkeString.h"
#include "wke/wkeWebView.h"
#include "wke/wkeWebWindow.h"
#include "wke/wkeGlobalVar.h"
#include "content/browser/WebPage.h"
#include "content/web_impl_win/BlinkPlatformImpl.h"
#include "content/web_impl_win/WebThreadImpl.h"
#include "content/resources/HeaderFooterHtml.h"
#include "third_party/WebKit/Source/web/WebViewImpl.h"
#include "third_party/WebKit/Source/web/WebSettingsImpl.h"
#include "third_party/WebKit/public/web/WebPrintScalingOption.h"
#include "third_party/WebKit/public/web/WebPrintParams.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
#include "third_party/WebKit/public/web/WebScriptSource.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/skia/include/core/SkStream.h"
#include "third_party/skia/include/core/SkDocument.h"
#include "third_party/skia/include/core/SkPicture.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
#include "skia/ext/refptr.h"
#include "wtf/text/WTFString.h"
#include "wtf/text/WTFStringUtil.h"
#include "base/values.h"
#include "base/json/json_writer.h"
#include "net/WebURLLoaderInternal.h"
#include "net/InitializeHandleInfo.h"
#include <v8.h>
#include <shlwapi.h>
namespace net {
	void WSCI_setHook(void* j, void* hook);
	void WSCI_sendtext(void* j, char* buf, size_t len);
	void WSCI_sendblob(void* j, char* buf, size_t len);
}
namespace wke {

void printingTest(wkeWebView webview);
wkeMemBuf* printingTest2(wkeWebView webview);

const int kPointsPerInch = 72;

// Length of an inch in CSS's 1px unit.
// http://dev.w3.org/csswg/css3-values/#the-px-unit
const int kPixelsPerInch = 96;
const float kPrintingMinimumShrinkFactor = 1.25f;

void changeRequestUrl(wkeNetJob jobPtr, const char* url)
{
    wke::checkThreadCallIsValid(__FUNCTION__);
    net::WebURLLoaderInternal* job = (net::WebURLLoaderInternal*)jobPtr;
    blink::KURL newUrl(blink::ParsedURLString, url);
    job->m_response.setURL(newUrl);
    job->firstRequest()->setURL(newUrl);
    job->m_initializeHandleInfo->url = url;
    ASSERT(!job->m_url);
}

bool setDebugConfig(wkeWebView webview, const char* debugString, const char* param)
{
    if (0 == strcmp(debugString, "changeRequestUrl")) {
        wkeNetJob job = (wkeNetJob)webview;
        changeRequestUrl(job, param);
        return true;
    }

    content::WebPage* webpage = nullptr;
    blink::WebViewImpl* webViewImpl = nullptr;
    blink::WebSettingsImpl* settings = nullptr;
    if (webview)
        webpage = webview->getWebPage();
    if (webpage)
        webViewImpl = webpage->webViewImpl();
    if (webViewImpl)
        settings = webViewImpl->settingsImpl();

    String stringDebug(debugString);
    Vector<String> result;
    stringDebug.split(",", result);

    if (result.size() == 0)
        return true;

    String item = result[0];
    if ("setCookieJarPath" == item || "setCookieJarFullPath" == item) {
        std::string pathStr(param);
        if (pathStr.size() == 0)
            return true;

        if ("setCookieJarPath" == item) {
            if (pathStr[pathStr.size() - 1] != '\\' && pathStr[pathStr.size() - 1] != '/')
                pathStr += '\\';

            pathStr += "cookies.dat";
        }

        std::vector<char> result;
        WTF::Utf8ToMByte(pathStr.c_str(), pathStr.size(), &result, CP_ACP);
        if (0 == result.size())
            return true;
        result.push_back('\0');
        webview->setCookieJarFullPath(&result[0]);

        return true;
    } else if ("setLocalStorageFullPath" == item) {
        std::string pathStr(param);
        if (pathStr.size() == 0)
            return true;

        webview->setLocalStorageFullPath(pathStr.c_str());

        return true;
    } else if ("smootTextEnable" == item) {
        wke::g_smootTextEnable = atoi(param) == 1;
    }
	else if ("wsCallback" == item) {
		webview->webPage()->wkeHandler().wsCallback = (void*)(param);
		return true;
	}
	else if ("wsCallbackParam" == item) {
		webview->webPage()->wkeHandler().wsCallbackParam = (void*)(param);
		return true;
	}

    return false;
}

bool getDebugConfig(wkeWebView webview, const char* debugString, void **ret)
{
	if (strcmp("setwshook", debugString) == 0) {
		*ret = (void*)net::WSCI_setHook;
		return true;
	}
	else if (strcmp("sendtext", debugString) == 0) {
		*ret = (void*)net::WSCI_sendtext;
		return true;
	}
	else if (strcmp("sendblob", debugString) == 0) {
		*ret = (void*)net::WSCI_sendblob;
		return true;
	}
	content::WebPage* webpage = nullptr;
	blink::WebViewImpl* webViewImpl = nullptr;
	blink::WebSettingsImpl* settings = nullptr;
	if (webview)
		webpage = webview->getWebPage();
	if (webpage)
		webViewImpl = webpage->webViewImpl();
	if (webViewImpl)
		settings = webViewImpl->settingsImpl();

	String stringDebug(debugString);
	Vector<String> result;
	stringDebug.split(",", result);

	if (result.size() == 0)
		return true;

	String item = result[0];

	return false;
}

void printingTest(wkeWebView webview)
{
    content::WebPage* webpage = webview->getWebPage();
    blink::WebFrame* frame = webpage->mainFrame();

    blink::WebRect printContentArea(0, 0, 500, 600);
    blink::WebRect printableArea(0, 0, 500, 600);
    blink::WebSize paperSize(500, 600);
    const int kPointsPerInch = 72;
    int printerDPI = kPointsPerInch;
    blink::WebPrintScalingOption printScalingOption = blink::WebPrintScalingOptionSourceSize;
    blink::WebPrintParams webkitParams(printContentArea, printableArea, paperSize, printerDPI, printScalingOption);

    blink::WebView* blinkWebView = frame->view();
    blinkWebView->settings()->setShouldPrintBackgrounds(false);

    int pageCount = frame->printBegin(webkitParams);

    double cssScaleFactor = 1.0f;
    float webkitPageShrinkFactor = frame->getPrintPageShrink(0);
    float scaleFactor = cssScaleFactor * webkitPageShrinkFactor;

    SkPictureRecorder recorder;
    recorder.beginRecording(500 / scaleFactor, 600 / scaleFactor, NULL, 0);

    SkCanvas* canvas = recorder.getRecordingCanvas();

    frame->printPage(0, canvas);
    frame->printEnd();

    skia::RefPtr<SkPicture> content = skia::AdoptRef(recorder.endRecordingAsPicture());

    SkDynamicMemoryWStream pdfStream;
    skia::RefPtr<SkDocument> pdfDoc = skia::AdoptRef(SkDocument::CreatePDF(&pdfStream));

    SkRect contentArea = SkRect::MakeIWH(500, 600);
    SkCanvas* pdfCanvas = pdfDoc->beginPage(500, 600, nullptr);

    pdfCanvas->scale(scaleFactor, scaleFactor);
    pdfCanvas->drawPicture(content.get());
    pdfCanvas->flush();

    pdfDoc->endPage();
    pdfDoc->close();

    SkData* pdfData = (pdfStream.copyToData());

    HANDLE hFile = CreateFileW(L"D:\\1.pdf", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (!hFile || INVALID_HANDLE_VALUE == hFile)
        return;

    DWORD numberOfBytesWritten = 0;
    ::WriteFile(hFile, pdfData->data(), pdfData->size(), &numberOfBytesWritten, NULL);
    ::CloseHandle(hFile);

    pdfData->unref();
}

void readFile(const wchar_t* path, std::vector<char>* buffer)
{
    HANDLE hFile = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (INVALID_HANDLE_VALUE == hFile)
        return;

    DWORD fileSizeHigh;
    const DWORD bufferSize = ::GetFileSize(hFile, &fileSizeHigh);

    DWORD numberOfBytesRead = 0;
    buffer->resize(bufferSize);
    BOOL b = ::ReadFile(hFile, &buffer->at(0), bufferSize, &numberOfBytesRead, nullptr);
    ::CloseHandle(hFile);
    b = b;
}

static void executeScript(blink::WebFrame* frame, const char* scriptFormat, const base::Value& parameters)
{
    std::string json;
    base::JSONWriter::Write(parameters, &json);

    const int strSize = 2 * (strlen(scriptFormat) + json.size());
    char* script = (char*)malloc(strSize);
    sprintf(script, scriptFormat, json.c_str());

    blink::WebScriptSource source(blink::WebString::fromUTF8(script));
    frame->executeScript(source);
    free(script);
}

const char kPageLoadScriptFormat[] = "document.open(); document.write(%s); document.close();";
const char kSettingHeaderFooterDate[] = "date";
const char kPageSetupScriptFormat[] = "setup(%s);";

static int getWindowDPI(HWND hWnd)
{
    HDC screenDC = ::GetDC(hWnd);
    int dpiX = ::GetDeviceCaps(screenDC, LOGPIXELSX);//96100%120125%
    ::ReleaseDC(nullptr, screenDC);

    return dpiX;
}

int convertUnit(int value, int oldUnit, int newUnit)
{
    // With integer arithmetic, to divide a value with correct rounding, you need
    // to add half of the divisor value to the dividend value. You need to do the
    // reverse with negative number.
    if (value >= 0) {
        return ((value * newUnit) + (oldUnit / 2)) / oldUnit;
    } else {
        return ((value * newUnit) - (oldUnit / 2)) / oldUnit;
    }
}

void printHeaderAndFooter(
    bool isPrintPageHeadAndFooter,
    blink::WebCanvas* canvas,
    int windowDPI,
    int pageNumber,
    int totalPages,
    const blink::WebFrame& sourceFrame,
    float webkitScaleFactor,
    blink::WebSize pageSizeInPt,
    int topMargin,
    int bottomMargin
    )
{
    blink::WebSize pageSizeInPx(convertUnit(pageSizeInPt.width, kPointsPerInch, windowDPI), convertUnit(pageSizeInPt.height, kPointsPerInch, windowDPI));

    SkAutoCanvasRestore autoRestore(canvas, true);
    canvas->scale(1 / webkitScaleFactor, 1 / webkitScaleFactor);

    blink::WebView* webView = blink::WebView::create(NULL);
    webView->settings()->setJavaScriptEnabled(true);

    blink::WebLocalFrame* frame = blink::WebLocalFrame::create(blink::WebTreeScopeType::Document, NULL);
    webView->setMainFrame(frame);

#if 0
    std::vector<char> buffer;
    readFile(L"E:\\mycode\\miniblink49\\trunk\\content\\resources\\HeaderFooterHtml.htm", &buffer);
    base::StringValue html(std::string(buffer.data(), buffer.size()));
#else
    base::StringValue html(std::string(content::kHeaderFooterHtml, sizeof(content::kHeaderFooterHtml)));
#endif

    // Load page with script to avoid async operations.
    executeScript(frame, kPageLoadScriptFormat, html);

    SYSTEMTIME st = { 0 };
    ::GetLocalTime(&st);

    char dataBuffer[0x100];
    sprintf(dataBuffer, "%d-%d-%d", st.wYear, st.wMonth, st.wDay);

    base::DictionaryValue* options = new base::DictionaryValue();
    options->SetBoolean("isPrintPageHeadAndFooter", isPrintPageHeadAndFooter);
    options->SetString("date", dataBuffer);
    options->SetDouble("width", pageSizeInPt.width);
    options->SetDouble("height", pageSizeInPt.height);
    options->SetDouble("topMargin", topMargin);
    options->SetDouble("bottomMargin", bottomMargin);

    char* pageNumberStr = (char*)malloc(0x100);
    sprintf(pageNumberStr, "%d/%d", pageNumber, totalPages);
    options->SetString("pageNumber", pageNumberStr);
    free(pageNumberStr);

    blink::KURL kurl = sourceFrame.document().url();
    options->SetString("url", kurl.getUTF8String().utf8().data());

    std::string title = sourceFrame.document().title().utf8();
    options->SetString("title", title.empty() ? "print document" : title);

    executeScript(frame, kPageSetupScriptFormat, *options);

    blink::WebPrintParams webkitParams(pageSizeInPt);
    webkitParams.printerDPI = windowDPI;

    frame->printBegin(webkitParams);
    frame->printPage(0, canvas);
    frame->printEnd();

    webView->close();
    frame->close();

    delete options;
}

const wkePdfDatas* printToPdf(wkeWebView webView, blink::WebFrame* webFrame, const wkePrintSettings* params)
{
    content::WebPage* webpage = webView->getWebPage();
    if (!webpage)
        return nullptr;

    blink::WebFrame* frame = webFrame;
    if (!frame)
        frame = webpage->mainFrame();

    if (!frame)
        return nullptr;

    int windowDPI = 72; // chromiumdesired_dpi=72Ӳ룬getWindowDPI(webView->windowHandle());
    int dpi = params->dpi;
    int srcWidth = convertUnit(params->width, dpi, kPointsPerInch); // תptDPI72Ҳ˵px
    int srcHeight = convertUnit(params->height, dpi, kPointsPerInch);

    int marginTop = convertUnit(params->marginTop, dpi, kPointsPerInch);
    int marginBottom = convertUnit(params->marginBottom, dpi, kPointsPerInch);
    int marginLeft = convertUnit(params->marginLeft, dpi, kPointsPerInch);
    int marginRight = convertUnit(params->marginRight, dpi, kPointsPerInch);

    // PrepareFrameAndViewForPrint, ComputeWebKitPrintParamsInDesiredDpi
    blink::WebSize printContentSize(srcWidth - marginLeft - marginRight, srcHeight - marginTop - marginBottom);

    blink::WebRect printContentArea(0, 0, (printContentSize.width) /*/ kPrintingMinimumShrinkFactor*/, (printContentSize.height) /*/ kPrintingMinimumShrinkFactor*/);
    blink::WebSize paperSize(srcWidth, srcHeight);
    blink::WebRect printableArea(0, 0, paperSize.width, paperSize.height);

    SkRect clipRect = SkRect::MakeIWH(printContentSize.width, printContentSize.height);

    float webkitScaleFactor = 1.0 / kPrintingMinimumShrinkFactor;

    blink::WebPrintScalingOption printScalingOption = blink::WebPrintScalingOptionSourceSize;
    blink::WebPrintParams webkitParams(printContentArea, printableArea, paperSize, dpi, printScalingOption);

    blink::WebView* blinkWebView = frame->view();
    blink::WebSize oldSize = webpage->viewportSize();

    blink::WebSize printLayoutSize(printContentArea.width, printContentArea.height);

    if (params->isLandscape)
        printLayoutSize.width = ((int)((printLayoutSize.width) * kPrintingMinimumShrinkFactor));
    else
        printLayoutSize.height = ((int)((printLayoutSize.height) * kPrintingMinimumShrinkFactor));

    printLayoutSize.width = printLayoutSize.width; // convertUnit(printLayoutSize.width, kPointsPerInch, windowDPI); // pt -> px
    printLayoutSize.height = printLayoutSize.height; // convertUnit(printLayoutSize.height, kPointsPerInch, windowDPI);

    webpage->setViewportSize(printLayoutSize); // paperSize

//     double oldZoom = blinkWebView->zoomLevel();
//     double zoomLevel = blink::WebView::zoomFactorToZoomLevel(0.5);
//     blinkWebView->setZoomLevel(zoomLevel);

//     float oldZoom = blinkWebView->pageScaleFactor();
//     blinkWebView->setDefaultPageScaleLimits(0.5, 1.5);
//     blinkWebView->setPageScaleFactor(0.5);

    int pageCount = frame->printBegin(webkitParams);
    if (0 == pageCount)
        return nullptr;

    blinkWebView->settings()->setShouldPrintBackgrounds(params->isPrintBackgroud);

    wkePdfDatas* result = new wkePdfDatas();
    result->count = pageCount;
    result->sizes = (size_t*)malloc(pageCount * sizeof(size_t*));
    result->datas = (const void**)malloc(pageCount * sizeof(void*));

    for (int i = 0; i < pageCount; ++i) {
        float webkitPageShrinkFactor = frame->getPrintPageShrink(i);

        SkDynamicMemoryWStream pdfStream;
        skia::RefPtr<SkDocument> document = skia::AdoptRef(SkDocument::CreatePDF(&pdfStream, kPointsPerInch));

        SkCanvas* canvas = document->beginPage(srcWidth / webkitPageShrinkFactor, srcHeight / webkitPageShrinkFactor);
        canvas->scale(webkitPageShrinkFactor, webkitPageShrinkFactor);

        printHeaderAndFooter(params->isPrintPageHeadAndFooter, canvas, windowDPI, i + 1, pageCount, *frame, webkitPageShrinkFactor, paperSize, marginTop, marginBottom);

        SkRect clipRectTemp = SkRect::MakeIWH(clipRect.width() / webkitPageShrinkFactor, clipRect.height() / webkitPageShrinkFactor);

        canvas->save();
        canvas->translate(marginLeft / webkitPageShrinkFactor, marginTop / webkitPageShrinkFactor);
        canvas->clipRect(clipRectTemp);
        frame->printPage(i, canvas);
        canvas->restore();

        canvas->flush();
        document->endPage();
        document->close();

        SkData* pdfData = pdfStream.copyToData();

        result->sizes[i] = pdfData->size();
        result->datas[i] = malloc(pdfData->size());
        memcpy((void*)(result->datas[i]), pdfData->data(), pdfData->size());

        pdfData->unref();
    }

    frame->printEnd();

    //blinkWebView->setZoomLevel(oldZoom);
    //blinkWebView->setPageScaleFactor(oldZoom);
    webpage->setViewportSize(oldSize);

    return result;
}

const wkeMemBuf* printToBitmap(wkeWebView webView, const wkeScreenshotSettings* settings)
{
    content::WebPage* webpage = webView->getWebPage();
    if (!webpage)
        return nullptr;
    blink::WebFrame* webFrame = webpage->mainFrame();
    if (!webFrame)
        return nullptr;

    blink::WebSize contentsSize = webFrame->contentsSize();

    int width = contentsSize.width;
    int height = contentsSize.height;

    if (width <= 0 || height <= 0)
        return nullptr;

    SkBitmap bitmap;
    bitmap.allocN32Pixels(width + 0.5, height + 0.5);

    SkCanvas canvas(bitmap);

    blink::WebString css;
    webFrame->drawInCanvas(blink::WebRect(0, 0, width, height), css, &canvas);

    canvas.flush();

    size_t size = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + bitmap.getSize();

    BITMAPFILEHEADER fileHeader = {
        0x4d42,
        sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + size,
        0, 0,
        sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)
    };

    BITMAPINFOHEADER bmiHeader = {
        sizeof(BITMAPINFOHEADER),
        width,
        -height,
        1,
        32,
        BI_RGB,
    };

    std::vector<char> bmpData;
    bmpData.resize(size);

    char* destBuffer = reinterpret_cast<char*>(&bmpData.at(0));
    size_t offset = 0;

    memcpy(destBuffer, &fileHeader, sizeof(fileHeader));
    offset += sizeof(fileHeader);

    memcpy(destBuffer + offset, &bmiHeader, sizeof(bmiHeader));
    offset += sizeof(bmiHeader);

    bitmap.copyPixelsTo(destBuffer + offset, size);

    wkeMemBuf* result = wkeCreateMemBuf(nullptr, destBuffer, size);
    return result;
}

}

void wkeUtilRelasePrintPdfDatas(const wkePdfDatas* datas)
{
    for (int i = 0; i < datas->count; ++i) {
        free((void *)(datas->datas[i]));
    }

    free((void *)(datas->sizes));
    free((void *)(datas->datas));
    delete datas;
}

const wkePdfDatas* wkeUtilPrintToPdf(wkeWebView webView, wkeWebFrameHandle frameId, const wkePrintSettings* settings)
{
    content::WebPage* webPage = webView->webPage();
    blink::WebFrame* webFrame = webPage->getWebFrameFromFrameId(wke::CWebView::wkeWebFrameHandleToFrameId(webPage, frameId));
    return wke::printToPdf(webView, webFrame, settings);
}

const wkeMemBuf* wkePrintToBitmap(wkeWebView webView, wkeWebFrameHandle frameId, const wkeScreenshotSettings* settings)
{
    return wke::printToBitmap(webView, settings);
}<commit_msg>* 格式整理<commit_after>
#include "wke/wke2.h"
#include "wke/wkeString.h"
#include "wke/wkeWebView.h"
#include "wke/wkeWebWindow.h"
#include "wke/wkeGlobalVar.h"
#include "content/browser/WebPage.h"
#include "content/web_impl_win/BlinkPlatformImpl.h"
#include "content/web_impl_win/WebThreadImpl.h"
#include "content/resources/HeaderFooterHtml.h"
#include "third_party/WebKit/Source/web/WebViewImpl.h"
#include "third_party/WebKit/Source/web/WebSettingsImpl.h"
#include "third_party/WebKit/public/web/WebPrintScalingOption.h"
#include "third_party/WebKit/public/web/WebPrintParams.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
#include "third_party/WebKit/public/web/WebScriptSource.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/skia/include/core/SkStream.h"
#include "third_party/skia/include/core/SkDocument.h"
#include "third_party/skia/include/core/SkPicture.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
#include "skia/ext/refptr.h"
#include "wtf/text/WTFString.h"
#include "wtf/text/WTFStringUtil.h"
#include "base/values.h"
#include "base/json/json_writer.h"
#include "net/WebURLLoaderInternal.h"
#include "net/InitializeHandleInfo.h"
#include <v8.h>
#include <shlwapi.h>

namespace net {

void WSCI_setHook(void* j, void* hook);
void WSCI_sendtext(void* j, char* buf, size_t len);
void WSCI_sendblob(void* j, char* buf, size_t len);

}

namespace wke {

bool setDebugConfig(wkeWebView webview, const char* debugString, const char* param)
{
    return false;
}

bool getDebugConfig(wkeWebView webview, const char* debugString, void **ret)
{
    return false;
}

const wkePdfDatas* printToPdf(wkeWebView webView, blink::WebFrame* webFrame, const wkePrintSettings* params)
{
    return nullptr;
}

const wkeMemBuf* printToBitmap(wkeWebView webView, const wkeScreenshotSettings* settings)
{
    return nullptr;
}

}

void wkeUtilRelasePrintPdfDatas(const wkePdfDatas* datas)
{
    for (int i = 0; i < datas->count; ++i) {
        free((void *)(datas->datas[i]));
    }

    free((void *)(datas->sizes));
    free((void *)(datas->datas));
    delete datas;
}

const wkePdfDatas* wkeUtilPrintToPdf(wkeWebView webView, wkeWebFrameHandle frameId, const wkePrintSettings* settings)
{
    content::WebPage* webPage = webView->webPage();
    blink::WebFrame* webFrame = webPage->getWebFrameFromFrameId(wke::CWebView::wkeWebFrameHandleToFrameId(webPage, frameId));
    return wke::printToPdf(webView, webFrame, settings);
}

const wkeMemBuf* wkePrintToBitmap(wkeWebView webView, wkeWebFrameHandle frameId, const wkeScreenshotSettings* settings)
{
    return wke::printToBitmap(webView, settings);
}<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017 dresden elektronik ingenieurtechnik gmbh.
 * All rights reserved.
 *
 * The software in this package is published under the terms of the BSD
 * style license a copy of which has been included with this distribution in
 * the LICENSE.txt file.
 *
 */

#include "poll_manager.h"
#include "de_web_plugin_private.h"

/*! Constructor.
 */
PollManager::PollManager(QObject *parent) :
    QObject(parent)
{
    pollState = StateIdle;
    timer = new QTimer(this);
    timer->setSingleShot(true);
    connect(timer, SIGNAL(timeout()), this, SLOT(pollTimerFired()));
    plugin = qobject_cast<DeRestPluginPrivate*>(parent);
}

/*! Queues polling of the node.
    \param restNode - the node to poll
 */
void PollManager::poll(RestNodeBase *restNode, const QDateTime &tStart)
{
    Resource *r = dynamic_cast<Resource*>(restNode);
    DBG_Assert(r != 0);
    if (!r)
    {
        return;
    }

    PollItem pitem;

    if (!restNode->node()->nodeDescriptor().receiverOnWhenIdle())
    {
        return;
    }

    if (r->prefix() == RLights)
    {
        LightNode *lightNode = static_cast<LightNode*>(restNode);
        DBG_Assert(lightNode != 0);
        pitem.endpoint = lightNode->haEndpoint().endpoint();
    }
    else if (r->prefix() == RSensors)
    {
        Sensor *sensor = static_cast<Sensor*>(restNode);
        DBG_Assert(sensor != 0);
        pitem.endpoint = sensor->fingerPrint().endpoint;
    }
    else
    {
        return;
    }

    pitem.id = restNode->id();
    pitem.prefix = r->prefix();
    pitem.address = restNode->address();
    pitem.tStart = tStart;

    for (int i = 0; i < r->itemCount(); i++)
    {
        const ResourceItem *item = r->itemForIndex(i);
        const char *suffix = item ? item->descriptor().suffix : 0;

        if (suffix == RStateOn ||
            suffix == RStateBri ||
            suffix == RStateColorMode ||
            suffix == RStateConsumption ||
            suffix == RStatePower ||
            suffix == RAttrModelId)
        {
            pitem.items.push_back(suffix);
        }
    }

    for (PollItem &i : items)
    {
        if (i.prefix == r->prefix() && i.id == restNode->id())
        {
            i.items = pitem.items; // update
            if (tStart.isValid())
            {
                i.tStart = tStart;
            }
            return;
        }
    }

    items.push_back(pitem);

    if (!timer->isActive())
    {
        timer->start(1);
    }
}

/*! Delays polling for \p ms milliseconds.
 */
void PollManager::delay(int ms)
{
    timer->stop();
    timer->start(ms);
}

/*! Handle APS confirm if related to polling.
 */
void PollManager::apsdeDataConfirm(const deCONZ::ApsDataConfirm &conf)
{
    if (pollState != StateWait)
    {
        return;
    }

    if (apsReqId != conf.id())
    {
        return;
    }

    if (dstAddr.hasExt() && conf.dstAddress().hasExt()
        && dstAddr.ext() != conf.dstAddress().ext())
    {

    }

    else if (dstAddr.hasNwk() && conf.dstAddress().hasNwk()
        && dstAddr.nwk() != conf.dstAddress().nwk())
    {

    }

    DBG_Printf(DBG_INFO_L2, "Poll APS confirm %u status: 0x%02X\n", conf.id(), conf.status());

    pollState = StateIdle;
    timer->stop();
    timer->start(1);
}

/*! Timer callback to proceed polling.
 */
void PollManager::pollTimerFired()
{
    if (pollState == StateWait)
    {
        DBG_Printf(DBG_INFO, "timout on poll APS confirm\n");
        pollState = StateIdle;
    }

    DBG_Assert(pollState == StateIdle);

    if (items.empty())
    {
        return;
    }

    QDateTime now = QDateTime::currentDateTime();
    PollItem &pitem = items.front();
    Resource *r = plugin->getResource(pitem.prefix, pitem.id);
    ResourceItem *item = 0;
    RestNodeBase *restNode = 0;
    const LightNode *lightNode = 0;
    if (r && r->prefix() == RLights)
    {
        restNode = plugin->getLightNodeForId(pitem.id);
        lightNode = static_cast<LightNode*>(restNode);
        item = r->item(RStateReachable);
    }
    else if (r && r->prefix() == RSensors)
    {
        restNode = plugin->getSensorNodeForId(pitem.id);
        item = r->item(RConfigReachable);
    }

    if (pitem.tStart.isValid() && pitem.tStart > now)
    {
        if (items.size() > 1)
        {
            PollItem tmp = pitem;
            items.front() = items.back();
            items.back() = tmp;
        }
        timer->start(1);
        return;
    }

    if (!r || pitem.items.empty() ||
        !restNode ||
        //!restNode->lastRx().isValid() ||
        !item || !item->toBool()) // not reachable
    {
        items.front() = items.back();
        items.pop_back();
        timer->start(1);
        return;
    }

    quint16 clusterId = 0;
    std::vector<quint16> attributes;

    item = r->item(RStateOn);
    bool isOn = item ? item->toBool() : false;
    const char *&suffix = pitem.items[0];

    for (size_t i = 0; pitem.items[0] == 0 && i < pitem.items.size(); i++)
    {
        if (pitem.items[i] != 0)
        {
            pitem.items[0] = pitem.items[i]; // move to front
            pitem.items[i] = 0; // clear
            break;
        }
    }

    if (!suffix)
    {
        pitem.items.clear(); // all done
    }

    if (suffix == RStateOn)
    {
        clusterId = ONOFF_CLUSTER_ID;
        attributes.push_back(0x0000); // onOff
    }
    else if (suffix == RStateBri && isOn)
    {
        NodeValue &val = restNode->getZclValue(LEVEL_CLUSTER_ID, 0x0000);

        if (isOn || !val.timestamp.isValid())
        {
            clusterId = LEVEL_CLUSTER_ID;
            attributes.push_back(0x0000); // current level
        }
    }
    else if (suffix == RStateColorMode && lightNode)
    {
        clusterId = COLOR_CLUSTER_ID;
        item = r->item(RConfigColorCapabilities);

        if (!item)
        {
            attributes.push_back(0x0008); // color mode
            attributes.push_back(0x4001); // enhanced color mode
            attributes.push_back(0x400a); // color capabilities
            attributes.push_back(0x400b); // color temperature min
            attributes.push_back(0x400c); // color temperature max
        }
        else
        {
            quint16 cap = item->toNumber();
            std::vector<quint16> toCheck;
            if (cap & 0x0002) // enhanced hue supported
            {
                toCheck.push_back(0x4001); // enhanced color mode
                toCheck.push_back(0x4000); // enhanced hue
                toCheck.push_back(0x0001); // saturation
            }
            else if (cap & 0x0001)
            {
                toCheck.push_back(0x0000); // hue
                toCheck.push_back(0x0001); // saturation
                toCheck.push_back(0x0008); // color mode
            }
            else
            {
                toCheck.push_back(0x0008); // color mode
            }

            if (cap & 0x0004)
            {
                toCheck.push_back(0x4002); // Color loop active
            }

            if (cap & 0x0008)
            {
                toCheck.push_back(0x0003); // currentX
                toCheck.push_back(0x0004); // currentY
            }

            if (cap & 0x0010)
            {
                toCheck.push_back(0x0007); // color temperature
            }

            for (const deCONZ::ZclCluster &cl : lightNode->haEndpoint().inClusters())
            {
                if (cl.id() != COLOR_CLUSTER_ID)
                {
                    continue;
                }

                for (const deCONZ::ZclAttribute &attr : cl.attributes())
                {
                    for (quint16 attrId : toCheck)
                    {
                        // discard attributes which are not be available
                        if (attrId == attr.id() && attr.isAvailable())
                        {
                            NodeValue &val = restNode->getZclValue(clusterId, attrId);
                            if (isOn || !val.timestamp.isValid())
                            {
                                attributes.push_back(attrId);
                            }
                        }
                    }
                }

                break;
            }
        }
    }
    else if (suffix == RStateConsumption)
    {
        clusterId = METERING_CLUSTER_ID;
        attributes.push_back(0x0000); // Curent Summation Delivered
    }
    else if (suffix == RStatePower)
    {
        clusterId = ELECTRICAL_MEASUREMENT_CLUSTER_ID;
        attributes.push_back(0x050b); // Active Power
        item = r->item(RAttrModelId);
        if (! item->toString().startsWith(QLatin1String("Plug"))) // OSRAM plug
        {
            attributes.push_back(0x0505); // RMS Voltage
            attributes.push_back(0x0508); // RMS Current
        }
    }
    else if (suffix == RAttrModelId)
    {
        item = r->item(RAttrModelId);
        if (item && (item->toString().isEmpty() || item->toString() == QLatin1String("unknown") ||
             (item->lastSet().secsTo(now) > READ_MODEL_ID_INTERVAL && item->toString().startsWith("FLS-A")) // dynamic model ids
            ))
        {
            clusterId = BASIC_CLUSTER_ID;
            //attributes.push_back(0x0004); // manufacturer
            attributes.push_back(0x0005); // model id
        }
    }

    size_t fresh = 0;
    for (quint16 attrId : attributes)
    {
        NodeValue &val = restNode->getZclValue(clusterId, attrId);

        if (val.timestampLastReport.isValid() && val.timestampLastReport.secsTo(now) < 360)
        {
            fresh++;
        }
    }

    if (clusterId && fresh > 0 && fresh == attributes.size())
    {
        DBG_Printf(DBG_INFO, "Poll APS request to 0x%016llX cluster: 0x%04X dropped, values are fresh enough\n", pitem.address.ext(), clusterId);
        suffix = 0; // clear
        timer->start(100);
    }
    else if (!attributes.empty() && clusterId &&
        plugin->readAttributes(restNode, pitem.endpoint, clusterId, attributes))
    {
        pollState = StateWait;
        // TODO this hack to get aps request id
        DBG_Assert(plugin->tasks.back().taskType == TaskReadAttributes);
        apsReqId = plugin->tasks.back().req.id();
        dstAddr = pitem.address;
        timer->start(20 * 1000); // wait for confirm
        suffix = 0; // clear
        DBG_Printf(DBG_INFO_L2, "Poll APS request %u to 0x%016llX cluster: 0x%04X\n", apsReqId, dstAddr.ext(), clusterId);
    }
    else if (suffix)
    {
        suffix = 0; // clear
        timer->start(100);
    }
    else
    {
        if (clusterId)
        {
            DBG_Printf(DBG_INFO, "Poll APS request to 0x%016llX cluster: 0x%04X dropped\n", pitem.address.ext(), clusterId);
        }
        timer->start(100);
        items.front() = items.back();
        items.pop_back();
    }

}
<commit_msg>Fix SEGV when restNode->node() isn't available yet<commit_after>/*
 * Copyright (c) 2017 dresden elektronik ingenieurtechnik gmbh.
 * All rights reserved.
 *
 * The software in this package is published under the terms of the BSD
 * style license a copy of which has been included with this distribution in
 * the LICENSE.txt file.
 *
 */

#include "poll_manager.h"
#include "de_web_plugin_private.h"

/*! Constructor.
 */
PollManager::PollManager(QObject *parent) :
    QObject(parent)
{
    pollState = StateIdle;
    timer = new QTimer(this);
    timer->setSingleShot(true);
    connect(timer, SIGNAL(timeout()), this, SLOT(pollTimerFired()));
    plugin = qobject_cast<DeRestPluginPrivate*>(parent);
}

/*! Queues polling of the node.
    \param restNode - the node to poll
 */
void PollManager::poll(RestNodeBase *restNode, const QDateTime &tStart)
{
    Resource *r = dynamic_cast<Resource*>(restNode);
    DBG_Assert(r != 0);
    if (!r || !restNode->node())
    {
        return;
    }

    PollItem pitem;

    if (!restNode->node()->nodeDescriptor().receiverOnWhenIdle())
    {
        return;
    }

    if (r->prefix() == RLights)
    {
        LightNode *lightNode = static_cast<LightNode*>(restNode);
        DBG_Assert(lightNode != 0);
        pitem.endpoint = lightNode->haEndpoint().endpoint();
    }
    else if (r->prefix() == RSensors)
    {
        Sensor *sensor = static_cast<Sensor*>(restNode);
        DBG_Assert(sensor != 0);
        pitem.endpoint = sensor->fingerPrint().endpoint;
    }
    else
    {
        return;
    }

    pitem.id = restNode->id();
    pitem.prefix = r->prefix();
    pitem.address = restNode->address();
    pitem.tStart = tStart;

    for (int i = 0; i < r->itemCount(); i++)
    {
        const ResourceItem *item = r->itemForIndex(i);
        const char *suffix = item ? item->descriptor().suffix : 0;

        if (suffix == RStateOn ||
            suffix == RStateBri ||
            suffix == RStateColorMode ||
            suffix == RStateConsumption ||
            suffix == RStatePower ||
            suffix == RAttrModelId)
        {
            pitem.items.push_back(suffix);
        }
    }

    for (PollItem &i : items)
    {
        if (i.prefix == r->prefix() && i.id == restNode->id())
        {
            i.items = pitem.items; // update
            if (tStart.isValid())
            {
                i.tStart = tStart;
            }
            return;
        }
    }

    items.push_back(pitem);

    if (!timer->isActive())
    {
        timer->start(1);
    }
}

/*! Delays polling for \p ms milliseconds.
 */
void PollManager::delay(int ms)
{
    timer->stop();
    timer->start(ms);
}

/*! Handle APS confirm if related to polling.
 */
void PollManager::apsdeDataConfirm(const deCONZ::ApsDataConfirm &conf)
{
    if (pollState != StateWait)
    {
        return;
    }

    if (apsReqId != conf.id())
    {
        return;
    }

    if (dstAddr.hasExt() && conf.dstAddress().hasExt()
        && dstAddr.ext() != conf.dstAddress().ext())
    {

    }

    else if (dstAddr.hasNwk() && conf.dstAddress().hasNwk()
        && dstAddr.nwk() != conf.dstAddress().nwk())
    {

    }

    DBG_Printf(DBG_INFO_L2, "Poll APS confirm %u status: 0x%02X\n", conf.id(), conf.status());

    pollState = StateIdle;
    timer->stop();
    timer->start(1);
}

/*! Timer callback to proceed polling.
 */
void PollManager::pollTimerFired()
{
    if (pollState == StateWait)
    {
        DBG_Printf(DBG_INFO, "timout on poll APS confirm\n");
        pollState = StateIdle;
    }

    DBG_Assert(pollState == StateIdle);

    if (items.empty())
    {
        return;
    }

    QDateTime now = QDateTime::currentDateTime();
    PollItem &pitem = items.front();
    Resource *r = plugin->getResource(pitem.prefix, pitem.id);
    ResourceItem *item = 0;
    RestNodeBase *restNode = 0;
    const LightNode *lightNode = 0;
    if (r && r->prefix() == RLights)
    {
        restNode = plugin->getLightNodeForId(pitem.id);
        lightNode = static_cast<LightNode*>(restNode);
        item = r->item(RStateReachable);
    }
    else if (r && r->prefix() == RSensors)
    {
        restNode = plugin->getSensorNodeForId(pitem.id);
        item = r->item(RConfigReachable);
    }

    if (pitem.tStart.isValid() && pitem.tStart > now)
    {
        if (items.size() > 1)
        {
            PollItem tmp = pitem;
            items.front() = items.back();
            items.back() = tmp;
        }
        timer->start(1);
        return;
    }

    if (!r || pitem.items.empty() ||
        !restNode ||
        //!restNode->lastRx().isValid() ||
        !item || !item->toBool()) // not reachable
    {
        items.front() = items.back();
        items.pop_back();
        timer->start(1);
        return;
    }

    quint16 clusterId = 0;
    std::vector<quint16> attributes;

    item = r->item(RStateOn);
    bool isOn = item ? item->toBool() : false;
    const char *&suffix = pitem.items[0];

    for (size_t i = 0; pitem.items[0] == 0 && i < pitem.items.size(); i++)
    {
        if (pitem.items[i] != 0)
        {
            pitem.items[0] = pitem.items[i]; // move to front
            pitem.items[i] = 0; // clear
            break;
        }
    }

    if (!suffix)
    {
        pitem.items.clear(); // all done
    }

    if (suffix == RStateOn)
    {
        clusterId = ONOFF_CLUSTER_ID;
        attributes.push_back(0x0000); // onOff
    }
    else if (suffix == RStateBri && isOn)
    {
        NodeValue &val = restNode->getZclValue(LEVEL_CLUSTER_ID, 0x0000);

        if (isOn || !val.timestamp.isValid())
        {
            clusterId = LEVEL_CLUSTER_ID;
            attributes.push_back(0x0000); // current level
        }
    }
    else if (suffix == RStateColorMode && lightNode)
    {
        clusterId = COLOR_CLUSTER_ID;
        item = r->item(RConfigColorCapabilities);

        if (!item)
        {
            attributes.push_back(0x0008); // color mode
            attributes.push_back(0x4001); // enhanced color mode
            attributes.push_back(0x400a); // color capabilities
            attributes.push_back(0x400b); // color temperature min
            attributes.push_back(0x400c); // color temperature max
        }
        else
        {
            quint16 cap = item->toNumber();
            std::vector<quint16> toCheck;
            if (cap & 0x0002) // enhanced hue supported
            {
                toCheck.push_back(0x4001); // enhanced color mode
                toCheck.push_back(0x4000); // enhanced hue
                toCheck.push_back(0x0001); // saturation
            }
            else if (cap & 0x0001)
            {
                toCheck.push_back(0x0000); // hue
                toCheck.push_back(0x0001); // saturation
                toCheck.push_back(0x0008); // color mode
            }
            else
            {
                toCheck.push_back(0x0008); // color mode
            }

            if (cap & 0x0004)
            {
                toCheck.push_back(0x4002); // Color loop active
            }

            if (cap & 0x0008)
            {
                toCheck.push_back(0x0003); // currentX
                toCheck.push_back(0x0004); // currentY
            }

            if (cap & 0x0010)
            {
                toCheck.push_back(0x0007); // color temperature
            }

            for (const deCONZ::ZclCluster &cl : lightNode->haEndpoint().inClusters())
            {
                if (cl.id() != COLOR_CLUSTER_ID)
                {
                    continue;
                }

                for (const deCONZ::ZclAttribute &attr : cl.attributes())
                {
                    for (quint16 attrId : toCheck)
                    {
                        // discard attributes which are not be available
                        if (attrId == attr.id() && attr.isAvailable())
                        {
                            NodeValue &val = restNode->getZclValue(clusterId, attrId);
                            if (isOn || !val.timestamp.isValid())
                            {
                                attributes.push_back(attrId);
                            }
                        }
                    }
                }

                break;
            }
        }
    }
    else if (suffix == RStateConsumption)
    {
        clusterId = METERING_CLUSTER_ID;
        attributes.push_back(0x0000); // Curent Summation Delivered
    }
    else if (suffix == RStatePower)
    {
        clusterId = ELECTRICAL_MEASUREMENT_CLUSTER_ID;
        attributes.push_back(0x050b); // Active Power
        item = r->item(RAttrModelId);
        if (! item->toString().startsWith(QLatin1String("Plug"))) // OSRAM plug
        {
            attributes.push_back(0x0505); // RMS Voltage
            attributes.push_back(0x0508); // RMS Current
        }
    }
    else if (suffix == RAttrModelId)
    {
        item = r->item(RAttrModelId);
        if (item && (item->toString().isEmpty() || item->toString() == QLatin1String("unknown") ||
             (item->lastSet().secsTo(now) > READ_MODEL_ID_INTERVAL && item->toString().startsWith("FLS-A")) // dynamic model ids
            ))
        {
            clusterId = BASIC_CLUSTER_ID;
            //attributes.push_back(0x0004); // manufacturer
            attributes.push_back(0x0005); // model id
        }
    }

    size_t fresh = 0;
    for (quint16 attrId : attributes)
    {
        NodeValue &val = restNode->getZclValue(clusterId, attrId);

        if (val.timestampLastReport.isValid() && val.timestampLastReport.secsTo(now) < 360)
        {
            fresh++;
        }
    }

    if (clusterId && fresh > 0 && fresh == attributes.size())
    {
        DBG_Printf(DBG_INFO, "Poll APS request to 0x%016llX cluster: 0x%04X dropped, values are fresh enough\n", pitem.address.ext(), clusterId);
        suffix = 0; // clear
        timer->start(100);
    }
    else if (!attributes.empty() && clusterId &&
        plugin->readAttributes(restNode, pitem.endpoint, clusterId, attributes))
    {
        pollState = StateWait;
        // TODO this hack to get aps request id
        DBG_Assert(plugin->tasks.back().taskType == TaskReadAttributes);
        apsReqId = plugin->tasks.back().req.id();
        dstAddr = pitem.address;
        timer->start(20 * 1000); // wait for confirm
        suffix = 0; // clear
        DBG_Printf(DBG_INFO_L2, "Poll APS request %u to 0x%016llX cluster: 0x%04X\n", apsReqId, dstAddr.ext(), clusterId);
    }
    else if (suffix)
    {
        suffix = 0; // clear
        timer->start(100);
    }
    else
    {
        if (clusterId)
        {
            DBG_Printf(DBG_INFO, "Poll APS request to 0x%016llX cluster: 0x%04X dropped\n", pitem.address.ext(), clusterId);
        }
        timer->start(100);
        items.front() = items.back();
        items.pop_back();
    }

}
<|endoftext|>


<commit_before>/*===================================================================

  The Medical Imaging Interaction Toolkit (MITK)

  Copyright (c) German Cancer Research Center,
  Division of Medical and Biological Informatics.
  All rights reserved.

  This software is distributed WITHOUT ANY WARRANTY; without
  even the implied warranty of MERCHANTABILITY or FITNESS FOR
  A PARTICULAR PURPOSE.

  See LICENSE.txt or http://www.mitk.org for details.

  ===================================================================*/

#include "./mitkPhotoacousticMotionCorrectionFilter.h"
#include <mitkImageReadAccessor.h>

mitk::PhotoacousticMotionCorrectionFilter::
    PhotoacousticMotionCorrectionFilter() {
  // Set the defaults for the OpticalFlowFarneback algorithm
  // The values are taken directly out of Thomas's
  // US-CV-Based-Optical-Flow-Carotis.ipyn
  m_batch = 5;
  m_pyr_scale = 0.5;
  m_levels = 1;
  m_winsize = 40;
  m_iterations = 2;
  m_poly_n = 7;
  m_poly_sigma = 1.5;
  m_flags = 0;

  SetNumberOfIndexedInputs(2);
  SetNumberOfIndexedOutputs(2);
}

mitk::PhotoacousticMotionCorrectionFilter::
    ~PhotoacousticMotionCorrectionFilter() {}

// void mitk::PhotoacousticMotionCorrectionFilter::SetInput(Image::Pointer
// paImage,
//                                                          Image::Pointer
//                                                          usImage)
// {
//   m_paImage = paImage;
//   m_usImage = usImage;
// }

void mitk::PhotoacousticMotionCorrectionFilter::GenerateData() {
  MITK_INFO << "Start motion compensation.";

  m_paImage = this->GetInput(0);
  m_usImage = this->GetInput(1);

  // Check that we actually got some images
  if (!m_paImage || !m_usImage) {
    // TODO: Throw some error here
  }
  // Check that the image dimensions are the same
  if (m_paImage->GetDimension() != m_usImage->GetDimension() &&
      m_usImage->GetDimension() == 3) {
    MITK_INFO << "Mismatching image dimensions detected in the motion "
                 "compensation filter.";
    // TODO: Throw some error here
  }
  for (unsigned int i = 0; i < m_paImage->GetDimension(); i++) {
    if (m_paImage->GetDimensions()[i] != m_usImage->GetDimensions()[i]) {
      MITK_INFO << "Mismatching image dimensions detected in the motion "
                   "compensation filter.";
      // TODO: Throw some error here
    }
  }

  // Initialize output images
  if (!m_paCompensated) {
    m_paCompensated = mitk::Image::New();
  }
  if (!m_usCompensated) {
    m_usCompensated = mitk::Image::New();
  }
  m_paCompensated->Initialize(m_paImage->GetPixelType(),
                              m_paImage->GetDimension(),
                              m_paImage->GetDimensions());
  m_usCompensated->Initialize(m_usImage->GetPixelType(),
                              m_usImage->GetDimension(),
                              m_usImage->GetDimensions());

  // TODO: remove debug messages

  // Initialize the slices
  mitk::Image::Pointer pa_slice = mitk::Image::New();
  mitk::Image::Pointer us_slice = mitk::Image::New();
  pa_slice->Initialize(m_paImage->GetPixelType(), 2,
                       m_paImage->GetDimensions());
  us_slice->Initialize(m_usImage->GetPixelType(), 2,
                       m_usImage->GetDimensions());

  MITK_INFO << "Start iteration.";
  // Iterate over all the slices
  for (unsigned int i = 0; i < m_paImage->GetDimensions()[2]; i++) {

    // Get a read accessor for each slice
    mitk::ImageReadAccessor pa_accessor(m_paImage, m_paImage->GetSliceData(i));
    mitk::ImageReadAccessor us_accessor(m_paImage, m_usImage->GetSliceData(i));

    // Write the correct image data into the slice
    pa_slice->SetImportVolume(pa_accessor.GetData());
    us_slice->SetImportVolume(us_accessor.GetData());

    // Convert them first to an itk::Image and then to a cv::Mat
    mitk::CastToItkImage(pa_slice, m_itkPaImage);
    mitk::CastToItkImage(us_slice, m_itkUsImage);
    MITK_INFO << "Generate Matrix.";

    m_PaMatC = itk::OpenCVImageBridge::ITKImageToCVMat<itk::Image<float, 2>>(
      m_itkPaImage);
    m_UsMatC = itk::OpenCVImageBridge::ITKImageToCVMat<itk::Image<float, 2>>(
        m_itkUsImage);

    m_PaMat = m_PaMatC.getUMat( cv::ACCESS_READ );
    m_UsMat = m_UsMatC.getUMat( cv::ACCESS_READ );

    MITK_INFO << "Matrix generated.";
    // At the beginning of a batch we set new references and the compensation
    // can be skipped.
    // TODO: handle m_batch == 0
    // if (i % m_batch == 0) {
    //   m_UsRef = m_UsMat;
    //   m_UsRes = m_UsMatC;
    //   m_PaRes = m_PaMatC;
    //   continue;
    // } else {
    //   // Calculate the flow using the Farneback algorithm
    //   // TODO: flags hard coded to 0, rethink.
    //   cv::calcOpticalFlowFarneback(m_UsRef, m_UsMat, m_Flow, m_pyr_scale, m_levels,
    //                                m_winsize, m_iterations, m_poly_n,
    //                                m_poly_sigma, 0);

    //   // Apply flow to the matrices
    //   cv::remap(m_PaMatC, m_PaRes, m_Flow, cv::noArray(), cv::INTER_LINEAR);
    //   cv::remap(m_UsMatC, m_UsRes, m_Flow, cv::noArray(), cv::INTER_LINEAR);
    // }

    // TODO: Actually do something, not just retransform
    m_PaRes = m_PaMatC;
    m_UsRes = m_UsMatC;

    m_OpenCVToImageFilter->SetOpenCVMat(m_PaRes);
    m_OpenCVToImageFilter->Update();
    pa_slice = m_OpenCVToImageFilter->GetOutput();
    mitk::ImageReadAccessor pa_slice_accessor(pa_slice);
    m_paCompensated->SetSlice(pa_slice_accessor.GetData(), i);
    m_OpenCVToImageFilter->SetOpenCVMat(m_UsRes);
    m_OpenCVToImageFilter->Update();
    us_slice = m_OpenCVToImageFilter->GetOutput();
    mitk::ImageReadAccessor us_slice_accessor(us_slice);
    m_paCompensated->SetSlice(us_slice_accessor.GetData(), i);
}

  this->SetNthOutput(1, m_usCompensated);
  this->SetNthOutput(0, m_paCompensated);
  MITK_INFO << "We succeeded in running through the whole thing!";
}
<commit_msg>cv::Mat were deep copied<commit_after>/*===================================================================

  The Medical Imaging Interaction Toolkit (MITK)

  Copyright (c) German Cancer Research Center,
  Division of Medical and Biological Informatics.
  All rights reserved.

  This software is distributed WITHOUT ANY WARRANTY; without
  even the implied warranty of MERCHANTABILITY or FITNESS FOR
  A PARTICULAR PURPOSE.

  See LICENSE.txt or http://www.mitk.org for details.

  ===================================================================*/

#include "./mitkPhotoacousticMotionCorrectionFilter.h"
#include <mitkImageReadAccessor.h>

mitk::PhotoacousticMotionCorrectionFilter::
    PhotoacousticMotionCorrectionFilter() {
  // Set the defaults for the OpticalFlowFarneback algorithm
  // The values are taken directly out of Thomas's
  // US-CV-Based-Optical-Flow-Carotis.ipyn
  m_batch = 5;
  m_pyr_scale = 0.5;
  m_levels = 1;
  m_winsize = 40;
  m_iterations = 2;
  m_poly_n = 7;
  m_poly_sigma = 1.5;
  m_flags = 0;

  this->SetNumberOfIndexedInputs(2);
  this->SetNumberOfIndexedOutputs(2);
  mitk::Image::Pointer newOutput = mitk::Image::New();
  this->SetNthOutput(0, newOutput);
  this->SetNthOutput(1, newOutput);
}

mitk::PhotoacousticMotionCorrectionFilter::
    ~PhotoacousticMotionCorrectionFilter() {}

// void mitk::PhotoacousticMotionCorrectionFilter::SetInput(Image::Pointer
// paImage,
//                                                          Image::Pointer
//                                                          usImage)
// {
//   m_paImage = paImage;
//   m_usImage = usImage;
// }

void mitk::PhotoacousticMotionCorrectionFilter::GenerateData() {
  MITK_INFO << "Start motion compensation.";

  m_paImage = this->GetInput(0);
  m_usImage = this->GetInput(1);

  // Check that we actually got some images
  if (!m_paImage || !m_usImage) {
    // TODO: Throw some error here
  }
  // Check that the image dimensions are the same
  if (m_paImage->GetDimension() != m_usImage->GetDimension() &&
      m_usImage->GetDimension() == 3) {
    MITK_INFO << "Mismatching image dimensions detected in the motion "
                 "compensation filter.";
    // TODO: Throw some error here
  }
  for (unsigned int i = 0; i < m_paImage->GetDimension(); i++) {
    if (m_paImage->GetDimensions()[i] != m_usImage->GetDimensions()[i]) {
      MITK_INFO << "Mismatching image dimensions detected in the motion "
                   "compensation filter.";
      // TODO: Throw some error here
    }
  }

  // Initialize output images
  if (!m_paCompensated) {
    m_paCompensated = mitk::Image::New();
  }
  if (!m_usCompensated) {
    m_usCompensated = mitk::Image::New();
  }
  m_paCompensated->Initialize(m_paImage->GetPixelType(),
                              m_paImage->GetDimension(),
                              m_paImage->GetDimensions());
  m_usCompensated->Initialize(m_usImage->GetPixelType(),
                              m_usImage->GetDimension(),
                              m_usImage->GetDimensions());

  // TODO: remove debug messages

  // Initialize the slices
  mitk::Image::Pointer pa_slice = mitk::Image::New();
  mitk::Image::Pointer us_slice = mitk::Image::New();
  pa_slice->Initialize(m_paImage->GetPixelType(), 2,
                       m_paImage->GetDimensions());
  us_slice->Initialize(m_usImage->GetPixelType(), 2,
                       m_usImage->GetDimensions());

  MITK_INFO << "Start iteration.";
  // Iterate over all the slices
  for (unsigned int i = 0; i < m_paImage->GetDimensions()[2]; i++) {

    // Get a read accessor for each slice
    mitk::ImageReadAccessor pa_accessor(m_paImage, m_paImage->GetSliceData(i));
    mitk::ImageReadAccessor us_accessor(m_paImage, m_usImage->GetSliceData(i));

    // Write the correct image data into the slice
    pa_slice->SetImportVolume(pa_accessor.GetData());
    us_slice->SetImportVolume(us_accessor.GetData());

    // Convert them first to an itk::Image and then to a cv::Mat
    mitk::CastToItkImage(pa_slice, m_itkPaImage);
    mitk::CastToItkImage(us_slice, m_itkUsImage);
    MITK_INFO << "Generate Matrix.";

    m_PaMatC = itk::OpenCVImageBridge::ITKImageToCVMat<itk::Image<float, 2>>(
      m_itkPaImage);
    m_UsMatC = itk::OpenCVImageBridge::ITKImageToCVMat<itk::Image<float, 2>>(
        m_itkUsImage);

    m_PaMat = m_PaMatC.getUMat( cv::ACCESS_READ ).clone();
    m_UsMat = m_UsMatC.getUMat( cv::ACCESS_READ ).clone();

    MITK_INFO << "Matrix generated.";
    // At the beginning of a batch we set new references and the compensation
    // can be skipped.
    // TODO: handle m_batch == 0
    if (i % m_batch == 0) {
      MITK_INFO << "Start of batch.";
      m_UsRef = m_UsMat.clone();
      m_UsRes = m_UsMatC.clone();
      m_PaRes = m_PaMatC.clone();
      continue;
    } else {
      // Calculate the flow using the Farneback algorithm
      // TODO: flags hard coded to 0, rethink.
      MITK_INFO << "Apply algorithm.";
      cv::calcOpticalFlowFarneback(m_UsRef, m_UsMat, m_Flow, m_pyr_scale, m_levels,
                                   m_winsize, m_iterations, m_poly_n,
                                   m_poly_sigma, 0);

      // Apply flow to the matrices
      cv::remap(m_PaMatC, m_PaRes, m_Flow, cv::noArray(), cv::INTER_LINEAR);
      cv::remap(m_UsMatC, m_UsRes, m_Flow, cv::noArray(), cv::INTER_LINEAR);
    }

    // TODO: Actually do something, not just retransform
    // m_PaRes = m_PaMatC;
    // m_UsRes = m_UsMatC;

    m_OpenCVToImageFilter->SetOpenCVMat(m_PaRes);
    m_OpenCVToImageFilter->Update();
    pa_slice = m_OpenCVToImageFilter->GetOutput();
    mitk::ImageReadAccessor pa_slice_accessor(pa_slice);
    m_paCompensated->SetSlice(pa_slice_accessor.GetData(), i);
    m_OpenCVToImageFilter->SetOpenCVMat(m_UsRes);
    m_OpenCVToImageFilter->Update();
    us_slice = m_OpenCVToImageFilter->GetOutput();
    mitk::ImageReadAccessor us_slice_accessor(us_slice);
    m_paCompensated->SetSlice(us_slice_accessor.GetData(), i);
}

  this->SetNthOutput(1, m_usCompensated);
  this->SetNthOutput(0, m_paCompensated);
  MITK_INFO << "We succeeded in running through the whole thing!";
}
<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/
#ifndef itkRelabelComponentImageFilter_hxx
#define itkRelabelComponentImageFilter_hxx

#include "itkRelabelComponentImageFilter.h"
#include "itkImageRegionIterator.h"
#include "itkNumericTraits.h"
#include "itkProgressReporter.h"
#include <map>

namespace itk
{
template <typename TInputImage, typename TOutputImage>
void
RelabelComponentImageFilter<TInputImage, TOutputImage>::GenerateInputRequestedRegion()
{
  // call the superclass' implementation of this method
  Superclass::GenerateInputRequestedRegion();

  // We need all the input.
  InputImagePointer input = const_cast<InputImageType *>(this->GetInput());
  if (input)
  {
    input->SetRequestedRegion(input->GetLargestPossibleRegion());
  }
}

template <typename TInputImage, typename TOutputImage>
void
RelabelComponentImageFilter<TInputImage, TOutputImage>::GenerateData()
{
  SizeValueType i;

  // Use a map to keep track of the size of each object.  Object
  // number -> ObjectType (which has Object number and the two sizes)
  using MapType = std::map<LabelType, RelabelComponentObjectType>;
  MapType                    sizeMap;
  typename MapType::iterator mapIt;
  using MapValueType = typename MapType::value_type;

  // Get the input and the output
  typename TInputImage::ConstPointer input = this->GetInput();
  typename TOutputImage::Pointer     output = this->GetOutput();

  // Setup a progress reporter.  We have 2 stages to the algorithm so
  // use the total number of pixels accessed. We walk the entire input
  // in the first pass, then walk just the output requested region in
  // the second pass.
  ProgressReporter progress(
    this, 0, input->GetRequestedRegion().GetNumberOfPixels() + output->GetRequestedRegion().GetNumberOfPixels());

  // Calculate the size of pixel
  float physicalPixelSize = 1.0;
  for (i = 0; i < TInputImage::ImageDimension; ++i)
  {
    physicalPixelSize *= input->GetSpacing()[i];
  }

  RelabelComponentObjectType initialSize;
  initialSize.m_SizeInPixels = 1;
  initialSize.m_SizeInPhysicalUnits = physicalPixelSize;

  // First pass: walk the entire input image and determine what
  // labels are used and the number of pixels used in each label.
  //

  // walk the input
  ImageRegionConstIterator<InputImageType> it(input, input->GetRequestedRegion());
  it.GoToBegin();

  while (!it.IsAtEnd())
  {
    // Get the input pixel value
    const auto inputValue = static_cast<LabelType>(it.Get());

    // if the input pixel is not the background
    if (inputValue != NumericTraits<LabelType>::ZeroValue())
    {
      // Does this label already exist
      mapIt = sizeMap.find(inputValue);
      if (mapIt == sizeMap.end())
      {
        // label is not currently in the map
        initialSize.m_ObjectNumber = inputValue;
        sizeMap.insert(MapValueType(inputValue, initialSize));
      }
      else
      {
        // label is already in the map, update the values
        (*mapIt).second.m_SizeInPixels++;
        (*mapIt).second.m_SizeInPhysicalUnits += physicalPixelSize;
      }
    }

    // increment the iterators
    ++it;
    progress.CompletedPixel();
  }

  // Now we need to reorder the labels. Use the m_ObjectSortingOrder
  // to determine how to sort the objects. Define a map for converting
  // input labels to output labels.
  //
  using VectorType = std::vector<RelabelComponentObjectType>;
  VectorType                    sizeVector;
  typename VectorType::iterator vit;

  using RelabelMapType = std::map<LabelType, LabelType>;
  using RelabelMapValueType = typename RelabelMapType::value_type;
  RelabelMapType relabelMap;

  // copy the original object map to a vector so we can sort it
  for (mapIt = sizeMap.begin(); mapIt != sizeMap.end(); ++mapIt)
  {
    sizeVector.push_back((*mapIt).second);
  }

  // Sort the objects by size by default, unless m_SortByObjectSize
  // is set to false.
  if (m_SortByObjectSize)
  {
    std::sort(sizeVector.begin(), sizeVector.end(), RelabelComponentSizeInPixelsComparator());
  }

  // create a lookup table to map the input label to the output label.
  // cache the object sizes for later access by the user
  m_NumberOfObjects = static_cast<LabelType>(sizeVector.size());
  m_OriginalNumberOfObjects = static_cast<LabelType>(sizeVector.size());
  m_SizeOfObjectsInPixels.clear();
  m_SizeOfObjectsInPixels.resize(m_NumberOfObjects);
  m_SizeOfObjectsInPhysicalUnits.clear();
  m_SizeOfObjectsInPhysicalUnits.resize(m_NumberOfObjects);
  int NumberOfObjectsRemoved = 0;
  for (i = 0, vit = sizeVector.begin(); vit != sizeVector.end(); ++vit, ++i)
  {
    // if we find an object smaller than the minimum size, we
    // terminate the loop.
    if (m_MinimumObjectSize > 0 && (*vit).m_SizeInPixels < m_MinimumObjectSize)
    {
      // map small objects to the background
      NumberOfObjectsRemoved++;
      relabelMap.insert(RelabelMapValueType((*vit).m_ObjectNumber, 0));
    }
    else
    {
      // map for input labels to output labels (Note we use i+1 in the
      // map since index 0 is the background)
      relabelMap.insert(RelabelMapValueType((*vit).m_ObjectNumber, i + 1));

      // cache object sizes for later access by the user
      m_SizeOfObjectsInPixels[i] = (*vit).m_SizeInPixels;
      m_SizeOfObjectsInPhysicalUnits[i] = (*vit).m_SizeInPhysicalUnits;
    }
  }

  // update number of objects and resize cache vectors if we have removed small
  // objects
  m_NumberOfObjects -= NumberOfObjectsRemoved;
  if (NumberOfObjectsRemoved > 0)
  {
    m_SizeOfObjectsInPixels.resize(m_NumberOfObjects);
    m_SizeOfObjectsInPhysicalUnits.resize(m_NumberOfObjects);
  }

  // Second pass: walk just the output requested region and relabel
  // the necessary pixels.
  //

  // Allocate the output
  this->AllocateOutputs();

  // Remap the labels.  Note we only walk the region of the output
  // that was requested.  This may be a subset of the input image.
  OutputPixelType                      outputValue;
  ImageRegionIterator<OutputImageType> oit;
  oit = ImageRegionIterator<OutputImageType>(output, output->GetRequestedRegion());
  it = ImageRegionConstIterator<InputImageType>(input, output->GetRequestedRegion());

  it.GoToBegin();
  oit.GoToBegin();
  while (!oit.IsAtEnd())
  {
    const auto inputValue = static_cast<LabelType>(it.Get());

    if (inputValue != NumericTraits<LabelType>::ZeroValue())
    {
      // lookup the mapped label
      outputValue = static_cast<OutputPixelType>(relabelMap[inputValue]);
      oit.Set(outputValue);
    }
    else
    {
      oit.Set(inputValue);
    }

    // increment the iterators
    ++it;
    ++oit;
    progress.CompletedPixel();
  }
}

template <typename TInputImage, typename TOutputImage>
void
RelabelComponentImageFilter<TInputImage, TOutputImage>::PrintSelf(std::ostream & os, Indent indent) const
{
  Superclass::PrintSelf(os, indent);

  os << indent << "NumberOfObjects: " << m_NumberOfObjects << std::endl;
  os << indent << "OriginalNumberOfObjects: " << m_OriginalNumberOfObjects << std::endl;
  os << indent << "NumberOfObjectsToPrint: " << m_NumberOfObjectsToPrint << std::endl;
  os << indent << "MinimumObjectSizez: " << m_MinimumObjectSize << std::endl;
  os << indent << "SortByObjectSize: " << m_SortByObjectSize << std::endl;

  typename ObjectSizeInPixelsContainerType::const_iterator it;
  ObjectSizeInPhysicalUnitsContainerType::const_iterator   fit;
  LabelType                                                i;

  // limit the number of objects to print
  LabelType numPrint = m_NumberOfObjectsToPrint;
  if (numPrint > m_SizeOfObjectsInPixels.size())
  {
    numPrint = static_cast<LabelType>(m_SizeOfObjectsInPixels.size());
  }

  for (i = 0, it = m_SizeOfObjectsInPixels.begin(), fit = m_SizeOfObjectsInPhysicalUnits.begin(); i < numPrint;
       ++it, ++fit, ++i)
  {
    os << indent << "Object #" << i + 1 << ": " << *it << " pixels, " << *fit << " physical units" << std::endl;
  }
  if (numPrint < m_SizeOfObjectsInPixels.size())
  {
    os << indent << "..." << std::endl;
  }
}
} // end namespace itk

#endif
<commit_msg>BUG: Fix RelabelComponentImageFilter with sorting off, size on<commit_after>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/
#ifndef itkRelabelComponentImageFilter_hxx
#define itkRelabelComponentImageFilter_hxx

#include "itkRelabelComponentImageFilter.h"
#include "itkImageRegionIterator.h"
#include "itkNumericTraits.h"
#include "itkProgressReporter.h"
#include <map>

namespace itk
{
template <typename TInputImage, typename TOutputImage>
void
RelabelComponentImageFilter<TInputImage, TOutputImage>::GenerateInputRequestedRegion()
{
  // call the superclass' implementation of this method
  Superclass::GenerateInputRequestedRegion();

  // We need all the input.
  InputImagePointer input = const_cast<InputImageType *>(this->GetInput());
  if (input)
  {
    input->SetRequestedRegion(input->GetLargestPossibleRegion());
  }
}

template <typename TInputImage, typename TOutputImage>
void
RelabelComponentImageFilter<TInputImage, TOutputImage>::GenerateData()
{
  SizeValueType i;

  // Use a map to keep track of the size of each object.  Object
  // number -> ObjectType (which has Object number and the two sizes)
  using MapType = std::map<LabelType, RelabelComponentObjectType>;
  MapType                    sizeMap;
  typename MapType::iterator mapIt;
  using MapValueType = typename MapType::value_type;

  // Get the input and the output
  typename TInputImage::ConstPointer input = this->GetInput();
  typename TOutputImage::Pointer     output = this->GetOutput();

  // Setup a progress reporter.  We have 2 stages to the algorithm so
  // use the total number of pixels accessed. We walk the entire input
  // in the first pass, then walk just the output requested region in
  // the second pass.
  ProgressReporter progress(
    this, 0, input->GetRequestedRegion().GetNumberOfPixels() + output->GetRequestedRegion().GetNumberOfPixels());

  // Calculate the size of pixel
  float physicalPixelSize = 1.0;
  for (i = 0; i < TInputImage::ImageDimension; ++i)
  {
    physicalPixelSize *= input->GetSpacing()[i];
  }

  RelabelComponentObjectType initialSize;
  initialSize.m_SizeInPixels = 1;
  initialSize.m_SizeInPhysicalUnits = physicalPixelSize;

  // First pass: walk the entire input image and determine what
  // labels are used and the number of pixels used in each label.
  //

  // walk the input
  ImageRegionConstIterator<InputImageType> it(input, input->GetRequestedRegion());
  it.GoToBegin();

  while (!it.IsAtEnd())
  {
    // Get the input pixel value
    const auto inputValue = static_cast<LabelType>(it.Get());

    // if the input pixel is not the background
    if (inputValue != NumericTraits<LabelType>::ZeroValue())
    {
      // Does this label already exist
      mapIt = sizeMap.find(inputValue);
      if (mapIt == sizeMap.end())
      {
        // label is not currently in the map
        initialSize.m_ObjectNumber = inputValue;
        sizeMap.insert(MapValueType(inputValue, initialSize));
      }
      else
      {
        // label is already in the map, update the values
        (*mapIt).second.m_SizeInPixels++;
        (*mapIt).second.m_SizeInPhysicalUnits += physicalPixelSize;
      }
    }

    // increment the iterators
    ++it;
    progress.CompletedPixel();
  }

  // Now we need to reorder the labels. Use the m_ObjectSortingOrder
  // to determine how to sort the objects. Define a map for converting
  // input labels to output labels.
  //
  using VectorType = std::vector<RelabelComponentObjectType>;
  VectorType                    sizeVector;
  typename VectorType::iterator vit;

  using RelabelMapType = std::map<LabelType, LabelType>;
  using RelabelMapValueType = typename RelabelMapType::value_type;
  RelabelMapType relabelMap;

  // copy the original object map to a vector so we can sort it
  for (mapIt = sizeMap.begin(); mapIt != sizeMap.end(); ++mapIt)
  {
    sizeVector.push_back((*mapIt).second);
  }

  // Sort the objects by size by default, unless m_SortByObjectSize
  // is set to false.
  if (m_SortByObjectSize)
  {
    std::sort(sizeVector.begin(), sizeVector.end(), RelabelComponentSizeInPixelsComparator());
  }

  // create a lookup table to map the input label to the output label.
  // cache the object sizes for later access by the user
  m_NumberOfObjects = static_cast<LabelType>(sizeVector.size());
  m_OriginalNumberOfObjects = static_cast<LabelType>(sizeVector.size());
  m_SizeOfObjectsInPixels.clear();
  m_SizeOfObjectsInPixels.resize(m_NumberOfObjects);
  m_SizeOfObjectsInPhysicalUnits.clear();
  m_SizeOfObjectsInPhysicalUnits.resize(m_NumberOfObjects);
  int NumberOfObjectsRemoved = 0;
  for (i = 0, vit = sizeVector.begin(); vit != sizeVector.end(); ++vit)
  {
    // if we find an object smaller than the minimum size, we
    // terminate the loop.
    if (m_MinimumObjectSize > 0 && (*vit).m_SizeInPixels < m_MinimumObjectSize)
    {
      // map small objects to the background
      ++NumberOfObjectsRemoved;
      relabelMap.insert(RelabelMapValueType((*vit).m_ObjectNumber, 0));
    }
    else
    {
      // map for input labels to output labels (Note we use i+1 in the
      // map since index 0 is the background)
      relabelMap.insert(RelabelMapValueType((*vit).m_ObjectNumber, i + 1));

      // cache object sizes for later access by the user
      m_SizeOfObjectsInPixels[i] = (*vit).m_SizeInPixels;
      m_SizeOfObjectsInPhysicalUnits[i] = (*vit).m_SizeInPhysicalUnits;
      ++i;
    }
  }

  // update number of objects and resize cache vectors if we have removed small
  // objects
  m_NumberOfObjects -= NumberOfObjectsRemoved;
  if (NumberOfObjectsRemoved > 0)
  {
    m_SizeOfObjectsInPixels.resize(m_NumberOfObjects);
    m_SizeOfObjectsInPhysicalUnits.resize(m_NumberOfObjects);
  }

  // Second pass: walk just the output requested region and relabel
  // the necessary pixels.
  //

  // Allocate the output
  this->AllocateOutputs();

  // Remap the labels.  Note we only walk the region of the output
  // that was requested.  This may be a subset of the input image.
  OutputPixelType                      outputValue;
  ImageRegionIterator<OutputImageType> oit;
  oit = ImageRegionIterator<OutputImageType>(output, output->GetRequestedRegion());
  it = ImageRegionConstIterator<InputImageType>(input, output->GetRequestedRegion());

  it.GoToBegin();
  oit.GoToBegin();
  while (!oit.IsAtEnd())
  {
    const auto inputValue = static_cast<LabelType>(it.Get());

    if (inputValue != NumericTraits<LabelType>::ZeroValue())
    {
      // lookup the mapped label
      outputValue = static_cast<OutputPixelType>(relabelMap[inputValue]);
      oit.Set(outputValue);
    }
    else
    {
      oit.Set(inputValue);
    }

    // increment the iterators
    ++it;
    ++oit;
    progress.CompletedPixel();
  }
}

template <typename TInputImage, typename TOutputImage>
void
RelabelComponentImageFilter<TInputImage, TOutputImage>::PrintSelf(std::ostream & os, Indent indent) const
{
  Superclass::PrintSelf(os, indent);

  os << indent << "NumberOfObjects: " << m_NumberOfObjects << std::endl;
  os << indent << "OriginalNumberOfObjects: " << m_OriginalNumberOfObjects << std::endl;
  os << indent << "NumberOfObjectsToPrint: " << m_NumberOfObjectsToPrint << std::endl;
  os << indent << "MinimumObjectSizez: " << m_MinimumObjectSize << std::endl;
  os << indent << "SortByObjectSize: " << m_SortByObjectSize << std::endl;

  typename ObjectSizeInPixelsContainerType::const_iterator it;
  ObjectSizeInPhysicalUnitsContainerType::const_iterator   fit;
  LabelType                                                i;

  // limit the number of objects to print
  LabelType numPrint = m_NumberOfObjectsToPrint;
  if (numPrint > m_SizeOfObjectsInPixels.size())
  {
    numPrint = static_cast<LabelType>(m_SizeOfObjectsInPixels.size());
  }

  for (i = 0, it = m_SizeOfObjectsInPixels.begin(), fit = m_SizeOfObjectsInPhysicalUnits.begin(); i < numPrint;
       ++it, ++fit, ++i)
  {
    os << indent << "Object #" << i + 1 << ": " << *it << " pixels, " << *fit << " physical units" << std::endl;
  }
  if (numPrint < m_SizeOfObjectsInPixels.size())
  {
    os << indent << "..." << std::endl;
  }
}
} // end namespace itk

#endif
<|endoftext|>