-
Notifications
You must be signed in to change notification settings - Fork 0
/
Vector.ts
202 lines (180 loc) · 6.44 KB
/
Vector.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
/**
* @author Ikaros Kappler
* @date 2019-01-30
* @modified 2019-02-23 Added the toSVGString function, overriding Line.toSVGString.
* @modified 2019-03-20 Added JSDoc tags.
* @modified 2019-04-19 Added the clone function (overriding Line.clone()).
* @modified 2019-09-02 Added the Vector.perp() function.
* @modified 2019-09-02 Added the Vector.inverse() function.
* @modified 2019-12-04 Added the Vector.inv() function.
* @modified 2020-03-23 Ported to Typescript from JS.
* @modified 2021-01-20 Added UID.
* @version 1.3.0
*
* @file Vector
* @public
**/
import { VertTuple } from "./VertTuple";
import { Vertex } from "./Vertex";
import { SVGSerializable } from "./interfaces";
/**
* @classdesc A vector (Vertex,Vertex) is a line with a visible direction.<br>
* <br>
* Vectors are drawn with an arrow at their end point.<br>
* <b>The Vector class extends the Line class.</b>
*
* @requires VertTuple
* @requires Vertex
**/
export class Vector extends VertTuple<Vector> implements SVGSerializable {
/**
* Required to generate proper CSS classes and other class related IDs.
**/
readonly className : string = "Vector";
/**
* The constructor.
*
* @constructor
* @name Vector
* @extends Line
* @param {Vertex} vertA - The start vertex of the vector.
* @param {Vertex} vertB - The end vertex of the vector.
**/
constructor( vertA:Vertex, vertB:Vertex ) {
super(vertA,vertB,(a:Vertex,b:Vertex)=>new Vector(a,b));
};
/**
* Get the perpendicular of this vector which is located at a.
*
* @param {Number} t The position on the vector.
* @return {Vector} A new vector being the perpendicular of this vector sitting on a.
**/
perp():Vector {
var v : Vector = this.clone();
v.sub( this.a );
v = new Vector( new Vertex(), new Vertex(-v.b.y,v.b.x) );
v.a.add( this.a );
v.b.add( this.a );
return v;
};
/**
* The inverse of a vector is a vector witht the same magnitude but oppose direction.
*
* Please not that the origin of this vector changes here: a->b becomes b->a.
*
* @return {Vector}
**/
inverse():Vector {
var tmp = this.a;
this.a = this.b;
this.b = tmp;
return this;
};
/**
* This function computes the inverse of the vector, which means 'a' stays untouched.
*
* @return {Vector} this for chaining.
**/
inv():Vector {
this.b.x = this.a.x-(this.b.x-this.a.x);
this.b.y = this.a.y-(this.b.y-this.a.y);
return this;
};
/**
* Get the intersection if this vector and the specified vector.
*
* @method intersection
* @param {Vector} line The second vector.
* @return {Vertex} The intersection (may lie outside the end-points).
* @instance
* @memberof Line
**/
intersection( line:Vector ):Vertex|null {
var denominator = this.denominator(line);
if( denominator == 0 )
return null;
var a = this.a.y - line.a.y;
var b = this.a.x - line.a.x;
var numerator1 = ((line.b.x - line.a.x) * a) - ((line.b.y - line.a.y) * b);
var numerator2 = ((this.b.x - this.a.x) * a) - ((this.b.y - this.a.y) * b);
a = numerator1 / denominator; // NaN if parallel lines
b = numerator2 / denominator;
// TODO:
// FOR A VECTOR THE LINE-INTERSECTION MUST BE ON BOTH VECTORS
// if we cast these lines infinitely in both directions, they intersect here:
return new Vertex( this.a.x + (a * (this.b.x - this.a.x)),
this.a.y + (a * (this.b.y - this.a.y)) );
};
/**
* Create an SVG representation of this line.
*
* @deprecated DEPRECATION Please use the drawutilssvg library and an XMLSerializer instead.
* @method toSVGString
* @override
* @param {object=} options - A set of options, like 'className'.
* @return {string} The SVG string representation.
* @instance
* @memberof Vector
**/
toSVGString( options:{className?:string} ) {
options = options || {};
var buffer = [];
var vertices = Vector.utils.buildArrowHead( this.a, this.b, 8, 1.0, 1.0 );
buffer.push( '<g' );
if( options.className )
buffer.push( ' class="' + options.className + '"' );
buffer.push( '>' );
buffer.push( ' <line' );
buffer.push( ' x1="' + this.a.x + '"' );
buffer.push( ' y1="' + this.a.y + '"' );
buffer.push( ' x2="' + vertices[0].x + '"' );
buffer.push( ' y2="' + vertices[0].y + '"' );
buffer.push( ' />' );
// Add arrow head
buffer.push( ' <polygon points="' );
for( var i = 0; i < vertices.length; i++ ) {
if( i > 0 )
buffer.push( ' ' );
buffer.push( '' + vertices[i].x + ',' + vertices[i].y );
}
buffer.push( '"/>' );
buffer.push( '</g>' );
return buffer.join('');
};
static utils = {
/**
* Generate a four-point arrow head, starting at the vector end minus the
* arrow head length.
*
* The first vertex in the returned array is guaranteed to be the located
* at the vector line end minus the arrow head length.
*
*
* Due to performance all params are required.
*
* The params scaleX and scaleY are required for the case that the scaling is not uniform (x and y
* scaling different). Arrow heads should not look distored on non-uniform scaling.
*
* If unsure use 1.0 for scaleX and scaleY (=no distortion).
* For headlen use 8, it's a good arrow head size.
*
* Example:
* buildArrowHead( new Vertex(0,0), new Vertex(50,100), 8, 1.0, 1.0 )
*
* @param {Vertex} zA - The start vertex of the vector to calculate the arrow head for.
* @param {Vertex} zB - The end vertex of the vector.
* @param {number} headlen - The length of the arrow head (along the vector direction. A good value is 12).
* @param {number} scaleX - The horizontal scaling during draw.
* @param {number} scaleY - the vertical scaling during draw.
**/
buildArrowHead : ( zA:Vertex, zB:Vertex, headlen:number, scaleX:number, scaleY:number ) => {
var angle = Math.atan2( (zB.y-zA.y)*scaleY, (zB.x-zA.x)*scaleX );
var vertices = [];
vertices.push( new Vertex(zB.x*scaleX-(headlen)*Math.cos(angle), zB.y*scaleY-(headlen)*Math.sin(angle)) );
vertices.push( new Vertex(zB.x*scaleX-(headlen*1.35)*Math.cos(angle-Math.PI/8), zB.y*scaleY-(headlen*1.35)*Math.sin(angle-Math.PI/8) ) );
vertices.push( new Vertex(zB.x*scaleX, zB.y*scaleY) );
vertices.push( new Vertex(zB.x*scaleX-(headlen*1.35)*Math.cos(angle+Math.PI/8), zB.y*scaleY-(headlen*1.35)*Math.sin(angle+Math.PI/8)) );
return vertices;
}
}
}