-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSegment.m
More file actions
151 lines (145 loc) · 4.36 KB
/
Segment.m
File metadata and controls
151 lines (145 loc) · 4.36 KB
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
%% Segment: A single connection between two points
%
% A single connection between two points without marker!
%
%%% Fields
%
% * Start: A Point that represents where this segment starts
%
% * Stop: A Point that represents where this segment ends
%
% * Color: A 1x3 vector that represents the color
%
% * Style: A character vector that represents the style (i.e., dashed.
% etc.)
%
%%% Methods
%
% * Segment
%
% * equals
%
% * dataEquals
%
%%% Remarks
%
% This class keeps data for a single segment - a connection. It does not
% care about what the endpoints look like - only where they are.
%
% The Point will not have a style - just coordinates
%
classdef Segment < handle
properties (Access = public)
Start;
Stop;
Color double;
Style char;
end
methods
%% Constructor
%
% Segment(S, E, C, L) will use start S and stop E to make a
% segment, with color C and line style L.
%
%%% Remarks
%
% S and E can be Points or coordinates - if the latter, they will
% be constructed into points
function this = Segment(start, stop, color, style)
if nargin == 0
return;
end
if isa(start, 'Point')
this.Start = start;
this.Stop = stop;
else
this.Start = Point(start);
this.Stop = Point(stop);
end
pts = sort([this.Start, this.Stop]);
this.Start = pts(1);
this.Stop = pts(2);
this.Color = color;
if strcmp(style, 'none')
this.Style = '';
else
this.Style = style;
end
end
end
methods (Access = public)
function tf = equals(this, that)
if isempty(this)
tf = [];
return;
elseif isempty(that)
tf = false;
return;
end
orig = this;
this = reshape(this, 1, []);
that = reshape(that, 1, []);
if isscalar(that)
tmp(numel(this)) = that;
tmp(:) = that;
that = tmp;
tmp = tmp(false);
end
if isscalar(this)
tmp(numel(that)) = this;
tmp(:) = this;
this = tmp;
end
tf = this.dataEquals(that) ...
& cellfun(@isequal, {this.Color}, {that.Color}) ...
& strcmp({this.Style}, {that.Style});
if isscalar(orig)
tf = reshape(tf, size(that));
else
tf = reshape(tf, size(orig));
end
end
function tf = eq(this, that)
tf = this.equals(that);
end
function tf = ne(this, that)
tf = ~this.equals(that);
end
function tf = dataEquals(this, that)
if isempty(this) || isempty(that)
tf = [];
else
tf = dataEquals([this.Start], [that.Start]) ...
& dataEquals([this.Stop], [that.Stop]);
tf = reshape(tf, size(this));
end
end
function [sorted, inds] = sort(segments, varargin)
if isempty(segments)
sorted = segments;
inds = [];
return;
elseif isscalar(segments)
sorted = segments;
inds = 1;
return;
end
% sort by Point start -> stop
starts = [segments.Start];
xx1 = reshape([starts.X], [], 1);
yy1 = reshape([starts.Y], [], 1);
zz1 = reshape([starts.Z], [], 1);
stops = [segments.Stop];
xx2 = reshape([stops.X], [], 1);
yy2 = reshape([stops.Y], [], 1);
zz2 = reshape([stops.Z], [], 1);
colors = vertcat(segments.Color);
styles = reshape(string({segments.Style}), [], 1);
tmp = compose('%0.5f %0.5f %0.5f %0.5f %0.5f %0.5f %0.5f %0.5f %0.5f %s', ...
[xx1, yy1, zz1, xx2, yy2, zz2, colors], styles);
[~, inds] = sort(tmp, varargin{:});
sorted = segments(inds);
sorted = reshape(sorted, size(segments));
end
end
end