Euclidean Vectors
Python 2, 238.5 (594 562 482 477-50%) bytes
from math import*
def F(x):s='%.3g'%x;return[[s+'.',s]['.'in s].ljust(4,'0'),s][x>99]
I=input()
V=I.split('\n');N=len(V)
l=max(len(x)for x in V)
q=[' '*(l+2)];V=q+[' '+x.ljust(l+1)for x in V]+q
for k in range(N*l):
i,j=k/l,k%l;c=V[i+1][j+1]
if c in'<>^v'and['|'not in zip(*V)[j+1][i:i+3],'-'not in V[i+1][j:j+3]][c>'?']:a,b=i,j
if c=='x':A,B=i,j
Y=A-a;X=b-B;a=atan2(Y,X)/pi*180%360
print[F(hypot(X,Y))+' units @ '+F(a)+' degrees '+' NS'[cmp(Y,0)]+' EW'[cmp(X,0)],''][I=='x']
Explanation
Finds the start and end positions by looking at each character in the input.
Start is x
End is found by looking at each arrow (<>^v
), and their neighbors.
If neighbors are continuing vectors, ignore. Else, this is the end.
Look at the neighbors perpendicular to the arrow direction.
If they contain a perpendicular line, then it is a continuing vector.
Examples (_
indicates space):
_#_
->_ Neighbors marked by #
_#_
___
->_ (end)
___
_|_
->_ (not end)
___
___
->| (end)
___
---
->_ (end)
___
Because the end point is found, there can be any number of vectors (30% bonus).
JavaScript (ES6), 305 bytes - 50% bonus = 152.5 score
v=>(l=v.search`
`+1,s=v.search`x`,u=0,d="-",v.replace(/[<>v^]/g,(p,i)=>{c=o=>v[i+o]!=q;with(Math)if(p<"?"?c(l,q="|")&c(-l):c(1,q="-")&c(-1))d=(atan2(x=i%l-s%l,y=(i/l|0)-(s/l|0))*180/PI+270)%360,u=sqrt(x*x+y*y)}),u[p="toPrecision"](3)+` units @ ${d[p](3)} degrees`)
Explanation
Input must be padded with spaces. Uses all bonuses.
v=>(
l=v.search`
`+1, // l = line length
s=v.search`x`, // s = index of start point
u=0, // u = units
d= // d = degrees
w="-", // w = cardinal direction
v.replace(/[<>v^]/g,(p,i)=>{ // for each endpoint
c=o=>v[i+o]!=q; // compares cell at offset to char
with(Math) // save having to write "Math."
if(p<"?"?c(l,q="|")&c(-l):c(1,q="-")&c(-1)) // check for line branching off
d=(atan2(
x=i%l-s%l, // x = relative x
y=(i/l|0)-(s/l|0) // y = relative y
)*180/PI+270)%360, // convert to degrees
u=sqrt(x*x+y*y),
w="N S"[sign(y)+1]+"W E"[sign(x)+1] // get cardinal direction
}),
u[p="toPrecision"](3)+` units @ ${d[p](3)} degrees `+w // format output
)
Test
var solution = v=>(l=v.search`
`+1,s=v.search`x`,u=0,d=w="-",v.replace(/[<>v^]/g,(p,i)=>{c=o=>v[i+o]!=q;with(Math)if(p<"?"?c(l,q="|")&c(-l):c(1,q="-")&c(-1))d=(atan2(x=i%l-s%l,y=(i/l|0)-(s/l|0))*180/PI+270)%360,u=sqrt(x*x+y*y),w="N S"[sign(y)+1]+"W E"[sign(x)+1]}),u[p="toPrecision"](3)+` units @ ${d[p](3)} degrees `+w)
<textarea id="input" rows="6" cols="60">x
|
|<-----^
| |
v------></textarea><br />
<button onclick="result.textContent=solution(input.value)">Go</button>
<pre id="result"></pre>