AlignmentMapper.ts 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. /*
  2. * Copyright (c) 2021 RCSB PDB and contributors, licensed under MIT, See LICENSE file for more info.
  3. * @author Joan Segura Mora <joan.segura@rcsb.org>
  4. */
  5. import {AlignedRegion} from "@rcsb/rcsb-api-tools/build/RcsbGraphQL/Types/Borrego/GqlTypes";
  6. export namespace AlignmentMapper {
  7. export function mapRangeToRegionList(range:{begin:number,end:number}, regionList:AlignedRegion[], pointer:"query"|"target"): {begin:number,end:number}[]|undefined {
  8. return regionList.map(region=>mapRangeToRegion(range,region,pointer)).filter((o): o is typeof range => o!=null);
  9. }
  10. export function mapRangeToRegion(range:{begin:number,end:number}, region:AlignedRegion, pointer:"query"|"target"): {begin:number,end:number}|undefined {
  11. if(!areIntersectingRegions({query_begin:range.begin, query_end: range.end, target_begin:range.begin, target_end:range.end}, region, pointer))
  12. return;
  13. const cPointer: "query"|"target" = pointer == "query" ? "target" : "query";
  14. return {
  15. begin: mapPointToRegion(range.begin, region, pointer) ?? region[ALIGNMENT_POINTER[cPointer].begin],
  16. end: mapPointToRegion(range.end, region, pointer) ?? region[ALIGNMENT_POINTER[cPointer].end]
  17. }
  18. }
  19. export function mapPointToRegion(p:number, region:AlignedRegion, pointer:"query"|"target"): number|undefined {
  20. if(region[ALIGNMENT_POINTER[pointer].begin]<=p && p<=region[ALIGNMENT_POINTER[pointer].end]) {
  21. const cPointer: "query"|"target" = pointer == "query" ? "target" : "query";
  22. return region[ALIGNMENT_POINTER[cPointer].begin] + (p-region[ALIGNMENT_POINTER[pointer].begin]);
  23. }
  24. return;
  25. }
  26. export function areIntersectingRegions(regionA:AlignedRegion,regionB:AlignedRegion, pointer:"query"|"target"): boolean {
  27. return !(regionA[ALIGNMENT_POINTER[pointer].begin] > regionB[ALIGNMENT_POINTER[pointer].end] || regionA[ALIGNMENT_POINTER[pointer].end] < regionB[ALIGNMENT_POINTER[pointer].begin]);
  28. }
  29. export function getAllQueryIntersections(regionListA:AlignedRegion[],regionListB:AlignedRegion[]): [{query_begin:number;query_end:number;},{query_begin:number;query_end:number;}][] {
  30. return regionListA.map(
  31. regionA=>regionListB.filter(
  32. regionB=>areIntersectingRegions(regionA,regionB,"target")
  33. ).map(
  34. regionB=>getQueryIntersection(regionA,regionB)
  35. )
  36. ).flat();
  37. }
  38. export function getAllTargetIntersections(regionListA:AlignedRegion[],regionListB:AlignedRegion[]): [{target_begin:number;target_end:number;},{target_begin:number;target_end:number;}][] {
  39. return regionListA.map(
  40. regionA=>regionListB.filter(
  41. regionB=>areIntersectingRegions(regionA,regionB,"query")
  42. ).map(
  43. regionB=>getTargetIntersection(regionA,regionB)
  44. )
  45. ).flat();
  46. }
  47. export function getQueryIntersection(regionA:AlignedRegion,regionB:AlignedRegion): [{query_begin:number;query_end:number;},{query_begin:number;query_end:number;}] {
  48. const [targetRegionA, targetRegionB] = getTargetIntersection(swapQueryAndTarget(regionA), swapQueryAndTarget(regionB));
  49. return [{
  50. query_begin:targetRegionA.target_begin,
  51. query_end:targetRegionA.target_end
  52. },{
  53. query_begin:targetRegionB.target_begin,
  54. query_end:targetRegionB.target_end
  55. }];
  56. }
  57. export function getTargetIntersection(regionA:AlignedRegion,regionB:AlignedRegion): [{target_begin:number;target_end:number;},{target_begin:number;target_end:number;}] {
  58. const out = {
  59. target_begin_A: 0,
  60. target_end_A: 0,
  61. target_begin_B: 0,
  62. target_end_B: 0
  63. }
  64. if( typeof mapPointToRegion( regionA.query_begin, regionB, "query" ) === "number"){
  65. out.target_begin_A = regionA.target_begin;
  66. out.target_begin_B = mapPointToRegion( regionA.query_begin, regionB, "query" )!;
  67. }else if( typeof mapPointToRegion( regionB.query_begin, regionA, "query" ) === "number" ){
  68. out.target_begin_A = mapPointToRegion( regionB.query_begin, regionA, "query" )!;
  69. out.target_begin_B = regionB.target_begin;
  70. }else{
  71. throw "Intersection Error: No intersection was found";
  72. }
  73. if( typeof mapPointToRegion( regionA.query_end, regionB, "query" ) === "number"){
  74. out.target_end_A = regionA.target_end;
  75. out.target_end_B = mapPointToRegion( regionA.query_end, regionB, "query" )!;
  76. }else if( typeof mapPointToRegion( regionB.query_end, regionA, "query" ) === "number" ){
  77. out.target_end_A = mapPointToRegion( regionB.query_end, regionA, "query" )!;
  78. out.target_end_B = regionB.target_end;
  79. }else{
  80. throw "Intersection Error: No intersection was found";
  81. }
  82. if(out.target_end_A-out.target_begin_A != out.target_end_B-out.target_begin_B)
  83. throw `Intersection Error: Inconsistent intersection range [${out.target_begin_A},${out.target_end_A}] [${out.target_begin_B},${out.target_end_B}]`;
  84. return [{
  85. target_begin:out.target_begin_A,
  86. target_end:out.target_end_A
  87. },{
  88. target_begin:out.target_begin_B,
  89. target_end:out.target_end_B
  90. }];
  91. }
  92. export function range(start:number, stop:number, step:number =1): number[] {
  93. const length = Math.ceil((stop+1 - start) / step);
  94. return Array.from({length}, (_, i) => (i * step) + start);
  95. }
  96. export function swapQueryAndTarget(region:AlignedRegion): AlignedRegion{
  97. return {
  98. query_begin: region.target_begin,
  99. query_end: region.target_end,
  100. target_begin: region.query_begin,
  101. target_end: region.query_end
  102. };
  103. }
  104. }
  105. interface AlignmentPointerInterface {
  106. query: {
  107. begin: "query_begin",
  108. end: "query_end"
  109. },
  110. target: {
  111. begin: "target_begin",
  112. end: "target_end"
  113. }
  114. }
  115. const ALIGNMENT_POINTER: AlignmentPointerInterface = {
  116. query: {
  117. begin: "query_begin",
  118. end: "query_end"
  119. },
  120. target: {
  121. begin: "target_begin",
  122. end: "target_end"
  123. }
  124. }