📄 object.cc
字号:
arrow_at_end = at_end; aht = a;}line_object::line_object(const position &s, const position &e, position *p, int i): v(p), n(i), linear_object(s, e){}void line_object::print(){ if (lt.type == line_type::invisible) return; out->line(strt, v, n, lt); if (arrow_at_start) draw_arrow(strt, strt-v[0], aht, lt); if (arrow_at_end) draw_arrow(en, v[n-1] - (n > 1 ? v[n - 2] : strt), aht, lt);}void line_object::update_bounding_box(bounding_box *p){ p->encompass(strt); for (int i = 0; i < n; i++) p->encompass(v[i]);}void line_object::move_by(const position &pos){ linear_object::move_by(pos); for (int i = 0; i < n; i++) v[i] += pos;} void spline_object::update_bounding_box(bounding_box *p){ p->encompass(strt); p->encompass(en); /* If p1 = q1/2 + q2/2 p2 = q1/6 + q2*5/6 p3 = q2*5/6 + q3/6 p4 = q2/2 + q3/2 [ the points for the Bezier cubic ] and t = .5 then (1-t)^3*p1 + 3*t*(t - 1)^2*p2 + 3*t^2*(1-t)*p3 + t^3*p4 [ the equation for the Bezier cubic ] = .125*q1 + .75*q2 + .125*q3 */ for (int i = 1; i < n; i++) p->encompass((i == 1 ? strt : v[i-2])*.125 + v[i-1]*.75 + v[i]*.125);}arrow_object::arrow_object(const position &s, const position &e, position *p, int i): line_object(s, e, p, i){}spline_object::spline_object(const position &s, const position &e, position *p, int i): line_object(s, e, p, i){}void spline_object::print(){ if (lt.type == line_type::invisible) return; out->spline(strt, v, n, lt); if (arrow_at_start) draw_arrow(strt, strt-v[0], aht, lt); if (arrow_at_end) draw_arrow(en, v[n-1] - (n > 1 ? v[n - 2] : strt), aht, lt);}line_object::~line_object(){ a_delete v;}linear_object *object_spec::make_line(position *curpos, direction *dirp){ static position last_line; static int have_last_line = 0; *dirp = dir; // No need to look at at since `at' attribute sets `from' attribute. position startpos = (flags & HAS_FROM) ? from : *curpos; if (!(flags & HAS_SEGMENT)) { if ((flags & IS_SAME) && (type == LINE_OBJECT || type == ARROW_OBJECT) && have_last_line) segment_pos = last_line; else switch (dir) { case UP_DIRECTION: segment_pos.y = segment_height; break; case DOWN_DIRECTION: segment_pos.y = -segment_height; break; case LEFT_DIRECTION: segment_pos.x = -segment_width; break; case RIGHT_DIRECTION: segment_pos.x = segment_width; break; default: assert(0); } } segment_list = new segment(segment_pos, segment_is_absolute, segment_list); // reverse the segment_list so that it's in forward order segment *old = segment_list; segment_list = 0; while (old != 0) { segment *tem = old->next; old->next = segment_list; segment_list = old; old = tem; } // Absolutise all movements position endpos = startpos; int nsegments = 0; for (segment *s = segment_list; s; s = s->next, nsegments++) if (s->is_absolute) endpos = s->pos; else { endpos += s->pos; s->pos = endpos; s->is_absolute = 1; // to avoid confusion } // handle chop line_object *p = 0; position *v = new position[nsegments]; int i = 0; for (s = segment_list; s; s = s->next, i++) v[i] = s->pos; if (flags & IS_DEFAULT_CHOPPED) { lookup_variable("circlerad", &start_chop); end_chop = start_chop; flags |= IS_CHOPPED; } if (flags & IS_CHOPPED) { position start_chop_vec, end_chop_vec; if (start_chop != 0.0) { start_chop_vec = v[0] - startpos; start_chop_vec *= start_chop / hypot(start_chop_vec); } if (end_chop != 0.0) { end_chop_vec = (v[nsegments - 1] - (nsegments > 1 ? v[nsegments - 2] : startpos)); end_chop_vec *= end_chop / hypot(end_chop_vec); } startpos += start_chop_vec; v[nsegments - 1] -= end_chop_vec; endpos -= end_chop_vec; } switch (type) { case SPLINE_OBJECT: p = new spline_object(startpos, endpos, v, nsegments); break; case ARROW_OBJECT: p = new arrow_object(startpos, endpos, v, nsegments); break; case LINE_OBJECT: p = new line_object(startpos, endpos, v, nsegments); break; default: assert(0); } have_last_line = 1; last_line = endpos - startpos; *curpos = endpos; return p;}class arc_object : public linear_object { int clockwise; position cent; double rad;public: arc_object(int, const position &, const position &, const position &); position origin() { return cent; } position center() { return cent; } double radius() { return rad; } position north(); position south(); position east(); position west(); position north_east(); position north_west(); position south_east(); position south_west(); void update_bounding_box(bounding_box *); object_type type() { return ARC_OBJECT; } void print(); void move_by(const position &pos);};arc_object::arc_object(int cw, const position &s, const position &e, const position &c): linear_object(s, e), clockwise(cw), cent(c){ rad = hypot(c - s);}void arc_object::move_by(const position &pos){ linear_object::move_by(pos); cent += pos;}// we get arc corners from the corresponding circleposition arc_object::north(){ position result(cent); result.y += rad; return result;}position arc_object::south(){ position result(cent); result.y -= rad; return result;}position arc_object::east(){ position result(cent); result.x += rad; return result;}position arc_object::west(){ position result(cent); result.x -= rad; return result;}position arc_object::north_east(){ position result(cent); result.x += rad/M_SQRT2; result.y += rad/M_SQRT2; return result;}position arc_object::north_west(){ position result(cent); result.x -= rad/M_SQRT2; result.y += rad/M_SQRT2; return result;}position arc_object::south_east(){ position result(cent); result.x += rad/M_SQRT2; result.y -= rad/M_SQRT2; return result;}position arc_object::south_west(){ position result(cent); result.x -= rad/M_SQRT2; result.y -= rad/M_SQRT2; return result;}void arc_object::print(){ if (lt.type == line_type::invisible) return; if (clockwise) out->arc(en, cent, strt, lt); else out->arc(strt, cent, en, lt); if (arrow_at_start) { position c = cent - strt; draw_arrow(strt, (clockwise ? position(c.y, -c.x) : position(-c.y, c.x)), aht, lt); } if (arrow_at_end) { position e = en - cent; draw_arrow(en, (clockwise ? position(e.y, -e.x) : position(-e.y, e.x)), aht, lt); }}inline double max(double a, double b){ return a > b ? a : b;}void arc_object::update_bounding_box(bounding_box *p){ p->encompass(strt); p->encompass(en); position start_offset = strt - cent; if (start_offset.x == 0.0 && start_offset.y == 0.0) return; position end_offset = en - cent; if (end_offset.x == 0.0 && end_offset.y == 0.0) return; double start_quad = atan2(start_offset.y, start_offset.x)/(M_PI/2.0); double end_quad = atan2(end_offset.y, end_offset.x)/(M_PI/2.0); if (clockwise) { double temp = start_quad; start_quad = end_quad; end_quad = temp; } if (start_quad < 0.0) start_quad += 4.0; while (end_quad <= start_quad) end_quad += 4.0; double radius = max(hypot(start_offset), hypot(end_offset)); for (int q = int(start_quad) + 1; q < end_quad; q++) { position offset; switch (q % 4) { case 0: offset.x = radius; break; case 1: offset.y = radius; break; case 2: offset.x = -radius; break; case 3: offset.y = -radius; break; } p->encompass(cent + offset); }}// We ignore the with attribute. The at attribute always refers to the center.linear_object *object_spec::make_arc(position *curpos, direction *dirp){ *dirp = dir; int cw = (flags & IS_CLOCKWISE) != 0; // compute the start position startpos; if (flags & HAS_FROM) startpos = from; else startpos = *curpos; if (!(flags & HAS_RADIUS)) lookup_variable("arcrad", &radius); // compute the end position endpos; if (flags & HAS_TO) endpos = to; else { position m(radius, radius); // Adjust the signs. if (cw) { if (dir == DOWN_DIRECTION || dir == LEFT_DIRECTION) m.x = -m.x; if (dir == DOWN_DIRECTION || dir == RIGHT_DIRECTION) m.y = -m.y; *dirp = direction((dir + 3) % 4); } else { if (dir == UP_DIRECTION || dir == LEFT_DIRECTION) m.x = -m.x; if (dir == DOWN_DIRECTION || dir == LEFT_DIRECTION) m.y = -m.y; *dirp = direction((dir + 1) % 4); } endpos = startpos + m; } // compute the center position centerpos; if (flags & HAS_AT) centerpos = at; else if (startpos == endpos) centerpos = startpos; else { position h = (endpos - startpos)/2.0; double d = hypot(h); if (radius <= 0) radius = .25; // make the radius big enough while (radius < d) radius *= 2.0; double alpha = acos(d/radius); double theta = atan2(h.y, h.x); if (cw) theta -= alpha; else theta += alpha; centerpos = position(cos(theta), sin(theta))*radius + startpos; } arc_object *p = new arc_object(cw, startpos, endpos, centerpos); *curpos = endpos; return p;}graphic_object *object_spec::make_linear(position *curpos, direction *dirp){ linear_object *obj; if (type == ARC_OBJECT) obj = make_arc(curpos, dirp); else obj = make_line(curpos, dirp); if (type == ARROW_OBJECT && (flags & (HAS_LEFT_ARROW_HEAD|HAS_RIGHT_ARROW_HEAD)) == 0) flags |= HAS_RIGHT_ARROW_HEAD; if (obj && (flags & (HAS_LEFT_ARROW_HEAD|HAS_RIGHT_ARROW_HEAD))) { arrow_head_type a; int at_start = (flags & HAS_LEFT_ARROW_HEAD) != 0; int at_end = (flags & HAS_RIGHT_ARROW_HEAD) != 0; if (flags & HAS_HEIGHT) a.height = height; else lookup_variable("arrowht", &a.height); if (flags & HAS_WIDTH) a.width = width; else lookup_variable("arrowwid", &a.width); double solid; lookup_variable("arrowhead", &solid); a.solid = solid != 0.0; obj->add_arrows(at_start, at_end, a); } return obj;}object *object_spec::make_object(position *curpos, direction *dirp){ graphic_object *obj = 0; switch (type) { case BLOCK_OBJECT: obj = make_block(curpos, dirp); break; case BOX_OBJECT: obj = make_box(curpos, dirp); break; case TEXT_OBJECT: obj = make_text(curpos, dirp); break; case ELLIPSE_OBJECT: obj = make_ellipse(curpos, dirp); break; case CIRCLE_OBJECT: obj = make_circle(curpos, dirp); break; case MOVE_OBJECT: obj = make_move(curpos, dirp); break; case ARC_OBJECT: case LINE_OBJECT: case SPLINE_OBJECT: case ARROW_OBJECT: obj = make_linear(curpos, dirp); break; case MARK_OBJECT: case OTHER_OBJECT: default: assert(0); break; } if (obj) { if (flags & IS_INVISIBLE) obj->set_invisible(); if (text != 0) obj->add_text(text, (flags & IS_ALIGNED) != 0); if (flags & IS_DOTTED) obj->set_dotted(dash_width); else if (flags & IS_DASHED) obj->set_dashed(dash_width); double th; if (flags & HAS_THICKNESS) th = thickness; else lookup_variable("linethick", &th); obj->set_thickness(th); if (flags & (IS_DEFAULT_FILLED|IS_FILLED)) { if (flags & IS_DEFAULT_FILLED) lookup_variable("fillval", &fill); if (fill < 0.0) error("bad fill value %1", fill); else obj->set_fill(fill); } } return obj;}struct string_list { string_list *next; char *str; string_list(char *); ~string_list();};string_list::string_list(char *s): next(0), str(s){}string_list::~string_list(){ a_delete str;} /* A path is used to hold the argument to the with attribute. For example,`.nw' or `.A.s' or `.A'. The major operation on a path is to take a place and follow the path through the place to place within the place.Note that `.A.B.C.sw' will work. */path::path(corner c): label_list(0), crn(c){}path::path(char *l, corner c): crn(c){ label_list = new string_list(l);}path::~path(){ while (label_list) { string_list *tem = label_list; label_list = label_list->next; delete tem; }}void path::append(corner c){ assert(crn == 0); crn = c;}void path::append(char *s){ for (string_list **p = &label_list; *p; p = &(*p)->next) ; *p = new string_list(s);}// return non-zero for successint path::follow(const place &pl, place *result) const{ const place *p = &pl; for (string_list *lb = label_list; lb; lb = lb->next) if (p->obj == 0 || (p = p->obj->find_label(lb->str)) == 0) { lex_error("object does not contain a place `%1'", lb->str); return 0; } if (crn == 0 || p->obj == 0) *result = *p; else { position pos = ((p->obj)->*(crn))(); result->x = pos.x; result->y = pos.y; result->obj = 0; } return 1;}void print_object_list(object *p){ for (; p; p = p->next) { p->print(); p->print_text(); }}void print_picture(object *obj){ bounding_box bb; for (object *p = obj; p; p = p->next) p->update_bounding_box(&bb); double scale; lookup_variable("scale", &scale); out->start_picture(scale, bb.ll, bb.ur); print_object_list(obj); out->finish_picture();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -