<commit_before>#include "raiden.h"
#include "reflection.h"
//#include "transform.h"
#include "gtest.h"
#include "sampling.h"

TEST(FrConductor,Au){
   Float air_ior[3]={1,1,1};
//    float au_ior[3]={0.15557,0.42415,1.3831};
//    float au_k[3] = {3.5024,2.4721,1.9155};
    Float au_ior[3]={0.18299,0.42108,1.3734};
   Float au_k[3] = {3.4242,2.3459,1.7704};

   Spectrum air=Spectrum::FromRGB(air_ior);
   Spectrum ior=Spectrum::FromRGB(au_ior);
   Spectrum k=Spectrum::FromRGB(au_k);

   Spectrum r=FrConductor(1,air,ior,k);
   Float au[3];
   r.ToRGB(au);
//    EXPECT_FLOAT_EQ(au[0],1.000);
//    EXPECT_FLOAT_EQ(au[1],0.766);
//    EXPECT_FLOAT_EQ(au[2],0.336);

   EXPECT_GE(au[0],0.9);
   EXPECT_GE(au[1],0.7);
   EXPECT_GE(au[2],0.3);
}

TEST(HairBSDF,WhiteFurnace){
   RNG rng;
   auto wo=UniformSampleSphere({rng.UniformFloat(),rng.UniformFloat()});
   for(Float betam=0.1;betam<=1;betam+=0.2){
      for(Float betan=0.1;betan<=1;betan+=0.2){
         int count=300000;
         Spectrum sigmaA(0);
         Spectrum sum(0);
         for(int i=0;i<count;++i){
            Float h=-1+2*rng.UniformFloat();
            HairBSDF bsdf(h,1.55f,sigmaA,betam,betan,0.0f);
            auto wi=UniformSampleSphere({rng.UniformFloat(),rng.UniformFloat()});
            sum+=bsdf.f(wo,wi)*AbsCosTheta(wi);
         }
         sum=sum/(count*UniformSpherePdf());
         EXPECT_GT(sum.y(),0.95);
         EXPECT_LT(sum.y(),1.05);
      }
   }
}<commit_msg>上传单元测试<commit_after>#include "raiden.h"
#include "reflection.h"
//#include "transform.h"
#include "gtest.h"
#include "sampling.h"

TEST(FrConductor,Au){
   Float air_ior[3]={1,1,1};
//    float au_ior[3]={0.15557,0.42415,1.3831};
//    float au_k[3] = {3.5024,2.4721,1.9155};
    Float au_ior[3]={0.18299,0.42108,1.3734};
   Float au_k[3] = {3.4242,2.3459,1.7704};

   Spectrum air=Spectrum::FromRGB(air_ior);
   Spectrum ior=Spectrum::FromRGB(au_ior);
   Spectrum k=Spectrum::FromRGB(au_k);

   Spectrum r=FrConductor(1,air,ior,k);
   Float au[3];
   r.ToRGB(au);
//    EXPECT_FLOAT_EQ(au[0],1.000);
//    EXPECT_FLOAT_EQ(au[1],0.766);
//    EXPECT_FLOAT_EQ(au[2],0.336);

   EXPECT_GE(au[0],0.9);
   EXPECT_GE(au[1],0.7);
   EXPECT_GE(au[2],0.3);
}

TEST(HairBSDF,WhiteFurnace){
   RNG rng;
   auto wo=UniformSampleSphere({rng.UniformFloat(),rng.UniformFloat()});
   for(Float betam=0.1;betam<=1;betam+=0.2){
      for(Float betan=0.1;betan<=1;betan+=0.2){
         int count=300000;
         Spectrum sigmaA(0);
         Spectrum sum(0);
         for(int i=0;i<count;++i){
            Float h=-1+2*rng.UniformFloat();
            HairBSDF bsdf(h,1.55f,sigmaA,betam,betan,0.0f);
            auto wi=UniformSampleSphere({rng.UniformFloat(),rng.UniformFloat()});
            sum+=bsdf.f(wo,wi)*AbsCosTheta(wi);
         }
         sum=sum/(count*UniformSpherePdf());
         EXPECT_GT(sum.y(),0.95);
         EXPECT_LT(sum.y(),1.05);
      }
   }
}

TEST(HairBSDF,SampleWeights){
   RNG rng;
   auto wo=UniformSampleSphere({rng.UniformFloat(),rng.UniformFloat()});
    for(Float betam=0.1;betam<=1;betam+=0.2){
      for(Float betan=0.1;betan<=1;betan+=0.2){
         int count=1000;
         Spectrum sigmaA(0);
         for(int i=0;i<count;++i){
            Float h=-1+2*rng.UniformFloat();
            HairBSDF bsdf(h,1.55f,sigmaA,betam,betan,0.0f);
            Vector3f wi;
            Float pdf;
            auto f=bsdf.Sample_f(wo,&wi,{rng.UniformFloat(),rng.UniformFloat()},&pdf);
            if(pdf>0){
               EXPECT_EQ(f.y()*AbsCosTheta(wi),pdf);
            }
         }
      }
   }
}<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/views/bubble/bubble_frame_view.h"

#include <algorithm>

#include "grit/ui_resources.h"
#include "ui/base/hit_test.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/path.h"
#include "ui/gfx/screen.h"
#include "ui/views/bubble/bubble_border.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
#include "ui/views/window/client_view.h"

namespace {

// Padding, in pixels, for the title view, when it exists.
const int kTitleTopInset = 12;
const int kTitleLeftInset = 19;
const int kTitleBottomInset = 12;

// Get the |vertical| or horizontal screen overflow of the |window_bounds|.
int GetOffScreenLength(const gfx::Rect& monitor_bounds,
                       const gfx::Rect& window_bounds,
                       bool vertical) {
  if (monitor_bounds.IsEmpty() || monitor_bounds.Contains(window_bounds))
    return 0;

  //  window_bounds
  //  +-------------------------------+
  //  |             top               |
  //  |      +----------------+       |
  //  | left | monitor_bounds | right |
  //  |      +----------------+       |
  //  |            bottom             |
  //  +-------------------------------+
  if (vertical)
    return std::max(0, monitor_bounds.y() - window_bounds.y()) +
           std::max(0, window_bounds.bottom() - monitor_bounds.bottom());
  return std::max(0, monitor_bounds.x() - window_bounds.x()) +
         std::max(0, window_bounds.right() - monitor_bounds.right());
}

}  // namespace

namespace views {

BubbleFrameView::BubbleFrameView(const gfx::Insets& content_margins)
    : bubble_border_(NULL),
      content_margins_(content_margins),
      title_(NULL),
      close_(NULL),
      titlebar_extra_view_(NULL) {
  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
  title_ = new Label(string16(), rb.GetFont(ui::ResourceBundle::MediumFont));
  title_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
  AddChildView(title_);

  close_ = new LabelButton(this, string16());
  close_->SetImage(CustomButton::STATE_NORMAL,
                   *rb.GetImageNamed(IDR_CLOSE_DIALOG).ToImageSkia());
  close_->SetImage(CustomButton::STATE_HOVERED,
                   *rb.GetImageNamed(IDR_CLOSE_DIALOG_H).ToImageSkia());
  close_->SetImage(CustomButton::STATE_PRESSED,
                   *rb.GetImageNamed(IDR_CLOSE_DIALOG_P).ToImageSkia());
  close_->SetSize(close_->GetPreferredSize());
  close_->set_border(NULL);
  close_->SetVisible(false);
  AddChildView(close_);
}

BubbleFrameView::~BubbleFrameView() {}

gfx::Rect BubbleFrameView::GetBoundsForClientView() const {
  gfx::Rect client_bounds = GetLocalBounds();
  client_bounds.Inset(GetInsets());
  client_bounds.Inset(bubble_border_->GetInsets());
  return client_bounds;
}

gfx::Rect BubbleFrameView::GetWindowBoundsForClientBounds(
    const gfx::Rect& client_bounds) const {
  return const_cast<BubbleFrameView*>(this)->GetUpdatedWindowBounds(
      gfx::Rect(), client_bounds.size(), false);
}

int BubbleFrameView::NonClientHitTest(const gfx::Point& point) {
  if (!bounds().Contains(point))
    return HTNOWHERE;
  if (close_->visible() && close_->GetMirroredBounds().Contains(point))
    return HTCLOSE;
  if (!GetWidget()->widget_delegate()->CanResize())
    return GetWidget()->client_view()->NonClientHitTest(point);

  const int size = bubble_border_->GetBorderThickness() + 4;
  const int hit = GetHTComponentForFrame(point, size, size, size, size, true);
  if (hit == HTNOWHERE && point.y() < title_->bounds().bottom())
    return HTCAPTION;
  return hit;
}

void BubbleFrameView::GetWindowMask(const gfx::Size& size,
                                    gfx::Path* window_mask) {
  if (bubble_border_->shadow() != BubbleBorder::NO_SHADOW_OPAQUE_BORDER)
    return;

  // Use a window mask roughly matching the border in the image assets.
  static const int kBorderStrokeSize = 1;
  static const SkScalar kCornerRadius = SkIntToScalar(6);
  gfx::Insets border_insets = bubble_border_->GetInsets();
  const SkRect rect = { SkIntToScalar(border_insets.left() - kBorderStrokeSize),
                        SkIntToScalar(border_insets.top() - kBorderStrokeSize),
                        SkIntToScalar(size.width() - border_insets.right() +
                                      kBorderStrokeSize),
                        SkIntToScalar(size.height() - border_insets.bottom() +
                                      kBorderStrokeSize) };
  window_mask->addRoundRect(rect, kCornerRadius, kCornerRadius);
}

void BubbleFrameView::ResetWindowControls() {}

void BubbleFrameView::UpdateWindowIcon() {}

void BubbleFrameView::UpdateWindowTitle() {}

gfx::Insets BubbleFrameView::GetInsets() const {
  gfx::Insets insets = content_margins_;
  const int title_height = title_->text().empty() ? 0 :
      title_->GetPreferredSize().height() + kTitleTopInset + kTitleBottomInset;
  const int close_height = close_->visible() ? close_->height() : 0;
  insets += gfx::Insets(std::max(title_height, close_height), 0, 0, 0);
  return insets;
}

gfx::Size BubbleFrameView::GetPreferredSize() {
  const gfx::Size client(GetWidget()->client_view()->GetPreferredSize());
  gfx::Size size(GetUpdatedWindowBounds(gfx::Rect(), client, false).size());
  // Accommodate the width of the title bar elements.
  int title_bar_width = GetInsets().width() + border()->GetInsets().width() +
      kTitleLeftInset + title_->GetPreferredSize().width() +
      close_->width() + 1;
  if (titlebar_extra_view_ != NULL)
    title_bar_width += titlebar_extra_view_->GetPreferredSize().width();
  size.SetToMax(gfx::Size(title_bar_width, 0));
  return size;
}

void BubbleFrameView::Layout() {
  gfx::Rect bounds(GetLocalBounds());
  bounds.Inset(border()->GetInsets());
  // Small additional insets yield the desired 10px visual close button insets.
  bounds.Inset(0, 0, close_->width() + 1, 0);
  close_->SetPosition(gfx::Point(bounds.right(), bounds.y() + 2));

  gfx::Rect title_bounds(bounds);
  title_bounds.Inset(kTitleLeftInset, kTitleTopInset, 0, 0);
  gfx::Size title_size(title_->GetPreferredSize());
  const int title_width = std::max(0, close_->bounds().x() - title_bounds.x());
  title_size.SetToMin(gfx::Size(title_width, title_size.height()));
  title_bounds.set_size(title_size);
  title_->SetBoundsRect(title_bounds);

  if (titlebar_extra_view_) {
    const int extra_width = close_->bounds().x() - title_->bounds().right();
    gfx::Size size = titlebar_extra_view_->GetPreferredSize();
    size.SetToMin(gfx::Size(std::max(0, extra_width), size.height()));
    gfx::Rect titlebar_extra_view_bounds(
        bounds.right() - size.width(),
        title_bounds.y(),
        size.width(),
        title_bounds.height());
    titlebar_extra_view_bounds.Subtract(title_bounds);
    titlebar_extra_view_->SetBoundsRect(titlebar_extra_view_bounds);
  }
}

const char* BubbleFrameView::GetClassName() const {
  return "BubbleFrameView";
}

void BubbleFrameView::ChildPreferredSizeChanged(View* child) {
  if (child == titlebar_extra_view_ || child == title_)
    Layout();
}

void BubbleFrameView::ButtonPressed(Button* sender, const ui::Event& event) {
  if (sender == close_)
    GetWidget()->Close();
}

void BubbleFrameView::SetBubbleBorder(BubbleBorder* border) {
  bubble_border_ = border;
  set_border(bubble_border_);

  // Update the background, which relies on the border.
  set_background(new views::BubbleBackground(border));
}

void BubbleFrameView::SetTitle(const string16& title) {
  title_->SetText(title);
}

void BubbleFrameView::SetShowCloseButton(bool show) {
  close_->SetVisible(show);
}

void BubbleFrameView::SetTitlebarExtraView(View* view) {
  DCHECK(view);
  DCHECK(!titlebar_extra_view_);
  AddChildView(view);
  titlebar_extra_view_ = view;
}

gfx::Rect BubbleFrameView::GetUpdatedWindowBounds(const gfx::Rect& anchor_rect,
                                                  gfx::Size client_size,
                                                  bool adjust_if_offscreen) {
  gfx::Insets insets(GetInsets());
  client_size.Enlarge(insets.width(), insets.height());

  const BubbleBorder::Arrow arrow = bubble_border_->arrow();
  if (adjust_if_offscreen && BubbleBorder::has_arrow(arrow)) {
    if (!bubble_border_->is_arrow_at_center(arrow)) {
      // Try to mirror the anchoring if the bubble does not fit on the screen.
      MirrorArrowIfOffScreen(true, anchor_rect, client_size);
      MirrorArrowIfOffScreen(false, anchor_rect, client_size);
    } else {
      // Mirror as needed vertically if the arrow is on a horizontal edge and
      // vice-versa.
      MirrorArrowIfOffScreen(BubbleBorder::is_arrow_on_horizontal(arrow),
                             anchor_rect,
                             client_size);
      OffsetArrowIfOffScreen(anchor_rect, client_size);
    }
  }

  // Calculate the bounds with the arrow in its updated location and offset.
  return bubble_border_->GetBounds(anchor_rect, client_size);
}

gfx::Rect BubbleFrameView::GetMonitorBounds(const gfx::Rect& rect) {
  // TODO(scottmg): Native is wrong. http://crbug.com/133312
  return gfx::Screen::GetNativeScreen()->GetDisplayNearestPoint(
      rect.CenterPoint()).work_area();
}

void BubbleFrameView::MirrorArrowIfOffScreen(
    bool vertical,
    const gfx::Rect& anchor_rect,
    const gfx::Size& client_size) {
  // Check if the bounds don't fit on screen.
  gfx::Rect monitor_rect(GetMonitorBounds(anchor_rect));
  gfx::Rect window_bounds(bubble_border_->GetBounds(anchor_rect, client_size));
  if (GetOffScreenLength(monitor_rect, window_bounds, vertical) > 0) {
    BubbleBorder::Arrow arrow = bubble_border()->arrow();
    // Mirror the arrow and get the new bounds.
    bubble_border_->set_arrow(
        vertical ? BubbleBorder::vertical_mirror(arrow) :
                   BubbleBorder::horizontal_mirror(arrow));
    gfx::Rect mirror_bounds =
        bubble_border_->GetBounds(anchor_rect, client_size);
    // Restore the original arrow if mirroring doesn't show more of the bubble.
    if (GetOffScreenLength(monitor_rect, mirror_bounds, vertical) >=
        GetOffScreenLength(monitor_rect, window_bounds, vertical))
      bubble_border_->set_arrow(arrow);
    else
      SchedulePaint();
  }
}

void BubbleFrameView::OffsetArrowIfOffScreen(const gfx::Rect& anchor_rect,
                                             const gfx::Size& client_size) {
  BubbleBorder::Arrow arrow = bubble_border()->arrow();
  DCHECK(BubbleBorder::is_arrow_at_center(arrow));

  // Get the desired bubble bounds without adjustment.
  bubble_border_->set_arrow_offset(0);
  gfx::Rect window_bounds(bubble_border_->GetBounds(anchor_rect, client_size));

  gfx::Rect monitor_rect(GetMonitorBounds(anchor_rect));
  if (monitor_rect.IsEmpty() || monitor_rect.Contains(window_bounds))
    return;

  // Calculate off-screen adjustment.
  const bool is_horizontal = BubbleBorder::is_arrow_on_horizontal(arrow);
  int offscreen_adjust = 0;
  if (is_horizontal) {
    if (window_bounds.x() < monitor_rect.x())
      offscreen_adjust = monitor_rect.x() - window_bounds.x();
    else if (window_bounds.right() > monitor_rect.right())
      offscreen_adjust = monitor_rect.right() - window_bounds.right();
  } else {
    if (window_bounds.y() < monitor_rect.y())
      offscreen_adjust = monitor_rect.y() - window_bounds.y();
    else if (window_bounds.bottom() > monitor_rect.bottom())
      offscreen_adjust = monitor_rect.bottom() - window_bounds.bottom();
  }

  // For center arrows, arrows are moved in the opposite direction of
  // |offscreen_adjust|, e.g. positive |offscreen_adjust| means bubble
  // window needs to be moved to the right and that means we need to move arrow
  // to the left, and that means negative offset.
  bubble_border_->set_arrow_offset(
      bubble_border_->GetArrowOffset(window_bounds.size()) - offscreen_adjust);
  if (offscreen_adjust)
    SchedulePaint();
}

}  // namespace views
<commit_msg>Fix BubbleFrameView titlebar sizing.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/views/bubble/bubble_frame_view.h"

