seq_loc_mapper.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:62k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: seq_loc_mapper.cpp,v $
  4.  * PRODUCTION Revision 1000.1  2004/06/01 19:24:12  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.20
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: seq_loc_mapper.cpp,v 1000.1 2004/06/01 19:24:12 gouriano Exp $
  10. * ===========================================================================
  11. *
  12. *                            PUBLIC DOMAIN NOTICE
  13. *               National Center for Biotechnology Information
  14. *
  15. *  This software/database is a "United States Government Work" under the
  16. *  terms of the United States Copyright Act.  It was written as part of
  17. *  the author's official duties as a United States Government employee and
  18. *  thus cannot be copyrighted.  This software/database is freely available
  19. *  to the public for use. The National Library of Medicine and the U.S.
  20. *  Government have not placed any restriction on its use or reproduction.
  21. *
  22. *  Although all reasonable efforts have been taken to ensure the accuracy
  23. *  and reliability of the software and data, the NLM and the U.S.
  24. *  Government do not and cannot warrant the performance or results that
  25. *  may be obtained by using this software or data. The NLM and the U.S.
  26. *  Government disclaim all warranties, express or implied, including
  27. *  warranties of performance, merchantability or fitness for any particular
  28. *  purpose.
  29. *
  30. *  Please cite the author in any work or product based on this material.
  31. *
  32. * ===========================================================================
  33. *
  34. * Author: Aleksey Grichenko
  35. *
  36. * File Description:
  37. *   Seq-loc mapper
  38. *
  39. */
  40. #include <ncbi_pch.hpp>
  41. #include <objmgr/seq_loc_mapper.hpp>
  42. #include <objmgr/scope.hpp>
  43. #include <objmgr/objmgr_exception.hpp>
  44. #include <objmgr/seq_map.hpp>
  45. #include <objmgr/seq_map_ci.hpp>
  46. #include <objmgr/impl/synonyms.hpp>
  47. #include <objmgr/impl/seq_align_mapper.hpp>
  48. #include <objmgr/impl/seq_loc_cvt.hpp>
  49. #include <objects/seqloc/Seq_loc.hpp>
  50. #include <objects/seqfeat/Seq_feat.hpp>
  51. #include <objects/seqfeat/Cdregion.hpp>
  52. #include <objects/seqloc/Seq_loc_equiv.hpp>
  53. #include <objects/seqloc/Seq_bond.hpp>
  54. #include <objects/seqalign/seqalign__.hpp>
  55. #include <algorithm>
  56. BEGIN_NCBI_SCOPE
  57. BEGIN_SCOPE(objects)
  58. CMappingRange::CMappingRange(CSeq_id_Handle     src_id,
  59.                              TSeqPos            src_from,
  60.                              TSeqPos            src_length,
  61.                              ENa_strand         src_strand,
  62.                              CSeq_id_Handle     dst_id,
  63.                              TSeqPos            dst_from,
  64.                              ENa_strand         dst_strand)
  65.     : m_Src_id_Handle(src_id),
  66.       m_Src_from(src_from),
  67.       m_Src_to(src_from + src_length - 1),
  68.       m_Src_strand(src_strand),
  69.       m_Dst_id_Handle(dst_id),
  70.       m_Dst_from(dst_from),
  71.       m_Dst_strand(dst_strand),
  72.       m_Reverse(!SameOrientation(src_strand, dst_strand))
  73. {
  74.     return;
  75. }
  76. bool CMappingRange::CanMap(TSeqPos from,
  77.                            TSeqPos to,
  78.                            bool is_set_strand,
  79.                            ENa_strand strand) const
  80. {
  81.     if (from > m_Src_to || to < m_Src_from) {
  82.         return false;
  83.     }
  84.     return SameOrientation(is_set_strand ? strand : eNa_strand_unknown,
  85.         m_Src_strand)  ||  (m_Src_strand == eNa_strand_unknown);
  86. }
  87. TSeqPos CMappingRange::Map_Pos(TSeqPos pos) const
  88. {
  89.     _ASSERT(pos >= m_Src_from  &&  pos <= m_Src_to);
  90.     if (!m_Reverse) {
  91.         return m_Dst_from + pos - m_Src_from;
  92.     }
  93.     else {
  94.         return m_Dst_from + m_Src_to - pos;
  95.     }
  96. }
  97. CMappingRange::TRange CMappingRange::Map_Range(TSeqPos from, TSeqPos to) const
  98. {
  99.     if (!m_Reverse) {
  100.         return TRange(Map_Pos(max(from, m_Src_from)),
  101.             Map_Pos(min(to, m_Src_to)));
  102.     }
  103.     else {
  104.         return TRange(Map_Pos(min(to, m_Src_to)),
  105.             Map_Pos(max(from, m_Src_from)));
  106.     }
  107. }
  108. bool CMappingRange::Map_Strand(bool is_set_strand,
  109.                                ENa_strand src,
  110.                                ENa_strand* dst) const
  111. {
  112.     _ASSERT(dst);
  113.     if (is_set_strand) {
  114.         *dst = m_Reverse ? Reverse(src) : src;
  115.         return true;
  116.     }
  117.     if (m_Dst_strand != eNa_strand_unknown) {
  118.         // Destination strand may be set for nucleotides
  119.         // even if the source one is not set.
  120.         *dst = m_Dst_strand;
  121.         return true;
  122.     }
  123.     return false;
  124. }
  125. const CMappingRange::TFuzz kEmptyFuzz(0);
  126. CInt_fuzz::ELim CMappingRange::x_ReverseFuzzLim(CInt_fuzz::ELim lim) const
  127. {
  128.     switch ( lim ) {
  129.     case CInt_fuzz::eLim_gt:
  130.         return CInt_fuzz::eLim_lt;
  131.     case CInt_fuzz::eLim_lt:
  132.         return CInt_fuzz::eLim_gt;
  133.     case CInt_fuzz::eLim_tr:
  134.         return CInt_fuzz::eLim_tl;
  135.     case CInt_fuzz::eLim_tl:
  136.         return CInt_fuzz::eLim_tr;
  137.     default:
  138.         return lim;
  139.     }
  140. }
  141. CMappingRange::TRangeFuzz CMappingRange::Map_Fuzz(TRangeFuzz& fuzz) const
  142. {
  143.     // Maps some fuzz types to reverse strand
  144.     if ( !m_Reverse ) {
  145.         return fuzz;
  146.     }
  147.     TRangeFuzz res(fuzz.second, fuzz.first);
  148.     if ( res.first ) {
  149.         switch ( res.first->Which() ) {
  150.         case CInt_fuzz::e_Lim:
  151.             {
  152.                 res.first->SetLim(x_ReverseFuzzLim(res.first->GetLim()));
  153.                 break;
  154.             }
  155.         default:
  156.             // Other types are not converted
  157.             break;
  158.         }
  159.     }
  160.     if ( fuzz.second ) {
  161.         switch ( res.second->Which() ) {
  162.         case CInt_fuzz::e_Lim:
  163.             {
  164.                 res.second->SetLim(x_ReverseFuzzLim(res.second->GetLim()));
  165.                 break;
  166.             }
  167.         default:
  168.             // Other types are not converted
  169.             break;
  170.         }
  171.     }
  172.     return res;
  173. }
  174. CSeq_loc_Mapper::CSeq_loc_Mapper(const CSeq_feat&  map_feat,
  175.                                  EFeatMapDirection dir,
  176.                                  CScope*           scope)
  177.     : m_Scope(scope),
  178.       m_MergeFlag(eMergeNone),
  179.       m_GapFlag(eGapPreserve),
  180.       m_KeepNonmapping(false),
  181.       m_UseWidth(false),
  182.       m_Dst_width(0)
  183. {
  184.     _ASSERT(map_feat.IsSetProduct());
  185.     int frame = 0;
  186.     if (map_feat.GetData().IsCdregion()) {
  187.         frame = map_feat.GetData().GetCdregion().GetFrame();
  188.     }
  189.     if (dir == eLocationToProduct) {
  190.         x_Initialize(map_feat.GetLocation(), map_feat.GetProduct(), frame);
  191.     }
  192.     else {
  193.         x_Initialize(map_feat.GetProduct(), map_feat.GetLocation(), frame);
  194.     }
  195. }
  196. CSeq_loc_Mapper::CSeq_loc_Mapper(const CSeq_loc& source,
  197.                                  const CSeq_loc& target,
  198.                                  CScope* scope)
  199.     : m_Scope(scope),
  200.       m_MergeFlag(eMergeNone),
  201.       m_GapFlag(eGapPreserve),
  202.       m_KeepNonmapping(false),
  203.       m_UseWidth(false),
  204.       m_Dst_width(0)
  205. {
  206.     x_Initialize(source, target);
  207. }
  208. CSeq_loc_Mapper::CSeq_loc_Mapper(const CSeq_align& map_align,
  209.                                  const CSeq_id&    to_id,
  210.                                  CScope*           scope)
  211.     : m_Scope(scope),
  212.       m_MergeFlag(eMergeNone),
  213.       m_GapFlag(eGapPreserve),
  214.       m_KeepNonmapping(false),
  215.       m_UseWidth(false),
  216.       m_Dst_width(0)
  217. {
  218.     x_Initialize(map_align, to_id);
  219. }
  220. CSeq_loc_Mapper::CSeq_loc_Mapper(const CSeq_align& map_align,
  221.                                  size_t            to_row,
  222.                                  CScope*           scope)
  223.     : m_Scope(scope),
  224.       m_MergeFlag(eMergeNone),
  225.       m_GapFlag(eGapPreserve),
  226.       m_KeepNonmapping(false),
  227.       m_UseWidth(false),
  228.       m_Dst_width(0)
  229. {
  230.     x_Initialize(map_align, to_row);
  231. }
  232. CSeq_loc_Mapper::CSeq_loc_Mapper(CBioseq_Handle target_seq)
  233.     : m_Scope(&target_seq.GetScope()),
  234.       m_MergeFlag(eMergeNone),
  235.       m_GapFlag(eGapPreserve),
  236.       m_KeepNonmapping(false),
  237.       m_UseWidth(false),
  238.       m_Dst_width(0)
  239. {
  240.     CConstRef<CSeq_id> dst_id = target_seq.GetSeqId();
  241.     x_Initialize(target_seq.GetSeqMap(),
  242.         dst_id.GetPointerOrNull());
  243.     // Ignore seq-map destination ranges, map whole sequence to itself,
  244.     // use unknown strand only.
  245.     m_DstRanges.resize(1);
  246.     m_DstRanges[0].clear();
  247.     if (m_Scope) {
  248.         CConstRef<CSynonymsSet> dst_syns = m_Scope->GetSynonyms(*dst_id);
  249.         ITERATE(CSynonymsSet, dst_syn_it, *dst_syns) {
  250.             m_DstRanges[0][target_seq.GetSeq_id_Handle()]
  251.                 .push_back(TRange::GetWhole());
  252.         }
  253.     }
  254.     else {
  255.         m_DstRanges[0][target_seq.GetSeq_id_Handle()]
  256.             .push_back(TRange::GetWhole());
  257.     }
  258. }
  259. CSeq_loc_Mapper::CSeq_loc_Mapper(const CSeqMap& seq_map,
  260.                                  const CSeq_id* dst_id,
  261.                                  CScope*        scope)
  262.     : m_Scope(scope),
  263.       m_MergeFlag(eMergeNone),
  264.       m_GapFlag(eGapPreserve),
  265.       m_KeepNonmapping(false),
  266.       m_UseWidth(false),
  267.       m_Dst_width(0)
  268. {
  269.     x_Initialize(seq_map, dst_id);
  270. }
  271. CSeq_loc_Mapper::CSeq_loc_Mapper(size_t          depth,
  272.                                  CBioseq_Handle& source_seq)
  273.     : m_Scope(&source_seq.GetScope()),
  274.       m_MergeFlag(eMergeNone),
  275.       m_GapFlag(eGapPreserve),
  276.       m_KeepNonmapping(false),
  277.       m_UseWidth(false),
  278.       m_Dst_width(0)
  279. {
  280.     if (depth > 0) {
  281.         depth--;
  282.         x_Initialize(source_seq.GetSeqMap(),
  283.             depth, source_seq.GetSeqId().GetPointer());
  284.     }
  285.     else /* if (depth == 0) */ {
  286.         // Synonyms conversion
  287.         CConstRef<CSeq_id> dst_id = source_seq.GetSeqId();
  288.         m_DstRanges.resize(1);
  289.         if (m_Scope) {
  290.             CConstRef<CSynonymsSet> dst_syns = m_Scope->GetSynonyms(*dst_id);
  291.             ITERATE(CSynonymsSet, dst_syn_it, *dst_syns) {
  292.                 m_DstRanges[0][source_seq.GetSeq_id_Handle()]
  293.                     .push_back(TRange::GetWhole());
  294.             }
  295.         }
  296.         else {
  297.             m_DstRanges[0][source_seq.GetSeq_id_Handle()]
  298.                 .push_back(TRange::GetWhole());
  299.         }
  300.     }
  301. }
  302. CSeq_loc_Mapper::CSeq_loc_Mapper(size_t         depth,
  303.                                  const CSeqMap& source_seqmap,
  304.                                  const CSeq_id* src_id,
  305.                                  CScope*        scope)
  306.     : m_Scope(scope),
  307.       m_MergeFlag(eMergeNone),
  308.       m_GapFlag(eGapPreserve),
  309.       m_KeepNonmapping(false),
  310.       m_UseWidth(false),
  311.       m_Dst_width(0)
  312. {
  313.     if (depth > 0) {
  314.         depth--;
  315.         x_Initialize(source_seqmap, depth, src_id);
  316.     }
  317.     else /* if (depth == 0) */ {
  318.         // Synonyms conversion
  319.         m_DstRanges.resize(1);
  320.         if (bool(m_Scope)  &&  src_id) {
  321.             CSeq_id_Handle src_idh = CSeq_id_Handle::GetHandle(*src_id);
  322.             CConstRef<CSynonymsSet> dst_syns = m_Scope->GetSynonyms(*src_id);
  323.             ITERATE(CSynonymsSet, dst_syn_it, *dst_syns) {
  324.                 m_DstRanges[0][src_idh]
  325.                     .push_back(TRange::GetWhole());
  326.             }
  327.         }
  328.     }
  329. }
  330. CSeq_loc_Mapper::~CSeq_loc_Mapper(void)
  331. {
  332.     return;
  333. }
  334. void CSeq_loc_Mapper::PreserveDestinationLocs(void)
  335. {
  336.     for (size_t str_idx = 0; str_idx < m_DstRanges.size(); str_idx++) {
  337.         NON_CONST_ITERATE(TDstIdMap, id_it, m_DstRanges[str_idx]) {
  338.             id_it->second.sort();
  339.             TSeqPos dst_start = kInvalidSeqPos;
  340.             TSeqPos dst_stop = kInvalidSeqPos;
  341.             ITERATE(TDstRanges, rg_it, id_it->second) {
  342.                 // Collect and merge ranges
  343.                 if (dst_start == kInvalidSeqPos) {
  344.                     dst_start = rg_it->GetFrom();
  345.                     dst_stop = rg_it->GetTo();
  346.                     continue;
  347.                 }
  348.                 if (rg_it->GetFrom() <= dst_stop + 1) {
  349.                     // overlapping or abutting ranges, continue collecting
  350.                     dst_stop = max(dst_stop, rg_it->GetTo());
  351.                     continue;
  352.                 }
  353.                 // Separate ranges, add conversion and restart collecting
  354.                 CRef<CMappingRange> cvt(new CMappingRange(
  355.                     id_it->first, dst_start, dst_stop - dst_start + 1,
  356.                     ENa_strand(str_idx),
  357.                     id_it->first, dst_start, ENa_strand(str_idx)));
  358.                 m_IdMap[cvt->m_Src_id_Handle].insert(TRangeMap::value_type(
  359.                     TRange(cvt->m_Src_from, cvt->m_Src_to), cvt));
  360.             }
  361.             if (dst_start < dst_stop) {
  362.                 CRef<CMappingRange> cvt(new CMappingRange(
  363.                     id_it->first, dst_start, dst_stop - dst_start + 1,
  364.                     ENa_strand(str_idx),
  365.                     id_it->first, dst_start, ENa_strand(str_idx)));
  366.                 m_IdMap[cvt->m_Src_id_Handle].insert(TRangeMap::value_type(
  367.                     TRange(cvt->m_Src_from, cvt->m_Src_to), cvt));
  368.             }
  369.         }
  370.     }
  371.     m_DstRanges.clear();
  372. }
  373. CSeq_loc_Mapper::TMappedRanges&
  374. CSeq_loc_Mapper::x_GetMappedRanges(const CSeq_id_Handle& id,
  375.                                    int strand_idx) const
  376. {
  377.     TRangesByStrand& str_vec = m_MappedLocs[id];
  378.     if ((int)str_vec.size() <= strand_idx) {
  379.         str_vec.resize(strand_idx + 1);
  380.     }
  381.     return str_vec[strand_idx];
  382. }
  383. void CSeq_loc_Mapper::x_PushRangesToDstMix(void)
  384. {
  385.     if (m_MappedLocs.size() == 0) {
  386.         return;
  387.     }
  388.     // Push everything already mapped to the destination mix
  389.     CRef<CSeq_loc> loc = x_GetMappedSeq_loc();
  390.     if ( !m_Dst_loc ) {
  391.         m_Dst_loc = loc;
  392.         return;
  393.     }
  394.     if ( !loc->IsNull() ) {
  395.         x_PushLocToDstMix(loc);
  396.     }
  397. }
  398. int CSeq_loc_Mapper::x_CheckSeqWidth(const CSeq_id& id, int width)
  399. {
  400.     if (!m_Scope) {
  401.         return width;
  402.     }
  403.     CBioseq_Handle handle;
  404.     try {
  405.         handle = m_Scope->GetBioseqHandle(id);
  406.     } catch (...) {
  407.         return width;
  408.     }
  409.     if ( !handle ) {
  410.         return width;
  411.     }
  412.     switch ( handle.GetBioseqMolType() ) {
  413.     case CSeq_inst::eMol_dna:
  414.     case CSeq_inst::eMol_rna:
  415.     case CSeq_inst::eMol_na:
  416.         {
  417.             if ( width != 3 ) {
  418.                 if ( width ) {
  419.                     // width already set to a different value
  420.                     NCBI_THROW(CLocMapperException, eBadLocation,
  421.                                "Location contains different sequence types");
  422.                 }
  423.                 width = 3;
  424.             }
  425.             break;
  426.         }
  427.     case CSeq_inst::eMol_aa:
  428.         {
  429.             if ( width != 1 ) {
  430.                 if ( width ) {
  431.                     // width already set to a different value
  432.                     NCBI_THROW(CLocMapperException, eBadLocation,
  433.                                "Location contains different sequence types");
  434.                 }
  435.                 width = 1;
  436.             }
  437.             break;
  438.         }
  439.     default:
  440.         return width;
  441.     }
  442.     // Destination width should always be checked first
  443.     if ( !m_Dst_width ) {
  444.         m_Dst_width = width;
  445.     }
  446.     TWidthFlags wid_cvt = 0;
  447.     if (width == 1) {
  448.         wid_cvt |= fWidthProtToNuc;
  449.     }
  450.     if (m_Dst_width == 1) {
  451.         wid_cvt |= fWidthNucToProt;
  452.     }
  453.     CConstRef<CSynonymsSet> syns = m_Scope->GetSynonyms(id);
  454.     ITERATE(CSynonymsSet, syn_it, *syns) {
  455.         m_Widths[syns->GetSeq_id_Handle(syn_it)] = wid_cvt;
  456.     }
  457.     return width;
  458. }
  459. int CSeq_loc_Mapper::x_CheckSeqWidth(const CSeq_loc& loc,
  460.                                      TSeqPos* total_length)
  461. {
  462.     int width = 0;
  463.     *total_length = 0;
  464.     for (CSeq_loc_CI it(loc); it; ++it) {
  465.         *total_length += it.GetRange().GetLength();
  466.         if ( !m_Scope ) {
  467.             continue; // don't check sequence type;
  468.         }
  469.         width = x_CheckSeqWidth(it.GetSeq_id(), width);
  470.     }
  471.     return width;
  472. }
  473. TSeqPos CSeq_loc_Mapper::x_GetRangeLength(const CSeq_loc_CI& it)
  474. {
  475.     if (it.IsWhole()  &&  IsReverse(it.GetStrand())) {
  476.         // For reverse strand we need real interval length, not just "whole"
  477.         CBioseq_Handle h;
  478.         if (m_Scope) {
  479.             h = m_Scope->GetBioseqHandle(it.GetSeq_id());
  480.         }
  481.         if ( !h ) {
  482.             NCBI_THROW(CLocMapperException, eUnknownLength,
  483.                        "Can not map from minus strand -- "
  484.                        "unknown sequence length");
  485.         }
  486.         return h.GetBioseqLength();
  487.     }
  488.     else {
  489.         return it.GetRange().GetLength();
  490.     }
  491. }
  492. void CSeq_loc_Mapper::x_AddConversion(const CSeq_id& src_id,
  493.                                       TSeqPos        src_start,
  494.                                       ENa_strand     src_strand,
  495.                                       const CSeq_id& dst_id,
  496.                                       TSeqPos        dst_start,
  497.                                       ENa_strand     dst_strand,
  498.                                       TSeqPos        length)
  499. {
  500.     if (m_DstRanges.size() <= size_t(dst_strand)) {
  501.         m_DstRanges.resize(size_t(dst_strand) + 1);
  502.     }
  503.     if (m_Scope) {
  504.         CConstRef<CSynonymsSet> syns = m_Scope->GetSynonyms(src_id);
  505.         ITERATE(CSynonymsSet, syn_it, *syns) {
  506.             CRef<CMappingRange> cvt(new CMappingRange(
  507.                 CSynonymsSet::GetSeq_id_Handle(syn_it),
  508.                 src_start, length, src_strand,
  509.                 CSeq_id_Handle::GetHandle(dst_id), dst_start, dst_strand));
  510.             m_IdMap[cvt->m_Src_id_Handle].insert(TRangeMap::value_type(
  511.                 TRange(cvt->m_Src_from, cvt->m_Src_to), cvt));
  512.         }
  513.         CConstRef<CSynonymsSet> dst_syns = m_Scope->GetSynonyms(dst_id);
  514.         ITERATE(CSynonymsSet, dst_syn_it, *dst_syns) {
  515.             m_DstRanges[size_t(dst_strand)]
  516.                 [CSynonymsSet::GetSeq_id_Handle(dst_syn_it)]
  517.                 .push_back(TRange(dst_start, dst_start + length - 1));
  518.         }
  519.     }
  520.     else {
  521.         CRef<CMappingRange> cvt(new CMappingRange(
  522.             CSeq_id_Handle::GetHandle(src_id),
  523.             src_start, length, src_strand,
  524.             CSeq_id_Handle::GetHandle(dst_id), dst_start, dst_strand));
  525.         m_IdMap[cvt->m_Src_id_Handle].insert(TRangeMap::value_type(
  526.             TRange(cvt->m_Src_from, cvt->m_Src_to), cvt));
  527.         m_DstRanges[size_t(dst_strand)][CSeq_id_Handle::GetHandle(dst_id)]
  528.             .push_back(TRange(dst_start, dst_start + length - 1));
  529.     }
  530. }
  531. void CSeq_loc_Mapper::x_NextMappingRange(const CSeq_id& src_id,
  532.                                          TSeqPos&       src_start,
  533.                                          TSeqPos&       src_len,
  534.                                          ENa_strand     src_strand,
  535.                                          const CSeq_id& dst_id,
  536.                                          TSeqPos&       dst_start,
  537.                                          TSeqPos&       dst_len,
  538.                                          ENa_strand     dst_strand)
  539. {
  540.     TSeqPos cvt_src_start = src_start;
  541.     TSeqPos cvt_dst_start = dst_start;
  542.     TSeqPos cvt_length;
  543.     if (src_len == dst_len) {
  544.         cvt_length = src_len;
  545.         src_len = 0;
  546.         dst_len = 0;
  547.     }
  548.     else if (src_len > dst_len) {
  549.         // reverse interval for minus strand
  550.         if (IsReverse(src_strand)) {
  551.             cvt_src_start += src_len - dst_len;
  552.         }
  553.         else {
  554.             src_start += dst_len;
  555.         }
  556.         cvt_length = dst_len;
  557.         src_len -= cvt_length;
  558.         dst_len = 0;
  559.     }
  560.     else { // if (src_len < dst_len)
  561.         // reverse interval for minus strand
  562.         if ( IsReverse(dst_strand) ) {
  563.             cvt_dst_start += dst_len - src_len;
  564.         }
  565.         else {
  566.             dst_start += src_len;
  567.         }
  568.         cvt_length = src_len;
  569.         dst_len -= cvt_length;
  570.         src_len = 0;
  571.     }
  572.     x_AddConversion(
  573.         src_id, cvt_src_start, src_strand,
  574.         dst_id, cvt_dst_start, dst_strand,
  575.         cvt_length);
  576. }
  577. void CSeq_loc_Mapper::x_Initialize(const CSeq_loc& source,
  578.                                    const CSeq_loc& target,
  579.                                    int             frame)
  580. {
  581.     // Check sequence type or total location length to
  582.     // adjust intervals according to character width.
  583.     TSeqPos dst_total_len;
  584.     x_CheckSeqWidth(target, &dst_total_len);
  585.     TSeqPos src_total_len;
  586.     int src_width = x_CheckSeqWidth(source, &src_total_len);
  587.     if (!src_width  ||  !m_Dst_width) {
  588.         // Try to detect types by lengths
  589.         if (src_total_len == kInvalidSeqPos || dst_total_len== kInvalidSeqPos) {
  590.             NCBI_THROW(CLocMapperException, eBadLocation,
  591.                        "Undefined location length -- "
  592.                        "unable to detect sequence type");
  593.         }
  594.         if (src_total_len == dst_total_len) {
  595.             src_width = 1;
  596.             m_Dst_width = 1;
  597.             _ASSERT(!frame);
  598.         }
  599.         // truncate incomplete left and right codons
  600.         else if (src_total_len/3 == dst_total_len) {
  601.             src_width = 3;
  602.             m_Dst_width = 1;
  603.         }
  604.         else if (dst_total_len/3 == src_total_len) {
  605.             src_width = 1;
  606.             m_Dst_width = 3;
  607.         }
  608.         else {
  609.             NCBI_THROW(CAnnotException, eBadLocation,
  610.                        "Wrong location length -- "
  611.                        "unable to detect sequence type");
  612.         }
  613.     }
  614.     else {
  615.         if (src_width == m_Dst_width) {
  616.             src_width = 1;
  617.             m_Dst_width = 1;
  618.             _ASSERT(!frame);
  619.         }
  620.     }
  621.     m_UseWidth |= (src_width != m_Dst_width);
  622.     // Create conversions
  623.     CSeq_loc_CI src_it(source);
  624.     CSeq_loc_CI dst_it(target);
  625.     TSeqPos src_start = src_it.GetRange().GetFrom()*m_Dst_width;
  626.     TSeqPos src_len = x_GetRangeLength(src_it)*m_Dst_width;
  627.     TSeqPos dst_start = dst_it.GetRange().GetFrom()*src_width;
  628.     TSeqPos dst_len = x_GetRangeLength(dst_it)*src_width;
  629.     if ( frame ) {
  630.         // ignore pre-frame range
  631.         if (src_width == 3) {
  632.             src_start += frame - 1;
  633.         }
  634.         if (m_Dst_width == 3) {
  635.             dst_start += frame - 1;
  636.         }
  637.     }
  638.     while (src_it  &&  dst_it) {
  639.         x_NextMappingRange(
  640.             src_it.GetSeq_id(), src_start, src_len, src_it.GetStrand(),
  641.             dst_it.GetSeq_id(), dst_start, dst_len, dst_it.GetStrand());
  642.         if (src_len == 0  &&  ++src_it) {
  643.             src_start = src_it.GetRange().GetFrom()*m_Dst_width;
  644.             src_len = x_GetRangeLength(src_it)*m_Dst_width;
  645.         }
  646.         if (dst_len == 0  &&  ++dst_it) {
  647.             dst_start = dst_it.GetRange().GetFrom()*src_width;
  648.             dst_len = x_GetRangeLength(dst_it)*src_width;
  649.         }
  650.     }
  651. }
  652. void CSeq_loc_Mapper::x_Initialize(const CSeq_align& map_align,
  653.                                    const CSeq_id&    to_id)
  654. {
  655.     switch ( map_align.GetSegs().Which() ) {
  656.     case CSeq_align::C_Segs::e_Dendiag:
  657.         {
  658.             const TDendiag& diags = map_align.GetSegs().GetDendiag();
  659.             ITERATE(TDendiag, diag_it, diags) {
  660.                 size_t to_row = size_t(-1);
  661.                 for (size_t i = 0; i < (*diag_it)->GetIds().size(); ++i) {
  662.                     // find the first row with required ID
  663.                     // ??? check if there are multiple rows with the same ID?
  664.                     if ( (*diag_it)->GetIds()[i]->Equals(to_id) ) {
  665.                         to_row = i;
  666.                         break;
  667.                     }
  668.                 }
  669.                 if (to_row == size_t(-1)) {
  670.                     NCBI_THROW(CLocMapperException, eBadAlignment,
  671.                                "Target ID not found in the alignment");
  672.                 }
  673.                 x_InitAlign(**diag_it, to_row);
  674.             }
  675.             break;
  676.         }
  677.     case CSeq_align::C_Segs::e_Denseg:
  678.         {
  679.             const CDense_seg& dseg = map_align.GetSegs().GetDenseg();
  680.             size_t to_row = size_t(-1);
  681.             for (size_t i = 0; i < dseg.GetIds().size(); ++i) {
  682.                 if (dseg.GetIds()[i]->Equals(to_id)) {
  683.                     to_row = i;
  684.                     break;
  685.                 }
  686.             }
  687.             if (to_row == size_t(-1)) {
  688.                 NCBI_THROW(CLocMapperException, eBadAlignment,
  689.                            "Target ID not found in the alignment");
  690.             }
  691.             x_InitAlign(dseg, to_row);
  692.             break;
  693.         }
  694.     case CSeq_align::C_Segs::e_Std:
  695.         {
  696.             const TStd& std_segs = map_align.GetSegs().GetStd();
  697.             ITERATE(TStd, std_seg, std_segs) {
  698.                 size_t to_row = size_t(-1);
  699.                 for (size_t i = 0; i < (*std_seg)->GetIds().size(); ++i) {
  700.                     if ((*std_seg)->GetIds()[i]->Equals(to_id)) {
  701.                         to_row = i;
  702.                         break;
  703.                     }
  704.                 }
  705.                 if (to_row == size_t(-1)) {
  706.                     NCBI_THROW(CLocMapperException, eBadAlignment,
  707.                                "Target ID not found in the alignment");
  708.                 }
  709.                 x_InitAlign(**std_seg, to_row);
  710.             }
  711.             break;
  712.         }
  713.     case CSeq_align::C_Segs::e_Packed:
  714.         {
  715.             const CPacked_seg& pseg = map_align.GetSegs().GetPacked();
  716.             size_t to_row = size_t(-1);
  717.             for (size_t i = 0; i < pseg.GetIds().size(); ++i) {
  718.                 if (pseg.GetIds()[i]->Equals(to_id)) {
  719.                     to_row = i;
  720.                     break;
  721.                 }
  722.             }
  723.             if (to_row == size_t(-1)) {
  724.                 NCBI_THROW(CLocMapperException, eBadAlignment,
  725.                            "Target ID not found in the alignment");
  726.             }
  727.             x_InitAlign(pseg, to_row);
  728.             break;
  729.         }
  730.     case CSeq_align::C_Segs::e_Disc:
  731.         {
  732.             const CSeq_align_set& aln_set = map_align.GetSegs().GetDisc();
  733.             ITERATE(CSeq_align_set::Tdata, aln, aln_set.Get()) {
  734.                 x_Initialize(**aln, to_id);
  735.             }
  736.             break;
  737.         }
  738.     default:
  739.         NCBI_THROW(CLocMapperException, eBadAlignment,
  740.                    "Unsupported alignment type");
  741.     }
  742. }
  743. void CSeq_loc_Mapper::x_Initialize(const CSeq_align& map_align,
  744.                                    size_t            to_row)
  745. {
  746.     switch ( map_align.GetSegs().Which() ) {
  747.     case CSeq_align::C_Segs::e_Dendiag:
  748.         {
  749.             const TDendiag& diags = map_align.GetSegs().GetDendiag();
  750.             ITERATE(TDendiag, diag_it, diags) {
  751.                 x_InitAlign(**diag_it, to_row);
  752.             }
  753.             break;
  754.         }
  755.     case CSeq_align::C_Segs::e_Denseg:
  756.         {
  757.             const CDense_seg& dseg = map_align.GetSegs().GetDenseg();
  758.             x_InitAlign(dseg, to_row);
  759.             break;
  760.         }
  761.     case CSeq_align::C_Segs::e_Std:
  762.         {
  763.             const TStd& std_segs = map_align.GetSegs().GetStd();
  764.             ITERATE(TStd, std_seg, std_segs) {
  765.                 x_InitAlign(**std_seg, to_row);
  766.             }
  767.             break;
  768.         }
  769.     case CSeq_align::C_Segs::e_Packed:
  770.         {
  771.             const CPacked_seg& pseg = map_align.GetSegs().GetPacked();
  772.             x_InitAlign(pseg, to_row);
  773.             break;
  774.         }
  775.     case CSeq_align::C_Segs::e_Disc:
  776.         {
  777.             // The same row in each sub-alignment?
  778.             const CSeq_align_set& aln_set = map_align.GetSegs().GetDisc();
  779.             ITERATE(CSeq_align_set::Tdata, aln, aln_set.Get()) {
  780.                 x_Initialize(**aln, to_row);
  781.             }
  782.             break;
  783.         }
  784.     default:
  785.         NCBI_THROW(CLocMapperException, eBadAlignment,
  786.                    "Unsupported alignment type");
  787.     }
  788. }
  789. void CSeq_loc_Mapper::x_InitAlign(const CDense_diag& diag, size_t to_row)
  790. {
  791.     if (diag.GetStarts()[to_row] < 0) {
  792.         // Destination ID is not present in this dense-diag
  793.         return;
  794.     }
  795.     size_t dim = diag.GetDim();
  796.     _ASSERT(to_row < dim);
  797.     if (dim != diag.GetIds().size()) {
  798.         ERR_POST(Warning << "Invalid 'ids' size in dendiag");
  799.         dim = min(dim, diag.GetIds().size());
  800.     }
  801.     if (dim != diag.GetStarts().size()) {
  802.         ERR_POST(Warning << "Invalid 'starts' size in dendiag");
  803.         dim = min(dim, diag.GetStarts().size());
  804.     }
  805.     bool have_strands = diag.IsSetStrands();
  806.     if (have_strands && dim != diag.GetStrands().size()) {
  807.         ERR_POST(Warning << "Invalid 'strands' size in dendiag");
  808.         dim = min(dim, diag.GetStrands().size());
  809.     }
  810.     ENa_strand dst_strand = have_strands ?
  811.         diag.GetStrands()[to_row] : eNa_strand_unknown;
  812.     const CSeq_id& dst_id = *diag.GetIds()[to_row];
  813.     if (!m_Dst_width) {
  814.         m_Dst_width = x_CheckSeqWidth(dst_id, m_Dst_width);
  815.     }
  816.     for (size_t row = 0; row < dim; ++row) {
  817.         if (row == to_row) {
  818.             continue;
  819.         }
  820.         if (diag.GetStarts()[row] < 0) {
  821.             continue;
  822.         }
  823.         // In alignments with multiple sequence types segment length
  824.         // should be multiplied by character width.
  825.         int src_width = 0;
  826.         const CSeq_id& src_id = *diag.GetIds()[row];
  827.         src_width = x_CheckSeqWidth(src_id, src_width);
  828.         m_UseWidth |= (src_width != m_Dst_width);
  829.         int dst_width_rel = (m_UseWidth) ? 1 : m_Dst_width;
  830.         int src_width_rel = (m_UseWidth) ? 1 : src_width;
  831.         TSeqPos src_start = diag.GetStarts()[row]*dst_width_rel;
  832.         TSeqPos src_len = diag.GetLen()*src_width*dst_width_rel;
  833.         TSeqPos dst_start = diag.GetStarts()[to_row]*src_width_rel;
  834.         TSeqPos dst_len = diag.GetLen()*m_Dst_width*src_width_rel;
  835.         ENa_strand src_strand = have_strands ?
  836.             diag.GetStrands()[row] : eNa_strand_unknown;
  837.         x_NextMappingRange(
  838.             src_id, src_start, src_len, src_strand,
  839.             dst_id, dst_start, dst_len, dst_strand);
  840.         _ASSERT(!src_len  &&  !dst_len);
  841.     }
  842. }
  843. void CSeq_loc_Mapper::x_InitAlign(const CDense_seg& denseg, size_t to_row)
  844. {
  845.     size_t dim = denseg.GetDim();
  846.     _ASSERT(to_row < dim);
  847.     size_t numseg = denseg.GetNumseg();
  848.     // claimed dimension may not be accurate :-/
  849.     if (numseg != denseg.GetLens().size()) {
  850.         ERR_POST(Warning << "Invalid 'lens' size in denseg");
  851.         numseg = min(numseg, denseg.GetLens().size());
  852.     }
  853.     if (dim != denseg.GetIds().size()) {
  854.         ERR_POST(Warning << "Invalid 'ids' size in denseg");
  855.         dim = min(dim, denseg.GetIds().size());
  856.     }
  857.     if (dim*numseg != denseg.GetStarts().size()) {
  858.         ERR_POST(Warning << "Invalid 'starts' size in denseg");
  859.         dim = min(dim*numseg, denseg.GetStarts().size()) / numseg;
  860.     }
  861.     bool have_strands = denseg.IsSetStrands();
  862.     if (have_strands && dim*numseg != denseg.GetStrands().size()) {
  863.         ERR_POST(Warning << "Invalid 'strands' size in denseg");
  864.         dim = min(dim*numseg, denseg.GetStrands().size()) / numseg;
  865.     }
  866.     const CSeq_id& dst_id = *denseg.GetIds()[to_row];
  867.     if (!m_Dst_width) {
  868.         if ( denseg.IsSetWidths() ) {
  869.             m_Dst_width = denseg.GetWidths()[to_row];
  870.         }
  871.         else {
  872.             m_Dst_width = x_CheckSeqWidth(dst_id, m_Dst_width);
  873.         }
  874.     }
  875.     for (size_t row = 0; row < dim; ++row) {
  876.         if (row == to_row) {
  877.             continue;
  878.         }
  879.         const CSeq_id& src_id = *denseg.GetIds()[row];
  880.         int src_width = 0;
  881.         if ( denseg.IsSetWidths() ) {
  882.             src_width = denseg.GetWidths()[row];
  883.         }
  884.         else {
  885.             src_width = x_CheckSeqWidth(src_id, src_width);
  886.         }
  887.         m_UseWidth |= (src_width != m_Dst_width);
  888.         int dst_width_rel = (m_UseWidth) ? 1 : m_Dst_width;
  889.         int src_width_rel = (m_UseWidth) ? 1 : src_width;
  890.         for (size_t seg = 0; seg < numseg; ++seg) {
  891.             int i_src_start = denseg.GetStarts()[seg*dim + row];
  892.             int i_dst_start = denseg.GetStarts()[seg*dim + to_row];
  893.             if (i_src_start < 0  ||  i_dst_start < 0) {
  894.                 continue;
  895.             }
  896.             ENa_strand dst_strand = have_strands ?
  897.                 denseg.GetStrands()[seg*dim + to_row] : eNa_strand_unknown;
  898.             ENa_strand src_strand = have_strands ?
  899.                 denseg.GetStrands()[seg*dim + row] : eNa_strand_unknown;
  900.             // In alignments with multiple sequence types segment length
  901.             // should be multiplied by character width.
  902.             TSeqPos src_len = denseg.GetLens()[seg]*src_width*dst_width_rel;
  903.             TSeqPos dst_len = denseg.GetLens()[seg]*m_Dst_width*src_width_rel;
  904.             TSeqPos src_start = (TSeqPos)(i_src_start)*dst_width_rel;
  905.             TSeqPos dst_start = (TSeqPos)(i_dst_start)*src_width_rel;
  906.             x_NextMappingRange(
  907.                 src_id, src_start, src_len, src_strand,
  908.                 dst_id, dst_start, dst_len, dst_strand);
  909.             _ASSERT(!src_len  &&  !dst_len);
  910.         }
  911.     }
  912. }
  913. void CSeq_loc_Mapper::x_InitAlign(const CStd_seg& sseg, size_t to_row)
  914. {
  915.     size_t dim = sseg.GetDim();
  916.     if (dim != sseg.GetLoc().size()) {
  917.         ERR_POST(Warning << "Invalid 'loc' size in std-seg");
  918.         dim = min(dim, sseg.GetLoc().size());
  919.     }
  920.     if (sseg.IsSetIds()
  921.         && dim != sseg.GetIds().size()) {
  922.         ERR_POST(Warning << "Invalid 'ids' size in std-seg");
  923.         dim = min(dim, sseg.GetIds().size());
  924.     }
  925.     const CSeq_loc& dst_loc = *sseg.GetLoc()[to_row];
  926.     for (size_t row = 0; row < dim; ++row ) {
  927.         if (row == to_row) {
  928.             continue;
  929.         }
  930.         const CSeq_loc& src_loc = *sseg.GetLoc()[row];
  931.         if ( src_loc.IsEmpty() ) {
  932.             // skipped row in this segment
  933.             continue;
  934.         }
  935.         x_Initialize(src_loc, dst_loc);
  936.     }
  937. }
  938. void CSeq_loc_Mapper::x_InitAlign(const CPacked_seg& pseg, size_t to_row)
  939. {
  940.     size_t dim    = pseg.GetDim();
  941.     size_t numseg = pseg.GetNumseg();
  942.     // claimed dimension may not be accurate :-/
  943.     if (numseg != pseg.GetLens().size()) {
  944.         ERR_POST(Warning << "Invalid 'lens' size in packed-seg");
  945.         numseg = min(numseg, pseg.GetLens().size());
  946.     }
  947.     if (dim != pseg.GetIds().size()) {
  948.         ERR_POST(Warning << "Invalid 'ids' size in packed-seg");
  949.         dim = min(dim, pseg.GetIds().size());
  950.     }
  951.     if (dim*numseg != pseg.GetStarts().size()) {
  952.         ERR_POST(Warning << "Invalid 'starts' size in packed-seg");
  953.         dim = min(dim*numseg, pseg.GetStarts().size()) / numseg;
  954.     }
  955.     bool have_strands = pseg.IsSetStrands();
  956.     if (have_strands && dim*numseg != pseg.GetStrands().size()) {
  957.         ERR_POST(Warning << "Invalid 'strands' size in packed-seg");
  958.         dim = min(dim*numseg, pseg.GetStrands().size()) / numseg;
  959.     }
  960.     const CSeq_id& dst_id = *pseg.GetIds()[to_row];
  961.     if (!m_Dst_width) {
  962.         m_Dst_width = x_CheckSeqWidth(dst_id, m_Dst_width);
  963.     }
  964.     for (size_t row = 0; row < dim; ++row) {
  965.         if (row == to_row) {
  966.             continue;
  967.         }
  968.         const CSeq_id& src_id = *pseg.GetIds()[row];
  969.         int src_width = 0;
  970.         src_width = x_CheckSeqWidth(src_id, src_width);
  971.         m_UseWidth |= (src_width != m_Dst_width);
  972.         int dst_width_rel = (m_UseWidth) ? 1 : m_Dst_width;
  973.         int src_width_rel = (m_UseWidth) ? 1 : src_width;
  974.         for (size_t seg = 0; seg < numseg; ++seg) {
  975.             if (!pseg.GetPresent()[row]  ||  !pseg.GetPresent()[to_row]) {
  976.                 continue;
  977.             }
  978.             ENa_strand dst_strand = have_strands ?
  979.                 pseg.GetStrands()[seg*dim + to_row] : eNa_strand_unknown;
  980.             ENa_strand src_strand = have_strands ?
  981.                 pseg.GetStrands()[seg*dim + row] : eNa_strand_unknown;
  982.             // In alignments with multiple sequence types segment length
  983.             // should be multiplied by character width.
  984.             TSeqPos src_len = pseg.GetLens()[seg]*src_width*dst_width_rel;
  985.             TSeqPos dst_len = pseg.GetLens()[seg]*m_Dst_width*src_width_rel;
  986.             TSeqPos src_start = pseg.GetStarts()[seg*dim + row]*dst_width_rel;
  987.             TSeqPos dst_start = pseg.GetStarts()[seg*dim + to_row]*src_width_rel;
  988.             x_NextMappingRange(
  989.                 src_id, src_start, src_len, src_strand,
  990.                 dst_id, dst_start, dst_len, dst_strand);
  991.             _ASSERT(!src_len  &&  !dst_len);
  992.         }
  993.     }
  994. }
  995. void CSeq_loc_Mapper::x_Initialize(const CSeqMap& seq_map,
  996.                                    const CSeq_id* top_id)
  997. {
  998.     CSeqMap::const_iterator seg_it =
  999.         seq_map.begin_resolved(m_Scope.GetPointerOrNull(), size_t(-1),
  1000.         CSeqMap::fFindRef);
  1001.     TSeqPos top_start = kInvalidSeqPos;
  1002.     TSeqPos top_stop = kInvalidSeqPos;
  1003.     TSeqPos dst_seg_start = kInvalidSeqPos;
  1004.     CConstRef<CSeq_id> dst_id;
  1005.     for ( ; seg_it; ++seg_it) {
  1006.         _ASSERT(seg_it.GetType() == CSeqMap::eSeqRef);
  1007.         if (seg_it.GetPosition() > top_stop  ||  !dst_id) {
  1008.             // New top-level segment
  1009.             top_start = seg_it.GetPosition();
  1010.             top_stop = seg_it.GetEndPosition() - 1;
  1011.             if (top_id) {
  1012.                 // Top level is a bioseq
  1013.                 dst_id.Reset(top_id);
  1014.                 dst_seg_start = top_start;
  1015.             }
  1016.             else {
  1017.                 // Top level is a seq-loc, positions are
  1018.                 // on the first-level references
  1019.                 dst_id = seg_it.GetRefSeqid().GetSeqId();
  1020.                 dst_seg_start = seg_it.GetRefPosition();
  1021.                 continue;
  1022.             }
  1023.         }
  1024.         // when top_id is set, destination position = GetPosition(),
  1025.         // else it needs to be calculated from top_start/stop and dst_start/stop.
  1026.         TSeqPos dst_from = dst_seg_start + seg_it.GetPosition() - top_start;
  1027.         _ASSERT(dst_from >= dst_seg_start);
  1028.         TSeqPos dst_len = seg_it.GetLength();
  1029.         CConstRef<CSeq_id> src_id(seg_it.GetRefSeqid().GetSeqId());
  1030.         TSeqPos src_from = seg_it.GetRefPosition();
  1031.         TSeqPos src_len = dst_len;
  1032.         ENa_strand src_strand = seg_it.GetRefMinusStrand() ?
  1033.             eNa_strand_minus : eNa_strand_unknown;
  1034.         x_NextMappingRange(*src_id, src_from, src_len, src_strand,
  1035.             *dst_id, dst_from, dst_len, eNa_strand_unknown);
  1036.         _ASSERT(src_len == 0  &&  dst_len == 0);
  1037.     }
  1038. }
  1039. void CSeq_loc_Mapper::x_Initialize(const CSeqMap& seq_map,
  1040.                                    size_t         depth,
  1041.                                    const CSeq_id* top_id)
  1042. {
  1043.     CSeqMap::const_iterator seg_it =
  1044.         seq_map.begin_resolved(m_Scope.GetPointerOrNull(), depth,
  1045.         CSeqMap::fFindRef);
  1046.     TSeqPos top_start = kInvalidSeqPos;
  1047.     TSeqPos top_stop = kInvalidSeqPos;
  1048.     TSeqPos src_seg_start = kInvalidSeqPos;
  1049.     TSeqPos last_stop = kInvalidSeqPos;
  1050.     CConstRef<CSeq_id> src_id;
  1051.     TSeqPos src_from = 0;
  1052.     TSeqPos src_len = 0;
  1053.     TSeqPos dst_from = 0;
  1054.     TSeqPos dst_len = 0;
  1055.     CConstRef<CSeq_id> dst_id;
  1056.     ENa_strand dst_strand = eNa_strand_unknown;
  1057.     for ( ; seg_it; ++seg_it) {
  1058.         _ASSERT(seg_it.GetType() == CSeqMap::eSeqRef);
  1059.         if (seg_it.GetPosition() > top_stop  ||  !src_id) {
  1060.             // New top-level segment
  1061.             top_start = seg_it.GetPosition();
  1062.             top_stop = seg_it.GetEndPosition() - 1;
  1063.             if (top_id) {
  1064.                 // Top level is a bioseq
  1065.                 src_id.Reset(top_id);
  1066.                 src_seg_start = top_start;
  1067.             }
  1068.             else {
  1069.                 // Top level is a seq-loc, positions are
  1070.                 // on the first-level references
  1071.                 src_id = seg_it.GetRefSeqid().GetSeqId();
  1072.                 src_seg_start = seg_it.GetRefPosition();
  1073.                 continue;
  1074.             }
  1075.         }
  1076.         if (seg_it.GetPosition() >= last_stop) {
  1077.             x_NextMappingRange(*src_id, src_from, src_len, eNa_strand_unknown,
  1078.                 *dst_id, dst_from, dst_len, dst_strand);
  1079.             _ASSERT(src_len == 0  &&  dst_len == 0);
  1080.         }
  1081.         src_from = src_seg_start + seg_it.GetPosition() - top_start;
  1082.         src_len = seg_it.GetLength();
  1083.         dst_from = seg_it.GetRefPosition();
  1084.         dst_len = src_len;
  1085.         dst_id.Reset(seg_it.GetRefSeqid().GetSeqId());
  1086.         dst_strand = seg_it.GetRefMinusStrand() ?
  1087.             eNa_strand_minus : eNa_strand_unknown;
  1088.         last_stop = seg_it.GetEndPosition();
  1089.     }
  1090.     if (src_len > 0) {
  1091.         x_NextMappingRange(*src_id, src_from, src_len, eNa_strand_unknown,
  1092.             *dst_id, dst_from, dst_len, dst_strand);
  1093.     }
  1094. }
  1095. CSeq_loc_Mapper::TRangeIterator
  1096. CSeq_loc_Mapper::x_BeginMappingRanges(CSeq_id_Handle id,
  1097.                                       TSeqPos from,
  1098.                                       TSeqPos to)
  1099. {
  1100.     TIdMap::iterator ranges = m_IdMap.find(id);
  1101.     if (ranges == m_IdMap.end()) {
  1102.         return TRangeIterator();
  1103.     }
  1104.     return ranges->second.begin(TRange(from, to));
  1105. }
  1106. bool CSeq_loc_Mapper::x_MapInterval(const CSeq_id&   src_id,
  1107.                                     TRange           src_rg,
  1108.                                     bool             is_set_strand,
  1109.                                     ENa_strand       src_strand,
  1110.                                     TRangeFuzz       orig_fuzz)
  1111. {
  1112.     bool res = false;
  1113.     if (m_UseWidth  &&
  1114.         m_Widths[CSeq_id_Handle::GetHandle(src_id)] & fWidthProtToNuc) {
  1115.         src_rg = TRange(src_rg.GetFrom()*3, src_rg.GetTo()*3 + 2);
  1116.     }
  1117.     CSeq_id_Handle src_idh = CSeq_id_Handle::GetHandle(src_id);
  1118.     // Sorted mapping ranges
  1119.     typedef vector< CRef<CMappingRange> > TSortedMappings;
  1120.     TSortedMappings mappings;
  1121.     TRangeIterator rg_it = x_BeginMappingRanges(
  1122.         src_idh, src_rg.GetFrom(), src_rg.GetTo());
  1123.     for ( ; rg_it; ++rg_it) {
  1124.         mappings.push_back(rg_it->second);
  1125.     }
  1126.     sort(mappings.begin(), mappings.end(), CMappingRangeRef_Less());
  1127.     TSeqPos last_src_to = 0;
  1128.     for (size_t idx = 0; idx < mappings.size(); ++idx) {
  1129.         const CMappingRange& cvt = *mappings[idx];
  1130.         if ( !cvt.CanMap(src_rg.GetFrom(), src_rg.GetTo(),
  1131.             is_set_strand, src_strand) ) {
  1132.             continue;
  1133.         }
  1134.         TSeqPos from = src_rg.GetFrom();
  1135.         TSeqPos to = src_rg.GetTo();
  1136.         TRangeFuzz fuzz = cvt.Map_Fuzz(orig_fuzz);
  1137.         if (from < cvt.m_Src_from) {
  1138.             from = cvt.m_Src_from;
  1139.             // Set partial only if a non-empty range is to be skipped
  1140.             if (cvt.m_Src_from > last_src_to + 1) {
  1141.                 if ( cvt.m_Reverse ) {
  1142.                     if (!fuzz.second) {
  1143.                         fuzz.second.Reset(new CInt_fuzz);
  1144.                     }
  1145.                     fuzz.second->SetLim(CInt_fuzz::eLim_gt);
  1146.                 }
  1147.                 else {
  1148.                     if (!fuzz.first) {
  1149.                         fuzz.first.Reset(new CInt_fuzz);
  1150.                     }
  1151.                     fuzz.first->SetLim(CInt_fuzz::eLim_lt);
  1152.                 }
  1153.                 m_Partial = true;
  1154.             }
  1155.         }
  1156.         last_src_to = cvt.m_Src_to;
  1157.         if ( to > cvt.m_Src_to ) {
  1158.             to = cvt.m_Src_to;
  1159.             // Set partial only if a non-empty range is to be skipped
  1160.             if (idx == mappings.size() - 1 ||
  1161.                 mappings[idx+1]->m_Src_from > last_src_to + 1) {
  1162.                 if ( cvt.m_Reverse ) {
  1163.                     if (!fuzz.first) {
  1164.                         fuzz.first.Reset(new CInt_fuzz);
  1165.                     }
  1166.                     fuzz.first->SetLim(CInt_fuzz::eLim_lt);
  1167.                 }
  1168.                 else {
  1169.                     if (!fuzz.second) {
  1170.                         fuzz.second.Reset(new CInt_fuzz);
  1171.                     }
  1172.                     fuzz.second->SetLim(CInt_fuzz::eLim_gt);
  1173.                 }
  1174.                 m_Partial = true;
  1175.             }
  1176.         }
  1177.         if ( from > to ) {
  1178.             continue;
  1179.         }
  1180.         TRange rg = cvt.Map_Range(from, to);
  1181.         ENa_strand dst_strand;
  1182.         bool is_set_dst_strand = cvt.Map_Strand(is_set_strand,
  1183.             src_strand, &dst_strand);
  1184.         x_GetMappedRanges(cvt.m_Dst_id_Handle,
  1185.             is_set_dst_strand ? int(dst_strand) + 1 : 0)
  1186.             .push_back(TRangeWithFuzz(rg, fuzz));
  1187.         res = true;
  1188.     }
  1189.     return res;
  1190. }
  1191. void CSeq_loc_Mapper::x_PushLocToDstMix(CRef<CSeq_loc> loc)
  1192. {
  1193.     _ASSERT(loc);
  1194.     if ( !m_Dst_loc  ||  !m_Dst_loc->IsMix() ) {
  1195.         CRef<CSeq_loc> tmp = m_Dst_loc;
  1196.         m_Dst_loc.Reset(new CSeq_loc);
  1197.         m_Dst_loc->SetMix();
  1198.         if ( tmp ) {
  1199.             m_Dst_loc->SetMix().Set().push_back(tmp);
  1200.         }
  1201.     }
  1202.     CSeq_loc_mix::Tdata& mix = m_Dst_loc->SetMix().Set();
  1203.     if ( loc->IsNull() ) {
  1204.         if ( m_GapFlag == eGapRemove ) {
  1205.             return;
  1206.         }
  1207.         if ( mix.size() > 0  &&  (*mix.rbegin())->IsNull() ) {
  1208.             // do not create duplicate NULLs
  1209.             return;
  1210.         }
  1211.     }
  1212.     mix.push_back(loc);
  1213. }
  1214. CRef<CSeq_loc> CSeq_loc_Mapper::Map(const CSeq_loc& src_loc)
  1215. {
  1216.     m_Dst_loc.Reset();
  1217.     m_Partial = false; // reset for each location
  1218.     x_MapSeq_loc(src_loc);
  1219.     x_PushRangesToDstMix();
  1220.     x_OptimizeSeq_loc(m_Dst_loc);
  1221.     return m_Dst_loc;
  1222. }
  1223. CRef<CSeq_align> CSeq_loc_Mapper::Map(const CSeq_align& src_align)
  1224. {
  1225.     m_Dst_loc.Reset();
  1226.     m_Partial = false; // reset for each location
  1227.     return x_MapSeq_align(src_align);
  1228. }
  1229. void CSeq_loc_Mapper::x_MapSeq_loc(const CSeq_loc& src_loc)
  1230. {
  1231.     switch ( src_loc.Which() ) {
  1232.     case CSeq_loc::e_Null:
  1233.         if (m_GapFlag == eGapRemove) {
  1234.             return;
  1235.         }
  1236.         // Proceed to seq-loc duplication
  1237.     case CSeq_loc::e_not_set:
  1238.     case CSeq_loc::e_Feat:
  1239.     {
  1240.         x_PushRangesToDstMix();
  1241.         CRef<CSeq_loc> loc(new CSeq_loc);
  1242.         loc->Assign(src_loc);
  1243.         x_PushLocToDstMix(loc);
  1244.         break;
  1245.     }
  1246.     case CSeq_loc::e_Empty:
  1247.     {
  1248.         bool res = false;
  1249.         TRangeIterator mit = x_BeginMappingRanges(
  1250.             CSeq_id_Handle::GetHandle(src_loc.GetEmpty()),
  1251.             TRange::GetWhole().GetFrom(),
  1252.             TRange::GetWhole().GetTo());
  1253.         for ( ; mit; ++mit) {
  1254.             CMappingRange& cvt = *mit->second;
  1255.             if ( cvt.GoodSrcId(src_loc.GetEmpty()) ) {
  1256.                 x_GetMappedRanges(
  1257.                     CSeq_id_Handle::GetHandle(src_loc.GetEmpty()), 0)
  1258.                     .push_back(TRangeWithFuzz(TRange::GetEmpty(),
  1259.                     TRangeFuzz(kEmptyFuzz, kEmptyFuzz)));
  1260.                 res = true;
  1261.                 break;
  1262.             }
  1263.         }
  1264.         if ( !res ) {
  1265.             if ( m_KeepNonmapping ) {
  1266.                 x_PushRangesToDstMix();
  1267.                 CRef<CSeq_loc> loc(new CSeq_loc);
  1268.                 loc->Assign(src_loc);
  1269.                 x_PushLocToDstMix(loc);
  1270.             }
  1271.             else {
  1272.                 m_Partial = true;
  1273.             }
  1274.         }
  1275.         break;
  1276.     }
  1277.     case CSeq_loc::e_Whole:
  1278.     {
  1279.         const CSeq_id& src_id = src_loc.GetWhole();
  1280.         // Convert to the allowed master seq interval
  1281.         TSeqPos src_to = kInvalidSeqPos;
  1282.         if ( m_Scope ) {
  1283.             CBioseq_Handle bh = m_Scope->GetBioseqHandle(src_id);
  1284.             src_to = bh ? bh.GetBioseqLength() : kInvalidSeqPos;
  1285.         }
  1286.         bool res = x_MapInterval(src_id, TRange(0, src_to),
  1287.             false, eNa_strand_unknown,
  1288.             TRangeFuzz(kEmptyFuzz, kEmptyFuzz));
  1289.         if ( !res ) {
  1290.             if ( m_KeepNonmapping ) {
  1291.                 x_PushRangesToDstMix();
  1292.                 CRef<CSeq_loc> loc(new CSeq_loc);
  1293.                 loc->Assign(src_loc);
  1294.                 x_PushLocToDstMix(loc);
  1295.             }
  1296.             else {
  1297.                 m_Partial = true;
  1298.             }
  1299.         }
  1300.         break;
  1301.     }
  1302.     case CSeq_loc::e_Int:
  1303.     {
  1304.         const CSeq_interval& src_int = src_loc.GetInt();
  1305.         TRangeFuzz fuzz(kEmptyFuzz, kEmptyFuzz);
  1306.         if ( src_int.IsSetFuzz_from() ) {
  1307.             fuzz.first.Reset(new CInt_fuzz);
  1308.             fuzz.first->Assign(src_int.GetFuzz_from());
  1309.         }
  1310.         if ( src_int.IsSetFuzz_to() ) {
  1311.             fuzz.second.Reset(new CInt_fuzz);
  1312.             fuzz.second->Assign(src_int.GetFuzz_to());
  1313.         }
  1314.         bool res = x_MapInterval(src_int.GetId(),
  1315.             TRange(src_int.GetFrom(), src_int.GetTo()),
  1316.             src_int.IsSetStrand(),
  1317.             src_int.IsSetStrand() ? src_int.GetStrand() : eNa_strand_unknown,
  1318.             fuzz);
  1319.         if ( !res ) {
  1320.             if ( m_KeepNonmapping ) {
  1321.                 x_PushRangesToDstMix();
  1322.                 CRef<CSeq_loc> loc(new CSeq_loc);
  1323.                 loc->Assign(src_loc);
  1324.                 x_PushLocToDstMix(loc);
  1325.             }
  1326.             else {
  1327.                 m_Partial = true;
  1328.             }
  1329.         }
  1330.         break;
  1331.     }
  1332.     case CSeq_loc::e_Pnt:
  1333.     {
  1334.         const CSeq_point& pnt = src_loc.GetPnt();
  1335.         TRangeFuzz fuzz(kEmptyFuzz, kEmptyFuzz);
  1336.         if ( pnt.IsSetFuzz() ) {
  1337.             fuzz.first.Reset(new CInt_fuzz);
  1338.             fuzz.first->Assign(pnt.GetFuzz());
  1339.         }
  1340.         bool res = x_MapInterval(pnt.GetId(),
  1341.             TRange(pnt.GetPoint(), pnt.GetPoint()),
  1342.             pnt.IsSetStrand(),
  1343.             pnt.IsSetStrand() ? pnt.GetStrand() : eNa_strand_unknown,
  1344.             fuzz);
  1345.         if ( !res ) {
  1346.             if ( m_KeepNonmapping ) {
  1347.                 x_PushRangesToDstMix();
  1348.                 CRef<CSeq_loc> loc(new CSeq_loc);
  1349.                 loc->Assign(src_loc);
  1350.                 x_PushLocToDstMix(loc);
  1351.             }
  1352.             else {
  1353.                 m_Partial = true;
  1354.             }
  1355.         }
  1356.         break;
  1357.     }
  1358.     case CSeq_loc::e_Packed_int:
  1359.     {
  1360.         const CPacked_seqint::Tdata& src_ints = src_loc.GetPacked_int().Get();
  1361.         ITERATE ( CPacked_seqint::Tdata, i, src_ints ) {
  1362.             const CSeq_interval& si = **i;
  1363.             TRangeFuzz fuzz(kEmptyFuzz, kEmptyFuzz);
  1364.             if ( si.IsSetFuzz_from() ) {
  1365.                 fuzz.first.Reset(new CInt_fuzz);
  1366.                 fuzz.first->Assign(si.GetFuzz_from());
  1367.             }
  1368.             if ( si.IsSetFuzz_to() ) {
  1369.                 fuzz.second.Reset(new CInt_fuzz);
  1370.                 fuzz.second->Assign(si.GetFuzz_to());
  1371.             }
  1372.             bool res = x_MapInterval(si.GetId(),
  1373.                 TRange(si.GetFrom(), si.GetTo()),
  1374.                 si.IsSetStrand(),
  1375.                 si.IsSetStrand() ? si.GetStrand() : eNa_strand_unknown,
  1376.                 fuzz);
  1377.             if ( !res ) {
  1378.                 if ( m_KeepNonmapping ) {
  1379.                     x_PushRangesToDstMix();
  1380.                     x_GetMappedRanges(CSeq_id_Handle::GetHandle(si.GetId()),
  1381.                         si.IsSetStrand() ? int(si.GetStrand()) + 1 : 0)
  1382.                         .push_back(TRangeWithFuzz(
  1383.                         TRange(si.GetFrom(), si.GetTo()), fuzz));
  1384.                 }
  1385.                 else {
  1386.                     m_Partial = true;
  1387.                 }
  1388.             }
  1389.         }
  1390.         break;
  1391.     }
  1392.     case CSeq_loc::e_Packed_pnt:
  1393.     {
  1394.         const CPacked_seqpnt& src_pack_pnts = src_loc.GetPacked_pnt();
  1395.         const CPacked_seqpnt::TPoints& src_pnts = src_pack_pnts.GetPoints();
  1396.         ITERATE ( CPacked_seqpnt::TPoints, i, src_pnts ) {
  1397.             TRangeFuzz fuzz(kEmptyFuzz, kEmptyFuzz);
  1398.             if ( src_pack_pnts.IsSetFuzz() ) {
  1399.                 fuzz.first.Reset(new CInt_fuzz);
  1400.                 fuzz.first->Assign(src_pack_pnts.GetFuzz());
  1401.             }
  1402.             bool res = x_MapInterval(
  1403.                 src_pack_pnts.GetId(),
  1404.                 TRange(*i, *i), src_pack_pnts.IsSetStrand(),
  1405.                 src_pack_pnts.IsSetStrand() ?
  1406.                 src_pack_pnts.GetStrand() : eNa_strand_unknown,
  1407.                 fuzz);
  1408.             if ( !res ) {
  1409.                 if ( m_KeepNonmapping ) {
  1410.                     x_PushRangesToDstMix();
  1411.                     x_GetMappedRanges(
  1412.                         CSeq_id_Handle::GetHandle(src_pack_pnts.GetId()),
  1413.                         src_pack_pnts.IsSetStrand() ?
  1414.                         int(src_pack_pnts.GetStrand()) + 1 : 0)
  1415.                         .push_back(TRangeWithFuzz(TRange(*i, *i), fuzz));
  1416.                 }
  1417.                 else {
  1418.                     m_Partial = true;
  1419.                 }
  1420.             }
  1421.         }
  1422.         break;
  1423.     }
  1424.     case CSeq_loc::e_Mix:
  1425.     {
  1426.         x_PushRangesToDstMix();
  1427.         CRef<CSeq_loc> prev = m_Dst_loc;
  1428.         m_Dst_loc.Reset();
  1429.         const CSeq_loc_mix::Tdata& src_mix = src_loc.GetMix().Get();
  1430.         ITERATE ( CSeq_loc_mix::Tdata, i, src_mix ) {
  1431.             x_MapSeq_loc(**i);
  1432.         }
  1433.         x_PushRangesToDstMix();
  1434.         CRef<CSeq_loc> mix = m_Dst_loc;
  1435.         m_Dst_loc = prev;
  1436.         x_OptimizeSeq_loc(mix);
  1437.         x_PushLocToDstMix(mix);
  1438.         break;
  1439.     }
  1440.     case CSeq_loc::e_Equiv:
  1441.     {
  1442.         x_PushRangesToDstMix();
  1443.         CRef<CSeq_loc> prev = m_Dst_loc;
  1444.         m_Dst_loc.Reset();
  1445.         const CSeq_loc_equiv::Tdata& src_equiv = src_loc.GetEquiv().Get();
  1446.         CRef<CSeq_loc> equiv(new CSeq_loc);
  1447.         equiv->SetEquiv();
  1448.         ITERATE ( CSeq_loc_equiv::Tdata, i, src_equiv ) {
  1449.             x_MapSeq_loc(**i);
  1450.             x_PushRangesToDstMix();
  1451.             x_OptimizeSeq_loc(m_Dst_loc);
  1452.             equiv->SetEquiv().Set().push_back(m_Dst_loc);
  1453.             m_Dst_loc.Reset();
  1454.         }
  1455.         m_Dst_loc = prev;
  1456.         x_PushLocToDstMix(equiv);
  1457.         break;
  1458.     }
  1459.     case CSeq_loc::e_Bond:
  1460.     {
  1461.         x_PushRangesToDstMix();
  1462.         CRef<CSeq_loc> prev = m_Dst_loc;
  1463.         m_Dst_loc.Reset();
  1464.         const CSeq_bond& src_bond = src_loc.GetBond();
  1465.         CRef<CSeq_loc> dst_loc(new CSeq_loc);
  1466.         dst_loc->SetBond();
  1467.         CRef<CSeq_loc> pntA;
  1468.         CRef<CSeq_loc> pntB;
  1469.         TRangeFuzz fuzzA(kEmptyFuzz, kEmptyFuzz);
  1470.         if ( src_bond.GetA().IsSetFuzz() ) {
  1471.             fuzzA.first.Reset(new CInt_fuzz);
  1472.             fuzzA.first->Assign(src_bond.GetA().GetFuzz());
  1473.         }
  1474.         bool resA = x_MapInterval(src_bond.GetA().GetId(),
  1475.             TRange(src_bond.GetA().GetPoint(), src_bond.GetA().GetPoint()),
  1476.             src_bond.GetA().IsSetStrand(),
  1477.             src_bond.GetA().IsSetStrand() ?
  1478.             src_bond.GetA().GetStrand() : eNa_strand_unknown,
  1479.             fuzzA);
  1480.         if ( resA ) {
  1481.             pntA = x_GetMappedSeq_loc();
  1482.             _ASSERT(pntA);
  1483.             if ( !pntA->IsPnt() ) {
  1484.                 NCBI_THROW(CLocMapperException, eBadLocation,
  1485.                            "Bond point A can not be mapped to a point");
  1486.             }
  1487.         }
  1488.         else {
  1489.             pntA.Reset(new CSeq_loc);
  1490.             pntA->SetPnt().Assign(src_bond.GetA());
  1491.         }
  1492.         bool resB = false;
  1493.         if ( src_bond.IsSetB() ) {
  1494.             TRangeFuzz fuzzB(kEmptyFuzz, kEmptyFuzz);
  1495.             if ( src_bond.GetB().IsSetFuzz() ) {
  1496.                 fuzzB.first.Reset(new CInt_fuzz);
  1497.                 fuzzB.first->Assign(src_bond.GetB().GetFuzz());
  1498.             }
  1499.             resB = x_MapInterval(src_bond.GetB().GetId(),
  1500.                 TRange(src_bond.GetB().GetPoint(), src_bond.GetB().GetPoint()),
  1501.                 src_bond.GetB().IsSetStrand(),
  1502.                 src_bond.GetB().IsSetStrand() ?
  1503.                 src_bond.GetB().GetStrand() : eNa_strand_unknown,
  1504.                 fuzzB);
  1505.         }
  1506.         if ( resB ) {
  1507.             pntB = x_GetMappedSeq_loc();
  1508.             _ASSERT(pntB);
  1509.             if ( !pntB->IsPnt() ) {
  1510.                 NCBI_THROW(CLocMapperException, eBadLocation,
  1511.                            "Bond point B can not be mapped to a point");
  1512.             }
  1513.         }
  1514.         else {
  1515.             pntB.Reset(new CSeq_loc);
  1516.             pntB->SetPnt().Assign(src_bond.GetB());
  1517.         }
  1518.         m_Dst_loc = prev;
  1519.         if ( resA  ||  resB  ||  m_KeepNonmapping ) {
  1520.             CSeq_bond& dst_bond = dst_loc->SetBond();
  1521.             dst_bond.SetA(pntA->SetPnt());
  1522.             if ( src_bond.IsSetB() ) {
  1523.                 dst_bond.SetB(pntB->SetPnt());
  1524.             }
  1525.             x_PushLocToDstMix(dst_loc);
  1526.         }
  1527.         m_Partial |= (!resA || !resB);
  1528.         break;
  1529.     }
  1530.     default:
  1531.         NCBI_THROW(CAnnotException, eBadLocation,
  1532.                    "Unsupported location type");
  1533.     }
  1534. }
  1535. CRef<CSeq_loc> CSeq_loc_Mapper::x_RangeToSeq_loc(const CSeq_id_Handle& idh,
  1536.                                                  TSeqPos from,
  1537.                                                  TSeqPos to,
  1538.                                                  int strand_idx,
  1539.                                                  TRangeFuzz rg_fuzz)
  1540. {
  1541.     if (m_UseWidth  &&  (m_Widths[idh] & fWidthNucToProt)) {
  1542.         from = from/3;
  1543.         to = to/3;
  1544.     }
  1545.     CRef<CSeq_loc> loc(new CSeq_loc);
  1546.     // If both fuzzes are set, create interval, not point.
  1547.     if (from == to  &&  (!rg_fuzz.first  ||  !rg_fuzz.second)) {
  1548.         // point
  1549.         loc->SetPnt().SetId().Assign(*idh.GetSeqId());
  1550.         loc->SetPnt().SetPoint(from);
  1551.         if (strand_idx > 0) {
  1552.             loc->SetPnt().SetStrand(ENa_strand(strand_idx - 1));
  1553.         }
  1554.         if ( rg_fuzz.first ) {
  1555.             loc->SetPnt().SetFuzz(*rg_fuzz.first);
  1556.         }
  1557.         else if ( rg_fuzz.second ) {
  1558.             loc->SetPnt().SetFuzz(*rg_fuzz.second);
  1559.         }
  1560.     }
  1561.     else {
  1562.         // interval
  1563.         loc->SetInt().SetId().Assign(*idh.GetSeqId());
  1564.         loc->SetInt().SetFrom(from);
  1565.         loc->SetInt().SetTo(to);
  1566.         if (strand_idx > 0) {
  1567.             loc->SetInt().SetStrand(ENa_strand(strand_idx - 1));
  1568.         }
  1569.         if ( rg_fuzz.first ) {
  1570.             loc->SetInt().SetFuzz_from(*rg_fuzz.first);
  1571.         }
  1572.         if ( rg_fuzz.second ) {
  1573.             loc->SetInt().SetFuzz_to(*rg_fuzz.second);
  1574.         }
  1575.     }
  1576.     return loc;
  1577. }
  1578. void CSeq_loc_Mapper::x_OptimizeSeq_loc(CRef<CSeq_loc>& loc)
  1579. {
  1580.     if ( !loc ) {
  1581.         loc.Reset(new CSeq_loc);
  1582.         loc->SetNull();
  1583.         return;
  1584.     }
  1585.     switch (loc->Which()) {
  1586.     case CSeq_loc::e_not_set:
  1587.     case CSeq_loc::e_Feat:
  1588.     case CSeq_loc::e_Null:
  1589.     case CSeq_loc::e_Empty:
  1590.     case CSeq_loc::e_Whole:
  1591.     case CSeq_loc::e_Int:
  1592.     case CSeq_loc::e_Pnt:
  1593.     case CSeq_loc::e_Equiv:
  1594.     case CSeq_loc::e_Bond:
  1595.     case CSeq_loc::e_Packed_int:  // pack ?
  1596.     case CSeq_loc::e_Packed_pnt:  // pack ?
  1597.         return;
  1598.     case CSeq_loc::e_Mix:
  1599.     {
  1600.         switch ( loc->GetMix().Get().size() ) {
  1601.         case 0:
  1602.             loc->SetNull();
  1603.             break;
  1604.         case 1:
  1605.         {
  1606.             CRef<CSeq_loc> single = *loc->SetMix().Set().begin();
  1607.             loc = single;
  1608.             break;
  1609.         }
  1610.         default:
  1611.             break;
  1612.         }
  1613.         break;
  1614.     }
  1615.     default:
  1616.         NCBI_THROW(CAnnotException, eBadLocation,
  1617.                    "Unsupported location type");
  1618.     }
  1619. }
  1620. CRef<CSeq_loc> CSeq_loc_Mapper::x_GetMappedSeq_loc(void)
  1621. {
  1622.     CRef<CSeq_loc> dst_loc(new CSeq_loc);
  1623.     CSeq_loc_mix::Tdata& dst_mix = dst_loc->SetMix().Set();
  1624.     NON_CONST_ITERATE(TRangesById, id_it, m_MappedLocs) {
  1625.         if ( !id_it->first ) {
  1626.             if (m_GapFlag == eGapPreserve) {
  1627.                 CRef<CSeq_loc> null_loc(new CSeq_loc);
  1628.                 null_loc->SetNull();
  1629.                 dst_mix.push_back(null_loc);
  1630.             }
  1631.             continue;
  1632.         }
  1633.         for (int str = 0; str < (int)id_it->second.size(); ++str) {
  1634.             if (id_it->second[str].size() == 0) {
  1635.                 continue;
  1636.             }
  1637.             TSeqPos from = kInvalidSeqPos;
  1638.             TSeqPos to = kInvalidSeqPos;
  1639.             TRangeFuzz fuzz(kEmptyFuzz, kEmptyFuzz);
  1640.             id_it->second[str].sort();
  1641.             NON_CONST_ITERATE(TMappedRanges, rg_it, id_it->second[str]) {
  1642.                 if ( rg_it->first.Empty() ) {
  1643.                     // Empty seq-loc
  1644.                     CRef<CSeq_loc> loc(new CSeq_loc);
  1645.                     loc->SetEmpty().Assign(*id_it->first.GetSeqId());
  1646.                     dst_mix.push_back(loc);
  1647.                     continue;
  1648.                 }
  1649.                 if (to == kInvalidSeqPos) {
  1650.                     from = rg_it->first.GetFrom();
  1651.                     to = rg_it->first.GetTo();
  1652.                     fuzz = rg_it->second;
  1653.                     continue;
  1654.                 }
  1655.                 if (m_MergeFlag == eMergeAbutting) {
  1656.                     if (rg_it->first.GetFrom() == to + 1) {
  1657.                         to = rg_it->first.GetTo();
  1658.                         fuzz.second = rg_it->second.second;
  1659.                         continue;
  1660.                     }
  1661.                 }
  1662.                 if (m_MergeFlag == eMergeAll) {
  1663.                     if (rg_it->first.GetFrom() <= to + 1) {
  1664.                         to = rg_it->first.GetTo();
  1665.                         fuzz.second = rg_it->second.second;
  1666.                         continue;
  1667.                     }
  1668.                 }
  1669.                 // Add new interval or point
  1670.                 dst_mix.push_back(x_RangeToSeq_loc(id_it->first, from, to,
  1671.                     str, fuzz));
  1672.                 from = rg_it->first.GetFrom();
  1673.                 to = rg_it->first.GetTo();
  1674.                 fuzz = rg_it->second;
  1675.             }
  1676.             // last interval or point
  1677.             dst_mix.push_back(x_RangeToSeq_loc(id_it->first, from, to,
  1678.                 str, fuzz));
  1679.         }
  1680.     }
  1681.     m_MappedLocs.clear();
  1682.     x_OptimizeSeq_loc(dst_loc);
  1683.     return dst_loc;
  1684. }
  1685. CRef<CSeq_align> CSeq_loc_Mapper::x_MapSeq_align(const CSeq_align& src_align)
  1686. {
  1687.     CSeq_align_Mapper aln_mapper(src_align);
  1688.     aln_mapper.Convert(*this);
  1689.     return aln_mapper.GetDstAlign();
  1690.     /*
  1691.     ITERATE(TIdMap, id_it, m_IdMap) {
  1692.         ITERATE(TRangeMap, rg_it, id_it->second) {
  1693.             aln_mapper.Convert(*rg_it->second,
  1694.                 m_UseWidth ? m_Widths[id_it->first] : 0);
  1695.         }
  1696.     }
  1697.     */
  1698. }
  1699. END_SCOPE(objects)
  1700. END_NCBI_SCOPE
  1701. /*
  1702. * ---------------------------------------------------------------------------
  1703. * $Log: seq_loc_mapper.cpp,v $
  1704. * Revision 1000.1  2004/06/01 19:24:12  gouriano
  1705. * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.20
  1706. *
  1707. * Revision 1.20  2004/05/26 14:29:20  grichenk
  1708. * Redesigned CSeq_align_Mapper: preserve non-mapping intervals,
  1709. * fixed strands handling, improved performance.
  1710. *
  1711. * Revision 1.19  2004/05/21 21:42:13  gorelenk
  1712. * Added PCH ncbi_pch.hpp
  1713. *
  1714. * Revision 1.18  2004/05/10 20:22:24  grichenk
  1715. * Fixed more warnings (removed inlines)
  1716. *
  1717. * Revision 1.17  2004/05/10 18:26:37  grichenk
  1718. * Fixed 'not used' warnings
  1719. *
  1720. * Revision 1.16  2004/05/07 13:53:18  grichenk
  1721. * Preserve fuzz from original location.
  1722. * Better detection of partial locations.
  1723. *
  1724. * Revision 1.15  2004/05/05 14:04:22  grichenk
  1725. * Use fuzz to indicate truncated intervals. Added KeepNonmapping flag.
  1726. *
  1727. * Revision 1.14  2004/04/23 15:34:49  grichenk
  1728. * Added PreserveDestinationLocs().
  1729. *
  1730. * Revision 1.13  2004/04/12 14:35:59  grichenk
  1731. * Fixed mapping of alignments between nucleotides and proteins
  1732. *
  1733. * Revision 1.12  2004/04/06 13:56:33  grichenk
  1734. * Added possibility to remove gaps (NULLs) from mapped location
  1735. *
  1736. * Revision 1.11  2004/03/31 20:44:26  grichenk
  1737. * Fixed warnings about unhandled cases in switch.
  1738. *
  1739. * Revision 1.10  2004/03/30 21:21:09  grichenk
  1740. * Reduced number of includes.
  1741. *
  1742. * Revision 1.9  2004/03/30 17:00:00  grichenk
  1743. * Fixed warnings, moved inline functions to hpp.
  1744. *
  1745. * Revision 1.8  2004/03/30 15:42:34  grichenk
  1746. * Moved alignment mapper to separate file, added alignment mapping
  1747. * to CSeq_loc_Mapper.
  1748. *
  1749. * Revision 1.7  2004/03/29 15:13:56  grichenk
  1750. * Added mapping down to segments of a bioseq or a seqmap.
  1751. * Fixed: preserve ranges already on the target bioseq(s).
  1752. *
  1753. * Revision 1.6  2004/03/22 21:10:58  grichenk
  1754. * Added mapping from segments to master sequence or through a seq-map.
  1755. *
  1756. * Revision 1.5  2004/03/19 14:19:08  grichenk
  1757. * Added seq-loc mapping through a seq-align.
  1758. *
  1759. * Revision 1.4  2004/03/16 15:47:28  vasilche
  1760. * Added CBioseq_set_Handle and set of EditHandles
  1761. *
  1762. * Revision 1.3  2004/03/11 18:48:02  shomrat
  1763. * skip if empty
  1764. *
  1765. * Revision 1.2  2004/03/11 04:54:48  grichenk
  1766. * Removed inline
  1767. *
  1768. * Revision 1.1  2004/03/10 16:22:29  grichenk
  1769. * Initial revision
  1770. *
  1771. *
  1772. * ===========================================================================
  1773. */