/************************************************************************* * Copyright (C) 1995-2017, Rene Brun and Fons Rademakers. * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ #include "ROOT/RPadBase.hxx" #include "ROOT/RLogger.hxx" #include "ROOT/RPadExtent.hxx" #include "ROOT/RPadPos.hxx" #include #include #include #include #include using namespace std::string_literals; ROOT::Experimental::RPadBase::~RPadBase() = default; /////////////////////////////////////////////////////////////////////////// /// Use provided style for pad and all primitives inside void ROOT::Experimental::RPadBase::UseStyle(const std::shared_ptr &style) { RDrawable::UseStyle(style); for (auto &drawable : fPrimitives) drawable->UseStyle(style); } /////////////////////////////////////////////////////////////////////////// /// Find primitive with specified id std::shared_ptr ROOT::Experimental::RPadBase::FindPrimitive(const std::string &id) const { for (auto &drawable : fPrimitives) { if (drawable->GetId() == id) return drawable.get_shared(); const RPadBase *pad_draw = dynamic_cast (drawable.get()); if (pad_draw) { auto subelem = pad_draw->FindPrimitive(id); if (subelem) return subelem; } } return nullptr; } /////////////////////////////////////////////////////////////////////////// /// Find primitive with unique id, produce for RDisplayItem /// Such id used for client-server identification of objects std::shared_ptr ROOT::Experimental::RPadBase::FindPrimitiveByDisplayId(const std::string &id) const { auto p = id.find("_"); if (p == std::string::npos) return nullptr; auto prim = GetPrimitive(std::stoul(id.substr(0,p))); if (!prim) return nullptr; auto subid = id.substr(p+1); if (RDisplayItem::ObjectIDFromPtr(prim.get()) == subid) return prim; auto subpad = std::dynamic_pointer_cast(prim); return subpad ? subpad->FindPrimitiveByDisplayId(subid) : nullptr; } /////////////////////////////////////////////////////////////////////////// /// Find subpad which contains primitive with given display id const ROOT::Experimental::RPadBase *ROOT::Experimental::RPadBase::FindPadForPrimitiveWithDisplayId(const std::string &id) const { auto p = id.find("_"); if (p == std::string::npos) return nullptr; auto prim = GetPrimitive(std::stoul(id.substr(0,p))); if (!prim) return nullptr; auto subid = id.substr(p+1); if (RDisplayItem::ObjectIDFromPtr(prim.get()) == subid) return this; auto subpad = std::dynamic_pointer_cast(prim); return subpad ? subpad->FindPadForPrimitiveWithDisplayId(subid) : nullptr; } /////////////////////////////////////////////////////////////////////////// /// Method collect existing colors and assign new values if required void ROOT::Experimental::RPadBase::AssignAutoColors() { int cnt = 0; RColor col; for (auto &drawable : fPrimitives) { for (auto &attr: drawable->fAttr) { // only boolean attribute can return true if (!attr.second->GetBool()) continue; auto pos = attr.first.rfind("_color_auto"); if ((pos > 0) && (pos == attr.first.length() - 11)) { // FIXME: dummy code to assign autocolors, later should use RPalette switch (cnt++ % 3) { case 0: col = RColor::kRed; break; case 1: col = RColor::kGreen; break; case 2: col = RColor::kBlue; break; } drawable->fAttr.AddString(attr.first.substr(0,pos) + "_color_rgb", col.AsHex()); } } } } /////////////////////////////////////////////////////////////////////////// /// Create display items for all primitives in the pad /// Each display item gets its special id, which used later for client-server communication /// Second parameter is version id which already delivered to the client void ROOT::Experimental::RPadBase::DisplayPrimitives(RPadBaseDisplayItem &paditem, RDisplayContext &ctxt) { paditem.SetAttributes(&GetAttrMap()); paditem.SetPadStyle(fStyle.lock()); unsigned indx = 0; for (auto &drawable : fPrimitives) { ctxt.SetDrawable(drawable.get(), indx++); auto item = drawable->Display(ctxt); if (!item) item = std::make_unique(true); item->SetObjectIDAsPtr(drawable.get()); item->SetIndex(ctxt.GetIndex()); // add object with the style paditem.Add(std::move(item), drawable->fStyle.lock()); } } /////////////////////////////////////////////////////////////////////////// /// Divide pad on nHoriz X nVert subpads /// Return array of array of pads std::vector>> ROOT::Experimental::RPadBase::Divide(int nHoriz, int nVert, const RPadExtent &padding) { std::vector>> ret; if (!nHoriz) R__ERROR_HERE("Gpad") << "Cannot divide into 0 horizontal sub-pads!"; if (!nVert) R__ERROR_HERE("Gpad") << "Cannot divide into 0 vertical sub-pads!"; if (!nHoriz || !nVert) return ret; // Start with the whole (sub-)pad: RPadExtent offset{1._normal, 1._normal}; /// We need n Pads plus n-1 padding. Thus each `(subPadSize + padding)` is `(parentPadSize + padding) / n`. offset = (offset + padding); offset *= {1. / nHoriz, 1. / nVert}; const RPadExtent size = offset - padding; for (int iHoriz = 0; iHoriz < nHoriz; ++iHoriz) { ret.emplace_back(); for (int iVert = 0; iVert < nVert; ++iVert) { RPadPos subPos = offset; subPos *= {1. * iHoriz, 1. * iVert}; auto subpad = Draw(this, subPos, size); ret.back().emplace_back(subpad); // printf("Create subpad pos %5.2f %5.2f\n", subPos.fHoriz.fNormal.fVal, subPos.fVert.fNormal.fVal); } } return ret; } ///////////////////////////////////////////////////////////////////////////////////////////////// /// Get a frame object for the pad. /// If frame not exists - creates and add to the end of primitives list std::shared_ptr ROOT::Experimental::RPadBase::GetOrCreateFrame() { auto frame = GetFrame(); if (!frame) { frame.reset(new RFrame()); fPrimitives.emplace_back(frame); } return frame; } ///////////////////////////////////////////////////////////////////////////////////////////////// /// Get a frame object if exists const std::shared_ptr ROOT::Experimental::RPadBase::GetFrame() const { for (auto &drawable : fPrimitives) { if (drawable->GetCssType() == "frame") { const std::shared_ptr frame = std::dynamic_pointer_cast(drawable.get_shared()); if (frame) return frame; } } return nullptr; } ///////////////////////////////////////////////////////////////////////////////////////////////// /// Get a frame object if exists std::shared_ptr ROOT::Experimental::RPadBase::GetFrame() { for (auto &drawable : fPrimitives) { if (drawable->GetCssType() == "frame") { std::shared_ptr frame = std::dynamic_pointer_cast(drawable.get_shared()); if (frame) return frame; } } return nullptr; } ///////////////////////////////////////////////////////////////////////////////////////////////// /// Get a pad axis from the RFrame. /// \param dimension - Index of the dimension of the RFrame user coordinate system. ROOT::Experimental::RPadUserAxisBase* ROOT::Experimental::RPadBase::GetAxis(size_t dimension) const { auto frame = GetFrame(); if (frame && dimension < frame->GetNDimensions()) return &frame->GetUserAxis(dimension); return nullptr; } ///////////////////////////////////////////////////////////////////////////////////////////////// /// Get a pad axis from the RFrame. /// \param dimension - Index of the dimension of the RFrame user coordinate system. ROOT::Experimental::RPadUserAxisBase* ROOT::Experimental::RPadBase::GetOrCreateAxis(size_t dimension) { auto frame = GetOrCreateFrame(); frame->GrowToDimensions(dimension); return &frame->GetUserAxis(dimension); } ///////////////////////////////////////////////////////////////////////////////////////////////// /// Set the range of an axis as begin, end. void ROOT::Experimental::RPadBase::SetAxisBounds(int dimension, double begin, double end) { GetOrCreateFrame()->GrowToDimensions(dimension); GetAxis(dimension)->SetBounds(begin, end); } ///////////////////////////////////////////////////////////////////////////////////////////////// /// Set the range of an axis as bound kind and bound (up or down). void ROOT::Experimental::RPadBase::SetAxisBound(int dimension, RPadUserAxisBase::EAxisBoundsKind boundsKind, double bound) { GetOrCreateFrame()->GrowToDimensions(dimension); GetAxis(dimension)->SetBound(boundsKind, bound); } ///////////////////////////////////////////////////////////////////////////////////////////////// /// Set the range of an axis as bound kind and bound (up or down). void ROOT::Experimental::RPadBase::SetAxisAutoBounds(int dimension) { GetOrCreateFrame()->GrowToDimensions(dimension); GetAxis(dimension)->SetAutoBounds(); } ///////////////////////////////////////////////////////////////////////////////////////////////// /// Set the range of an axis as bound kind and bound (up or down). void ROOT::Experimental::RPadBase::SetAllAxisBounds(const std::vector> &vecBeginAndEnd) { auto frame = GetOrCreateFrame(); frame->GrowToDimensions(vecBeginAndEnd.size()); if (vecBeginAndEnd.size() != frame->GetNDimensions()) { R__ERROR_HERE("Gpadv7") << "Array of axis bound has wrong size " << vecBeginAndEnd.size() << " versus numer of axes in frame " << frame->GetNDimensions(); return; } for (size_t i = 0, n = frame->GetNDimensions(); i < n; ++i) frame->GetUserAxis(i).SetBounds(vecBeginAndEnd[i][0], vecBeginAndEnd[i][1]); } ///////////////////////////////////////////////////////////////////////////////////////////////// /// Set the range of an axis as bound kind and bound (up or down). void ROOT::Experimental::RPadBase::SetAllAxisBound(const std::vector &vecBoundAndKind) { auto frame = GetOrCreateFrame(); frame->GrowToDimensions(vecBoundAndKind.size()); if (vecBoundAndKind.size() != frame->GetNDimensions()) { R__ERROR_HERE("Gpadv7") << "Array of axis bound has wrong size " << vecBoundAndKind.size() << " versus numer of axes in frame " << frame->GetNDimensions(); return; } for (size_t i = 0, n = frame->GetNDimensions(); i < n; ++i) frame->GetUserAxis(i).SetBound(vecBoundAndKind[i].fKind, vecBoundAndKind[i].fBound); } ///////////////////////////////////////////////////////////////////////////////////////////////// /// Collect all shared items to resolve shared_ptr after IO void ROOT::Experimental::RPadBase::CollectShared(Internal::RIOSharedVector_t &vect) { for (auto &handle : fPrimitives) { vect.emplace_back(&handle); auto drawable = handle.get(); if (drawable) drawable->CollectShared(vect); } } ///////////////////////////////////////////////////////////////////////////////////////////////// /// Set the range of an axis as bound kind and bound (up or down). void ROOT::Experimental::RPadBase::SetAllAxisAutoBounds() { auto frame = GetOrCreateFrame(); for (size_t i = 0, n = frame->GetNDimensions(); i < n; ++i) frame->GetUserAxis(i).SetAutoBounds(); } ///////////////////////////////////////////////////////////////////////////////////////////////// /// Convert user coordinates to normal coordinates. std::array ROOT::Experimental::RPadBase::UserToNormal(const std::array &pos) const { auto frame = GetFrame(); if (!frame) return {}; return frame->UserToNormal(pos); } ///////////////////////////////////////////////////////////////////////////////////////////////// /// Assign drawable version - for pad itself and all primitives void ROOT::Experimental::RPadBase::SetDrawableVersion(Version_t vers) { RDrawable::SetDrawableVersion(vers); for (auto &drawable : fPrimitives) drawable->SetDrawableVersion(vers); }