#include <algorithm>

#include "grit/ui_resources.h"
#include "ui/base/hit_test.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/path.h"
#include "ui/gfx/screen.h"
#include "ui/views/bubble/bubble_border.h"
#include "ui/views/controls/button/label_button.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
#include "ui/views/window/client_view.h"

namespace {

// Padding, in pixels, for the title view, when it exists.
const int kTitleTopInset = 12;
const int kTitleLeftInset = 19;
const int kTitleBottomInset = 12;

// Get the |vertical| or horizontal screen overflow of the |window_bounds|.
int GetOffScreenLength(const gfx::Rect& monitor_bounds,
                       const gfx::Rect& window_bounds,
                       bool vertical) {
  if (monitor_bounds.IsEmpty() || monitor_bounds.Contains(window_bounds))
    return 0;

  //  window_bounds
  //  +-------------------------------+
  //  |             top               |
  //  |      +----------------+       |
  //  | left | monitor_bounds | right |
  //  |      +----------------+       |
  //  |            bottom             |
  //  +-------------------------------+
  if (vertical)
    return std::max(0, monitor_bounds.y() - window_bounds.y()) +
           std::max(0, window_bounds.bottom() - monitor_bounds.bottom());
  return std::max(0, monitor_bounds.x() - window_bounds.x()) +
         std::max(0, window_bounds.right() - monitor_bounds.right());
}

}  // namespace

