5 #include "rs_graphicview.h"
6 #include "rs_graphic.h"
12 RS_Line::RS_Line(RS_EntityContainer * parent, const RS_LineData & d):
13 RS_AtomicEntity(parent), data(d)
25 RS_Entity * RS_Line::clone()
27 RS_Line * l = new RS_Line(*this);
32 void RS_Line::calculateBorders()
34 minV = Vector::minimum(data.startpoint, data.endpoint);
35 maxV = Vector::maximum(data.startpoint, data.endpoint);
38 /** @return RS2::EntityLine */
39 RS2::EntityType RS_Line::rtti() const
41 return RS2::EntityLine;
45 bool RS_Line::isEdge() const
50 /** @return Copy of data that defines the line. */
51 RS_LineData RS_Line::getData() const
56 VectorSolutions RS_Line::getRefPoints()
58 VectorSolutions ret(data.startpoint, data.endpoint);
62 /** @return Start point of the entity */
63 Vector RS_Line::getStartpoint() const
65 return data.startpoint;
68 /** @return End point of the entity */
69 Vector RS_Line::getEndpoint() const
74 /** Sets the startpoint */
75 void RS_Line::setStartpoint(Vector s)
81 /** Sets the endpoint */
82 void RS_Line::setEndpoint(Vector e)
89 * @return Direction 1. The angle at which the line starts at
92 double RS_Line::getDirection1() const
98 * @return Direction 2. The angle at which the line starts at
101 double RS_Line::getDirection2() const
106 Vector RS_Line::getNearestEndpoint(const Vector & coord, double * dist)
109 Vector * nearerPoint;
111 dist1 = data.startpoint.distanceTo(coord);
112 dist2 = data.endpoint.distanceTo(coord);
119 nearerPoint = &data.endpoint;
126 nearerPoint = &data.startpoint;
132 Vector RS_Line::getNearestPointOnEntity(const Vector & coord,
133 bool onEntity, double * dist, RS_Entity ** entity)
138 Vector ae = data.endpoint-data.startpoint;
139 Vector ea = data.startpoint-data.endpoint;
140 Vector ap = coord-data.startpoint;
141 Vector ep = coord-data.endpoint;
143 if (ae.magnitude() < 1.0e-6 || ea.magnitude() < 1.0e-6)
146 *dist = RS_MAXDOUBLE;
148 return Vector(false);
151 // Orthogonal projection from both sides:
152 Vector ba = ae * Vector::dotP(ae, ap) / (ae.magnitude() * ae.magnitude());
153 Vector be = ea * Vector::dotP(ea, ep) / (ea.magnitude() * ea.magnitude());
155 // Check if the projection is within this line:
156 if (onEntity == true && (ba.magnitude() > ae.magnitude() || be.magnitude() > ea.magnitude()))
158 return getNearestEndpoint(coord, dist);
163 *dist = coord.distanceTo(data.startpoint + ba);
165 return data.startpoint + ba;
169 Vector RS_Line::getNearestCenter(const Vector & coord, double * dist)
171 Vector p = (data.startpoint + data.endpoint) / 2.0;
174 *dist = p.distanceTo(coord);
179 Vector RS_Line::getNearestMiddle(const Vector & coord, double * dist)
181 return getNearestCenter(coord, dist);
184 Vector RS_Line::getNearestDist(double distance, const Vector & coord, double * dist)
186 double a1 = getAngle1();
189 dv.setPolar(distance, a1);
191 Vector p1 = data.startpoint + dv;
192 Vector p2 = data.endpoint - dv;
195 Vector * nearerPoint;
197 dist1 = p1.distanceTo(coord);
198 dist2 = p2.distanceTo(coord);
222 Vector RS_Line::getNearestDist(double distance, bool startp)
224 double a1 = getAngle1();
227 dv.setPolar(distance, a1);
231 ret = data.startpoint + dv;
233 ret = data.endpoint - dv;
238 /*Vector RS_Line::getNearestRef(const Vector& coord, double* dist)
242 Vector p1 = getNearestEndpoint(coord, &d1);
243 Vector p2 = getNearestMiddle(coord, &d2);
260 double RS_Line::getDistanceToPoint(const Vector & coord, RS_Entity ** entity,
261 RS2::ResolveLevel /*level*/, double /*solidDist*/)
263 RS_DEBUG->print("RS_Line::getDistanceToPoint");
268 // check endpoints first:
269 double dist = coord.distanceTo(getStartpoint());
273 RS_DEBUG->print("RS_Line::getDistanceToPoint: OK1");
277 dist = coord.distanceTo(getEndpoint());
281 RS_DEBUG->print("RS_Line::getDistanceToPoint: OK2");
286 Vector ae = data.endpoint-data.startpoint;
287 Vector ea = data.startpoint-data.endpoint;
288 Vector ap = coord-data.startpoint;
289 Vector ep = coord-data.endpoint;
291 if (ae.magnitude() < 1.0e-6 || ea.magnitude() < 1.0e-6)
293 RS_DEBUG->print("RS_Line::getDistanceToPoint: OK2a");
297 // Orthogonal projection from both sides:
298 Vector ba = ae * Vector::dotP(ae, ap) / RS_Math::pow(ae.magnitude(), 2);
299 Vector be = ea * Vector::dotP(ea, ep) / RS_Math::pow(ea.magnitude(), 2);
301 // Check if the projection is outside this line:
302 if (ba.magnitude() > ae.magnitude() || be.magnitude() > ea.magnitude())
304 // return distance to endpoint
305 getNearestEndpoint(coord, &dist);
306 RS_DEBUG->print("RS_Line::getDistanceToPoint: OK3");
309 //RS_DEBUG->print("ba: %f", ba.magnitude());
310 //RS_DEBUG->print("ae: %f", ae.magnitude());
312 Vector cp = Vector::crossP(ap, ae);
313 dist = cp.magnitude() / ae.magnitude();
315 RS_DEBUG->print("RS_Line::getDistanceToPoint: OK4");
320 void RS_Line::moveStartpoint(const Vector & pos)
322 data.startpoint = pos;
326 void RS_Line::moveEndpoint(const Vector & pos)
332 RS2::Ending RS_Line::getTrimPoint(const Vector & coord, const Vector & trimPoint)
334 double angEl = getAngle1();
335 double angM = trimPoint.angleTo(coord);
336 double angDif = angEl - angM;
342 angDif = 2 * M_PI - angDif;
344 if (angDif < M_PI / 2.0)
345 return RS2::EndingStart;
347 return RS2::EndingEnd;
350 void RS_Line::reverse()
352 Vector v = data.startpoint;
353 data.startpoint = data.endpoint;
357 /** @return the center point of the line. */
358 Vector RS_Line::getMiddlepoint()
360 return (data.startpoint + data.endpoint) / 2.0;
363 /** Sets the y coordinate of the startpoint */
364 void RS_Line::setStartpointY(double val)
366 data.startpoint.y = val;
370 /** Sets the y coordinate of the endpoint */
371 void RS_Line::setEndpointY(double val)
373 data.endpoint.y = val;
378 * @return The length of the line.
380 double RS_Line::getLength()
382 return data.startpoint.distanceTo(data.endpoint);
386 * @return The angle of the line (from start to endpoint).
388 double RS_Line::getAngle1() const
390 return data.startpoint.angleTo(data.endpoint);
394 * @return The angle of the line (from end to startpoint).
396 double RS_Line::getAngle2() const
398 return data.endpoint.angleTo(data.startpoint);
401 bool RS_Line::hasEndpointsWithinWindow(Vector v1, Vector v2)
403 if (data.startpoint.isInWindow(v1, v2) || data.endpoint.isInWindow(v1, v2))
409 void RS_Line::move(Vector offset)
411 RS_DEBUG->print("RS_Line::move1: sp: %f/%f, ep: %f/%f",
412 data.startpoint.x, data.startpoint.y, data.endpoint.x, data.endpoint.y);
413 RS_DEBUG->print("RS_Line::move1: offset: %f/%f", offset.x, offset.y);
414 data.startpoint.move(offset);
415 data.endpoint.move(offset);
417 RS_DEBUG->print("RS_Line::move2: sp: %f/%f, ep: %f/%f",
418 data.startpoint.x, data.startpoint.y, data.endpoint.x, data.endpoint.y);
421 void RS_Line::rotate(Vector center, double angle)
423 RS_DEBUG->print("RS_Line::rotate");
424 RS_DEBUG->print("RS_Line::rotate1: sp: %f/%f, ep: %f/%f",
425 data.startpoint.x, data.startpoint.y, data.endpoint.x, data.endpoint.y);
426 data.startpoint.rotate(center, angle);
427 data.endpoint.rotate(center, angle);
428 RS_DEBUG->print("RS_Line::rotate2: sp: %f/%f, ep: %f/%f",
429 data.startpoint.x, data.startpoint.y, data.endpoint.x, data.endpoint.y);
431 RS_DEBUG->print("RS_Line::rotate: OK");
434 void RS_Line::scale(Vector center, Vector factor)
436 RS_DEBUG->print("RS_Line::scale1: sp: %f/%f, ep: %f/%f",
437 data.startpoint.x, data.startpoint.y, data.endpoint.x, data.endpoint.y);
438 data.startpoint.scale(center, factor);
439 data.endpoint.scale(center, factor);
440 RS_DEBUG->print("RS_Line::scale2: sp: %f/%f, ep: %f/%f",
441 data.startpoint.x, data.startpoint.y, data.endpoint.x, data.endpoint.y);
445 void RS_Line::mirror(Vector axisPoint1, Vector axisPoint2)
447 data.startpoint.mirror(axisPoint1, axisPoint2);
448 data.endpoint.mirror(axisPoint1, axisPoint2);
453 * Stretches the given range of the entity by the given offset.
455 void RS_Line::stretch(Vector firstCorner, Vector secondCorner, Vector offset)
457 if (getStartpoint().isInWindow(firstCorner, secondCorner))
458 moveStartpoint(getStartpoint() + offset);
460 if (getEndpoint().isInWindow(firstCorner, secondCorner))
461 moveEndpoint(getEndpoint() + offset);
464 void RS_Line::moveRef(const Vector& ref, const Vector& offset)
466 if (ref.distanceTo(data.startpoint)<1.0e-4) {
467 moveStartpoint(data.startpoint+offset);
469 if (ref.distanceTo(data.endpoint)<1.0e-4) {
470 moveEndpoint(data.endpoint+offset);
474 //void RS_Line::draw(RS_Painter * painter, RS_GraphicView * view, double patternOffset)
475 void RS_Line::draw(PaintInterface * painter, RS_GraphicView * view, double patternOffset)
477 if (painter == NULL || view == NULL)
479 //printf("RS_Line::draw(): Bailing out!!! painter=%08X, view=%08X\n", painter, view);
483 double styleFactor = getStyleFactor(view);
485 if (getPen().getLineType() == RS2::SolidLine || isSelected()
486 || view->getDrawingMode() == RS2::ModePreview
487 || styleFactor < 0.0)
489 //printf("RS_Line::draw(): Drawing line...\n");
490 painter->drawLine(view->toGui(getStartpoint()), view->toGui(getEndpoint()));
496 RS_LineTypePattern * pat;
499 pat = &patternSelected;
501 pat = view->getPattern(getPen().getLineType());
503 RS_LineTypePattern * pat = (isSelected() ? &patternSelected : view->getPattern(getPen().getLineType()));
508 //printf("RS_Line::draw(): Pattern == NULL!\n");
509 RS_DEBUG->print(RS_Debug::D_WARNING, "RS_Line::draw: Invalid line pattern");
513 //printf("RS_Line::draw(): Drawing a patterned line...(?)\n");
514 // Pen to draw pattern is always solid:
515 RS_Pen pen = painter->getPen();
516 pen.setLineType(RS2::SolidLine);
517 painter->setPen(pen);
523 double length = getLength();
524 double angle = getAngle1();
526 // pattern segment length:
527 double patternSegmentLength = 0.0;
530 Vector * dp = new Vector[pat->num];
532 for (i=0; i<pat->num; ++i)
534 dp[i] = Vector(cos(angle) * fabs(pat->pattern[i] * styleFactor),
535 sin(angle) * fabs(pat->pattern[i] * styleFactor));
537 patternSegmentLength += fabs(pat->pattern[i] * styleFactor);
540 // handle pattern offset:
543 if (patternOffset < 0.0)
544 m = (int)ceil(patternOffset / patternSegmentLength);
546 m = (int)floor(patternOffset / patternSegmentLength);
548 patternOffset -= (m * patternSegmentLength);
549 //if (patternOffset<0.0) {
550 // patternOffset+=patternSegmentLength;
552 //RS_DEBUG->print("pattern. offset: %f", patternOffset);
553 Vector patternOffsetVec;
554 patternOffsetVec.setPolar(patternOffset, angle);
556 double tot = patternOffset;
558 // bool cutStartpoint, cutEndpoint, drop;
559 Vector curP = getStartpoint() + patternOffsetVec;
564 // line segment (otherwise space segment)
565 if (pat->pattern[i] > 0.0)
567 bool cutStartpoint = false;
568 bool cutEndpoint = false;
571 // drop the whole pattern segment line:
572 if ((tot + pat->pattern[i] * styleFactor) < 0.0)
578 // trim startpoint of pattern segment line to line startpoint
580 cutStartpoint = true;
582 // trim endpoint of pattern segment line to line endpoint
583 if ((tot + pat->pattern[i] * styleFactor) > length)
590 Vector p2 = curP + dp[i];
593 p1 = getStartpoint();
598 painter->drawLine(view->toGui(p1), view->toGui(p2));
603 tot += fabs(pat->pattern[i] * styleFactor);
604 //RS_DEBUG->print("pattern. tot: %f", tot);
611 done = (tot > length);
619 * Dumps the point's data to stdout.
621 std::ostream & operator<<(std::ostream & os, const RS_Line & l)
623 os << " Line: " << l.getData() << "\n";