CS456 Curves
Program - Curves
goal
To gain experience interacting with curves and polygons.
Polygon
Take your polygon class from the first program and implement Selectable for it, so that you can use it your applications.
New Objects
Add the following new objects to your classes. These should implement Drawable.
  • Curve{ just like Polygon } This has point just like Polygon. The difference is that these points define a Catmull-Rom curve rather than a polygon. If the first point and the last point are the same, then the curve is closed and can have a fill: color. This should implement Selectable. If the curve is not filled, then it is selected if the point is within 3 pixels of the curve. If the curve is filled then it is selected if the point is inside the curve.
  • Path{ contents:[ ... ], path:[ {x:10,y:20}, ...], slider:Group , sliderVal:0.5, width:100, height:200, model:[...] } This is a subclass of Group as implemented for the Layout assignment. It implements Selectable and Interactable as well as Layout. The contents are drawn just as they were before. They contents form the background for the slider that the user drags around. In addition, Path has a path attribute that is a list of points. These points define a Catmull-Rom curve. This curve is the path that the slider must follow.

    The slider: attribute is a Group. Its Layout properties are ignored. The slider: is drawn after contents: so that it always lies on top. The origin of the slider should always lie on the curve defined by the path and the sliderVal: attribute.

    The sliderVal: attribute is a value between 0.0 and 1.0. This defines a point on the path: curve where the slider's origin is to be located. Given the sliderVal: and the path: you determine the point where the origin of the slider: should be located. If the sliderVal=0.0 then the origin of the slider group should be at the first point in the path. If the sliderVal=1.0 then the origin should be at the last point in the path. For values in between 0.0 and 1.0 the slider should move smoothly along the path. By taking the first derivative of the path: at that point you can determine a vector that is the direction of travel at that point. The slider should be rotated so that it's up direction is opposite to the direction of travel. This will make the slider appear to follow the path: and to stay aligned with it.

    If Path receives a mouseDown() event that selects the slider then we begin dragging the slider. On every mouseMove() event we compute the nearest point on the path: curve and then use our linear length parameterization of the curve to compute a new value for sliderVal:. We then cause the display to update. This will make the slider drag along the path in a way that orients the slider to the path.

    Whenever the sliderVal: is changed it modifies the value referenced by the model: selection path. Whenever that referenced value in the model is changed, it changes sliderVal:.

    The Path object also implements Layout. It always reports min, desired, and max to be the values of the width: and height: attributes. If the Path is given a width or height different from these attributes, it should be scaled to fit the dimensions that it is given. This will allow Path to be embedded in a layout.

grading
__ 2) Polygons select correctly.
__ 2) slider: is placed at the correct point based on path: and sliderVal:
__ 2) slider: is rotated correctly relative to the path:
__ 2) sliderVal: correctly reflects the value reference by model:
__ 4) Interactive dragging of the slider works and correctly updates both sliderVal: and model:.
test 1
Select{ contents: [
		Polygon{ points: [ {x:300,y:200 }, {x:600,y:500 }, {x:500,y:500 }, {x:500,y:600 }, 
			{x:300,y:500 }, {x:100,y:600 }, {x:100,y:400 } ],
			border:{r:0,g:0,b:0},fill:{r:100,g:100,b:100} }
	]
}
test 2
Select{ contents: [
		Curve{ points: [ {x:300,y:200 }, {x:600,y:500 }, {x:500,y:500 }, {x:500,y:600 }, 
			{x:300,y:500 }, {x:100,y:600 }, {x:100,y:400 }, {x:300,y:200 } ],
			border:{r:0,g:0,b:0},fill:{r:100,g:100,b:100} }
	]
}
test 3
Select{ contents: [
		Curve{ points: [ {x:300,y:200 }, {x:600,y:500 }, {x:500,y:500 }, {x:500,y:600 }, 
			{x:300,y:500 }, {x:100,y:600 }, {x:100,y:400 }, {x:300,y:200 } ],
			border:{r:0,g:0,b:0} }
	]
}
test 4
Root{
	contents:[ VStack{ contents:[
		Button{ label:"zero", state:"idle", idle:{r:255,g:255,b:255}, hover:{r:200,g:200,b:255},
			active:{r:255,g:255,b:200}, model:["size" ], value:0.0,
			contents:[
				Rect{ class:"active", left:10, top:610, width:300, height:200, thickness:2, 
					border:{r:0,g:0,b:100}
				},
				Text{ class:"label", text:"wrong", x:720,y:250, font:"sans-serif",size:30 }
			]
		},

		Path{ path: [ {x:500,y:100}, {x:100,y:300}, {x:600,y:400}, {x:700,y:500} ],
			contents: [ 
				Curve{ points: [ {x:500,y:100}, {x:100,y:300}, {x:600,y:400}, {x:700,y:500} ],
						border:{r:255,g:0,b:0}, thickness:4
					}
				],
			slider: Group{ contents: [
						Polygon{ points:[ {x:0,y:-50}, {x:20,y:-20}, {x:40,y:-20}, {x:40,y:10}, 
								{x:0,y:20}, {x:-40,y:10}, {x:-40,y:-20}, {x:-20,y:20}],
								fill:{r:100, g:100, b:255}
						}
					]
				},
			sliderVal:1.0, width:800, height:600, model:[ "size" ]
		} ] }
	],
	model:{ size:0.5, location:{ number:144, street:"Inglewood" }, age:55 }
}