namespace views {

BubbleFrameView::BubbleFrameView(const gfx::Insets& content_margins)
    : bubble_border_(NULL),
      content_margins_(content_margins),
      title_(NULL),
      close_(NULL),
      titlebar_extra_view_(NULL) {
  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
  title_ = new Label(string16(), rb.GetFont(ui::ResourceBundle::MediumFont));
  title_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
  AddChildView(title_);

  close_ = new LabelButton(this, string16());
  close_->SetImage(CustomButton::STATE_NORMAL,
                   *rb.GetImageNamed(IDR_CLOSE_DIALOG).ToImageSkia());
  close_->SetImage(CustomButton::STATE_HOVERED,
                   *rb.GetImageNamed(IDR_CLOSE_DIALOG_H).ToImageSkia());
  close_->SetImage(CustomButton::STATE_PRESSED,
                   *rb.GetImageNamed(IDR_CLOSE_DIALOG_P).ToImageSkia());
  close_->SetSize(close_->GetPreferredSize());
  close_->set_border(NULL);
  close_->SetVisible(false);
  AddChildView(close_);
}

BubbleFrameView::~BubbleFrameView() {}

gfx::Rect BubbleFrameView::GetBoundsForClientView() const {
  gfx::Rect client_bounds = GetLocalBounds();
  client_bounds.Inset(GetInsets());
  client_bounds.Inset(bubble_border_->GetInsets());
  return client_bounds;
}

gfx::Rect BubbleFrameView::GetWindowBoundsForClientBounds(
    const gfx::Rect& client_bounds) const {
  return const_cast<BubbleFrameView*>(this)->GetUpdatedWindowBounds(
      gfx::Rect(), client_bounds.size(), false);
}

int BubbleFrameView::NonClientHitTest(const gfx::Point& point) {
  if (!bounds().Contains(point))
    return HTNOWHERE;
  if (close_->visible() && close_->GetMirroredBounds().Contains(point))
    return HTCLOSE;
  if (!GetWidget()->widget_delegate()->CanResize())
    return GetWidget()->client_view()->NonClientHitTest(point);

  const int size = bubble_border_->GetBorderThickness() + 4;
  const int hit = GetHTComponentForFrame(point, size, size, size, size, true);
  if (hit == HTNOWHERE && point.y() < title_->bounds().bottom())
    return HTCAPTION;
  return hit;
}

void BubbleFrameView::GetWindowMask(const gfx::Size& size,
                                    gfx::Path* window_mask) {
  if (bubble_border_->shadow() != BubbleBorder::NO_SHADOW_OPAQUE_BORDER)
    return;

  // Use a window mask roughly matching the border in the image assets.
  static const int kBorderStrokeSize = 1;
  static const SkScalar kCornerRadius = SkIntToScalar(6);
  gfx::Insets border_insets = bubble_border_->GetInsets();
  const SkRect rect = { SkIntToScalar(border_insets.left() - kBorderStrokeSize),
                        SkIntToScalar(border_insets.top() - kBorderStrokeSize),
                        SkIntToScalar(size.width() - border_insets.right() +
                                      kBorderStrokeSize),
                        SkIntToScalar(size.height() - border_insets.bottom() +
                                      kBorderStrokeSize) };
  window_mask->addRoundRect(rect, kCornerRadius, kCornerRadius);
}

void BubbleFrameView::ResetWindowControls() {}

void BubbleFrameView::UpdateWindowIcon() {}

void BubbleFrameView::UpdateWindowTitle() {}

gfx::Insets BubbleFrameView::GetInsets() const {
  gfx::Insets insets = content_margins_;
  const int title_height = title_->text().empty() ? 0 :
      title_->GetPreferredSize().height() + kTitleTopInset + kTitleBottomInset;
  const int close_height = close_->visible() ? close_->height() : 0;
  insets += gfx::Insets(std::max(title_height, close_height), 0, 0, 0);
  return insets;
}

gfx::Size BubbleFrameView::GetPreferredSize() {
  const gfx::Size client(GetWidget()->client_view()->GetPreferredSize());
  gfx::Size size(GetUpdatedWindowBounds(gfx::Rect(), client, false).size());
  // Accommodate the width of the title bar elements.
  int title_bar_width = GetInsets().width() + border()->GetInsets().width();
  if (!title_->text().empty())
    title_bar_width += kTitleLeftInset + title_->GetPreferredSize().width();
  if (close_->visible())
    title_bar_width += close_->width() + 1;
  if (titlebar_extra_view_ != NULL)
    title_bar_width += titlebar_extra_view_->GetPreferredSize().width();
  size.SetToMax(gfx::Size(title_bar_width, 0));
  return size;
}

void BubbleFrameView::Layout() {
  gfx::Rect bounds(GetLocalBounds());
  bounds.Inset(border()->GetInsets());
  // Small additional insets yield the desired 10px visual close button insets.
  bounds.Inset(0, 0, close_->width() + 1, 0);
  close_->SetPosition(gfx::Point(bounds.right(), bounds.y() + 2));

  gfx::Rect title_bounds(bounds);
  title_bounds.Inset(kTitleLeftInset, kTitleTopInset, 0, 0);
  gfx::Size title_size(title_->GetPreferredSize());
  const int title_width = std::max(0, close_->bounds().x() - title_bounds.x());
  title_size.SetToMin(gfx::Size(title_width, title_size.height()));
  title_bounds.set_size(title_size);
  title_->SetBoundsRect(title_bounds);

  if (titlebar_extra_view_) {
    const int extra_width = close_->bounds().x() - title_->bounds().right();
    gfx::Size size = titlebar_extra_view_->GetPreferredSize();
    size.SetToMin(gfx::Size(std::max(0, extra_width), size.height()));
    gfx::Rect titlebar_extra_view_bounds(
        bounds.right() - size.width(),
        title_bounds.y(),
        size.width(),
        title_bounds.height());
    titlebar_extra_view_bounds.Subtract(title_bounds);
    titlebar_extra_view_->SetBoundsRect(titlebar_extra_view_bounds);
  }
}

const char* BubbleFrameView::GetClassName() const {
  return "BubbleFrameView";
}

void BubbleFrameView::ChildPreferredSizeChanged(View* child) {
  if (child == titlebar_extra_view_ || child == title_)
    Layout();
}

void BubbleFrameView::ButtonPressed(Button* sender, const ui::Event& event) {
  if (sender == close_)
    GetWidget()->Close();
}

void BubbleFrameView::SetBubbleBorder(BubbleBorder* border) {
  bubble_border_ = border;
  set_border(bubble_border_);

  // Update the background, which relies on the border.
  set_background(new views::BubbleBackground(border));
}

void BubbleFrameView::SetTitle(const string16& title) {
  title_->SetText(title);
}

void BubbleFrameView::SetShowCloseButton(bool show) {
  close_->SetVisible(show);
}

void BubbleFrameView::SetTitlebarExtraView(View* view) {
  DCHECK(view);
  DCHECK(!titlebar_extra_view_);
  AddChildView(view);
  titlebar_extra_view_ = view;
}

gfx::Rect BubbleFrameView::GetUpdatedWindowBounds(const gfx::Rect& anchor_rect,
                                                  gfx::Size client_size,
                                                  bool adjust_if_offscreen) {
  gfx::Insets insets(GetInsets());
  client_size.Enlarge(insets.width(), insets.height());

  const BubbleBorder::Arrow arrow = bubble_border_->arrow();
  if (adjust_if_offscreen && BubbleBorder::has_arrow(arrow)) {
    if (!bubble_border_->is_arrow_at_center(arrow)) {
      // Try to mirror the anchoring if the bubble does not fit on the screen.
      MirrorArrowIfOffScreen(true, anchor_rect, client_size);
      MirrorArrowIfOffScreen(false, anchor_rect, client_size);
    } else {
      // Mirror as needed vertically if the arrow is on a horizontal edge and
      // vice-versa.
      MirrorArrowIfOffScreen(BubbleBorder::is_arrow_on_horizontal(arrow),
                             anchor_rect,
                             client_size);
      OffsetArrowIfOffScreen(anchor_rect, client_size);
    }
  }

  // Calculate the bounds with the arrow in its updated location and offset.
  return bubble_border_->GetBounds(anchor_rect, client_size);
}

gfx::Rect BubbleFrameView::GetMonitorBounds(const gfx::Rect& rect) {
  // TODO(scottmg): Native is wrong. http://crbug.com/133312
  return gfx::Screen::GetNativeScreen()->GetDisplayNearestPoint(
      rect.CenterPoint()).work_area();
}

void BubbleFrameView::MirrorArrowIfOffScreen(
    bool vertical,
    const gfx::Rect& anchor_rect,
    const gfx::Size& client_size) {
  // Check if the bounds don't fit on screen.
  gfx::Rect monitor_rect(GetMonitorBounds(anchor_rect));
  gfx::Rect window_bounds(bubble_border_->GetBounds(anchor_rect, client_size));
  if (GetOffScreenLength(monitor_rect, window_bounds, vertical) > 0) {
    BubbleBorder::Arrow arrow = bubble_border()->arrow();
    // Mirror the arrow and get the new bounds.
    bubble_border_->set_arrow(
        vertical ? BubbleBorder::vertical_mirror(arrow) :
                   BubbleBorder::horizontal_mirror(arrow));
    gfx::Rect mirror_bounds =
        bubble_border_->GetBounds(anchor_rect, client_size);
    // Restore the original arrow if mirroring doesn't show more of the bubble.
    if (GetOffScreenLength(monitor_rect, mirror_bounds, vertical) >=
        GetOffScreenLength(monitor_rect, window_bounds, vertical))
      bubble_border_->set_arrow(arrow);
    else
      SchedulePaint();
  }
}

void BubbleFrameView::OffsetArrowIfOffScreen(const gfx::Rect& anchor_rect,
                                             const gfx::Size& client_size) {
  BubbleBorder::Arrow arrow = bubble_border()->arrow();
  DCHECK(BubbleBorder::is_arrow_at_center(arrow));

  // Get the desired bubble bounds without adjustment.
  bubble_border_->set_arrow_offset(0);
  gfx::Rect window_bounds(bubble_border_->GetBounds(anchor_rect, client_size));

  gfx::Rect monitor_rect(GetMonitorBounds(anchor_rect));
  if (monitor_rect.IsEmpty() || monitor_rect.Contains(window_bounds))
    return;

  // Calculate off-screen adjustment.
  const bool is_horizontal = BubbleBorder::is_arrow_on_horizontal(arrow);
  int offscreen_adjust = 0;
  if (is_horizontal) {
    if (window_bounds.x() < monitor_rect.x())
      offscreen_adjust = monitor_rect.x() - window_bounds.x();
    else if (window_bounds.right() > monitor_rect.right())
      offscreen_adjust = monitor_rect.right() - window_bounds.right();
  } else {
    if (window_bounds.y() < monitor_rect.y())
      offscreen_adjust = monitor_rect.y() - window_bounds.y();
    else if (window_bounds.bottom() > monitor_rect.bottom())
      offscreen_adjust = monitor_rect.bottom() - window_bounds.bottom();
  }

  // For center arrows, arrows are moved in the opposite direction of
  // |offscreen_adjust|, e.g. positive |offscreen_adjust| means bubble
  // window needs to be moved to the right and that means we need to move arrow
  // to the left, and that means negative offset.
  bubble_border_->set_arrow_offset(
      bubble_border_->GetArrowOffset(window_bounds.size()) - offscreen_adjust);
  if (offscreen_adjust)
    SchedulePaint();
}

}  // namespace views
<|endoftext|>


<commit_before>//===- llvm/unittest/Support/MathExtrasTest.cpp - math utils tests --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "gtest/gtest.h"
#include "llvm/Support/MathExtras.h"

using namespace llvm;

namespace {

TEST(MathExtras, isPowerOf2_32) {
  EXPECT_TRUE(isPowerOf2_32(1 << 6));
  EXPECT_TRUE(isPowerOf2_32(1 << 12));
  EXPECT_FALSE(isPowerOf2_32((1 << 19) + 3));
  EXPECT_FALSE(isPowerOf2_32(0xABCDEF0));
}

TEST(MathExtras, isPowerOf2_64) {
  EXPECT_TRUE(isPowerOf2_64(1LL << 46));
  EXPECT_TRUE(isPowerOf2_64(1LL << 12));
  EXPECT_FALSE(isPowerOf2_64((1LL << 53) + 3));
  EXPECT_FALSE(isPowerOf2_64(0xABCDEF0ABCDEF0LL));
}

TEST(MathExtras, ByteSwap_32) {
  EXPECT_EQ(0x44332211u, ByteSwap_32(0x11223344));
  EXPECT_EQ(0xDDCCBBAAu, ByteSwap_32(0xAABBCCDD));
}

TEST(MathExtras, ByteSwap_64) {
  EXPECT_EQ(0x8877665544332211ULL, ByteSwap_64(0x1122334455667788LL));
  EXPECT_EQ(0x1100FFEEDDCCBBAAULL, ByteSwap_64(0xAABBCCDDEEFF0011LL));
}

TEST(MathExtras, CountLeadingZeros_32) {
  EXPECT_EQ(8u, CountLeadingZeros_32(0x00F000FF));
  EXPECT_EQ(8u, CountLeadingZeros_32(0x00F12345));
  for (unsigned i = 0; i <= 30; ++i) {
    EXPECT_EQ(31 - i, CountLeadingZeros_32(1 << i));
  }
}

TEST(MathExtras, CountLeadingZeros_64) {
  EXPECT_EQ(8u, CountLeadingZeros_64(0x00F1234500F12345LL));
  EXPECT_EQ(1u, CountLeadingZeros_64(1LL << 62));
  for (unsigned i = 0; i <= 62; ++i) {
    EXPECT_EQ(63 - i, CountLeadingZeros_64(1LL << i));
  }
}

TEST(MathExtras, CountLeadingOnes_32) {
  for (int i = 30; i >= 0; --i) {
    // Start with all ones and unset some bit.
    EXPECT_EQ(31u - i, CountLeadingOnes_32(0xFFFFFFFF ^ (1 << i)));
  }
}

TEST(MathExtras, CountLeadingOnes_64) {
  for (int i = 62; i >= 0; --i) {
    // Start with all ones and unset some bit.
    EXPECT_EQ(63u - i, CountLeadingOnes_64(0xFFFFFFFFFFFFFFFFLL ^ (1LL << i)));
  }
  for (int i = 30; i >= 0; --i) {
    // Start with all ones and unset some bit.
    EXPECT_EQ(31u - i, CountLeadingOnes_32(0xFFFFFFFF ^ (1 << i)));
  }
}

TEST(MathExtras, FloatBits) {
  static const float kValue = 5632.34;
  EXPECT_FLOAT_EQ(kValue, BitsToFloat(FloatToBits(kValue)));
}

TEST(MathExtras, DoubleBits) {
  static const double kValue = 87987234.983498;
  EXPECT_FLOAT_EQ(kValue, BitsToDouble(DoubleToBits(kValue)));
}

TEST(MathExtras, MinAlign) {
  EXPECT_EQ(1u, MinAlign(2, 3));
  EXPECT_EQ(2u, MinAlign(2, 4));
  EXPECT_EQ(1u, MinAlign(17, 64));
  EXPECT_EQ(256u, MinAlign(256, 512));
}

TEST(MathExtras, NextPowerOf2) {
  EXPECT_EQ(4u, NextPowerOf2(3));
  EXPECT_EQ(16u, NextPowerOf2(15));
  EXPECT_EQ(256u, NextPowerOf2(128));
}

TEST(MathExtras, RoundUpToAlignment) {
  EXPECT_EQ(8u, RoundUpToAlignment(5, 8));
  EXPECT_EQ(24u, RoundUpToAlignment(17, 8));
  EXPECT_EQ(0u, RoundUpToAlignment(~0LL, 8));
}

}
<commit_msg>Fixed header comment.<commit_after>//===- unittests/Support/MathExtrasTest.cpp - math utils tests ------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "gtest/gtest.h"
#include "llvm/Support/MathExtras.h"

using namespace llvm;

