Reputation: 31171
The following diagram illustrates a problem I have encountered creating a Manhattan diagram:
The box surrounds most of the line [(tx,midy)-(sx,midy)] that has overlapped an existing line (represented by psegment
in the code below). I have removed the overlapping arrow heads (and tails) and am a little stumped on how to check for overlap.
Here is the problematic code:
Line2D.Double segment = new Line2D.Double( sx, midy, tx, midy );
// Associate the middle-y point with the bounds of the target object.
// On subsequent draws of targets with a similar mid-y, make sure that
// there are no overlapping lines.
//
if( midPointMap.put( midy, segment ) != null ) {
//if( midy == 90 ) {
// New Line.
//
System.err.printf( "NEW: (%3.2f, %3d)-(%3.2f, %3d)\n", sx, midy, tx,
midy );
for( Line2D.Double psegment : midPointMap.getValues( midy ) ) {
// Previous Line.
//
System.err.printf( "OLD: (%3.2f, %3d)-(%3.2f, %3d)\n",
psegment.getX1(), midy, psegment.getX2(), midy );
}
//}
}
// Line for the bus.
//
result.moveTo( sx, midy );
result.lineTo( tx, midy );
Here is another example image to give you an idea of the Manhattan layout:
In the figure immediately above, the line between Dialog and Window has been overlapped (not quite visible at this zoom). The image illustrates how there can be multiple subclasses, and so detecting overlap must take into consideration multiple targets (tx, ty) for multiple sources (sx, sy) along the same mid-y line.
The midPointMap
variable is a hash set that can contain multiple values per key:
private MultiValueMap<Integer, Line2D.Double> midPointMap =
new MultiValueMap<Integer, Line2D.Double>();
This maps mid-y values against a set of line segments.
Any ideas how to not draw the line if it overlaps an existing line segment?
Update #1
Note that line segments for each "bus" are given in no particular order.
Upvotes: 0
Views: 3129
Reputation: 31171
Here is a complete solution:
// If line segments would overlap, this gets set to false.
//
boolean drawSegment = true;
Line2D.Double segment = new Line2D.Double( sx, midy, tx, midy );
// Associate the middle-y point with the bounds of the target object.
// On subsequent draws of targets with a similar mid-y, make sure that
// there are no overlapping lines.
//
if( midPointMap.put( midy, segment ) != null ) {
// Check previous lines for overlap. Each previous line segment has
// values in the form: (sx, mid-y)-(tx, mid-y), which map to
// (getX1(), midy)-(getX2(), midy).
//
for( Line2D.Double psegment : midPointMap.getValues( midy ) ) {
// If the lines have the same source point, and differ in their
// target point, then they might overlap
//
if( sx == psegment.getX1() && tx != psegment.getX2() ) {
double pdx = psegment.getX1() - psegment.getX2();
double cdx = sx - tx;
// At this juncture: the mid-y points are the same, the source
// points of the previous segment and the current segment are the
// same, and the target points of the segments differ.
//
// If both lines go in the same direction (relative to the same
// source point), then they overlap. The difference of the tx
// and X2 points is how much overlap exists.
//
// There are two actionable possibilities: (1) psegment is longer
// than the current segment; or (2) psegment is shorter.
//
// If psegment is longer, then no segment must be drawn. If
// psegment is shorter, the difference between psegment and the
// current segment must be drawn.
//
if( tx < sx && psegment.getX2() < sx ) {
// SEGMENT IS TO THE LEFT OF SOURCE
//
if( pdx > cdx ) {
// If the previous segment is longer, then draw nothing.
//
drawSegment = false;
}
else {
// If the previous segment is shorter, then draw the
// difference. That is, change the source point for
// this segment to the target point of the previous segment.
//
sx = psegment.getX2();
}
}
else if( tx > sx && psegment.getX2() > sx ) {
// SEGMENT IS TO THE RIGHT OF SOURCE
//
if( pdx < cdx ) {
// If the previous segment is longer, then draw nothing.
//
drawSegment = false;
}
else {
// If the previous segment is shorter, then draw the
// difference. That is, change the source point for
// this segment to the target point of the previous segment.
//
sx = psegment.getX2();
}
}
}
}
}
// Draw the line for the bus.
//
if( drawSegment ) {
result.moveTo( sx, midy );
result.lineTo( tx, midy );
}
Upvotes: 0
Reputation: 16383
I may be missing something (for example, I don't understand why you'd want to do this - maybe you are drawing things in different colors or something? If you are just trying to optimize a few write operations, I'm not sure that you are going to really gain anything by this).
But, assuming there is a good reason to do this, I'd think that the following algorithm would work:
I'm assuming that the layout of the segments is such that you can't have two segments that partially overlap each other, like this (segments are aA and bB):
a=====b===A=========B
If you do have that possibility, then you'll have to decide how to resolve that.
PS - please definitely add a brief description of why you want to eliminate those segments. I'm curious!
Upvotes: 1