GLine.java
/*
* ..::jDrawingLib::..
*
* Copyright (C) Federico Vera 2012 - 2023 <[email protected]>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or any later
* version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.dkt.graphics.elements;
import java.awt.Graphics2D;
/**
* This class represents a line segment
*
* @author Federico Vera {@literal<[email protected]>}
*/
public class GLine extends GraphicE {
private int x1, y1, x2, y2;
/**
* Copy constructor
*
* @param e {@code GLine} to copy
* @throws IllegalArgumentException if {@code e} is {@code null}
*/
public GLine(GLine e) {
super(e);
x1 = e.x1;
x2 = e.x2;
y1 = e.y1;
y2 = e.y2;
}
/**
* Constructs a new line segment based on the end points
*
* @param p1 start point
* @param p2 end point
*/
public GLine(
final GPoint p1,
final GPoint p2) throws IllegalArgumentException
{
this(p1.x(), p1.y(), p2.x(), p2.y());
}
/**
* Constructs a new line segment based on the end points
*
* @param x1 x coordinate of the start point
* @param y1 y coordinate of the start point
* @param x2 x coordinate of the end point
* @param y2 y coordinate of the end point
*/
public GLine(
final int x1,
final int y1,
final int x2,
final int y2)
{
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
/**
* Retrieves the middle point of the line
*
* @return middle point
*/
public GPoint getMiddlePoint() {
final int x = Math.min(x1, x2) + Math.abs(x1 - x2) / 2;
final int y = Math.min(y1, y2) + Math.abs(y1 - y2) / 2;
return new GPoint(x, y);
}
/**
* Constructs a new line based on its start point, length and angle
*
* @param x x coordinate of the start point
* @param y y coordinate of the start point
* @param length length of the vector
* @param angle angle (in degrees) of the line segment
*/
public GLine (
final int x,
final int y,
final double length,
final double angle)
{
this.x1 = x;
this.y1 = y;
this.x2 = x + (int)(length * Math.cos(Math.toRadians(angle)));
this.y2 = y + (int)(length * Math.sin(Math.toRadians(angle)));
}
/**
* Retrieves an orthogonal line that segment contains (0, 0) as it's start
* point
*
* @return Orthogonal {@code GLine}
*/
public GLine getOrthogal() {
return getOrthogal(0, 0);
}
/**
* Retrieves an orthogonal line segment that contains (x, y) as it's start
* point
*
* @param x x coordinate of the start point
* @param y y coordinate of the start point
* @return Orthogonal {@code GLine}
*/
public GLine getOrthogal(final int x, final int y) {
return new GLine(x, y, modulus(), 90 + getArgument());
}
/**
* Retrieves an parallel line segment that contains (x, y) as it's start
* point
*
* @param x x coordinate of the start point
* @param y y coordinate of the start point
* @return Orthogonal {@code GLine}
*/
public GLine getParallel(final int x, final int y) {
return new GLine(x, y, modulus(), getArgument());
}
/**
* Retrieves a copy of the start point of this line segment
*
* @return start {@link GPoint} of the line segment
*/
public GPoint getStartPoint() {
return new GPoint(x1, y1);
}
/**
* Retrieves a copy of the end point of this line segment
*
* @return end {@link GPoint} of the line segment
*/
public GPoint getEndPoint() {
return new GPoint(x2, y2);
}
/**
* Retrieves the argument of the line segment (in radians)
*
* @return angle in radians
*/
public double getRadArgument() {
return Math.atan2(y2 - y1, x2 - x1);
}
/**
* Retrieves the argument of the line segment (in degrees)
*
* @return angle in degrees
*/
public double getArgument() {
return Math.toDegrees(Math.atan2(y2 - y1, x2 - x1));
}
/**
* Retrieves the length of the line segment
*
* @return length
*/
public double modulus() {
return Math.hypot(y2 - y1, x2 - x1);
}
/**
* Tells if a point is contained in this line segment
*
* @param p point to check
* @return {@code true} if the point is contained in the segment and
* {@code false} otherwise
* @throws IllegalArgumentException if {@code p} is {@code null}
*/
public boolean contains(final GPoint p){
if (p == null){
throw new IllegalArgumentException("The point can't be null");
}
return contains(p.x(), p.y());
}
/**
* Tells if a point is contained in this line segment
*
* @param x the X coordinate of the point
* @param y the Y coordinate of the point
* @return {@code true} if the point is contained in the segment and
* {@code false} otherwise
*/
public boolean contains(final int x, final int y) {
if ( (x == x1 && y == y1) || (x == x2 && y == y2)) {
return true;
}
//http://stackoverflow.com/questions/17581738/
// check-if-a-point-projected-on-a-line-segment-is-not-outside-it
final double m = (double) (y2 - y1) / (x2 - x1);
final double r1 = y1 + m * x1;
final double r2 = y2 + m * x2;
final double r = y + m * x;
//@TODO This can be unbranched
return r1 < r2 ? (r1 <= r & r <= r2) : (r2 <= r & r <= r1);
}
@Override
public void draw(final Graphics2D g) {
g.setPaint(getPaint());
g.setStroke(getStroke());
g.drawLine(x1, y1, x2, y2);
}
@Override
public void traslate(final int x, final int y) {
x1 += x;
x2 += x;
y1 += y;
y2 += y;
}
@Override
public GLine clone() {
return new GLine(this);
}
@Override
public int hashCode() {
int hash = super.hashCode();
hash = 11 * hash + x1;
hash = 11 * hash + y1;
hash = 11 * hash + x2;
hash = 11 * hash + y2;
return hash;
}
@Override
public boolean equals(Object obj) {
if (!super.equals(obj)) {
return false;
}
final GLine other = (GLine) obj;
return !(
x1 != other.x1 |
y1 != other.y1 |
x2 != other.x2 |
y2 != other.y2
);
}
}