1919
2020import pixelitor .Canvas ;
2121import pixelitor .Views ;
22- import pixelitor .filters .gui .ColorParam ;
23- import pixelitor .filters .gui .EnumParam ;
24- import pixelitor .filters .gui .FilterButtonModel ;
25- import pixelitor .filters .gui .RangeParam ;
22+ import pixelitor .filters .gui .*;
2623import pixelitor .filters .util .ShapeWithColor ;
2724import pixelitor .io .FileIO ;
2825import pixelitor .utils .Distortion ;
@@ -80,7 +77,7 @@ public String toString() {
8077 }
8178
8279 private final EnumParam <CubeType > typeParam = new EnumParam <>("Type" , CubeType .class );
83- private final RangeParam sizeParam = new RangeParam ("Size" , 5 , 20 , 200 );
80+ private final GroupedRangeParam sizeParam = new GroupedRangeParam ("Size" , 5 , 20 , 200 );
8481 private final ColorParam topColorParam = new ColorParam ("Top Color" , WHITE , MANUAL_ALPHA_ONLY );
8582 private final ColorParam leftColorParam = new ColorParam ("Left Color" , LIGHT_GRAY , MANUAL_ALPHA_ONLY );
8683 private final ColorParam rightColorParam = new ColorParam ("Right Color" , GRAY , MANUAL_ALPHA_ONLY );
@@ -169,36 +166,40 @@ private List<ShapeWithColor> createShapes(int width, int height) {
169166 CubeType type = typeParam .getSelected ();
170167 boolean interlocking = type .isInterlocking ;
171168
172- double size = sizeParam .getValueAsDouble ();
169+ double size = sizeParam .getValueAsDouble (0 );
170+ double verSize = sizeParam .getValueAsDouble (1 );
171+
172+ double ratio = verSize / size ;
173+
173174 // isometric projection constants
174175 double longer = size * Math .cos (Math .PI / 6.0 );
175176 double shorter = size * Math .sin (Math .PI / 6.0 );
176177
177178 double horizontalSpacing = interlocking ? 3.0 * longer : 2.0 * longer ;
178- double verticalSpacing = interlocking ? size * 0.75 : (size + shorter );
179+ double verticalSpacing = ( interlocking ? size * 0.75 : (size + shorter )) * ratio ;
179180
180181 // add a buffer to ensure the pattern covers the entire image, even when offset
181182 int numCubesX = (int ) (width / horizontalSpacing ) + 2 ;
182- int numCubesY = (int ) (height / verticalSpacing ) + (interlocking ? 3 : 2 );
183+ int numCubesY = (int ) (height / Math . max ( 1.0 , verticalSpacing ) ) + (interlocking ? 3 : 2 );
183184
184185 double moveHorOffset = transform .getHorOffset (width );
185186 double moveVerOffset = transform .getVerOffset (height );
186187
187188 // special y-offset for interlocking to align rows correctly
188- double verOffset = moveVerOffset + (interlocking ? -size / 2.0 : 0 );
189+ double verOffset = moveVerOffset + (interlocking ? -size / 2.0 * ratio : 0 );
189190 for (int row = 0 ; row < numCubesY ; row ++) {
190191 // offset every other row for a staggered pattern
191192 double horOffset = moveHorOffset + (row % 2 == 0 ? 0 : longer );
192193 if (interlocking ) {
193- // interlocking pattern requires additional horizontal shift
194+ // the interlocking pattern requires additional horizontal shift
194195 horOffset *= 1.5 ;
195196 }
196197
197198 for (int col = 0 ; col < numCubesX ; col ++) {
198199 double baseX = horOffset + col * horizontalSpacing ;
199200 double baseY = verOffset + row * verticalSpacing ;
200201
201- addCubeShapes (shapes , baseX , baseY , longer , shorter , size , type ,
202+ addCubeShapes (shapes , baseX , baseY , longer , shorter , size , ratio , type ,
202203 topColor , rightColor , leftColor );
203204 }
204205 }
@@ -214,11 +215,11 @@ private record CubeFaces(Path2D top, Path2D right, Path2D left) {
214215 */
215216 private static void addCubeShapes (List <ShapeWithColor > shapes ,
216217 double baseX , double baseY ,
217- double longer , double shorter , double size ,
218+ double longer , double shorter , double size , double ratio ,
218219 CubeType type ,
219220 Color topColor , Color rightColor , Color leftColor ) {
220221
221- CubeFaces faces = createCubeFaces (baseX , baseY , longer , shorter , size , type .isInterlocking );
222+ CubeFaces faces = createCubeFaces (baseX , baseY , longer , shorter , size , ratio , type .isInterlocking );
222223
223224 shapes .add (new ShapeWithColor (faces .top , topColor ));
224225 shapes .add (new ShapeWithColor (faces .right , rightColor ));
@@ -247,103 +248,103 @@ private static void addCubeShapes(List<ShapeWithColor> shapes,
247248 /**
248249 * Creates the three visible faces of a single cube.
249250 */
250- private static CubeFaces createCubeFaces (double baseX , double baseY , double longer , double shorter , double size , boolean interlocking ) {
251+ private static CubeFaces createCubeFaces (double baseX , double baseY , double longer , double shorter , double size , double ratio , boolean interlocking ) {
251252 Path2D topFace ;
252253 Path2D rightFace ;
253254 Path2D leftFace ;
254255
255256 if (interlocking ) {
256- topFace = createInterlockingTop (baseX , baseY , longer , shorter , size );
257- rightFace = createInterlockingRight (baseX , baseY , longer , shorter , size );
258- leftFace = createInterlockingLeft (baseX , baseY , longer , shorter , size );
257+ topFace = createInterlockingTop (baseX , baseY , longer , shorter , size , ratio );
258+ rightFace = createInterlockingRight (baseX , baseY , longer , shorter , size , ratio );
259+ leftFace = createInterlockingLeft (baseX , baseY , longer , shorter , size , ratio );
259260 } else {
260- topFace = createBasicTop (baseX , baseY , longer , shorter , size );
261- rightFace = createBasicRight (baseX , baseY , longer , shorter , size );
262- leftFace = createBasicLeft (baseX , baseY , longer , shorter , size );
261+ topFace = createBasicTop (baseX , baseY , longer , shorter , size , ratio );
262+ rightFace = createBasicRight (baseX , baseY , longer , shorter , size , ratio );
263+ leftFace = createBasicLeft (baseX , baseY , longer , shorter , size , ratio );
263264 }
264265 return new CubeFaces (topFace , rightFace , leftFace );
265266 }
266267
267268 /**
268269 * Creates the path for the top face of a basic cube.
269270 */
270- private static Path2D createBasicTop (double baseX , double baseY , double longer , double shorter , double size ) {
271+ private static Path2D createBasicTop (double baseX , double baseY , double longer , double shorter , double size , double ratio ) {
271272 Path2D top = new Path2D .Double ();
272273 top .moveTo (baseX , baseY );
273- top .lineTo (baseX - longer , baseY - shorter );
274- top .lineTo (baseX , baseY - size );
275- top .lineTo (baseX + longer , baseY - shorter );
274+ top .lineTo (baseX - longer , baseY - shorter * ratio );
275+ top .lineTo (baseX , baseY - size * ratio );
276+ top .lineTo (baseX + longer , baseY - shorter * ratio );
276277 top .closePath ();
277278 return top ;
278279 }
279280
280281 /**
281282 * Creates the path for the right face of a basic cube.
282283 */
283- private static Path2D createBasicRight (double baseX , double baseY , double longer , double shorter , double size ) {
284+ private static Path2D createBasicRight (double baseX , double baseY , double longer , double shorter , double size , double ratio ) {
284285 Path2D right = new Path2D .Double ();
285286 right .moveTo (baseX , baseY );
286- right .lineTo (baseX + longer , baseY - shorter );
287- right .lineTo (baseX + longer , baseY - shorter + size );
288- right .lineTo (baseX , baseY + size );
287+ right .lineTo (baseX + longer , baseY - shorter * ratio );
288+ right .lineTo (baseX + longer , baseY - shorter * ratio + size * ratio );
289+ right .lineTo (baseX , baseY + size * ratio );
289290 right .closePath ();
290291 return right ;
291292 }
292293
293294 /**
294295 * Creates the path for the left face of a basic cube.
295296 */
296- private static Path2D createBasicLeft (double baseX , double baseY , double longer , double shorter , double size ) {
297+ private static Path2D createBasicLeft (double baseX , double baseY , double longer , double shorter , double size , double ratio ) {
297298 Path2D left = new Path2D .Double ();
298299 left .moveTo (baseX , baseY );
299- left .lineTo (baseX - longer , baseY - shorter );
300- left .lineTo (baseX - longer , baseY - shorter + size );
301- left .lineTo (baseX , baseY + size );
300+ left .lineTo (baseX - longer , baseY - shorter * ratio );
301+ left .lineTo (baseX - longer , baseY - shorter * ratio + size * ratio );
302+ left .lineTo (baseX , baseY + size * ratio );
302303 left .closePath ();
303304 return left ;
304305 }
305306
306307 /**
307308 * Creates the path for the top face of an interlocking cube.
308309 */
309- private static Path2D createInterlockingTop (double baseX , double baseY , double longer , double shorter , double size ) {
310+ private static Path2D createInterlockingTop (double baseX , double baseY , double longer , double shorter , double size , double ratio ) {
310311 Path2D top = new Path2D .Double ();
311312 top .moveTo (baseX , baseY );
312- top .lineTo (baseX - longer , baseY - shorter );
313- top .lineTo (baseX - longer / 2.0 , baseY - size / 2.0 - shorter / 2.0 );
314- top .lineTo (baseX , baseY - shorter );
315- top .lineTo (baseX + longer / 2.0 , baseY - size / 2.0 - shorter / 2.0 );
316- top .lineTo (baseX + longer , baseY - shorter );
313+ top .lineTo (baseX - longer , baseY - shorter * ratio );
314+ top .lineTo (baseX - longer / 2.0 , baseY - ( size / 2.0 + shorter / 2.0 ) * ratio );
315+ top .lineTo (baseX , baseY - shorter * ratio );
316+ top .lineTo (baseX + longer / 2.0 , baseY - ( size / 2.0 + shorter / 2.0 ) * ratio );
317+ top .lineTo (baseX + longer , baseY - shorter * ratio );
317318 top .closePath ();
318319 return top ;
319320 }
320321
321322 /**
322323 * Creates the path for the right face of an interlocking cube.
323324 */
324- private static Path2D createInterlockingRight (double baseX , double baseY , double longer , double shorter , double size ) {
325+ private static Path2D createInterlockingRight (double baseX , double baseY , double longer , double shorter , double size , double ratio ) {
325326 Path2D right = new Path2D .Double ();
326327 right .moveTo (baseX , baseY );
327- right .lineTo (baseX + longer , baseY - shorter );
328- right .lineTo (baseX + longer , baseY - shorter + size / 2.0 );
329- right .lineTo (baseX + longer / 2.0 , baseY + 0.25 * size );
330- right .lineTo (baseX + longer / 2.0 , baseY - shorter / 2.0 + size );
331- right .lineTo (baseX , baseY + size );
328+ right .lineTo (baseX + longer , baseY - shorter * ratio );
329+ right .lineTo (baseX + longer , baseY + (- shorter + size / 2.0 ) * ratio );
330+ right .lineTo (baseX + longer / 2.0 , baseY + ( 0.25 * size ) * ratio );
331+ right .lineTo (baseX + longer / 2.0 , baseY + (- shorter / 2.0 + size ) * ratio );
332+ right .lineTo (baseX , baseY + size * ratio );
332333 right .closePath ();
333334 return right ;
334335 }
335336
336337 /**
337338 * Creates the path for the left face of an interlocking cube.
338339 */
339- private static Path2D createInterlockingLeft (double baseX , double baseY , double longer , double shorter , double size ) {
340+ private static Path2D createInterlockingLeft (double baseX , double baseY , double longer , double shorter , double size , double ratio ) {
340341 Path2D left = new Path2D .Double ();
341342 left .moveTo (baseX , baseY );
342- left .lineTo (baseX - longer , baseY - shorter );
343- left .lineTo (baseX - longer , baseY - shorter + size / 2.0 );
344- left .lineTo (baseX - longer / 2.0 , baseY + 0.25 * size );
345- left .lineTo (baseX - longer / 2.0 , baseY - shorter / 2.0 + size );
346- left .lineTo (baseX , baseY + size );
343+ left .lineTo (baseX - longer , baseY - shorter * ratio );
344+ left .lineTo (baseX - longer , baseY + (- shorter + size / 2.0 ) * ratio );
345+ left .lineTo (baseX - longer / 2.0 , baseY + ( 0.25 * size ) * ratio );
346+ left .lineTo (baseX - longer / 2.0 , baseY + (- shorter / 2.0 + size ) * ratio );
347+ left .lineTo (baseX , baseY + size * ratio );
347348 left .closePath ();
348349 return left ;
349350 }
0 commit comments