summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrandomguy3 <randomguy3@7c02a99a-9b00-45e3-bf44-6f3dd7fddb64>2012-01-16 16:38:35 +0000
committerrandomguy3 <randomguy3@7c02a99a-9b00-45e3-bf44-6f3dd7fddb64>2012-01-16 16:38:35 +0000
commit525059964fbaf380ad2c3079b965d64e7c6d06d1 (patch)
tree12f0dda7ee8a3d32b20ca038461287ed58c94378
parent69ab4ccc98cfd63cc10099de0393dc675b20b646 (diff)
Some cleanup before calculating proper head and tail endpoints for Edge
git-svn-id: https://tikzit.svn.sourceforge.net/svnroot/tikzit/trunk@379 7c02a99a-9b00-45e3-bf44-6f3dd7fddb64
-rw-r--r--tikzit/src/common/Edge.h2
-rw-r--r--tikzit/src/common/Edge.m43
-rw-r--r--tikzit/src/common/Node.h43
-rw-r--r--tikzit/src/common/Node.m43
-rw-r--r--tikzit/src/common/NodeStyle.h2
-rw-r--r--tikzit/src/common/NodeStyle.m3
-rw-r--r--tikzit/src/common/util.h27
-rw-r--r--tikzit/src/common/util.m90
-rw-r--r--tikzit/src/linux/Node+Render.m30
-rw-r--r--tikzit/src/osx/NodeLayer.m2
10 files changed, 235 insertions, 50 deletions
diff --git a/tikzit/src/common/Edge.h b/tikzit/src/common/Edge.h
index 460ecc4..6069b9f 100644
--- a/tikzit/src/common/Edge.h
+++ b/tikzit/src/common/Edge.h
@@ -67,6 +67,8 @@ typedef enum {
// these are all cached values computed from the above
NSPoint src;
NSPoint targ;
+ NSPoint head;
+ NSPoint tail;
NSPoint cp1;
NSPoint cp2;
NSPoint mid;
diff --git a/tikzit/src/common/Edge.m b/tikzit/src/common/Edge.m
index c89be6d..680ddfa 100644
--- a/tikzit/src/common/Edge.m
+++ b/tikzit/src/common/Edge.m
@@ -72,6 +72,13 @@
return NO;
}
+- (NSPoint) _findContactPointOn:(Node*)node at:(float)angle {
+ return [node point];
+ Transformer *shapeTrans = [node shapeTransformer];
+ NSRect searchArea = [node boundsUsingShapeTransform:shapeTrans];
+ NSPoint
+}
+
- (void)updateControls {
// check for external modification to the node locations
if (src.x != [source point].x || src.y != [source point].y ||
@@ -90,9 +97,6 @@
float angleSrc = 0.0f;
float angleTarg = 0.0f;
- bend = normaliseAngleDeg (bend);
- inAngle = normaliseAngleDeg (inAngle);
- outAngle = normaliseAngleDeg (outAngle);
if (bendMode == EdgeBendModeBasic) {
float angle = good_atan(dx, dy);
float bnd = (float)bend * (M_PI / 180.0f);
@@ -102,6 +106,9 @@
angleSrc = (float)outAngle * (M_PI / 180.0f);
angleTarg = (float)inAngle * (M_PI / 180.0f);
}
+
+ head = [self _findContactPointOn:source at:angleSrc];
+ tail = [self _findContactPointOn:target at:angleTarg];
// give a default distance for self-loops
float cdist = (dx==0.0f && dy==0.0f) ? weight : sqrt(dx*dx + dy*dy) * weight;
@@ -139,8 +146,8 @@
float angle = good_atan(dx, dy);
float bnd = (float)bend * (M_PI / 180.0f);
- outAngle = round((angle - bnd) * (180.0f/M_PI));
- inAngle = round((M_PI + angle + bnd) * (180.0f/M_PI));
+ [self setOutAngle:round((angle - bnd) * (180.0f/M_PI))];
+ [self setInAngle:round((M_PI + angle + bnd) * (180.0f/M_PI))];
dirty = YES;
}
@@ -155,9 +162,7 @@
bend1 = outAngle - angle;
bend2 = angle - inAngle;
- bend = (bend1 + bend2) / 2;
-
- dirty = YES;
+ [self setBend:(bend1 + bend2) / 2];
}
- (BOOL)isSelfLoop {
@@ -200,13 +205,13 @@
- (int)inAngle {return inAngle;}
- (void)setInAngle:(int)a {
- inAngle = a;
+ inAngle = normaliseAngleDeg (a);
dirty = YES;
}
- (int)outAngle {return outAngle;}
- (void)setOutAngle:(int)a {
- outAngle = a;
+ outAngle = normaliseAngleDeg (a);
dirty = YES;
}
@@ -218,7 +223,7 @@
- (int)bend {return bend;}
- (void)setBend:(int)b {
- bend = b;
+ bend = normaliseAngleDeg (b);
dirty = YES;
}
@@ -368,22 +373,22 @@
bendMode = EdgeBendModeBasic;
if ([data isAtomSet:@"bend left"]) {
- bend = -30;
+ [self setBend:-30];
} else if ([data isAtomSet:@"bend right"]) {
- bend = 30;
+ [self setBend:30];
} else if ([data propertyForKey:@"bend left"] != nil) {
NSString *bnd = [data propertyForKey:@"bend left"];
- bend = -[bnd intValue];
+ [self setBend:-[bnd intValue]];
} else if ([data propertyForKey:@"bend right"] != nil) {
NSString *bnd = [data propertyForKey:@"bend right"];
- bend = [bnd intValue];
+ [self setBend:[bnd intValue]];
} else {
- bend = 0;
+ [self setBend:0];
if ([data propertyForKey:@"in"] != nil && [data propertyForKey:@"out"] != nil) {
bendMode = EdgeBendModeInOut;
- inAngle = [[data propertyForKey:@"in"] intValue];
- outAngle = [[data propertyForKey:@"out"] intValue];
+ [self setInAngle:[[data propertyForKey:@"in"] intValue]];
+ [self setOutAngle:[[data propertyForKey:@"out"] intValue]];
}
}
@@ -492,7 +497,7 @@
inAngle = outAngle;
outAngle = f;
- bend = -1 * bend;
+ [self setBend:-bend];
dirty = YES;
}
diff --git a/tikzit/src/common/Node.h b/tikzit/src/common/Node.h
index 73a4653..c3a604d 100644
--- a/tikzit/src/common/Node.h
+++ b/tikzit/src/common/Node.h
@@ -29,6 +29,9 @@
#import "NodeStyle.h"
#import "GraphElementData.h"
+@class Shape;
+@class Transformer;
+
/*!
@class Node
@brief A graph node, with associated location and style data.
@@ -42,6 +45,14 @@
}
/*!
+ @property shape
+ @brief The shape to use
+ @detail This is a convenience property that resolves the shape name
+ from the style, and uses a circle if there is no style.
+ */
+@property (readonly) Shape *shape;
+
+/*!
@property point
@brief The point where this node is located.
*/
@@ -86,6 +97,38 @@
- (id)init;
/*!
+ @brief Composes the shape transformer with another transformer
+ @param t The transform to apply before the shape transform
+ @result A transformer that first maps according to t, then according
+ to -shapeTransformer.
+ */
+- (Transformer*) shapeTransformerFromTransformer:(Transformer*)t;
+
+/*!
+ @brief A transformer that may be used to convert the shape to the
+ right position and scale
+ */
+- (Transformer*) shapeTransformer;
+
+/*!
+ @brief The bounding rect in the given co-ordinate system
+ @detail This is the bounding rect of the shape (after being
+ suitably translated and scaled). The label is not
+ considered.
+ @param shapeTrans The mapping from graph co-ordinates to the required
+ co-ordinates
+ @result The bounding rectangle
+ */
+- (NSRect) boundsUsingShapeTransform:(Transformer*)shapeTrans;
+
+/*!
+ @brief The bounding rect in graph co-ordinates
+ @detail This is the bounding rect of the shape (after being suitably
+ translated and scaled). The label is not considered.
+ */
+- (NSRect) boundingRect;
+
+/*!
@brief Try to attach a style of the correct name from the given style list.
@param styles an array of styles.
@result YES if successfully attached, NO otherwise.
diff --git a/tikzit/src/common/Node.m b/tikzit/src/common/Node.m
index 3421325..8880826 100644
--- a/tikzit/src/common/Node.m
+++ b/tikzit/src/common/Node.m
@@ -23,6 +23,9 @@
#import "Node.h"
+#import "Shape.h"
+#import "ShapeNames.h"
+
@implementation Node
@@ -41,6 +44,46 @@
return self;
}
+- (Shape*) shape {
+ if (style) {
+ return [Shape shapeForName:[style shapeName]];
+ } else {
+ return [Shape shapeForName:SHAPE_CIRCLE];
+ }
+}
+
+- (Transformer*) shapeTransformerFromTransformer:(Transformer*)t {
+ // we take a copy to keep the reflection attributes
+ Transformer *transformer = [[t copy] autorelease];
+ NSPoint screenPos = [t toScreen:point];
+ [transformer setOrigin:screenPos];
+ float scale = [t scale];
+ if (style) {
+ scale *= [style scale];
+ }
+ [transformer setScale:scale];
+ return transformer;
+}
+
+- (Transformer*) shapeTransformer {
+ float scale = 1.0f;
+ if (style) {
+ scale = [style scale];
+ }
+ return [Transformer transformerWithOrigin:point andScale:scale];
+}
+
+- (NSRect) boundsUsingShapeTransform:(Transformer*)shapeTrans {
+ float strokeThickness = style ? [style strokeThickness] : [NodeStyle defaultStrokeThickness];
+ NSRect screenBounds = [shapeTrans rectToScreen:[[self shape] boundingRect]];
+ screenBounds = NSInsetRect(screenBounds, -strokeThickness, -strokeThickness);
+ return screenBounds;
+}
+
+- (NSRect) boundingRect {
+ return [self boundsUsingShapeTransform:[self shapeTransformer]];
+}
+
- (BOOL)attachStyleFromTable:(NSArray*)styles {
NSString *style_name = [[[data propertyForKey:@"style"] retain] autorelease];
diff --git a/tikzit/src/common/NodeStyle.h b/tikzit/src/common/NodeStyle.h
index 4c0e883..eed5b32 100644
--- a/tikzit/src/common/NodeStyle.h
+++ b/tikzit/src/common/NodeStyle.h
@@ -93,6 +93,8 @@
@property (readonly) BOOL strokeColorIsKnown;
@property (readonly) BOOL fillColorIsKnown;
++ (int) defaultStrokeThickness;
+
/*!
@brief Designated initializer. Construct a blank style with name 'new'.
@result A default style.
diff --git a/tikzit/src/common/NodeStyle.m b/tikzit/src/common/NodeStyle.m
index d3e8f09..a2d22c7 100644
--- a/tikzit/src/common/NodeStyle.m
+++ b/tikzit/src/common/NodeStyle.m
@@ -26,11 +26,12 @@
@implementation NodeStyle
++ (int) defaultStrokeThickness { return 1; }
- (id)init {
self = [super initWithNotificationName:@"NodeStylePropertyChanged"];
if (self != nil) {
- strokeThickness = 1;
+ strokeThickness = [NodeStyle defaultStrokeThickness];
scale = 1.0f;
strokeColorRGB = [[ColorRGB alloc] initWithRed:0 green:0 blue:0];
fillColorRGB = [[ColorRGB alloc] initWithRed:255 green:255 blue:255];
diff --git a/tikzit/src/common/util.h b/tikzit/src/common/util.h
index 74871dc..82ba9d8 100644
--- a/tikzit/src/common/util.h
+++ b/tikzit/src/common/util.h
@@ -26,6 +26,14 @@
#define M_PI 3.141592654
#endif
+#ifndef MAX
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+#ifndef MIN
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
/*!
@brief Compute a bounding rectangle for two given points.
@param p1 a point.
@@ -85,6 +93,25 @@ float good_atan(float dx, float dy);
*/
float bezierInterpolate(float dist, float c0, float c1, float c2, float c3);
+/*!
+ * @brief Find whether two line segments intersect
+ * @param l1start The starting point of line segment 1
+ * @param l1end The ending point of line segment 1
+ * @param l2start The starting point of line segment 2
+ * @param l2end The ending point of line segment 2
+ * @param result A location to store the intersection point
+ * @result YES if they intersect, NO if they do not
+ */
+BOOL lineSegmentsIntersect(NSPoint l1start, NSPoint l1end, NSPoint l2start, NSPoint l2end, NSPoint *result);
+
+/*!
+ * @brief Find whether a line segment enters a rectangle
+ * @param lineStart The starting point of the line segment
+ * @param lineEnd The ending point of the line segment
+ * @param rect The rectangle
+ * @result YES if they intersect, NO if they do not
+ */
+BOOL lineSegmentIntersectsRect(NSPoint lineStart, NSPoint lineEnd, NSRect rect);
/*!
@brief Round val to nearest stepSize
diff --git a/tikzit/src/common/util.m b/tikzit/src/common/util.m
index feef76c..0445126 100644
--- a/tikzit/src/common/util.m
+++ b/tikzit/src/common/util.m
@@ -82,6 +82,91 @@ float bezierInterpolate(float dist, float c0, float c1, float c2, float c3) {
(dist*dist*dist) * c3;
}
+void lineCoeffsFromPoints(NSPoint p1, NSPoint p2, float *A, float *B, float *C) {
+ *A = p2.y - p1.y;
+ *B = p1.x - p2.x;
+ *C = (*A) * p1.x + (*B) * p1.y;
+}
+
+static BOOL lineSegmentContainsPoint(NSPoint l1, NSPoint l2, float x, float y) {
+ float maxX = l1.x > l2.x ? l2.x : l1.x;
+ float minX = l1.x > l2.x ? l1.x : l2.x;
+ float maxY = l1.y > l2.y ? l2.y : l1.y;
+ float minY = l1.y > l2.y ? l1.y : l2.y;
+ return x >= minX && x <= maxX && y >= minY && y <= maxY;
+}
+
+BOOL lineSegmentsIntersect(NSPoint l1start, NSPoint l1end, NSPoint l2start, NSPoint l2end, NSPoint *result) {
+ // Ax + By = C
+ float A1, B1, C1;
+ lineCoeffsFromPoints(l1start, l1end, &A1, &B1, &C1);
+ float A2, B2, C2;
+ lineCoeffsFromPoints(l2start, l2end, &A2, &B2, &C2);
+
+ float det = A1*B2 - A2*B1;
+ if (det == 0.0f) {
+ // parallel
+ return NO;
+ } else {
+ float x = (B2*C1 - B1*C2)/det;
+ float y = (A1*C2 - A2*C1)/det;
+
+ if (lineSegmentContainsPoint(l1start, l1end, x, y) &&
+ lineSegmentContainsPoint(l2start, l2end, x, y)) {
+ if (result) {
+ (*result).x = x;
+ (*result).y = y;
+ }
+ return YES;
+ }
+ }
+ return NO;
+}
+
+BOOL lineSegmentIntersectsRect(NSPoint lineStart, NSPoint lineEnd, NSRect rect) {
+ const float rectMaxX = NSMaxX(rect);
+ const float rectMinX = NSMinX(rect);
+ const float rectMaxY = NSMaxY(rect);
+ const float rectMinY = NSMinY(rect);
+
+ // check if the segment is entirely to one side of the rect
+ if (lineStart.x > rectMaxX && lineEnd.x > rectMaxX) {
+ return NO;
+ }
+ if (lineStart.x < rectMinX && lineEnd.x < rectMinX) {
+ return NO;
+ }
+ if (lineStart.y > rectMaxY && lineEnd.y > rectMaxY) {
+ return NO;
+ }
+ if (lineStart.y < rectMinY && lineEnd.y < rectMinY) {
+ return NO;
+ }
+
+ // Now check whether the (infinite) line intersects the rect
+ // (if it does, so does the segment, due to above checks)
+
+ // Ax + By = C
+ float A, B, C;
+ lineCoeffsFromPoints(lineStart, lineEnd, &A, &B, &C);
+
+ const float tlVal = A * rectMinX + B * rectMaxY - C;
+ const float trVal = A * rectMaxX + B * rectMaxY - C;
+ const float blVal = A * rectMinX + B * rectMinY - C;
+ const float brVal = A * rectMaxX + B * rectMinY - C;
+
+ if (tlVal < 0 && trVal < 0 && blVal < 0 && brVal < 0) {
+ // rect below line
+ return NO;
+ }
+ if (tlVal > 0 && trVal > 0 && blVal > 0 && brVal > 0) {
+ // rect above line
+ return NO;
+ }
+
+ return YES;
+}
+
float roundToNearest(float stepSize, float val) {
if (stepSize==0.0f) return val;
else return round(val/stepSize)*stepSize;
@@ -92,10 +177,10 @@ float radiansToDegrees (float radians) {
}
int normaliseAngleDeg (int degrees) {
- while (degrees >= 360) {
+ while (degrees > 180) {
degrees -= 360;
}
- while (degrees <= -360) {
+ while (degrees <= -180) {
degrees += 360;
}
return degrees;
@@ -111,3 +196,4 @@ NSString *alphaHex(unsigned short sh) {
}
+// vi:ft=objc:noet:ts=4:sts=4:sw=4
diff --git a/tikzit/src/linux/Node+Render.m b/tikzit/src/linux/Node+Render.m
index f168924..7450dba 100644
--- a/tikzit/src/linux/Node+Render.m
+++ b/tikzit/src/linux/Node+Render.m
@@ -21,7 +21,6 @@
#import "Shape+Render.h"
#import "ShapeNames.h"
-#define DEFAULT_STROKE_WIDTH 2.0f
#define MAX_LABEL_LENGTH 10
#define LABEL_PADDING_X 2
#define LABEL_PADDING_Y 2
@@ -29,30 +28,7 @@
@implementation Node (Render)
- (Transformer*) shapeTransformerForSurface:(id<Surface>)surface {
- Transformer *transformer = [[[surface transformer] copy] autorelease];
- NSPoint screenPos = [[surface transformer] toScreen:point];
- [transformer setOrigin:screenPos];
- CGFloat scale = [[surface transformer] scale];
- if (style) {
- scale *= [style scale];
- }
- [transformer setScale:scale];
- return transformer;
-}
-
-- (Shape*) shape {
- if (style) {
- return [Shape shapeForName:[style shapeName]];
- } else {
- return [Shape shapeForName:SHAPE_CIRCLE];
- }
-}
-
-- (NSRect) boundsUsingShapeTransform:(Transformer*)shapeTrans {
- float strokeThickness = style ? [style strokeThickness] : DEFAULT_STROKE_WIDTH;
- NSRect screenBounds = [shapeTrans rectToScreen:[[self shape] boundingRect]];
- screenBounds = NSInsetRect(screenBounds, -strokeThickness, -strokeThickness);
- return screenBounds;
+ return [self shapeTransformerFromTransformer:[surface transformer]];
}
- (NSRect) boundsOnSurface:(id<Surface>)surface {
@@ -147,7 +123,7 @@
- (void) renderToSurface:(id <Surface>)surface withContext:(id<RenderContext>)context state:(enum NodeState)state {
Transformer *shapeTrans = [self shapeTransformerForSurface:surface];
- float strokeThickness = style ? [style strokeThickness] : DEFAULT_STROKE_WIDTH;
+ float strokeThickness = style ? [style strokeThickness] : [NodeStyle defaultStrokeThickness];
[context saveState];
@@ -185,7 +161,7 @@
return NO;
}
- float strokeThickness = style ? [style strokeThickness] : DEFAULT_STROKE_WIDTH;
+ float strokeThickness = style ? [style strokeThickness] : [NodeStyle defaultStrokeThickness];
id<RenderContext> ctx = [surface createRenderContext];
[ctx setLineWidth:strokeThickness];
[[self shape] drawPathWithTransform:shapeTrans andContext:ctx];
diff --git a/tikzit/src/osx/NodeLayer.m b/tikzit/src/osx/NodeLayer.m
index da01bec..2c37c26 100644
--- a/tikzit/src/osx/NodeLayer.m
+++ b/tikzit/src/osx/NodeLayer.m
@@ -73,7 +73,7 @@
if ([node style] != nil) {
return [node.style strokeThickness];
} else {
- return 1;
+ return [NodeStyle defaultStrokeThickness];
}
}