namespace {

TEST(MathExtras, isPowerOf2_32) {
  EXPECT_TRUE(isPowerOf2_32(1 << 6));
  EXPECT_TRUE(isPowerOf2_32(1 << 12));
  EXPECT_FALSE(isPowerOf2_32((1 << 19) + 3));
  EXPECT_FALSE(isPowerOf2_32(0xABCDEF0));
}

TEST(MathExtras, isPowerOf2_64) {
  EXPECT_TRUE(isPowerOf2_64(1LL << 46));
  EXPECT_TRUE(isPowerOf2_64(1LL << 12));
  EXPECT_FALSE(isPowerOf2_64((1LL << 53) + 3));
  EXPECT_FALSE(isPowerOf2_64(0xABCDEF0ABCDEF0LL));
}

TEST(MathExtras, ByteSwap_32) {
  EXPECT_EQ(0x44332211u, ByteSwap_32(0x11223344));
  EXPECT_EQ(0xDDCCBBAAu, ByteSwap_32(0xAABBCCDD));
}

TEST(MathExtras, ByteSwap_64) {
  EXPECT_EQ(0x8877665544332211ULL, ByteSwap_64(0x1122334455667788LL));
  EXPECT_EQ(0x1100FFEEDDCCBBAAULL, ByteSwap_64(0xAABBCCDDEEFF0011LL));
}

TEST(MathExtras, CountLeadingZeros_32) {
  EXPECT_EQ(8u, CountLeadingZeros_32(0x00F000FF));
  EXPECT_EQ(8u, CountLeadingZeros_32(0x00F12345));
  for (unsigned i = 0; i <= 30; ++i) {
    EXPECT_EQ(31 - i, CountLeadingZeros_32(1 << i));
  }
}

TEST(MathExtras, CountLeadingZeros_64) {
  EXPECT_EQ(8u, CountLeadingZeros_64(0x00F1234500F12345LL));
  EXPECT_EQ(1u, CountLeadingZeros_64(1LL << 62));
  for (unsigned i = 0; i <= 62; ++i) {
    EXPECT_EQ(63 - i, CountLeadingZeros_64(1LL << i));
  }
}

TEST(MathExtras, CountLeadingOnes_32) {
  for (int i = 30; i >= 0; --i) {
    // Start with all ones and unset some bit.
    EXPECT_EQ(31u - i, CountLeadingOnes_32(0xFFFFFFFF ^ (1 << i)));
  }
}

TEST(MathExtras, CountLeadingOnes_64) {
  for (int i = 62; i >= 0; --i) {
    // Start with all ones and unset some bit.
    EXPECT_EQ(63u - i, CountLeadingOnes_64(0xFFFFFFFFFFFFFFFFLL ^ (1LL << i)));
  }
  for (int i = 30; i >= 0; --i) {
    // Start with all ones and unset some bit.
    EXPECT_EQ(31u - i, CountLeadingOnes_32(0xFFFFFFFF ^ (1 << i)));
  }
}

TEST(MathExtras, FloatBits) {
  static const float kValue = 5632.34;
  EXPECT_FLOAT_EQ(kValue, BitsToFloat(FloatToBits(kValue)));
}

TEST(MathExtras, DoubleBits) {
  static const double kValue = 87987234.983498;
  EXPECT_FLOAT_EQ(kValue, BitsToDouble(DoubleToBits(kValue)));
}

TEST(MathExtras, MinAlign) {
  EXPECT_EQ(1u, MinAlign(2, 3));
  EXPECT_EQ(2u, MinAlign(2, 4));
  EXPECT_EQ(1u, MinAlign(17, 64));
  EXPECT_EQ(256u, MinAlign(256, 512));
}

TEST(MathExtras, NextPowerOf2) {
  EXPECT_EQ(4u, NextPowerOf2(3));
  EXPECT_EQ(16u, NextPowerOf2(15));
  EXPECT_EQ(256u, NextPowerOf2(128));
}

TEST(MathExtras, RoundUpToAlignment) {
  EXPECT_EQ(8u, RoundUpToAlignment(5, 8));
  EXPECT_EQ(24u, RoundUpToAlignment(17, 8));
  EXPECT_EQ(0u, RoundUpToAlignment(~0LL, 8));
}

}
<|endoftext|>


<commit_before>/****************************************************************************
 * Copyright (c) 2012-2018 by the DataTransferKit authors                   *
 * All rights reserved.                                                     *
 *                                                                          *
 * This file is part of the DataTransferKit library. DataTransferKit is     *
 * distributed under a BSD 3-clause license. For the licensing terms see    *
 * the LICENSE file in the top-level directory.                             *
 *                                                                          *
 * SPDX-License-Identifier: BSD-3-Clause                                    *
 ****************************************************************************/

#ifndef DTK_DISTRIBUTED_SEARCH_TREE_DECL_HPP
#define DTK_DISTRIBUTED_SEARCH_TREE_DECL_HPP

#include <DTK_Box.hpp>
#include <DTK_DetailsDistributedSearchTreeImpl.hpp>
#include <DTK_DetailsUtils.hpp> // accumulate
#include <DTK_LinearBVH.hpp>

#include <Kokkos_View.hpp>

#include <mpi.h>

namespace DataTransferKit
{

/** \brief Distributed search tree
 *
 *  \note query() must be called as collective over all processes in the
 *  communicator passed to the constructor.
 */
template <typename DeviceType>
class DistributedSearchTree
{
  public:
    using bounding_volume_type = typename BVH<DeviceType>::bounding_volume_type;
    using size_type = typename BVH<DeviceType>::size_type;

    template <typename Primitives>
    DistributedSearchTree( MPI_Comm comm, Primitives const &primitives );

    /** Returns the smallest axis-aligned box able to contain all the objects
     *  stored in the tree or an invalid box if the tree is empty.
     */
    bounding_volume_type bounds() const { return _top_tree.bounds(); }

    /** Returns the global number of objects stored in the tree.
     */
    size_type size() const { return _top_tree_size; }

    /** Indicates whether the tree is empty on all processes.
     */
    bool empty() const { return size() == 0; }

    /** \brief Finds object satisfying the passed predicates (e.g. nearest to
     *  some point or overlaping with some box)
     *
     *  This query function performs a batch of spatial or k-nearest neighbors
     *  searches.  The results give indices of the objects that satisfy
     *  predicates (as given to the constructor).  They are organized in a
     *  distributed compressed row storage format.
     *
     *  \c indices stores the indices of the objects that satisfy the
     *  predicates.  \c offset stores the locations in the \c indices view that
     *  start a predicate, that is, \c queries(q) is satisfied by \c indices(o)
     *  for objects(q) <= o < objects(q+1) that live on processes
     *  \c ranks(o) respectively.  Following the usual convention,
     *  offset(n) = nnz, where \c n is the number of queries that
     *  were performed and \c nnz is the total number of collisions.
     *
     *  \note The views \c indices, \c offset, and \c ranks are passed by
     *  reference because \c Kokkos::realloc() calls the assignment operator.
     *
     *  \param[in] predicates Collection of predicates of the same type.  These
     *  may be spatial predicates or nearest predicates.
     *  \param[out] args
     *     - \c indices Object local indices that satisfy the predicates.
     *     - \c offset Array of predicate offsets for one-dimensional
     *       storage.
     *     - \c ranks Process ranks that own objects.
     *     - \c distances Computed distances (optional and only for nearest
     *       predicates).
     */
    template <typename Predicates, typename... Args>
    void query( Predicates const &predicates, Args &&... args ) const
    {
        // FIXME lame placeholder for concept check
        static_assert( Kokkos::is_view<Predicates>::value, "must pass a view" );
        using Tag = typename Predicates::value_type::Tag;
        Details::DistributedSearchTreeImpl<DeviceType>::queryDispatch(
            Tag{}, *this, predicates, std::forward<Args>( args )... );
    }

  private:
    friend struct Details::DistributedSearchTreeImpl<DeviceType>;
    MPI_Comm _comm;
    BVH<DeviceType> _top_tree;    // replicated
    BVH<DeviceType> _bottom_tree; // local
    size_type _top_tree_size;
    Kokkos::View<size_type *, DeviceType> _bottom_tree_sizes;
};

template <typename DeviceType>
template <typename Primitives>
DistributedSearchTree<DeviceType>::DistributedSearchTree(
    MPI_Comm comm, Primitives const &primitives )
    : _comm( comm )
    , _bottom_tree( primitives )
{
    int comm_rank;
    MPI_Comm_rank( _comm, &comm_rank );
    int comm_size;
    MPI_Comm_size( _comm, &comm_size );

    Kokkos::View<Box *, DeviceType> boxes(
        Kokkos::ViewAllocateWithoutInitializing( "rank_bounding_boxes" ),
        comm_size );
    // FIXME: I am not sure how to do the MPI allgather with Teuchos for data
    // living on the device so I copied to the host.
    auto boxes_host = Kokkos::create_mirror_view( boxes );
    boxes_host( comm_rank ) = _bottom_tree.bounds();
    MPI_Allgather( MPI_IN_PLACE, 0, MPI_DATATYPE_NULL,
                   static_cast<void *>( boxes_host.data() ), sizeof( Box ),
                   MPI_BYTE, _comm );
    Kokkos::deep_copy( boxes, boxes_host );

    _top_tree = BVH<DeviceType>( boxes );

    _bottom_tree_sizes = Kokkos::View<size_type *, DeviceType>(
        Kokkos::ViewAllocateWithoutInitializing( "leave_count_in_local_trees" ),
        comm_size );
    auto bottom_tree_sizes_host =
        Kokkos::create_mirror_view( _bottom_tree_sizes );
    bottom_tree_sizes_host( comm_rank ) = _bottom_tree.size();
    MPI_Allgather( MPI_IN_PLACE, 0, MPI_DATATYPE_NULL,
                   static_cast<void *>( bottom_tree_sizes_host.data() ),
                   sizeof( size_type ), MPI_BYTE, _comm );
    Kokkos::deep_copy( _bottom_tree_sizes, bottom_tree_sizes_host );

    _top_tree_size = accumulate( _bottom_tree_sizes, 0 );
}

} // namespace DataTransferKit

#endif
<commit_msg>Update outdated comment about not copying to the host when moving to MPI with CUDA support<commit_after>/****************************************************************************
 * Copyright (c) 2012-2018 by the DataTransferKit authors                   *
 * All rights reserved.                                                     *
 *                                                                          *
 * This file is part of the DataTransferKit library. DataTransferKit is     *
 * distributed under a BSD 3-clause license. For the licensing terms see    *
 * the LICENSE file in the top-level directory.                             *
 *                                                                          *
 * SPDX-License-Identifier: BSD-3-Clause                                    *
 ****************************************************************************/

#ifndef DTK_DISTRIBUTED_SEARCH_TREE_DECL_HPP
#define DTK_DISTRIBUTED_SEARCH_TREE_DECL_HPP

#include <DTK_Box.hpp>
#include <DTK_DetailsDistributedSearchTreeImpl.hpp>
#include <DTK_DetailsUtils.hpp> // accumulate
#include <DTK_LinearBVH.hpp>

#include <Kokkos_View.hpp>

#include <mpi.h>

namespace DataTransferKit
{

/** \brief Distributed search tree
 *
 *  \note query() must be called as collective over all processes in the
 *  communicator passed to the constructor.
 */
template <typename DeviceType>
class DistributedSearchTree
{
  public:
    using bounding_volume_type = typename BVH<DeviceType>::bounding_volume_type;
    using size_type = typename BVH<DeviceType>::size_type;

    template <typename Primitives>
    DistributedSearchTree( MPI_Comm comm, Primitives const &primitives );

    /** Returns the smallest axis-aligned box able to contain all the objects
     *  stored in the tree or an invalid box if the tree is empty.
     */
    bounding_volume_type bounds() const { return _top_tree.bounds(); }

    /** Returns the global number of objects stored in the tree.
     */
    size_type size() const { return _top_tree_size; }

    /** Indicates whether the tree is empty on all processes.
     */
    bool empty() const { return size() == 0; }

    /** \brief Finds object satisfying the passed predicates (e.g. nearest to
     *  some point or overlaping with some box)
     *
     *  This query function performs a batch of spatial or k-nearest neighbors
     *  searches.  The results give indices of the objects that satisfy
     *  predicates (as given to the constructor).  They are organized in a
     *  distributed compressed row storage format.
     *
     *  \c indices stores the indices of the objects that satisfy the
     *  predicates.  \c offset stores the locations in the \c indices view that
     *  start a predicate, that is, \c queries(q) is satisfied by \c indices(o)
     *  for objects(q) <= o < objects(q+1) that live on processes
     *  \c ranks(o) respectively.  Following the usual convention,
     *  offset(n) = nnz, where \c n is the number of queries that
     *  were performed and \c nnz is the total number of collisions.
     *
     *  \note The views \c indices, \c offset, and \c ranks are passed by
     *  reference because \c Kokkos::realloc() calls the assignment operator.
     *
     *  \param[in] predicates Collection of predicates of the same type.  These
     *  may be spatial predicates or nearest predicates.
     *  \param[out] args
     *     - \c indices Object local indices that satisfy the predicates.
     *     - \c offset Array of predicate offsets for one-dimensional
     *       storage.
     *     - \c ranks Process ranks that own objects.
     *     - \c distances Computed distances (optional and only for nearest
     *       predicates).
     */
    template <typename Predicates, typename... Args>
    void query( Predicates const &predicates, Args &&... args ) const
    {
        // FIXME lame placeholder for concept check
        static_assert( Kokkos::is_view<Predicates>::value, "must pass a view" );
        using Tag = typename Predicates::value_type::Tag;
        Details::DistributedSearchTreeImpl<DeviceType>::queryDispatch(
            Tag{}, *this, predicates, std::forward<Args>( args )... );
    }

