summaryrefslogtreecommitdiff
path: root/graphics/epix/samples/log.xp
blob: 4f16921cdf4a4865cc40b44242b6c37e1572f116 (plain)
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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
/* -*-ePiX-*- */
#include "epix.h"
using namespace ePiX;

// October 28, 2006
//
// This file depicts two sheets of the Riemann surface of log, together
// with the log function over the unit circle. Surface and path elements
// must be drawn together. However, path-like mesh elements must be drawn
// after surface elements that lie at the same location in the scene,
// since otherwise surface elements' edges occlude the path.
//
// A mesh_elt class stores the necessary P data as well as a flag marking
// the element as a segment or a surface patch. Elements are stored in a
// std::vector (global to the scene) and sorted by distance. To ensure that
// surface patches are printed first, their true distance is increased by a
// "fudge" amount (0.25), making the By_distance class see them as farther
// than they really are.
//
// Path elements are drawn in green; surface patches are shaded gray
// according to the angle between the incoming light (from a point source)
// and the surface normal.
//
// Surface patches are drawn as octagons to make the mesh appear smoother
// than a quadrilateral mesh. The vertices of a patch are the images of the
// corners and midpoints of a coordinate quadrilateral, "retracted" inward
// by a small "gap" EPS (possibly zero). A positive gap simulates surface
// transparency.
//
// (u,v+dv)            (u+0.5*du,v+dv)          (u+du,v+dv)
//    +----------------------+-----------------------+
//    | *--------------------*---------------------* |
//    | |                                          | |
//    | |                                          | |
//    | |                                          | |
//    + * (u+EPS,v+0.5*dv)                         * + (u+du,v+0.5*dv)
//    | |                                          | |
//    | |                                          | |
//    | | (u+EPS,v+EPS)                            | |
//    | *--------------------*---------------------* |
//    +----------------------+-----------------------+
//  (u,v)               (u+0.5*du,v)              (u+du,v)


const P LIGHT(2, 2, 0); // location of light, for shading
const P VIEWPT(15,-10,6);

// surface and path mesh fineness
const int N1(18);
const int N2(80);

const int N3(120);

const double du(4.5/N1);
const double dv(6.0/N2);

const double dt(4.0/N3);

// "gap size" between surface mesh elements
const double EPS(0); // (0.002);

// visual styles
void  path_color() { green(0.8); }
void label_color() { yellow(0.5); }
void   dot_color() { red(); }
void  path_width() { pen(1.5); }

// class can represent either a surface element or a path element
class mesh_elt {
private:
  P pt1, pt2, pt3, pt4, pt5, pt6, pt7, pt8, center;

  double fudge; // artificial increment to distance
  static bool last_was_seg;
  bool is_segment;

public:
  double how_far() const
  {
    return fudge + norm(center -  camera.viewpt());
  }

  mesh_elt(P f(double u, double v), double u0, double v0)
    : pt1(f(u0+EPS,v0+EPS)),       pt2(f(u0+0.5*du,v0+EPS)),
      pt3(f(u0+du-EPS,v0+EPS)),    pt4(f(u0+du-EPS,v0+0.5*dv)),
      pt5(f(u0+du-EPS,v0+dv-EPS)), pt6(f(u0+0.5*du,v0+dv-EPS)),
      pt7(f(u0+EPS,v0+dv-EPS)),    pt8(f(u0+EPS,v0+0.5*dv)),
      center(0.25*(pt1 + (pt3 + (pt5 + pt7)))),
      fudge(0.25), is_segment(false) { }

  mesh_elt(P f(double), double t0)
    : pt1(f(t0)), pt2(f(t0+0.25*dt)), pt3(f(t0+0.5*dt)),
      pt4(f(t0+0.75*dt)), pt5(f(t0+dt)), pt6(), pt7(), pt8(),
      center(0.333*(pt1 + (pt3 + pt5))),
      fudge(0), is_segment(true) { }

  void draw() const
  { 
    if (!is_segment) {
      P normal((pt2 - pt1)*(pt4 - pt1));
      normal *= 1/norm(normal);

      double dens(0.5*(1-((normal|LIGHT)/norm(LIGHT))));

      if (mesh_elt::last_was_seg)
	{
	  mesh_elt::last_was_seg=false;
	  plain(); // reset pen width
	}

      black();
      gray(dens);

      std::vector<P> bd;
      bd.push_back(pt1);
      bd.push_back(pt2);
      bd.push_back(pt3);
      bd.push_back(pt4);
      bd.push_back(pt5);
      bd.push_back(pt6);
      bd.push_back(pt7);
      bd.push_back(pt8);

      path temp(bd, true, true); // closed and filled
      temp.draw();
    }
    else { // segment
      if (!mesh_elt::last_was_seg)
	{
	  mesh_elt::last_was_seg=true;
	  path_width();
	  path_color();
	}

      std::vector<P> bd;
      bd.push_back(pt1);
      bd.push_back(pt2);
      bd.push_back(pt3);
      bd.push_back(pt4);
      bd.push_back(pt5);

      path temp(bd, false, false);
      temp.draw();
    }

  } // end of mesh_elt::draw()

}; // end of class mesh_elt

// initialize static data
bool mesh_elt::last_was_seg = false;

class By_distance {
public:
  bool operator() (const mesh_elt arg1, const mesh_elt arg2)
  {
    return (arg1.how_far()) > (arg2.how_far());
  }
};

// the maps to be plotted
P C_log(double u, double v)
{
  return polar(exp(u), M_PI*v) + P(0, 0, u+M_PI*v);
}

P C_log1(double t)
{
  return C_log(0,t);
}

int main() {
  bounding_box(P(-6, -12),P(6,12));
  unitlength("1in");
  picture(P(4,8));

  begin();
  fill();

  degrees();
  //  label_angle(90);
  label(P(0, ymin()), P(0,4), 
	"$z=\\mathrm{Re}\\,\\log(x+iy) + \\mathrm{Im}\\,\\log(x+iy)$", t);
  radians();
  //  label_angle(0);

  viewpoint(VIEWPT);
  camera.range(20);

  std::vector<mesh_elt> mesh_data;

  // surface elements
  for (int i=0; i<N1; ++i)
    for (int j=0; j<N2; ++j)
      mesh_data.push_back(mesh_elt(C_log, -3+du*i, -3+dv*j));

  // path elements
  for (int i=0; i<N3; ++i)
    mesh_data.push_back(mesh_elt(C_log1, -2+i*dt));

  stable_sort(mesh_data.begin(), mesh_data.end(), By_distance());

  for (int i=0; i<mesh_data.size(); ++i)
    mesh_data.at(i).draw();

  dot_color();
  marker(C_log(0,-2), BOX);
  marker(C_log(0, 0), BOX);
  marker(C_log(0, 2), BOX);

  label_color();
  label(C_log(0,-2), P(6, 0), "$-2\\pi i$", r);
  label(C_log(0, 0), P(6, 0), "$0$", r);
  label(C_log(0, 2), P(-6, 0), "$2\\pi i$", l);

  end();
}