github.com/biogo/biogo@v1.0.4/feat/feature.go (about)

     1  // Copyright ©2012 The bíogo Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package feat provides the base for storage and manipulation of biological interval information.
     6  package feat
     7  
     8  type Conformationer interface {
     9  	Conformation() Conformation
    10  	SetConformation(Conformation) error
    11  }
    12  
    13  type Conformation int8
    14  
    15  func (c Conformation) String() string {
    16  	switch c {
    17  	case UndefinedConformation:
    18  		return "undefined"
    19  	case Linear:
    20  		return "linear"
    21  	case Circular:
    22  		return "circular"
    23  	}
    24  	panic("feat: illegal conformation")
    25  }
    26  
    27  const (
    28  	UndefinedConformation Conformation = iota - 1
    29  	Linear
    30  	Circular
    31  )
    32  
    33  // Orienter wraps the Orientation method.
    34  //
    35  // Orientation returns the orientation of the feature relative to its location.
    36  type Orienter interface {
    37  	Orientation() Orientation
    38  }
    39  
    40  type OrientSetter interface {
    41  	SetOrientation(Orientation) error
    42  }
    43  
    44  type Orientation int8
    45  
    46  func (o Orientation) String() string {
    47  	switch o {
    48  	case Reverse:
    49  		return "reverse"
    50  	case NotOriented:
    51  		return "not oriented"
    52  	case Forward:
    53  		return "forward"
    54  	}
    55  	panic("feat: illegal orientation")
    56  }
    57  
    58  const (
    59  	Reverse Orientation = iota - 1
    60  	NotOriented
    61  	Forward
    62  )
    63  
    64  type Range interface {
    65  	Start() int
    66  	End() int
    67  	Len() int
    68  }
    69  
    70  // Feature is a Range whose coordinates are defined relative to a feature
    71  // location. Start and End return the coordinates of the feature relative to
    72  // its location which can be nil. In the latter case callers should make no
    73  // assumptions whether coordinates of such features are comparable.
    74  type Feature interface {
    75  	Range
    76  	// Name returns the name of the feature.
    77  	Name() string
    78  	// Description returns the description of the feature.
    79  	Description() string
    80  	// Location returns the reference feature on which the feature is located.
    81  	Location() Feature
    82  }
    83  
    84  type Offsetter interface {
    85  	SetOffset(int) error
    86  }
    87  
    88  type Mutable interface {
    89  	SetStart(int) error
    90  	SetEnd(int) error
    91  }
    92  
    93  type LocationSetter interface {
    94  	SetLocation(Feature) error
    95  }
    96  
    97  type Pair interface {
    98  	Features() [2]Feature
    99  }
   100  
   101  type Set interface {
   102  	Features() []Feature
   103  }
   104  
   105  type Adder interface {
   106  	Set
   107  	Add(...Feature)
   108  }
   109  
   110  type Collection interface {
   111  	Set
   112  	Location() Feature
   113  }
   114  
   115  // BasePositionOf returns the position in f coordinates converted to
   116  // coordinates relative to the first nil feature location, and a reference
   117  // which is the feature location preceding the nil. The returned reference
   118  // feature should be used by callers of BasePositionOf to verify that
   119  // coordinates are comparable.
   120  // BasePositionOf will panic if the feature chain is deeper than 1000 links.
   121  func BasePositionOf(f Feature, position int) (int, Feature) {
   122  	for n := 0; n < 1000; n++ {
   123  		position += f.Start()
   124  		if f.Location() != nil {
   125  			f = f.Location()
   126  			continue
   127  		}
   128  		return position, f
   129  	}
   130  	panic("feat: feature chain too long")
   131  }
   132  
   133  // PositionWithin returns the position in f coordinates converted to
   134  // coordinates relative to the given reference feature and a boolean
   135  // indicating whether f can be located relative to ref.
   136  // PositionWithin will panic if the feature chain is deeper than 1000 links.
   137  func PositionWithin(f, ref Feature, position int) (pos int, ok bool) {
   138  	for n := 0; n < 1000; n++ {
   139  		if f == ref {
   140  			return position, f != nil
   141  		}
   142  		position += f.Start()
   143  		if f.Location() != nil {
   144  			f = f.Location()
   145  			continue
   146  		}
   147  		return 0, false
   148  	}
   149  	panic("feat: feature chain too long")
   150  }
   151  
   152  // BaseOrientationOf returns the orientation of f relative to a reference
   153  // which is the first non-nil, non-orientable feature location, and that
   154  // reference feature. The returned reference feature should be used by callers
   155  // of BaseOrientationOf to verify that orientations are comparable. If f is
   156  // not orientable, the returned orientation will be NotOriented and the
   157  // reference will be the first orientable or last non-nil feature.
   158  // BaseOrientationOf will panic if the feature chain is deeper than 1000 links.
   159  func BaseOrientationOf(f Feature) (ori Orientation, ref Feature) {
   160  	o, ok := f.(Orienter)
   161  	if !ok || o.Orientation() == NotOriented {
   162  		for n := 0; n < 1000; n++ {
   163  			if o, ok = f.Location().(Orienter); ok && o.Orientation() != NotOriented {
   164  				return NotOriented, f.Location()
   165  			}
   166  			if f.Location() == nil {
   167  				return NotOriented, f
   168  			}
   169  			f = f.Location()
   170  		}
   171  		panic("feat: feature chain too long")
   172  	}
   173  
   174  	ori = Forward
   175  	for n := 0; n < 1000; n++ {
   176  		ori *= o.Orientation()
   177  		if o, ok = f.Location().(Orienter); ok && o.Orientation() != NotOriented {
   178  			f = f.Location()
   179  			continue
   180  		}
   181  		if f.Location() != nil {
   182  			return ori, f.Location()
   183  		}
   184  		return ori, f
   185  	}
   186  	panic("feat: feature chain too long")
   187  }
   188  
   189  // OrientationWithin returns the orientation of f relative to the given
   190  // reference feature. The returned orientation will be NotOriented if f is not
   191  // located within the reference or if f is not orientable.
   192  // OrientationWithin will panic if the feature chain is deeper than 1000 links.
   193  func OrientationWithin(f, ref Feature) Orientation {
   194  	if ref == nil {
   195  		return NotOriented
   196  	}
   197  	ori := Forward
   198  	for n := 0; n < 1000; n++ {
   199  		o, ok := f.(Orienter)
   200  		if !ok {
   201  			return NotOriented
   202  		}
   203  		if o := o.Orientation(); o != NotOriented {
   204  			if f == ref {
   205  				return ori
   206  			}
   207  			ori *= o
   208  			f = f.Location()
   209  			if f == ref {
   210  				return ori
   211  			}
   212  			continue
   213  		}
   214  		return NotOriented
   215  	}
   216  	panic("feat: feature chain too long")
   217  }