Liang–Barsky algorithm: Difference between revisions

Content deleted Content added
Link suggestions feature: 2 links added.
 
(75 intermediate revisions by 57 users not shown)
Line 1:
{{Short description|Line-clipping algorithm}}
In [[computer graphics]], the '''Liang–Barsky''' algorithm is a [[line clipping]] algorithm. The Liang–Barsky algorithm uses the parametric equation of a line and inequalities describing the range of the clipping box to determine the intersections between the line and the clipping box. With these intersections it knows which portion of the line should be drawn. This algorithm is significantly more efficient than [[Cohen–Sutherland]].
In [[computer graphics]], the '''Liang–Barsky algorithm''' (named after [[You-Dong Liang]] and [[Brian A. Barsky]]) is a [[line clipping]] algorithm. The Liang–Barsky algorithm uses the [[parametric equation]] of a line and inequalities describing the range of the clipping window to determine the intersections between the line and the [[clip window]]. With these intersections, it knows which portion of the line should be drawn. So this algorithm is significantly more efficient than [[Cohen–Sutherland]]. The idea of the Liang–Barsky clipping algorithm is to do as much testing as possible before computing line intersections.
 
==The algorithm== uses the parametric form of a straight line:
Below is a C# implementation for Liang–Barsky algorithm
<source lang="csharp">
internal sealed class LiangBarskyClipping : IClippingAlgorithm {
private Vector2 _clipMin, _clipMax;
 
:<math>x = x_0 + t (x_1 - x_0) = x_0 + t \Delta x,</math>
public IEnumerable<Vector2> GetBoundingPolygon() {
:<math>y = y_0 + t (y_1 - y_0) = y_0 + t \Delta y.</math>
yield return _clipMin;
yield return new Vector2(_clipMax.X, _clipMin.Y);
yield return _clipMax;
yield return new Vector2(_clipMin.X, _clipMax.Y);
}
 
A point is in the clip window, if
public void SetBoundingRectangle(Vector2 start, Vector2 end) {
:<math>x_\text{min} \le x_0 + t \Delta x \le x_\text{max}</math>
_clipMin = start;
and
_clipMax = end;
:<math>y_\text{min} \le y_0 + t \Delta y \le y_\text{max},</math>
}
which can be expressed as the 4 inequalities
:<math>t p_i \le q_i, \quad i = 1, 2, 3, 4,</math>
where
 
:<math>
public void SetBoundingPolygon(IEnumerable<Vector2> points) {
\begin{align}
throw new NotSupportedException("see Capabilities =)");
p_1 &= -\Delta x, & q_1 &= x_0 - x_\text{min}, & &\text{(left)} \\
}
p_2 &= \Delta x, & q_2 &= x_\text{max} - x_0, & &\text{(right)} \\
p_3 &= -\Delta y, & q_3 &= y_0 - y_\text{min}, & &\text{(bottom)} \\
p_4 &= \Delta y, & q_4 &= y_\text{max} - y_0. & &\text{(top)}
\end{align}
</math>
 
To compute the final [[line segment]]:
private delegate bool ClippingHandler(float p, float q);
# A line parallel to a clipping window edge has <math>p_i = 0</math> for that boundary.
# If for that <math>i</math>, <math>q_i < 0</math>, then the line is completely outside and can be eliminated.
# When <math>p_i < 0</math>, the line proceeds outside to inside the clip window, and when <math>p_i > 0</math>, the line proceeds inside to outside.
# For nonzero <math>p_i</math>, <math>u = q_i / p_i</math> gives <math>t</math> for the intersection point of the line and the window edge (possibly projected).
# The two actual intersections of the line with the window edges, if they exist, are described by <math>u_1</math> and <math>u_2</math>, calculated as follows. For <math>u_1</math>, look at boundaries for which <math>p_i < 0</math> (i.e. outside to inside). Take <math>u_1</math> to be the largest among <math>\{0, q_i / p_i\}</math>. For <math>u_2</math>, look at boundaries for which <math>p_i > 0</math> (i.e. inside to outside). Take <math>u_2</math> to be the minimum of <math>\{1, q_i / p_i\}</math>.
# If <math>u_1 > u_2</math>, the line is entirely outside the clip window. If <math>u_1 < 0 < 1 < u_2</math> it is entirely inside it.
 
<syntaxhighlight lang="c++">
public bool ClipLine(ref Line line) {
// Liang–Barsky line-clipping algorithm
Vector2 P = line.End - line.Start;
#include<iostream>
float tMinimum = 0, tMaximum = 1;
#include<graphics.h>
#include<math.h>
 
using namespace std;
ClippingHandler pqClip = delegate(float directedProjection,
float directedDistance) {
if (directedProjection == 0) {
if (directedDistance < 0) return false;
}
else {
float amount = directedDistance / directedProjection;
if (directedProjection < 0) {
if (amount > tMaximum) return false;
else if (amount > tMinimum) tMinimum = amount;
}
else {
if (amount < tMinimum) return false;
else if (amount < tMaximum) tMaximum = amount;
}
}
return true;
};
 
// this function gives the maximum
if (pqClip(-P.X, line.Start.X - _clipMin.X)) {
float maxi(float arr[], int n) {
if (pqClip(P.X, _clipMax.X - line.Start.X)) {
float m = 0;
if (pqClip(-P.Y, line.Start.Y - _clipMin.Y)) {
for (int i = 0; i < n; ++i)
if (pqClip(P.Y, _clipMax.Y - line.Start.Y)) {
if (tMaximumm < 1arr[i]) {
m = arr[i];
line.End.X = line.Start.X + tMaximum * P.X;
return m;
line.End.Y = line.Start.Y + tMaximum * P.Y;
}
}
if (tMinimum > 0) {
line.Start.X += tMinimum * P.X;
line.Start.Y += tMinimum * P.Y;
}
return true;
}
}
}
}
return false;
}
 
// this function gives the minimum
public ClippingCapabilities Capabilities {
float mini(float arr[], int n) {
get {
float m = 1;
return ClippingCapabilities.RectangleWindow;
for (int i = 0; i }< n; ++i)
}if (m > arr[i])
m = arr[i];
 
return m;
public override string ToString() {
return "Liang-Barsky algorithm";
}
}
</source>
 
void liang_barsky_clipper(float xmin, float ymin, float xmax, float ymax,
Java code:
float x1, float y1, float x2, float y2) {
<source lang="java">
// defining variables
/*
float p1 = -(x2 - x1);
* To change this template, choose Tools | Templates
float p2 = -p1;
* and open the template in the editor.
float p3 = -(y2 - y1);
*/
float p4 = -p3;
package lineclip;
/**
*
* @author Alamgir
*/
public class Algorithm
{
/**
* @param args the command line arguments
*/
private int x1, x2, y1, y2;
public void liang_barsky(int x1, int y1, int x2, int y2, int xmin, int ymin, int xmax, int ymax)
{
double deltaX, deltaY, p, q;
double u1 = 0.0, u2 = 1.0;
double r;
 
float deltaXq1 = (x2x1 - x1)xmin;
float deltaYq2 = (y2xmax - y1)x1;
float q3 = y1 - ymin;
float q4 = ymax - y1;
 
float exitParams[5], entryParams[5];
/*
int exitIndex = 1, entryIndex = 1;
* left edge, right edge, bottom edge and top edge checking
exitParams[0] = 1;
*/
entryParams[0] = 0;
double pPart[] = {-1 * deltaX, deltaX, -1 * deltaY, deltaY};
double qPart[] = {x1 - xmin, xmax - x1, y1 - ymin, ymax - y1};
 
rectangle(xmin, ymin, xmax, ymax); // drawing the clipping window
boolean accept = true;
 
if ((p1 == 0 && q1 < 0) || for(p2 int== i0 && q2 < 0) || (p3 == 0; i&& q3 < 4;0) i|| ++(p4 == 0 && q4 < 0)) {
outtextxy(80, 80, "Line is parallel to clipping window!");
{
p = pPart[ i ]return;
}
q = qPart[ i ];
if (p1 != 0) {
float r1 = q1 / p1;
float r2 = q2 / p2;
if (p1 < 0) {
entryParams[entryIndex++] = r1;
exitParams[exitIndex++] = r2;
} else {
entryParams[entryIndex++] = r2;
exitParams[exitIndex++] = r1;
}
}
if (p3 != 0) {
float r3 = q3 / p3;
float r4 = q4 / p4;
if (p3 < 0) {
entryParams[entryIndex++] = r3;
exitParams[exitIndex++] = r4;
} else {
entryParams[entryIndex++] = r4;
exitParams[exitIndex++] = r3;
}
}
 
float clippedX1, clippedY1, clippedX2, clippedY2;
if( p == 0 && q < 0 )
float u1, u2;
{
u1 = maxi(entryParams, entryIndex); // maximum of entry points
accept = false;
u2 = mini(exitParams, exitIndex); // minimum of exit points
break;
}
 
if (u1 > u2) {
r = q / p;
outtextxy(80, 80, "Line is outside the clipping window!");
return;
}
 
clippedX1 = x1 + if(x2 p- <x1) 0* )u1;
clippedY1 = y1 + (y2 - y1) * {u1;
clippedX2 = x1 + (x2 - x1) * u2;
u1 =Math.max(u1, r);
clippedY2 = y1 + (y2 - y1) * }u2;
 
setcolor(CYAN);
if( p > 0 )
line(clippedX1, clippedY1, clippedX2, clippedY2); // draw clipped segment
{
u2 = Math.min(u2, r);
}
 
ifsetlinestyle(1, u1 > u21, 0);
line(x1, y1, clippedX1, clippedY1); // original start to clipped start
{
line(x2, y2, clippedX2, clippedY2); // original end to clipped end
accept = false;
}
break;
}
//System.out.println(u1 +" " + u2);
 
int main() {
}
cout << "\nLiang-Barsky Line Clipping";
if(accept)
cout << "\nThe system window layout is: (0,0) at bottom left and (631, 467) at top right";
{
cout << "\nEnter the coordinates of the window (xmin, ymin, xmax, ymax): ";
if( u2 < 1 )
float xmin, ymin, xmax, ymax;
{
cin >> xmin >> ymin >> xmax >> ymax;
x2 = (int)(x1 + u2 * deltaX);
y2 = (int)(y1 + u2 * deltaY);
}
if( u1 > 0)
{
x1 = (int)(x1 + u1 * deltaX);
y1 = (int)(y1 + u1 * deltaY);
}
set(x1, y1, x2, y2);
}
else
{
set(-1, -1, -1, -1);
}
}
public void set( int x1, int y1, int x2, int y2 )
{
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
return;
}
public int getx1()
{
return x1;
}
public int getx2()
{
return x2;
}
public int gety1()
{
return y1;
}
public int gety2()
{
return y2;
}
}
</source>
 
cout << "\nEnter the endpoints of the line (x1, y1) and (x2, y2): ";
Alternative java code:
float x1, y1, x2, y2;
<source lang="java">
cin >> x1 >> y1 >> x2 >> y2;
 
int gd = DETECT, gm;
/**
initgraph(&gd, &gm, ""); // using winbgim
* 2d clipping with the Liang-Barsky algorithm.
*
* @author Philip Diffenderfer
*
*/
public class Clipping
{
/**
* A point in 2d space.
*/
public class Point
{
public float x, y, z;
}
/**
* A clipping bounds in 2d space.
*/
public class Bounds
{
public float xmin, ymin, xmax, ymax;
}
/**
* Clips the given points against the given clipping bounds. If the line
* lies outside of the clipping bounds then false is returned. If the line
* exists atleast partially in the clipping bounds then the points are
* clipped and true is returned.
*
* @param s
* The starting point of the line.
* @param e
* The ending point of the line.
* @param clip
* The bounds to clip against.
* @return
* True if the line exists in the clipping bounds.
*/
public boolean clipLine(Point s, Point e, Bounds clip)
{
// t-entering is initialized at 0 (s) and t-leaving is initialized at 1 (e)
float t[] = {0, 1};
float dx = e.x - s.x;
// Try clipping line on left edge
if (clipt(-dx, s.x - clip.xmin, t)) return false;
// Try clipping line on right edge
if (clipt(dx, clip.xmax - s.x, t)) return false;
float dy = e.y - s.y;
// Try clipping line on top edge
if (clipt(-dy, s.y - clip.ymin, t)) return false;
// Try clipping line on bottom edge
if (clipt(dy, clip.ymax - s.y, t)) return false;
// Was the ending point clipped?
if (t[1] < 1) {
e.x = s.x + t[1] * dx;
e.y = s.y + t[1] * dy;
}
// Was the starting point clipped?
if (t[0] > 0) {
s.x = s.x + t[0] * dx;
s.y = s.y + t[0] * dy;
}
// Line has been clipped and atleast partially exists in clip
return true;
}
/**
* Clips a line against a given edge and updates a respective t value if the
* line is clipped by that edge. If the line is completely outside the edge
* then true is returned, else false is returned if atleast a part of the
* line is on the inside of the edge.
*
* @param denom
* The denominator to the parametric equation for solving for t.
* @param num
* The numerator to the parametric equation for solving for t.
* @param t
* The array of t values where t[0] is t-entering and t[1] is t-leaving.
* @return
* True if the line is completely outside of the given edge, false if
* the line is atleast partially inside the edge.
*/
private boolean clipt(float denom, float num, float[] t)
{
// Potentially entering intersection...
if (denom > 0) {
// Value of t at intersection
float ti = num / denom;
// t-entering and t-leaving crossover, reject line.
if (ti > t[1]) {
return true;
}
// New t-entering found.
else if (ti > t[0]) {
t[0] = ti;
}
}
// Potentially leaving intersection...
else if (denom < 0) {
// Value of t at intersection
float ti = num / denom;
// t-entering and t-leaving crossover, reject line.
if (ti < t[0]) {
return true;
}
// New t-leaving found.
else if (ti < t[1]) {
t[1] = ti;
}
}
// Line outside of edge, reject.
else if (num > 0) {
return true;
}
// Line is partially or entirely inside of edge.
return false;
}
 
liang_barsky_clipper(xmin, ymin, xmax, ymax, x1, y1, x2, y2);
getch();
closegraph();
}
</syntaxhighlight>
</source>
 
==See also==
Algorithms used for the same purpose:
* [[Cyrus–Beck algorithm]]
* [[Nicholl–Lee–Nicholl algorithm]]
* [[Fast- clipping]]
 
==References==
[[Category:Clipping (computer graphics)]]
* Liang, Y. D., and Barsky, B., "[https://dl.acm.org/doi/pdf/10.1145/357332.357333 A New Concept and Method for Line Clipping]", ''ACM Transactions on Graphics'', 3(1):1–22, January 1984.
* Liang, Y. D., B. A., Barsky, and M. Slater, ''[https://www2.eecs.berkeley.edu/Pubs/TechRpts/1992/CSD-92-688.pdf Some Improvements to a Parametric Line Clipping Algorithm]'', CSD-92-688, Computer Science Division, University of California, Berkeley, 1992.
* James D. Foley. ''[https://books.google.com/books/about/Computer_graphics.html?id=-4ngT05gmAQC Computer graphics: principles and practice]''. Addison-Wesley Professional, 1996. p.&nbsp;117.
 
==External links==
* http://hinjang.com/articles/04.html#eight
* [http://www.skytopia.com/project/articles/compsci/clipping.html Skytopia: The Liang-Barsky line clipping algorithm in a nutshell!]
 
{{DEFAULTSORT:Liang-}}
{{Compu-graphics-stub}}
[[Category:Line clipping algorithms]]