  private:
    friend struct Details::DistributedSearchTreeImpl<DeviceType>;
    MPI_Comm _comm;
    BVH<DeviceType> _top_tree;    // replicated
    BVH<DeviceType> _bottom_tree; // local
    size_type _top_tree_size;
    Kokkos::View<size_type *, DeviceType> _bottom_tree_sizes;
};

template <typename DeviceType>
template <typename Primitives>
DistributedSearchTree<DeviceType>::DistributedSearchTree(
    MPI_Comm comm, Primitives const &primitives )
    : _comm( comm )
    , _bottom_tree( primitives )
{
    int comm_rank;
    MPI_Comm_rank( _comm, &comm_rank );
    int comm_size;
    MPI_Comm_size( _comm, &comm_size );

    Kokkos::View<Box *, DeviceType> boxes(
        Kokkos::ViewAllocateWithoutInitializing( "rank_bounding_boxes" ),
        comm_size );
    // FIXME when we move to MPI with CUDA-aware support, we will not need to
    // copy from the device to the host
    auto boxes_host = Kokkos::create_mirror_view( boxes );
    boxes_host( comm_rank ) = _bottom_tree.bounds();
    MPI_Allgather( MPI_IN_PLACE, 0, MPI_DATATYPE_NULL,
                   static_cast<void *>( boxes_host.data() ), sizeof( Box ),
                   MPI_BYTE, _comm );
    Kokkos::deep_copy( boxes, boxes_host );

    _top_tree = BVH<DeviceType>( boxes );

    _bottom_tree_sizes = Kokkos::View<size_type *, DeviceType>(
        Kokkos::ViewAllocateWithoutInitializing( "leave_count_in_local_trees" ),
        comm_size );
    auto bottom_tree_sizes_host =
        Kokkos::create_mirror_view( _bottom_tree_sizes );
    bottom_tree_sizes_host( comm_rank ) = _bottom_tree.size();
    MPI_Allgather( MPI_IN_PLACE, 0, MPI_DATATYPE_NULL,
                   static_cast<void *>( bottom_tree_sizes_host.data() ),
                   sizeof( size_type ), MPI_BYTE, _comm );
    Kokkos::deep_copy( _bottom_tree_sizes, bottom_tree_sizes_host );

    _top_tree_size = accumulate( _bottom_tree_sizes, 0 );
}

} // namespace DataTransferKit

#endif
<|endoftext|>


<commit_before>/***********************************************************************************************************************
*                                                                                *
* SPLASH build system v0.2                                                                                *
*                                                                                *
* Copyright (c) 2016 Andrew D. Zonenberg                                                                               *
* All rights reserved.                                                                                *
*                                                                                *
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the     *
* following conditions are met:                                                                                *
*                                                                                *
*    * Redistributions of source code must retain the above copyright notice, this list of conditions, and the         *
*      following disclaimer.                                                                                *
*                                                                                *
*    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the       *
*      following disclaimer in the documentation and/or other materials provided with the distribution.                *
*                                                                                *
*    * Neither the name of the author nor the names of any contributors may be used to endorse or promote products     *
*      derived from this software without specific prior written permission.                                           *
*                                                                                *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   *
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL *
* THE AUTHORS BE HELD LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES        *
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR       *
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE       *
* POSSIBILITY OF SUCH DAMAGE.                                                                                *
*                                                                                *
***********************************************************************************************************************/

#include "splashcore.h"

using namespace std;

Cache* g_cache = NULL;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Construction / destruction

Cache::Cache(string cachename)
{
	LogVerbose("Initializing cache subsystem...\n");
	LogIndenter li;

	//TODO: get cache path from command line arg or something?
	//Hard-coding the path prevents more than one splashctl instance from running on a given server.
	//This may or may not be what we want. If we DO want to limit to one instance, we need a way for multiple distinct
	//projects to share the splashctl/splashbuild back end.
	string home = getenv("HOME");
	if(!DoesDirectoryExist(home))
		LogFatal("home dir does not exist\n");
	m_cachePath = home + "/.splash/cache-" + cachename;

	//If the cache directory does not exist, create it
	if(!DoesDirectoryExist(m_cachePath))
	{
		LogDebug("Cache directory does not exist, creating it\n");
		MakeDirectoryRecursive(m_cachePath, 0600);
	}

	//It exists, load existing entries
	else
	{
		LogDebug("Cache directory exists, loading items\n");
		for(unsigned int i=0; i<256; i++)
		{
			//If the cache isn't very full we might not have entries in every bucket
			char hex[3];
			snprintf(hex, sizeof(hex), "%02x", i);
			string dirname = m_cachePath + "/" + hex;
			if(!DoesDirectoryExist(dirname))
				continue;

			//It exists, load whatever is in it
			vector<string> subdirs;
			FindSubdirs(dirname, subdirs);
			for(auto dir : subdirs)
			{
				//The object ID is what goes in our table, not the file hash
				string oid = GetBasenameOfFile(dir);
				if(!ValidateCacheEntry(oid))
				{
					LogWarning("Cache entry %s is not valid\n", oid.c_str());
					continue;
				}

				//TODO: load fail records too

				//Cache entry is valid, add to the cache table
				m_cacheIndex.emplace(oid);
			}
		}

		LogVerbose("%d cache entries loaded\n", (int)m_cacheIndex.size());
	}
}

Cache::~Cache()
{
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Status queries

NodeInfo::NodeState Cache::GetState(string id)
{
	lock_guard<recursive_mutex> lock(m_mutex);

	if(IsCached(id))
		return NodeInfo::READY;

	else if(IsFailed(id))
		return NodeInfo::FAILED;

	//TODO: check if it's building

	else
		return NodeInfo::MISSING;
}

/**
	@brief Determine if a particular object is in the cache.

	@param id		Object ID hash
 */
bool Cache::IsCached(string id)
{
	lock_guard<recursive_mutex> lock(m_mutex);

	if(m_cacheIndex.find(id) != m_cacheIndex.end())
		return true;

	return false;
}

/**
	@brief Determine if a particular object is in the cache with a "fail" record.

	@param id		Object ID hash
 */
bool Cache::IsFailed(string id)
{
	lock_guard<recursive_mutex> lock(m_mutex);

	if(m_cacheFails.find(id) != m_cacheFails.end())
		return true;

	return false;
}

/**
	@brief Stronger form of IsCached(). Checks if the internal hash is consistent

	@param id		Object ID hash
 */
bool Cache::ValidateCacheEntry(string id)
{
	lock_guard<recursive_mutex> lock(m_mutex);

	//If the directory doesn't exist, obviously we have nothing useful there
	string dir = GetStoragePath(id);
	if(!DoesDirectoryExist(dir))
		return false;

	//If we're missing the file or hash, can't possibly be valid
	string fpath = dir + "/data";
	string hpath = dir + "/hash";
	if( !DoesFileExist(fpath) || !DoesFileExist(hpath) )
		return false;

	//Get the expected hash and compare to the real one
	//If it's invalid, just get rid of the junk
	string expected = GetFileContents(hpath);
	string found = sha256_file(fpath);
	if(expected != found)
	{
		LogWarning("Cache directory %s is corrupted (hash match failed)\n", id.c_str());
		LogDebug("Expected hash: %s\n", expected.c_str());
		LogDebug("Found hash:    %s\n", found.c_str());
		ShellCommand(string("rm -I ") + dir + "/*");
		ShellCommand(string("rm -r ") + dir);
		return false;
	}

	return true;
}

/**
	@brief Gets the cache path used for storing a particular object
 */
string Cache::GetStoragePath(string id)
{
	return m_cachePath + "/" + id.substr(0, 2) + "/" + id;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Cache manipulation

/**
	@brief Reads a file from the cache
 */
string Cache::ReadCachedFile(string id)
{
	lock_guard<recursive_mutex> lock(m_mutex);

	//Sanity check
	if(!IsCached(id))
	{
		LogError("Requested file %s is not in cache\n", id.c_str());
		return "";
	}

	//Read the file
	string ret = GetFileContents(GetStoragePath(id) + "/data");

	return ret;
}

/**
	@brief Reads the log from a file from the cache
 */
string Cache::ReadCachedLog(string id)
{
	lock_guard<recursive_mutex> lock(m_mutex);

	//Sanity check
	if(!IsCached(id) && !IsFailed(id))
	{
		LogError("Requested log %s is not in cache\n", id.c_str());
		return "";
	}

	//Read the file
	string ret = GetFileContents(GetStoragePath(id) + "/log");

	return ret;
}

/**
	@brief Adds a new file's metadata to the cache, reporting that we couldn't actually make it
 */
void Cache::AddFailedFile(string basename, string id, string log)
{
	lock_guard<recursive_mutex> lock(m_mutex);

	//If the content is already in the cache, skip it
	if(IsCached(id) || IsFailed(id))
		return;

	//Create the directory. If it already exists, delete whatever junk was in there
	string dirname = GetStoragePath(id);
	if(DoesDirectoryExist(dirname))
	{
		LogWarning("Cache directory %s already exists but was not loaded, removing dead files\n", id.c_str());
		ShellCommand(string("rm -I ") + dirname + "/*");
	}
	else
		MakeDirectoryRecursive(dirname, 0600);

	//Create the "failed" record
	if(!PutFileContents(dirname + "/failed", ""))
		return;

	//Write the command stdout (not integrity checked)
	if(!PutFileContents(dirname + "/log", log))
		return;

	//Remember that we have this file cached
	m_cacheFails.emplace(id);
}

/**
	@brief Adds a file to the cache

	@param basename			Name of the file without directory information
	@param id				Object ID hash
	@param hash				SHA-256 sum of the file
	@param data				The data to write
	@param log				Standard output of the command that built this file
 */
void Cache::AddFile(string /*basename*/, string id, string hash, string data, string log)
{
	lock_guard<recursive_mutex> lock(m_mutex);

	//If the content is already in the cache, skip it
	if(IsCached(id) || IsFailed(id))
		return;

	//Create the directory. If it already exists, delete whatever junk was in there
	string dirname = GetStoragePath(id);
	if(DoesDirectoryExist(dirname))
	{
		LogWarning("Cache directory %s already exists but was not loaded, removing dead files\n", id.c_str());
		ShellCommand(string("rm -I ") + dirname + "/*");
	}
	else
		MakeDirectoryRecursive(dirname, 0600);

	//Write the file data to it
	if(!PutFileContents(dirname + "/data", data))
		return;

	//Write the hash
	if(!PutFileContents(dirname + "/hash", hash))
		return;

	//Write the command stdout (not integrity checked)
	if(!PutFileContents(dirname + "/log", log))
		return;

	//Sanity check
	string chash = sha256(data);
	if(chash != hash)
	{
		LogWarning("Adding new cache entry for id %s:\n", id.c_str());
		LogIndenter li;
		LogWarning("passed:     %s:\n", hash.c_str());
		LogWarning("calculated: %s:\n", chash.c_str());
	}

	//TODO: write the atime file?

	//Remember that we have this file cached
	m_cacheIndex.emplace(id);

	//TODO: add this file's size to the cache, if we went over the cap delete the LRU file
}
<commit_msg>splashcore: Cache now gives more useful error messages if you pass the wrong hash<commit_after>/***********************************************************************************************************************
*                                                                                *
* SPLASH build system v0.2                                                                                *
*                                                                                *
* Copyright (c) 2016 Andrew D. Zonenberg                                                                               *
* All rights reserved.                                                                                *
*                                                                                *
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the     *
* following conditions are met:                                                                                *
*                                                                                *
*    * Redistributions of source code must retain the above copyright notice, this list of conditions, and the         *
*      following disclaimer.                                                                                *
*                                                                                *
*    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the       *
*      following disclaimer in the documentation and/or other materials provided with the distribution.                *
*                                                                                *
*    * Neither the name of the author nor the names of any contributors may be used to endorse or promote products     *
*      derived from this software without specific prior written permission.                                           *
*                                                                                *
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED   *
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL *
* THE AUTHORS BE HELD LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES        *
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR       *
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE       *
* POSSIBILITY OF SUCH DAMAGE.                                                                                *
*                                                                                *
***********************************************************************************************************************/

#include "splashcore.h"

using namespace std;

Cache* g_cache = NULL;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Construction / destruction

Cache::Cache(string cachename)
{
	LogVerbose("Initializing cache subsystem...\n");
	LogIndenter li;

	//TODO: get cache path from command line arg or something?
	//Hard-coding the path prevents more than one splashctl instance from running on a given server.
	//This may or may not be what we want. If we DO want to limit to one instance, we need a way for multiple distinct
	//projects to share the splashctl/splashbuild back end.
	string home = getenv("HOME");
	if(!DoesDirectoryExist(home))
		LogFatal("home dir does not exist\n");
	m_cachePath = home + "/.splash/cache-" + cachename;

	//If the cache directory does not exist, create it
	if(!DoesDirectoryExist(m_cachePath))
	{
		LogDebug("Cache directory does not exist, creating it\n");
		MakeDirectoryRecursive(m_cachePath, 0600);
	}

	//It exists, load existing entries
	else
	{
		LogDebug("Cache directory exists, loading items\n");
		for(unsigned int i=0; i<256; i++)
		{
			//If the cache isn't very full we might not have entries in every bucket
			char hex[3];
			snprintf(hex, sizeof(hex), "%02x", i);
			string dirname = m_cachePath + "/" + hex;
			if(!DoesDirectoryExist(dirname))
				continue;

			//It exists, load whatever is in it
			vector<string> subdirs;
			FindSubdirs(dirname, subdirs);
			for(auto dir : subdirs)
			{
				//The object ID is what goes in our table, not the file hash
				string oid = GetBasenameOfFile(dir);
				if(!ValidateCacheEntry(oid))
				{
					LogWarning("Cache entry %s is not valid\n", oid.c_str());
					continue;
				}

				//TODO: load fail records too

				//Cache entry is valid, add to the cache table
				m_cacheIndex.emplace(oid);
			}
		}

		LogVerbose("%d cache entries loaded\n", (int)m_cacheIndex.size());
	}
}

Cache::~Cache()
{
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Status queries

NodeInfo::NodeState Cache::GetState(string id)
{
	lock_guard<recursive_mutex> lock(m_mutex);

	if(IsCached(id))
		return NodeInfo::READY;

	else if(IsFailed(id))
		return NodeInfo::FAILED;

	//TODO: check if it's building

	else
		return NodeInfo::MISSING;
}

/**
	@brief Determine if a particular object is in the cache.

	@param id		Object ID hash
 */
bool Cache::IsCached(string id)
{
	lock_guard<recursive_mutex> lock(m_mutex);

	if(m_cacheIndex.find(id) != m_cacheIndex.end())
		return true;

	return false;
}

/**
	@brief Determine if a particular object is in the cache with a "fail" record.

	@param id		Object ID hash
 */
bool Cache::IsFailed(string id)
{
	lock_guard<recursive_mutex> lock(m_mutex);

	if(m_cacheFails.find(id) != m_cacheFails.end())
		return true;

	return false;
}

/**
	@brief Stronger form of IsCached(). Checks if the internal hash is consistent

	@param id		Object ID hash
 */
bool Cache::ValidateCacheEntry(string id)
{
	lock_guard<recursive_mutex> lock(m_mutex);

	//If the directory doesn't exist, obviously we have nothing useful there
	string dir = GetStoragePath(id);
	if(!DoesDirectoryExist(dir))
		return false;

	//If we're missing the file or hash, can't possibly be valid
	string fpath = dir + "/data";
	string hpath = dir + "/hash";
	if( !DoesFileExist(fpath) || !DoesFileExist(hpath) )
		return false;

	//Get the expected hash and compare to the real one
	//If it's invalid, just get rid of the junk
	string expected = GetFileContents(hpath);
	string found = sha256_file(fpath);
	if(expected != found)
	{
		LogWarning("Cache directory %s is corrupted (hash match failed)\n", id.c_str());
		LogDebug("Expected hash: %s\n", expected.c_str());
		LogDebug("Found hash:    %s\n", found.c_str());
		ShellCommand(string("rm -I ") + dir + "/*");
		ShellCommand(string("rm -r ") + dir);
		return false;
	}

	return true;
}

/**
	@brief Gets the cache path used for storing a particular object
 */
string Cache::GetStoragePath(string id)
{
	return m_cachePath + "/" + id.substr(0, 2) + "/" + id;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Cache manipulation

/**
	@brief Reads a file from the cache
 */
string Cache::ReadCachedFile(string id)
{
	lock_guard<recursive_mutex> lock(m_mutex);

	//Sanity check
	if(!IsCached(id))
	{
		LogError("Requested file %s is not in cache\n", id.c_str());
		return "";
	}

	//Read the file
	string ret = GetFileContents(GetStoragePath(id) + "/data");

	return ret;
}

/**
	@brief Reads the log from a file from the cache
 */
string Cache::ReadCachedLog(string id)
{
	lock_guard<recursive_mutex> lock(m_mutex);

	//Sanity check
	if(!IsCached(id) && !IsFailed(id))
	{
		LogError("Requested log %s is not in cache\n", id.c_str());
		return "";
	}

	//Read the file
	string ret = GetFileContents(GetStoragePath(id) + "/log");

	return ret;
}

/**
	@brief Adds a new file's metadata to the cache, reporting that we couldn't actually make it
 */
void Cache::AddFailedFile(string basename, string id, string log)
{
	lock_guard<recursive_mutex> lock(m_mutex);

	//If the content is already in the cache, skip it
	if(IsCached(id) || IsFailed(id))
		return;

	//Create the directory. If it already exists, delete whatever junk was in there
	string dirname = GetStoragePath(id);
	if(DoesDirectoryExist(dirname))
	{
		LogWarning("Cache directory %s already exists but was not loaded, removing dead files\n", id.c_str());
		ShellCommand(string("rm -I ") + dirname + "/*");
	}
	else
		MakeDirectoryRecursive(dirname, 0600);

	//Create the "failed" record
	if(!PutFileContents(dirname + "/failed", ""))
		return;

	//Write the command stdout (not integrity checked)
	if(!PutFileContents(dirname + "/log", log))
		return;

	//Remember that we have this file cached
	m_cacheFails.emplace(id);
}

/**
	@brief Adds a file to the cache

	@param basename			Name of the file without directory information
	@param id				Object ID hash
	@param hash				SHA-256 sum of the file
	@param data				The data to write
	@param log				Standard output of the command that built this file
 */
void Cache::AddFile(string basename, string id, string hash, string data, string log)
{
	lock_guard<recursive_mutex> lock(m_mutex);

	//If the content is already in the cache, skip it
	if(IsCached(id) || IsFailed(id))
		return;

	//Create the directory. If it already exists, delete whatever junk was in there
	string dirname = GetStoragePath(id);
	if(DoesDirectoryExist(dirname))
	{
		LogWarning("Cache directory %s already exists but was not loaded, removing dead files\n", id.c_str());
		ShellCommand(string("rm -I ") + dirname + "/*");
	}
	else
		MakeDirectoryRecursive(dirname, 0600);

	//Write the file data to it
	if(!PutFileContents(dirname + "/data", data))
		return;

	//Write the hash
	if(!PutFileContents(dirname + "/hash", hash))
		return;

	//Write the command stdout (not integrity checked)
	if(!PutFileContents(dirname + "/log", log))
		return;

	//Sanity check
	string chash = sha256(data);
	if(chash != hash)
	{
		LogWarning("Adding new cache entry for id %s (%s):\n", id.c_str(), basename.c_str());
		LogIndenter li;
		LogWarning("passed:     %s:\n", hash.c_str());
		LogWarning("calculated: %s:\n", chash.c_str());
	}

	//TODO: write the atime file?

	//Remember that we have this file cached
	m_cacheIndex.emplace(id);

	//TODO: add this file's size to the cache, if we went over the cap delete the LRU file
}
<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

#include "AliTrackReference.h"
#include "TParticle.h"
#include "AliRun.h"
#include "TLorentzVector.h"

//
// Track Reference object is created every time particle is
// crossing detector bounds. The object is created by Step Manager
//
// The class stores the following informations:
// track label,
// track position: X,Y,X
// track momentum px, py, pz
// track length and time of fligth: both in cm
// status bits from Monte Carlo
//

ClassImp(AliTrackReference)

//_______________________________________________________________________
 AliTrackReference::AliTrackReference():
   fTrack(0),
   fX(0),
   fY(0),
   fZ(0),
   fPx(0),
   fPy(0),
   fPz(0),
   fLength(0)
{
  //
  // Default constructor
  // Creates empty object

  for(Int_t i=0; i<16; i++) ResetBit(BIT(i));
}

//_______________________________________________________________________
AliTrackReference::AliTrackReference(Int_t label, TVirtualMC *vMC) {
  //
  // Create Reference object out of label and
  // data in TVirtualMC object
  //
  // Creates an object and fill all parameters
  // from data in VirtualMC
  //
  // Sylwester Radomski, (S.Radomski@gsi.de)
  // GSI, Jan 31, 2003
  //

  TLorentzVector vec;

  fTrack = label;
  fLength = vMC->TrackLength();
  fTime = vMC->TrackTime();

  vMC->TrackPosition(vec);

  fX = vec[0];
  fY = vec[1];
  fZ = vec[2];

  vMC->TrackMomentum(vec);

  fPx = vec[0];
  fPy = vec[1];
  fPy = vec[2];

  // Set Up status code
  // Copy Bits from virtual MC

  for(Int_t i=0; i<16; i++) ResetBit(BIT(i));

  SetBit(BIT(0), vMC->IsNewTrack());
  SetBit(BIT(1), vMC->IsTrackAlive());
  SetBit(BIT(2), vMC->IsTrackDisappeared());
  SetBit(BIT(3), vMC->IsTrackEntering());
  SetBit(BIT(4), vMC->IsTrackExiting());
  SetBit(BIT(5), vMC->IsTrackInside());
  SetBit(BIT(6), vMC->IsTrackOut());
  SetBit(BIT(7), vMC->IsTrackStop());
}
//_______________________________________________________________________
<commit_msg>Correcting typo<commit_after>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

#include "AliTrackReference.h"
#include "TParticle.h"
#include "AliRun.h"
#include "TLorentzVector.h"

//
// Track Reference object is created every time particle is
// crossing detector bounds. The object is created by Step Manager
//
// The class stores the following informations:
// track label,
// track position: X,Y,X
// track momentum px, py, pz
// track length and time of fligth: both in cm
// status bits from Monte Carlo
//

ClassImp(AliTrackReference)

//_______________________________________________________________________
 AliTrackReference::AliTrackReference():
   fTrack(0),
   fX(0),
   fY(0),
   fZ(0),
   fPx(0),
   fPy(0),
   fPz(0),
   fLength(0)
{
  //
  // Default constructor
  // Creates empty object

  for(Int_t i=0; i<16; i++) ResetBit(BIT(i));
}

//_______________________________________________________________________
AliTrackReference::AliTrackReference(Int_t label, TVirtualMC *vMC) {
  //
  // Create Reference object out of label and
  // data in TVirtualMC object
  //
  // Creates an object and fill all parameters
  // from data in VirtualMC
  //
  // Sylwester Radomski, (S.Radomski@gsi.de)
  // GSI, Jan 31, 2003
  //

  TLorentzVector vec;

  fTrack = label;
  fLength = vMC->TrackLength();
  fTime = vMC->TrackTime();

  vMC->TrackPosition(vec);

  fX = vec[0];
  fY = vec[1];
  fZ = vec[2];

  vMC->TrackMomentum(vec);

  fPx = vec[0];
  fPy = vec[1];
  fPz = vec[2];

  // Set Up status code
  // Copy Bits from virtual MC

  for(Int_t i=0; i<16; i++) ResetBit(BIT(i));

  SetBit(BIT(0), vMC->IsNewTrack());
  SetBit(BIT(1), vMC->IsTrackAlive());
  SetBit(BIT(2), vMC->IsTrackDisappeared());
  SetBit(BIT(3), vMC->IsTrackEntering());
  SetBit(BIT(4), vMC->IsTrackExiting());
  SetBit(BIT(5), vMC->IsTrackInside());
  SetBit(BIT(6), vMC->IsTrackOut());
  SetBit(BIT(7), vMC->IsTrackStop());
}
//_______________________________________________________________________
<|endoftext|>


<commit_before>#pragma once

#include <optional>

#include "Runtime/Collision/CCollidableAABox.hpp"
#include "Runtime/World/CActor.hpp"

#include <zeus/CAxisAngle.hpp>
#include <zeus/CQuaternion.hpp>
#include <zeus/CTransform.hpp>
#include <zeus/CVector3f.hpp>

namespace urde {
class CCollisionInfoList;
struct SMoverData;

struct SMoverData {
  zeus::CVector3f x0_velocity;
  zeus::CAxisAngle xc_angularVelocity;
  zeus::CVector3f x18_momentum;
  zeus::CAxisAngle x24_;
  float x30_mass;

  SMoverData(float mass) : x30_mass(mass) {}
};

struct CMotionState {
  zeus::CVector3f x0_translation;
  zeus::CNUQuaternion xc_orientation;
  zeus::CVector3f x1c_velocity;
  zeus::CAxisAngle x28_angularMomentum;
  CMotionState(const zeus::CVector3f& origin, const zeus::CNUQuaternion& orientation, const zeus::CVector3f& velocity,
               const zeus::CAxisAngle& angle)
  : x0_translation(origin), xc_orientation(orientation), x1c_velocity(velocity), x28_angularMomentum(angle) {}
  CMotionState(const zeus::CVector3f& origin, const zeus::CNUQuaternion& orientation)
  : x0_translation(origin), xc_orientation(orientation) {}
};

class CPhysicsState {
  zeus::CVector3f x0_translation;
  zeus::CQuaternion xc_orientation;
  zeus::CVector3f x1c_constantForce;
  zeus::CAxisAngle x28_angularMomentum;
  zeus::CVector3f x34_momentum;
  zeus::CVector3f x40_force;
  zeus::CVector3f x4c_impulse;
  zeus::CAxisAngle x58_torque;
  zeus::CAxisAngle x64_angularImpulse;

public:
  CPhysicsState(const zeus::CVector3f& translation, const zeus::CQuaternion& orient, const zeus::CVector3f& v2,
                const zeus::CAxisAngle& a1, const zeus::CVector3f& v3, const zeus::CVector3f& v4,
                const zeus::CVector3f& v5, const zeus::CAxisAngle& a2, const zeus::CAxisAngle& a3)
  : x0_translation(translation)
  , xc_orientation(orient)
  , x1c_constantForce(v2)
  , x28_angularMomentum(a1)
  , x34_momentum(v3)
  , x40_force(v4)
  , x4c_impulse(v5)
  , x58_torque(a2)
  , x64_angularImpulse(a3) {}

  void SetTranslation(const zeus::CVector3f& tr) { x0_translation = tr; }
  void SetOrientation(const zeus::CQuaternion& orient) { xc_orientation = orient; }
  const zeus::CQuaternion& GetOrientation() const { return xc_orientation; }
  const zeus::CVector3f& GetTranslation() const { return x0_translation; }
  const zeus::CVector3f& GetConstantForceWR() const { return x1c_constantForce; }
  const zeus::CAxisAngle& GetAngularMomentumWR() const { return x28_angularMomentum; }
  const zeus::CVector3f& GetMomentumWR() const { return x34_momentum; }
  const zeus::CVector3f& GetForceWR() const { return x40_force; }
  const zeus::CVector3f& GetImpulseWR() const { return x4c_impulse; }
  const zeus::CAxisAngle& GetTorque() const { return x58_torque; }
  const zeus::CAxisAngle& GetAngularImpulseWR() const { return x64_angularImpulse; }
};

class CPhysicsActor : public CActor {
  friend class CGroundMovement;

protected:
  float xe8_mass;
  float xec_massRecip;
  float xf0_inertiaTensor;
  float xf4_inertiaTensorRecip;
  union {
    struct {
      bool xf8_24_movable : 1;
      bool xf8_25_angularEnabled : 1;
    };
    u8 _dummy = 0;
  };
  bool xf9_standardCollider = false;
  zeus::CVector3f xfc_constantForce;
  zeus::CAxisAngle x108_angularMomentum;
  zeus::CMatrix3f x114_;
  zeus::CVector3f x138_velocity;
  zeus::CAxisAngle x144_angularVelocity;
  zeus::CVector3f x150_momentum;
  zeus::CVector3f x15c_force;
  zeus::CVector3f x168_impulse;
  zeus::CAxisAngle x174_torque;
  zeus::CAxisAngle x180_angularImpulse;
  zeus::CVector3f x18c_moveImpulse;
  zeus::CAxisAngle x198_moveAngularImpulse;
  zeus::CAABox x1a4_baseBoundingBox;
  CCollidableAABox x1c0_collisionPrimitive;
  zeus::CVector3f x1e8_primitiveOffset;
  CMotionState x1f4_lastNonCollidingState;
  std::optional<zeus::CVector3f> x228_lastFloorPlaneNormal;
  float x238_maximumCollisionVelocity = 1000000.0f;
  float x23c_stepUpHeight;
  float x240_stepDownHeight;
  float x244_restitutionCoefModifier = 0.f;
  float x248_collisionAccuracyModifier = 1.f;
  u32 x24c_numTicksStuck = 0;
  u32 x250_numTicksPartialUpdate = 0;

public:
  CPhysicsActor(TUniqueId uid, bool active, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf,
                CModelData&& mData, const CMaterialList& matList, const zeus::CAABox& box, const SMoverData& moverData,
                const CActorParameters& actorParms, float stepUp, float stepDown);

  void Render(const CStateManager& mgr) const override;
  zeus::CVector3f GetOrbitPosition(const CStateManager& mgr) const override;
  zeus::CVector3f GetAimPosition(const CStateManager& mgr, float val) const override;
  virtual const CCollisionPrimitive* GetCollisionPrimitive() const;
  virtual zeus::CTransform GetPrimitiveTransform() const;
  virtual void CollidedWith(TUniqueId id, const CCollisionInfoList& list, CStateManager& mgr);
  virtual float GetStepUpHeight() const;
  virtual float GetStepDownHeight() const;
  virtual float GetWeight() const;

  float GetMass() const { return xe8_mass; }
  void SetPrimitiveOffset(const zeus::CVector2f& offset);
  const zeus::CVector3f& GetPrimitiveOffset() const { return x1e8_primitiveOffset; }
  void MoveCollisionPrimitive(const zeus::CVector3f& offset);
  void SetBoundingBox(const zeus::CAABox& box);
  zeus::CAABox GetMotionVolume(float dt) const;
  zeus::CVector3f CalculateNewVelocityWR_UsingImpulses() const;
  zeus::CAABox GetBoundingBox() const;
  const zeus::CAABox& GetBaseBoundingBox() const;
  void AddMotionState(const CMotionState& mst);
  CMotionState GetMotionState() const;
  const CMotionState& GetLastNonCollidingState() const { return x1f4_lastNonCollidingState; }
  void SetLastNonCollidingState(const CMotionState& mst) { x1f4_lastNonCollidingState = mst; }
  void SetMotionState(const CMotionState& mst);
  float GetMaximumCollisionVelocity() const { return x238_maximumCollisionVelocity; }
  void SetMaximumCollisionVelocity(float velocity) { x238_maximumCollisionVelocity = velocity; }
  void SetInertiaTensorScalar(float tensor);
  void SetMass(float mass);
  void SetAngularVelocityOR(const zeus::CAxisAngle& angVel);
  zeus::CAxisAngle GetAngularVelocityOR() const;
  const zeus::CAxisAngle& GetAngularVelocityWR() const { return x144_angularVelocity; }
  void SetAngularVelocityWR(const zeus::CAxisAngle& angVel);
  const zeus::CVector3f& GetForceOR() const { return x15c_force; }
  const zeus::CVector3f& GetImpulseOR() const { return x168_impulse; }
  const zeus::CVector3f& GetMoveImpulseOR() const { return x18c_moveImpulse; }
  void SetVelocityWR(const zeus::CVector3f& vel);
  void SetVelocityOR(const zeus::CVector3f& vel);
  void SetMomentumWR(const zeus::CVector3f& momentum) { x150_momentum = momentum; }
  const zeus::CVector3f& GetConstantForce() const { return xfc_constantForce; }
  void SetConstantForce(const zeus::CVector3f& force) { xfc_constantForce = force; }
  void SetAngularMomentum(const zeus::CAxisAngle& momentum) { x108_angularMomentum = momentum; }
  const zeus::CVector3f& GetMomentum() const { return x150_momentum; }
  const zeus::CVector3f& GetVelocity() const { return x138_velocity; }
  const zeus::CAxisAngle& GetAngularImpulse() const { return x180_angularImpulse; }
  void SetAngularImpulse(const zeus::CAxisAngle& impulse) { x180_angularImpulse = impulse; }
  zeus::CVector3f GetTotalForcesWR() const;
  void RotateInOneFrameOR(const zeus::CQuaternion& q, float d);
  void MoveInOneFrameOR(const zeus::CVector3f& trans, float d);
  void RotateToOR(const zeus::CQuaternion& q, float d);
  void MoveToOR(const zeus::CVector3f& trans, float d);
  void MoveToInOneFrameWR(const zeus::CVector3f& v1, float d);
  void MoveToWR(const zeus::CVector3f& trans, float d);
  zeus::CAxisAngle GetRotateToORAngularMomentumWR(const zeus::CQuaternion& q, float d) const;
  zeus::CVector3f GetMoveToORImpulseWR(const zeus::CVector3f& trans, float d) const;
  void ClearImpulses();
  void ClearForcesAndTorques();
  void Stop();
  void ComputeDerivedQuantities();
  bool WillMove(const CStateManager& mgr) const;
  void SetPhysicsState(const CPhysicsState& state);
  CPhysicsState GetPhysicsState() const;
  bool IsMovable() const { return xf8_24_movable; }
  void SetMovable(bool movable) { xf8_24_movable = movable; }
  bool IsAngularEnabled() const { return xf8_25_angularEnabled; }
  void SetAngularEnabled(bool enabled) { xf8_25_angularEnabled = enabled; }
  float GetCollisionAccuracyModifier() const { return x248_collisionAccuracyModifier; }
  void SetCollisionAccuracyModifier(float modifier) { x248_collisionAccuracyModifier = modifier; }
  float GetCoefficientOfRestitutionModifier() const { return x244_restitutionCoefModifier; }
  void SetCoefficientOfRestitutionModifier(float modifier) { x244_restitutionCoefModifier = modifier; }
  bool IsUseStandardCollider() const { return xf9_standardCollider; }
  u32 GetNumTicksPartialUpdate() const { return x250_numTicksPartialUpdate; }
  void SetNumTicksPartialUpdate(u32 ticks) { x250_numTicksPartialUpdate = ticks; }
  u32 GetNumTicksStuck() const { return x24c_numTicksStuck; }
  void SetNumTicksStuck(u32 ticks) { x24c_numTicksStuck = ticks; }
  const std::optional<zeus::CVector3f>& GetLastFloorPlaneNormal() const {
    return x228_lastFloorPlaneNormal;
  }
  void SetLastFloorPlaneNormal(const std::optional<zeus::CVector3f>& normal) { x228_lastFloorPlaneNormal = normal; }

  CMotionState PredictMotion_Internal(float) const;
  CMotionState PredictMotion(float dt) const;
  CMotionState PredictLinearMotion(float dt) const;
  CMotionState PredictAngularMotion(float dt) const;
  void ApplyForceOR(const zeus::CVector3f& force, const zeus::CAxisAngle& angle);
  void ApplyForceWR(const zeus::CVector3f& force, const zeus::CAxisAngle& angle);
  void ApplyImpulseOR(const zeus::CVector3f& impulse, const zeus::CAxisAngle& angle);
  void ApplyImpulseWR(const zeus::CVector3f& impulse, const zeus::CAxisAngle& angle);
  void ApplyTorqueWR(const zeus::CVector3f& torque);

  void UseCollisionImpulses();
  static constexpr float GravityConstant() { return 9.81f * 2.5f; } /* 9.81 m/s ^ 2 is normal acceleration under earth gravity, Tallon 4 is 2.5 times that */
};
} // namespace urde
<commit_msg>CPhysicsActor: Amend constructor names for CPhysicsState<commit_after>#pragma once

#include <optional>

#include "Runtime/Collision/CCollidableAABox.hpp"
#include "Runtime/World/CActor.hpp"

#include <zeus/CAxisAngle.hpp>
#include <zeus/CQuaternion.hpp>
#include <zeus/CTransform.hpp>
#include <zeus/CVector3f.hpp>

namespace urde {
class CCollisionInfoList;
struct SMoverData;

struct SMoverData {
  zeus::CVector3f x0_velocity;
  zeus::CAxisAngle xc_angularVelocity;
  zeus::CVector3f x18_momentum;
  zeus::CAxisAngle x24_;
  float x30_mass;

  SMoverData(float mass) : x30_mass(mass) {}
};

struct CMotionState {
  zeus::CVector3f x0_translation;
  zeus::CNUQuaternion xc_orientation;
  zeus::CVector3f x1c_velocity;
  zeus::CAxisAngle x28_angularMomentum;
  CMotionState(const zeus::CVector3f& origin, const zeus::CNUQuaternion& orientation, const zeus::CVector3f& velocity,
               const zeus::CAxisAngle& angle)
  : x0_translation(origin), xc_orientation(orientation), x1c_velocity(velocity), x28_angularMomentum(angle) {}
  CMotionState(const zeus::CVector3f& origin, const zeus::CNUQuaternion& orientation)
  : x0_translation(origin), xc_orientation(orientation) {}
};

class CPhysicsState {
  zeus::CVector3f x0_translation;
  zeus::CQuaternion xc_orientation;
  zeus::CVector3f x1c_constantForce;
  zeus::CAxisAngle x28_angularMomentum;
  zeus::CVector3f x34_momentum;
  zeus::CVector3f x40_force;
  zeus::CVector3f x4c_impulse;
  zeus::CAxisAngle x58_torque;
  zeus::CAxisAngle x64_angularImpulse;

public:
  CPhysicsState(const zeus::CVector3f& translation, const zeus::CQuaternion& orient,
                const zeus::CVector3f& constantForce, const zeus::CAxisAngle& angularMomentum,
                const zeus::CVector3f& momentum, const zeus::CVector3f& force, const zeus::CVector3f& impulse,
                const zeus::CAxisAngle& torque, const zeus::CAxisAngle& angularImpulse)
  : x0_translation(translation)
  , xc_orientation(orient)
  , x1c_constantForce(constantForce)
  , x28_angularMomentum(angularMomentum)
  , x34_momentum(momentum)
  , x40_force(force)
  , x4c_impulse(impulse)
  , x58_torque(torque)
  , x64_angularImpulse(angularImpulse) {}

  void SetTranslation(const zeus::CVector3f& tr) { x0_translation = tr; }
  void SetOrientation(const zeus::CQuaternion& orient) { xc_orientation = orient; }
  const zeus::CQuaternion& GetOrientation() const { return xc_orientation; }
  const zeus::CVector3f& GetTranslation() const { return x0_translation; }
  const zeus::CVector3f& GetConstantForceWR() const { return x1c_constantForce; }
  const zeus::CAxisAngle& GetAngularMomentumWR() const { return x28_angularMomentum; }
  const zeus::CVector3f& GetMomentumWR() const { return x34_momentum; }
  const zeus::CVector3f& GetForceWR() const { return x40_force; }
  const zeus::CVector3f& GetImpulseWR() const { return x4c_impulse; }
  const zeus::CAxisAngle& GetTorque() const { return x58_torque; }
  const zeus::CAxisAngle& GetAngularImpulseWR() const { return x64_angularImpulse; }
};

class CPhysicsActor : public CActor {
  friend class CGroundMovement;

protected:
  float xe8_mass;
  float xec_massRecip;
  float xf0_inertiaTensor;
  float xf4_inertiaTensorRecip;
  union {
    struct {
      bool xf8_24_movable : 1;
      bool xf8_25_angularEnabled : 1;
    };
    u8 _dummy = 0;
  };
  bool xf9_standardCollider = false;
  zeus::CVector3f xfc_constantForce;
  zeus::CAxisAngle x108_angularMomentum;
  zeus::CMatrix3f x114_;
  zeus::CVector3f x138_velocity;
  zeus::CAxisAngle x144_angularVelocity;
  zeus::CVector3f x150_momentum;
  zeus::CVector3f x15c_force;
  zeus::CVector3f x168_impulse;
  zeus::CAxisAngle x174_torque;
  zeus::CAxisAngle x180_angularImpulse;
  zeus::CVector3f x18c_moveImpulse;
  zeus::CAxisAngle x198_moveAngularImpulse;
  zeus::CAABox x1a4_baseBoundingBox;
  CCollidableAABox x1c0_collisionPrimitive;
  zeus::CVector3f x1e8_primitiveOffset;
  CMotionState x1f4_lastNonCollidingState;
  std::optional<zeus::CVector3f> x228_lastFloorPlaneNormal;
  float x238_maximumCollisionVelocity = 1000000.0f;
  float x23c_stepUpHeight;
  float x240_stepDownHeight;
  float x244_restitutionCoefModifier = 0.f;
  float x248_collisionAccuracyModifier = 1.f;
  u32 x24c_numTicksStuck = 0;
  u32 x250_numTicksPartialUpdate = 0;

public:
  CPhysicsActor(TUniqueId uid, bool active, std::string_view name, const CEntityInfo& info, const zeus::CTransform& xf,
                CModelData&& mData, const CMaterialList& matList, const zeus::CAABox& box, const SMoverData& moverData,
                const CActorParameters& actorParms, float stepUp, float stepDown);

  void Render(const CStateManager& mgr) const override;
  zeus::CVector3f GetOrbitPosition(const CStateManager& mgr) const override;
  zeus::CVector3f GetAimPosition(const CStateManager& mgr, float val) const override;
  virtual const CCollisionPrimitive* GetCollisionPrimitive() const;
  virtual zeus::CTransform GetPrimitiveTransform() const;
  virtual void CollidedWith(TUniqueId id, const CCollisionInfoList& list, CStateManager& mgr);
  virtual float GetStepUpHeight() const;
  virtual float GetStepDownHeight() const;
  virtual float GetWeight() const;

  float GetMass() const { return xe8_mass; }
  void SetPrimitiveOffset(const zeus::CVector2f& offset);
  const zeus::CVector3f& GetPrimitiveOffset() const { return x1e8_primitiveOffset; }
  void MoveCollisionPrimitive(const zeus::CVector3f& offset);
  void SetBoundingBox(const zeus::CAABox& box);
  zeus::CAABox GetMotionVolume(float dt) const;
  zeus::CVector3f CalculateNewVelocityWR_UsingImpulses() const;
  zeus::CAABox GetBoundingBox() const;
  const zeus::CAABox& GetBaseBoundingBox() const;
  void AddMotionState(const CMotionState& mst);
  CMotionState GetMotionState() const;
  const CMotionState& GetLastNonCollidingState() const { return x1f4_lastNonCollidingState; }
  void SetLastNonCollidingState(const CMotionState& mst) { x1f4_lastNonCollidingState = mst; }
  void SetMotionState(const CMotionState& mst);
  float GetMaximumCollisionVelocity() const { return x238_maximumCollisionVelocity; }
  void SetMaximumCollisionVelocity(float velocity) { x238_maximumCollisionVelocity = velocity; }
  void SetInertiaTensorScalar(float tensor);
  void SetMass(float mass);
  void SetAngularVelocityOR(const zeus::CAxisAngle& angVel);
  zeus::CAxisAngle GetAngularVelocityOR() const;
  const zeus::CAxisAngle& GetAngularVelocityWR() const { return x144_angularVelocity; }
  void SetAngularVelocityWR(const zeus::CAxisAngle& angVel);
  const zeus::CVector3f& GetForceOR() const { return x15c_force; }
  const zeus::CVector3f& GetImpulseOR() const { return x168_impulse; }
  const zeus::CVector3f& GetMoveImpulseOR() const { return x18c_moveImpulse; }
  void SetVelocityWR(const zeus::CVector3f& vel);
  void SetVelocityOR(const zeus::CVector3f& vel);
  void SetMomentumWR(const zeus::CVector3f& momentum) { x150_momentum = momentum; }
  const zeus::CVector3f& GetConstantForce() const { return xfc_constantForce; }
  void SetConstantForce(const zeus::CVector3f& force) { xfc_constantForce = force; }
  void SetAngularMomentum(const zeus::CAxisAngle& momentum) { x108_angularMomentum = momentum; }
  const zeus::CVector3f& GetMomentum() const { return x150_momentum; }
  const zeus::CVector3f& GetVelocity() const { return x138_velocity; }
  const zeus::CAxisAngle& GetAngularImpulse() const { return x180_angularImpulse; }
  void SetAngularImpulse(const zeus::CAxisAngle& impulse) { x180_angularImpulse = impulse; }
  zeus::CVector3f GetTotalForcesWR() const;
  void RotateInOneFrameOR(const zeus::CQuaternion& q, float d);
  void MoveInOneFrameOR(const zeus::CVector3f& trans, float d);
  void RotateToOR(const zeus::CQuaternion& q, float d);
  void MoveToOR(const zeus::CVector3f& trans, float d);
  void MoveToInOneFrameWR(const zeus::CVector3f& v1, float d);
  void MoveToWR(const zeus::CVector3f& trans, float d);
  zeus::CAxisAngle GetRotateToORAngularMomentumWR(const zeus::CQuaternion& q, float d) const;
  zeus::CVector3f GetMoveToORImpulseWR(const zeus::CVector3f& trans, float d) const;
  void ClearImpulses();
  void ClearForcesAndTorques();
  void Stop();
  void ComputeDerivedQuantities();
  bool WillMove(const CStateManager& mgr) const;
  void SetPhysicsState(const CPhysicsState& state);
  CPhysicsState GetPhysicsState() const;
  bool IsMovable() const { return xf8_24_movable; }
  void SetMovable(bool movable) { xf8_24_movable = movable; }
  bool IsAngularEnabled() const { return xf8_25_angularEnabled; }
  void SetAngularEnabled(bool enabled) { xf8_25_angularEnabled = enabled; }
  float GetCollisionAccuracyModifier() const { return x248_collisionAccuracyModifier; }
  void SetCollisionAccuracyModifier(float modifier) { x248_collisionAccuracyModifier = modifier; }
  float GetCoefficientOfRestitutionModifier() const { return x244_restitutionCoefModifier; }
  void SetCoefficientOfRestitutionModifier(float modifier) { x244_restitutionCoefModifier = modifier; }
  bool IsUseStandardCollider() const { return xf9_standardCollider; }
  u32 GetNumTicksPartialUpdate() const { return x250_numTicksPartialUpdate; }
  void SetNumTicksPartialUpdate(u32 ticks) { x250_numTicksPartialUpdate = ticks; }
  u32 GetNumTicksStuck() const { return x24c_numTicksStuck; }
  void SetNumTicksStuck(u32 ticks) { x24c_numTicksStuck = ticks; }
  const std::optional<zeus::CVector3f>& GetLastFloorPlaneNormal() const {
    return x228_lastFloorPlaneNormal;
  }
  void SetLastFloorPlaneNormal(const std::optional<zeus::CVector3f>& normal) { x228_lastFloorPlaneNormal = normal; }

  CMotionState PredictMotion_Internal(float) const;
  CMotionState PredictMotion(float dt) const;
  CMotionState PredictLinearMotion(float dt) const;
  CMotionState PredictAngularMotion(float dt) const;
  void ApplyForceOR(const zeus::CVector3f& force, const zeus::CAxisAngle& angle);
  void ApplyForceWR(const zeus::CVector3f& force, const zeus::CAxisAngle& angle);
  void ApplyImpulseOR(const zeus::CVector3f& impulse, const zeus::CAxisAngle& angle);
  void ApplyImpulseWR(const zeus::CVector3f& impulse, const zeus::CAxisAngle& angle);
  void ApplyTorqueWR(const zeus::CVector3f& torque);

  void UseCollisionImpulses();
  static constexpr float GravityConstant() { return 9.81f * 2.5f; } /* 9.81 m/s ^ 2 is normal acceleration under earth gravity, Tallon 4 is 2.5 times that */
};
} // namespace urde
<|endoftext|>


<commit_before><commit_msg>Add compact option<commit_after><|endoftext|>